rapidio: add global inbound port write interfaces
authorAlexandre Bounine <alexandre.bounine@idt.com>
Tue, 22 Mar 2016 21:26:44 +0000 (14:26 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 22 Mar 2016 22:36:02 +0000 (15:36 -0700)
Add new Port Write handler registration interfaces that attach PW
handlers to local mport device objects.  This is different from old
interface that attaches PW callback to individual RapidIO device.  The
new interfaces are intended for use for common event handling (e.g.
hot-plug notifications) while the old interface is available for
individual device drivers.

This patch is based on patch proposed by Andre van Herk but preserves
existing per-device interface and adds lock protection for list
handling.

Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Cc: Matt Porter <mporter@kernel.crashing.org>
Cc: Aurelien Jacquiot <a-jacquiot@ti.com>
Cc: Andre van Herk <andre.van.herk@prodrive-technologies.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/fsl_rio.h
arch/powerpc/sysdev/fsl_rmu.c
drivers/rapidio/devices/tsi721.c
drivers/rapidio/rio.c
include/linux/rio.h
include/linux/rio_drv.h

index 385371acc0d03a7dfa529e3aac9e0f4bf1971ad6..f5bf38b9459585fcd1f8d4a34ed24c8067e67daa 100644 (file)
@@ -726,6 +726,7 @@ int fsl_rio_setup(struct platform_device *dev)
                fsl_rio_inbound_mem_init(priv);
 
                dbell->mport[i] = port;
+               pw->mport[i] = port;
 
                if (rio_register_mport(port)) {
                        release_resource(&port->iores);
index d53407a34f32884909deb932625b49de9990b22d..12dd18fd479561dfafdc053463465ce0d73c4a07 100644 (file)
@@ -97,6 +97,7 @@ struct fsl_rio_dbell {
 };
 
 struct fsl_rio_pw {
+       struct rio_mport *mport[MAX_PORT_NUM];
        struct device *dev;
        struct rio_pw_regs __iomem *pw_regs;
        struct rio_port_write_msg port_write_msg;
index ffe0ee8327682496e4367d609a8cc86e1c482b72..c1826de4e749dc1ab15987831d310fb91f0fc6c9 100644 (file)
@@ -481,14 +481,14 @@ pw_done:
 static void fsl_pw_dpc(struct work_struct *work)
 {
        struct fsl_rio_pw *pw = container_of(work, struct fsl_rio_pw, pw_work);
-       u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)];
+       union rio_pw_msg msg_buffer;
+       int i;
 
        /*
         * Process port-write messages
         */
-       while (kfifo_out_spinlocked(&pw->pw_fifo, (unsigned char *)msg_buffer,
+       while (kfifo_out_spinlocked(&pw->pw_fifo, (unsigned char *)&msg_buffer,
                         RIO_PW_MSG_SIZE, &pw->pw_fifo_lock)) {
-               /* Process one message */
 #ifdef DEBUG_PW
                {
                u32 i;
@@ -496,15 +496,19 @@ static void fsl_pw_dpc(struct work_struct *work)
                for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
                        if ((i%4) == 0)
                                pr_debug("\n0x%02x: 0x%08x", i*4,
-                                        msg_buffer[i]);
+                                        msg_buffer.raw[i]);
                        else
-                               pr_debug(" 0x%08x", msg_buffer[i]);
+                               pr_debug(" 0x%08x", msg_buffer.raw[i]);
                }
                pr_debug("\n");
                }
 #endif
                /* Pass the port-write message to RIO core for processing */
-               rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
+               for (i = 0; i < MAX_PORT_NUM; i++) {
+                       if (pw->mport[i])
+                               rio_inb_pwrite_handler(pw->mport[i],
+                                                      &msg_buffer);
+               }
        }
 }
 
index db95d71ba4e9afd7d164c4bcb683c5a250c1673d..5e1d52674e174395a20c6d6e8c5692a36f905100 100644 (file)
@@ -36,8 +36,6 @@
 
 #include "tsi721.h"
 
-#define DEBUG_PW       /* Inbound Port-Write debugging */
-
 static void tsi721_omsg_handler(struct tsi721_device *priv, int ch);
 static void tsi721_imsg_handler(struct tsi721_device *priv, int ch);
 
@@ -282,30 +280,15 @@ static void tsi721_pw_dpc(struct work_struct *work)
 {
        struct tsi721_device *priv = container_of(work, struct tsi721_device,
                                                    pw_work);
-       u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)]; /* Use full size PW message
-                                                       buffer for RIO layer */
+       union rio_pw_msg pwmsg;
 
        /*
         * Process port-write messages
         */
