diff options
Diffstat (limited to 'drivers/rapidio/rio.c')
-rw-r--r-- | drivers/rapidio/rio.c | 142 |
1 files changed, 118 insertions, 24 deletions
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 673774bf6dd6..17973d3caa88 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -30,6 +30,20 @@ #include "rio.h" +/* + * struct rio_pwrite - RIO portwrite event + * @node: Node in list of doorbell events + * @pwcback: Doorbell event callback + * @context: Handler specific context to pass on event + */ +struct rio_pwrite { + struct list_head node; + + int (*pwcback)(struct rio_mport *mport, void *context, + union rio_pw_msg *msg, int step); + void *context; +}; + MODULE_DESCRIPTION("RapidIO Subsystem Core"); MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>"); MODULE_AUTHOR("Alexandre Bounine <alexandre.bounine@idt.com>"); @@ -514,7 +528,71 @@ int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res) } /** - * rio_request_inb_pwrite - request inbound port-write message service + * rio_add_mport_pw_handler - add port-write message handler into the list + * of mport specific pw handlers + * @mport: RIO master port to bind the portwrite callback + * @context: Handler specific context to pass on event + * @pwcback: Callback to execute when portwrite is received + * + * Returns 0 if the request has been satisfied. + */ +int rio_add_mport_pw_handler(struct rio_mport *mport, void *context, + int (*pwcback)(struct rio_mport *mport, + void *context, union rio_pw_msg *msg, int step)) +{ + int rc = 0; + struct rio_pwrite *pwrite; + + pwrite = kzalloc(sizeof(struct rio_pwrite), GFP_KERNEL); + if (!pwrite) { + rc = -ENOMEM; + goto out; + } + + pwrite->pwcback = pwcback; + pwrite->context = context; + mutex_lock(&mport->lock); + list_add_tail(&pwrite->node, &mport->pwrites); + mutex_unlock(&mport->lock); +out: + return rc; +} +EXPORT_SYMBOL_GPL(rio_add_mport_pw_handler); + +/** + * rio_del_mport_pw_handler - remove port-write message handler from the list + * of mport specific pw handlers + * @mport: RIO master port to bind the portwrite callback + * @context: Registered handler specific context to pass on event + * @pwcback: Registered callback function + * + * Returns 0 if the request has been satisfied. + */ +int rio_del_mport_pw_handler(struct rio_mport *mport, void *context, + int (*pwcback)(struct rio_mport *mport, + void *context, union rio_pw_msg *msg, int step)) +{ + int rc = -EINVAL; + struct rio_pwrite *pwrite; + + mutex_lock(&mport->lock); + list_for_each_entry(pwrite, &mport->pwrites, node) { + if (pwrite->pwcback == pwcback && pwrite->context == context) { + list_del(&pwrite->node); + kfree(pwrite); + rc = 0; + break; + } + } + mutex_unlock(&mport->lock); + + return rc; +} +EXPORT_SYMBOL_GPL(rio_del_mport_pw_handler); + +/** + * rio_request_inb_pwrite - request inbound port-write message service for + * specific RapidIO device * @rdev: RIO device to which register inbound port-write callback routine * @pwcback: Callback routine to execute when port-write is received * @@ -539,6 +617,7 @@ EXPORT_SYMBOL_GPL(rio_request_inb_pwrite); /** * rio_release_inb_pwrite - release inbound port-write message service + * associated with specific RapidIO device * @rdev: RIO device which registered for inbound port-write callback * * Removes callback from the rio_dev structure. Returns 0 if the request @@ -1002,52 +1081,66 @@ rd_err: } /** - * rio_inb_pwrite_handler - process inbound port-write message + * rio_inb_pwrite_handler - inbound port-write message handler + * @mport: mport device associated with port-write * @pw_msg: pointer to inbound port-write message * * Processes an inbound port-write message. Returns 0 if the request * has been satisfied. */ -int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) +int rio_inb_pwrite_handler(struct rio_mport *mport, union rio_pw_msg *pw_msg) { struct rio_dev *rdev; u32 err_status, em_perrdet, em_ltlerrdet; int rc, portnum; - - rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL); - if (rdev == NULL) { - /* Device removed or enumeration error */ - pr_debug("RIO: %s No matching device for CTag 0x%08x\n", - __func__, pw_msg->em.comptag); - return -EIO; - } - - pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev)); + struct rio_pwrite *pwrite; #ifdef DEBUG_PW { - u32 i; - for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) { + u32 i; + + pr_debug("%s: PW to mport_%d:\n", __func__, mport->id); + for (i = 0; i < RIO_PW_MSG_SIZE / sizeof(u32); i = i + 4) { pr_debug("0x%02x: %08x %08x %08x %08x\n", - i*4, pw_msg->raw[i], pw_msg->raw[i + 1], - pw_msg->raw[i + 2], pw_msg->raw[i + 3]); - i += 4; - } + i * 4, pw_msg->raw[i], pw_msg->raw[i + 1], + pw_msg->raw[i + 2], pw_msg->raw[i + 3]); + } } #endif - /* Call an external service function (if such is registered - * for this device). This may be the service for endpoints that send - * device-specific port-write messages. End-point messages expected - * to be handled completely by EP specific device driver. + rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL); + if (rdev) { + pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev)); + } else { + pr_debug("RIO: %s No matching device for CTag 0x%08x\n", + __func__, pw_msg->em.comptag); + } + + /* Call a device-specific handler (if it is registered for the device). + * This may be the service for endpoints that send device-specific + * port-write messages. End-point messages expected to be handled + * completely by EP specific device driver. * For switches rc==0 signals that no standard processing required. */ - if (rdev->pwcback != NULL) { + if (rdev && rdev->pwcback) { rc = rdev->pwcback(rdev, pw_msg, 0); if (rc == 0) return 0; } + mutex_lock(&mport->lock); + list_for_each_entry(pwrite, &mport->pwrites, node) + pwrite->pwcback(mport, pwrite->context, pw_msg, 0); + mutex_unlock(&mport->lock); + + if (!rdev) + return 0; + + /* + * FIXME: The code below stays as it was before for now until we decide + * how to do default PW handling in combination with per-mport callbacks + */ + portnum = pw_msg->em.is_port & 0xFF; /* Check if device and route to it are functional: @@ -2060,6 +2153,7 @@ int rio_mport_initialize(struct rio_mport *mport) mport->nscan = NULL; mutex_init(&mport->lock); mport->pwe_refcnt = 0; + INIT_LIST_HEAD(&mport->pwrites); return 0; } |