]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/rapidio/rio.c
rapidio: add global inbound port write interfaces
[karo-tx-linux.git] / drivers / rapidio / rio.c
index 673774bf6dd676b2d7a37b2b6dddf480e5eba2d3..17973d3caa88721f6230cab8d8607d13d5606ae0 100644 (file)
 
 #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;
 }