-       while (kfifo_out_spinlocked(&priv->pw_fifo, (unsigned char *)msg_buffer,
+       while (kfifo_out_spinlocked(&priv->pw_fifo, (unsigned char *)&pwmsg,
                         TSI721_RIO_PW_MSG_SIZE, &priv->pw_fifo_lock)) {
-               /* Process one message */
-#ifdef DEBUG_PW
-               {
-               u32 i;
-               pr_debug("%s : Port-Write Message:", __func__);
-               for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); ) {
-                       pr_debug("0x%02x: %08x %08x %08x %08x", i*4,
-                               msg_buffer[i], msg_buffer[i + 1],
-                               msg_buffer[i + 2], msg_buffer[i + 3]);
-                       i += 4;
-               }
-               pr_debug("\n");
-               }
-#endif
                /* Pass the port-write message to RIO core for processing */
-               rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
+               rio_inb_pwrite_handler(&priv->mport, &pwmsg);
        }
 }
 
@@ -2702,6 +2685,7 @@ static void tsi721_remove(struct pci_dev *pdev)
 
        tsi721_disable_ints(priv);
        tsi721_free_irq(priv);
+       flush_scheduled_work();
        rio_unregister_mport(&priv->mport);
 
        tsi721_unregister_dma(priv);
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;
 }
index cb3c47543bb09751e2561c49abc0ad12d23ca492..44f3da512c1583ad0f3324aa31dd8081d8485339 100644 (file)
@@ -245,6 +245,7 @@ enum rio_phy_type {
 /**
  * struct rio_mport - RIO master port info
  * @dbells: List of doorbell events
+ * @pwrites: List of portwrite events
  * @node: Node in global list of master ports
  * @nnode: Node in network list of master ports
  * @net: RIO net this mport is attached to
@@ -270,6 +271,7 @@ enum rio_phy_type {
  */
 struct rio_mport {
        struct list_head dbells;        /* list of doorbell events */
+       struct list_head pwrites;       /* list of portwrite events */
        struct list_head node;  /* node in global list of ports */
        struct list_head nnode; /* node in net list of ports */
        struct rio_net *net;    /* RIO net this mport is attached to */
index 9fb2bcd0a9876c1d56ba87ab904b46fc61b25135..5dff9a4cb6757be7d07b363686698d468612668e 100644 (file)
@@ -374,7 +374,14 @@ extern void rio_unmap_inb_region(struct rio_mport *mport, dma_addr_t lstart);
 extern int rio_request_inb_pwrite(struct rio_dev *,
                        int (*)(struct rio_dev *, union rio_pw_msg*, int));
 extern int rio_release_inb_pwrite(struct rio_dev *);
-extern int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg);
+extern int rio_add_mport_pw_handler(struct rio_mport *mport, void *dev_id,
+                       int (*pwcback)(struct rio_mport *mport, void *dev_id,
+                       union rio_pw_msg *msg, int step));
+extern int rio_del_mport_pw_handler(struct rio_mport *mport, void *dev_id,
+                       int (*pwcback)(struct rio_mport *mport, void *dev_id,
+                       union rio_pw_msg *msg, int step));
+extern int rio_inb_pwrite_handler(struct rio_mport *mport,
+                                 union rio_pw_msg *pw_msg);
 extern void rio_pw_enable(struct rio_mport *mport, int enable);
 
 /* LDM support */
This page took 0.03352 seconds and 5 git commands to generate.