aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rapidio
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2016-03-22 17:26:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-22 18:36:02 -0400
commit9a0b062742e7e039273c0c2ba4b96ad9ec7e7d8f (patch)
tree902e3fd63e79f4911b2896a67e8e06d93626abd4 /drivers/rapidio
parentb6cb95e8eb97e51a1a1b5609b59df859cc6dc2f2 (diff)
rapidio: add global inbound port write interfaces
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>
Diffstat (limited to 'drivers/rapidio')
-rw-r--r--drivers/rapidio/devices/tsi721.c24
-rw-r--r--drivers/rapidio/rio.c142
2 files changed, 122 insertions, 44 deletions
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c
index db95d71ba4e9..5e1d52674e17 100644
--- a/drivers/rapidio/devices/tsi721.c
+++ b/drivers/rapidio/devices/tsi721.c
@@ -36,8 +36,6 @@
36 36
37#include "tsi721.h" 37#include "tsi721.h"
38 38
39#define DEBUG_PW /* Inbound Port-Write debugging */
40
41static void tsi721_omsg_handler(struct tsi721_device *priv, int ch); 39static void tsi721_omsg_handler(struct tsi721_device *priv, int ch);
42static void tsi721_imsg_handler(struct tsi721_device *priv, int ch); 40static void tsi721_imsg_handler(struct tsi721_device *priv, int ch);
43 41
@@ -282,30 +280,15 @@ static void tsi721_pw_dpc(struct work_struct *work)
282{ 280{
283 struct tsi721_device *priv = container_of(work, struct tsi721_device, 281 struct tsi721_device *priv = container_of(work, struct tsi721_device,
284 pw_work); 282 pw_work);
285 u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)]; /* Use full size PW message 283 union rio_pw_msg pwmsg;
286 buffer for RIO layer */
287 284
288 /* 285 /*
289 * Process port-write messages 286 * Process port-write messages
290 */ 287 */
291 while (kfifo_out_spinlocked(&priv->pw_fifo, (unsigned char *)msg_buffer, 288 while (kfifo_out_spinlocked(&priv->pw_fifo, (unsigned char *)&pwmsg,
292 TSI721_RIO_PW_MSG_SIZE, &priv->pw_fifo_lock)) { 289 TSI721_RIO_PW_MSG_SIZE, &priv->pw_fifo_lock)) {
293 /* Process one message */
294#ifdef DEBUG_PW
295 {
296 u32 i;
297 pr_debug("%s : Port-Write Message:", __func__);
298 for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); ) {
299 pr_debug("0x%02x: %08x %08x %08x %08x", i*4,
300 msg_buffer[i], msg_buffer[i + 1],
301 msg_buffer[i + 2], msg_buffer[i + 3]);
302 i += 4;
303 }
304 pr_debug("\n");
305 }
306#endif
307 /* Pass the port-write message to RIO core for processing */ 290 /* Pass the port-write message to RIO core for processing */
308 rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer); 291 rio_inb_pwrite_handler(&priv->mport, &pwmsg);
309 } 292 }
310} 293}
311 294
@@ -2702,6 +2685,7 @@ static void tsi721_remove(struct pci_dev *pdev)
2702 2685
2703 tsi721_disable_ints(priv); 2686 tsi721_disable_ints(priv);
2704 tsi721_free_irq(priv); 2687 tsi721_free_irq(priv);
2688 flush_scheduled_work();
2705 rio_unregister_mport(&priv->mport); 2689 rio_unregister_mport(&priv->mport);
2706 2690
2707 tsi721_unregister_dma(priv); 2691 tsi721_unregister_dma(priv);
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 @@
30 30
31#include "rio.h" 31#include "rio.h"
32 32
33/*
34 * struct rio_pwrite - RIO portwrite event
35 * @node: Node in list of doorbell events
36 * @pwcback: Doorbell event callback
37 * @context: Handler specific context to pass on event
38 */
39struct rio_pwrite {
40 struct list_head node;
41
42 int (*pwcback)(struct rio_mport *mport, void *context,
43 union rio_pw_msg *msg, int step);
44 void *context;
45};
46
33MODULE_DESCRIPTION("RapidIO Subsystem Core"); 47MODULE_DESCRIPTION("RapidIO Subsystem Core");
34MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>"); 48MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>");
35MODULE_AUTHOR("Alexandre Bounine <alexandre.bounine@idt.com>"); 49MODULE_AUTHOR("Alexandre Bounine <alexandre.bounine@idt.com>");
@@ -514,7 +528,71 @@ int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res)
514} 528}
515 529
516/** 530/**
517 * rio_request_inb_pwrite - request inbound port-write message service 531 * rio_add_mport_pw_handler - add port-write message handler into the list
532 * of mport specific pw handlers
533 * @mport: RIO master port to bind the portwrite callback
534 * @context: Handler specific context to pass on event
535 * @pwcback: Callback to execute when portwrite is received
536 *
537 * Returns 0 if the request has been satisfied.
538 */
539int rio_add_mport_pw_handler(struct rio_mport *mport, void *context,
540 int (*pwcback)(struct rio_mport *mport,
541 void *context, union rio_pw_msg *msg, int step))
542{
543 int rc = 0;
544 struct rio_pwrite *pwrite;
545
546 pwrite = kzalloc(sizeof(struct rio_pwrite), GFP_KERNEL);
547 if (!pwrite) {
548 rc = -ENOMEM;
549 goto out;
550 }
551
552 pwrite->pwcback = pwcback;
553 pwrite->context = context;
554 mutex_lock(&mport->lock);
555 list_add_tail(&pwrite->node, &mport->pwrites);
556 mutex_unlock(&mport->lock);
557out:
558 return rc;
559}
560EXPORT_SYMBOL_GPL(rio_add_mport_pw_handler);
561
562/**
563 * rio_del_mport_pw_handler - remove port-write message handler from the list
564 * of mport specific pw handlers
565 * @mport: RIO master port to bind the portwrite callback
566 * @context: Registered handler specific context to pass on event
567 * @pwcback: Registered callback function
568 *
569 * Returns 0 if the request has been satisfied.
570 */
571int rio_del_mport_pw_handler(struct rio_mport *mport, void *context,
572 int (*pwcback)(struct rio_mport *mport,
573 void *context, union rio_pw_msg *msg, int step))
574{
575 int rc = -EINVAL;
576 struct rio_pwrite *pwrite;
577
578 mutex_lock(&mport->lock);
579 list_for_each_entry(pwrite, &mport->pwrites, node) {
580 if (pwrite->pwcback == pwcback && pwrite->context == context) {
581 list_del(&pwrite->node);
582 kfree(pwrite);
583 rc = 0;
584 break;
585 }
586 }
587 mutex_unlock(&mport->lock);
588
589 return rc;
590}
591EXPORT_SYMBOL_GPL(rio_del_mport_pw_handler);
592
593/**
594 * rio_request_inb_pwrite - request inbound port-write message service for
595 * specific RapidIO device
518 * @rdev: RIO device to which register inbound port-write callback routine 596 * @rdev: RIO device to which register inbound port-write callback routine
519 * @pwcback: Callback routine to execute when port-write is received 597 * @pwcback: Callback routine to execute when port-write is received
520 * 598 *
@@ -539,6 +617,7 @@ EXPORT_SYMBOL_GPL(rio_request_inb_pwrite);
539 617
540/** 618/**
541 * rio_release_inb_pwrite - release inbound port-write message service 619 * rio_release_inb_pwrite - release inbound port-write message service
620 * associated with specific RapidIO device
542 * @rdev: RIO device which registered for inbound port-write callback 621 * @rdev: RIO device which registered for inbound port-write callback
543 * 622 *
544 * Removes callback from the rio_dev structure. Returns 0 if the request 623 * Removes callback from the rio_dev structure. Returns 0 if the request
@@ -1002,52 +1081,66 @@ rd_err:
1002} 1081}
1003 1082
1004/** 1083/**
1005 * rio_inb_pwrite_handler - process inbound port-write message 1084 * rio_inb_pwrite_handler - inbound port-write message handler
1085 * @mport: mport device associated with port-write
1006 * @pw_msg: pointer to inbound port-write message 1086 * @pw_msg: pointer to inbound port-write message
1007 * 1087 *
1008 * Processes an inbound port-write message. Returns 0 if the request 1088 * Processes an inbound port-write message. Returns 0 if the request
1009 * has been satisfied. 1089 * has been satisfied.
1010 */ 1090 */
1011int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) 1091int rio_inb_pwrite_handler(struct rio_mport *mport, union rio_pw_msg *pw_msg)
1012{ 1092{
1013 struct rio_dev *rdev; 1093 struct rio_dev *rdev;
1014 u32 err_status, em_perrdet, em_ltlerrdet; 1094 u32 err_status, em_perrdet, em_ltlerrdet;
1015 int rc, portnum; 1095 int rc, portnum;
1016 1096 struct rio_pwrite *pwrite;
1017 rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL);
1018 if (rdev == NULL) {
1019 /* Device removed or enumeration error */
1020 pr_debug("RIO: %s No matching device for CTag 0x%08x\n",
1021 __func__, pw_msg->em.comptag);
1022 return -EIO;
1023 }
1024
1025 pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev));
1026 1097
1027#ifdef DEBUG_PW 1098#ifdef DEBUG_PW
1028 { 1099 {
1029 u32 i; 1100 u32 i;
1030 for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) { 1101
1102 pr_debug("%s: PW to mport_%d:\n", __func__, mport->id);
1103 for (i = 0; i < RIO_PW_MSG_SIZE / sizeof(u32); i = i + 4) {
1031 pr_debug("0x%02x: %08x %08x %08x %08x\n", 1104 pr_debug("0x%02x: %08x %08x %08x %08x\n",
1032 i*4, pw_msg->raw[i], pw_msg->raw[i + 1], 1105 i * 4, pw_msg->raw[i], pw_msg->raw[i + 1],
1033 pw_msg->raw[i + 2], pw_msg->raw[i + 3]); 1106 pw_msg->raw[i + 2], pw_msg->raw[i + 3]);
1034 i += 4; 1107 }
1035 }
1036 } 1108 }
1037#endif 1109#endif
1038 1110
1039 /* Call an external service function (if such is registered 1111 rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL);
1040 * for this device). This may be the service for endpoints that send 1112 if (rdev) {
1041 * device-specific port-write messages. End-point messages expected 1113 pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev));
1042 * to be handled completely by EP specific device driver. 1114 } else {
1115 pr_debug("RIO: %s No matching device for CTag 0x%08x\n",
1116 __func__, pw_msg->em.comptag);
1117 }
1118
1119 /* Call a device-specific handler (if it is registered for the device).
1120 * This may be the service for endpoints that send device-specific
1121 * port-write messages. End-point messages expected to be handled
1122 * completely by EP specific device driver.
1043 * For switches rc==0 signals that no standard processing required. 1123 * For switches rc==0 signals that no standard processing required.
1044 */ 1124 */
1045 if (rdev->pwcback != NULL) { 1125 if (rdev && rdev->pwcback) {
1046 rc = rdev->pwcback(rdev, pw_msg, 0); 1126 rc = rdev->pwcback(rdev, pw_msg, 0);
1047 if (rc == 0) 1127 if (rc == 0)
1048 return 0; 1128 return 0;
1049 } 1129 }
1050 1130
1131 mutex_lock(&mport->lock);
1132 list_for_each_entry(pwrite, &mport->pwrites, node)
1133 pwrite->pwcback(mport, pwrite->context, pw_msg, 0);
1134 mutex_unlock(&mport->lock);
1135
1136 if (!rdev)
1137 return 0;
1138
1139 /*
1140 * FIXME: The code below stays as it was before for now until we decide
1141 * how to do default PW handling in combination with per-mport callbacks
1142 */
1143
1051 portnum = pw_msg->em.is_port & 0xFF; 1144 portnum = pw_msg->em.is_port & 0xFF;
1052 1145
1053 /* Check if device and route to it are functional: 1146 /* Check if device and route to it are functional:
@@ -2060,6 +2153,7 @@ int rio_mport_initialize(struct rio_mport *mport)
2060 mport->nscan = NULL; 2153 mport->nscan = NULL;
2061 mutex_init(&mport->lock); 2154 mutex_init(&mport->lock);
2062 mport->pwe_refcnt = 0; 2155 mport->pwe_refcnt = 0;
2156 INIT_LIST_HEAD(&mport->pwrites);
2063 2157
2064 return 0; 2158 return 0;
2065} 2159}