aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rapidio/rio.c
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2013-05-24 18:55:05 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-24 19:22:50 -0400
commita11650e11093ed57dca78bf16e7836517c599098 (patch)
tree9823799d4c54337971b4654ea9e5510131dae9c5 /drivers/rapidio/rio.c
parent585dc0c2f68981c02a0bb6fc8fe191a3f513959c (diff)
rapidio: make enumeration/discovery configurable
Systems that use RapidIO fabric may need to implement their own enumeration and discovery methods which are better suitable for needs of a target application. The following set of patches is intended to simplify process of introduction of new RapidIO fabric enumeration/discovery methods. The first patch offers ability to add new RapidIO enumeration/discovery methods using kernel configuration options. This new configuration option mechanism allows to select statically linked or modular enumeration/discovery method(s) from the list of existing methods or use external module(s). This patch also updates the currently existing enumeration/discovery code to be used as a statically linked or modular method. The corresponding configuration option is named "Basic enumeration/discovery" method. This is the only one configuration option available today but new methods are expected to be introduced after adoption of provided patches. The second patch address a long time complaint of RapidIO subsystem users regarding fabric enumeration/discovery start sequence. Existing implementation offers only a boot-time enumeration/discovery start which requires synchronized boot of all endpoints in RapidIO network. While it works for small closed configurations with limited number of endpoints, using this approach in systems with large number of endpoints is quite challenging. To eliminate requirement for synchronized start the second patch introduces RapidIO enumeration/discovery start from user space. For compatibility with the existing RapidIO subsystem implementation, automatic boot time enumeration/discovery start can be configured in by specifying "rio-scan.scan=1" command line parameter if statically linked basic enumeration method is selected. This patch: Rework to implement RapidIO enumeration/discovery method selection combined with ability to use enumeration/discovery as a kernel module. This patch adds ability to introduce new RapidIO enumeration/discovery methods using kernel configuration options. Configuration option mechanism allows to select statically linked or modular enumeration/discovery method from the list of existing methods or use external modules. If a modular enumeration/discovery is selected each RapidIO mport device can have its own method attached to it. The existing enumeration/discovery code was updated to be used as statically linked or modular method. This configuration option is named "Basic enumeration/discovery" method. Several common routines have been moved from rio-scan.c to make them available to other enumeration methods and reduce number of exported symbols. Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Cc: Matt Porter <mporter@kernel.crashing.org> Cc: Li Yang <leoli@freescale.com> Cc: Kumar Gala <galak@kernel.crashing.org> Cc: Andre van Herk <andre.van.herk@Prodrive.nl> Cc: Micha Nelissen <micha.nelissen@Prodrive.nl> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rapidio/rio.c')
-rw-r--r--drivers/rapidio/rio.c222
1 files changed, 215 insertions, 7 deletions
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index d553b5d13722..6e75dda34799 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -31,7 +31,11 @@
31 31
32#include "rio.h" 32#include "rio.h"
33 33
34static LIST_HEAD(rio_devices);
35static DEFINE_SPINLOCK(rio_global_list_lock);
36
34static LIST_HEAD(rio_mports); 37static LIST_HEAD(rio_mports);
38static DEFINE_MUTEX(rio_mport_list_lock);
35static unsigned char next_portid; 39static unsigned char next_portid;
36static DEFINE_SPINLOCK(rio_mmap_lock); 40static DEFINE_SPINLOCK(rio_mmap_lock);
37 41
@@ -53,6 +57,32 @@ u16 rio_local_get_device_id(struct rio_mport *port)
53} 57}
54 58
55/** 59/**
60 * rio_add_device- Adds a RIO device to the device model
61 * @rdev: RIO device
62 *
63 * Adds the RIO device to the global device list and adds the RIO
64 * device to the RIO device list. Creates the generic sysfs nodes
65 * for an RIO device.
66 */
67int rio_add_device(struct rio_dev *rdev)
68{
69 int err;
70
71 err = device_add(&rdev->dev);
72 if (err)
73 return err;
74
75 spin_lock(&rio_global_list_lock);
76 list_add_tail(&rdev->global_list, &rio_devices);
77 spin_unlock(&rio_global_list_lock);
78
79 rio_create_sysfs_dev_files(rdev);
80
81 return 0;
82}
83EXPORT_SYMBOL_GPL(rio_add_device);
84
85/**
56 * rio_request_inb_mbox - request inbound mailbox service 86 * rio_request_inb_mbox - request inbound mailbox service
57 * @mport: RIO master port from which to allocate the mailbox resource 87 * @mport: RIO master port from which to allocate the mailbox resource
58 * @dev_id: Device specific pointer to pass on event 88 * @dev_id: Device specific pointer to pass on event
@@ -489,6 +519,7 @@ rio_mport_get_physefb(struct rio_mport *port, int local,
489 519
490 return ext_ftr_ptr; 520 return ext_ftr_ptr;
491} 521}
522EXPORT_SYMBOL_GPL(rio_mport_get_physefb);
492 523
493/** 524/**
494 * rio_get_comptag - Begin or continue searching for a RIO device by component tag 525 * rio_get_comptag - Begin or continue searching for a RIO device by component tag
@@ -521,6 +552,7 @@ exit:
521 spin_unlock(&rio_global_list_lock); 552 spin_unlock(&rio_global_list_lock);
522 return rdev; 553 return rdev;
523} 554}
555EXPORT_SYMBOL_GPL(rio_get_comptag);
524 556
525/** 557/**
526 * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port. 558 * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port.
@@ -545,6 +577,107 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
545 regval); 577 regval);
546 return 0; 578 return 0;
547} 579}
580EXPORT_SYMBOL_GPL(rio_set_port_lockout);
581
582/**
583 * rio_switch_init - Sets switch operations for a particular vendor switch
584 * @rdev: RIO device
585 * @do_enum: Enumeration/Discovery mode flag
586 *
587 * Searches the RIO switch ops table for known switch types. If the vid
588 * and did match a switch table entry, then call switch initialization
589 * routine to setup switch-specific routines.
590 */
591void rio_switch_init(struct rio_dev *rdev, int do_enum)
592{
593 struct rio_switch_ops *cur = __start_rio_switch_ops;
594 struct rio_switch_ops *end = __end_rio_switch_ops;
595
596 while (cur < end) {
597 if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
598 pr_debug("RIO: calling init routine for %s\n",
599 rio_name(rdev));
600 cur->init_hook(rdev, do_enum);
601 break;
602 }
603 cur++;
604 }
605
606 if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
607 pr_debug("RIO: adding STD routing ops for %s\n",
608 rio_name(rdev));
609 rdev->rswitch->add_entry = rio_std_route_add_entry;
610 rdev->rswitch->get_entry = rio_std_route_get_entry;
611 rdev->rswitch->clr_table = rio_std_route_clr_table;
612 }
613
614 if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
615 printk(KERN_ERR "RIO: missing routing ops for %s\n",
616 rio_name(rdev));
617}
618EXPORT_SYMBOL_GPL(rio_switch_init);
619
620/**
621 * rio_enable_rx_tx_port - enable input receiver and output transmitter of
622 * given port
623 * @port: Master port associated with the RIO network
624 * @local: local=1 select local port otherwise a far device is reached
625 * @destid: Destination ID of the device to check host bit
626 * @hopcount: Number of hops to reach the target
627 * @port_num: Port (-number on switch) to enable on a far end device
628 *
629 * Returns 0 or 1 from on General Control Command and Status Register
630 * (EXT_PTR+0x3C)
631 */
632int rio_enable_rx_tx_port(struct rio_mport *port,
633 int local, u16 destid,
634 u8 hopcount, u8 port_num)
635{
636#ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS
637 u32 regval;
638 u32 ext_ftr_ptr;
639
640 /*
641 * enable rx input tx output port
642 */
643 pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = "
644 "%d, port_num = %d)\n", local, destid, hopcount, port_num);
645
646 ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount);
647
648 if (local) {
649 rio_local_read_config_32(port, ext_ftr_ptr +
650 RIO_PORT_N_CTL_CSR(0),
651 &regval);
652 } else {
653 if (rio_mport_read_config_32(port, destid, hopcount,
654 ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), &regval) < 0)
655 return -EIO;
656 }
657
658 if (regval & RIO_PORT_N_CTL_P_TYP_SER) {
659 /* serial */
660 regval = regval | RIO_PORT_N_CTL_EN_RX_SER
661 | RIO_PORT_N_CTL_EN_TX_SER;
662 } else {
663 /* parallel */
664 regval = regval | RIO_PORT_N_CTL_EN_RX_PAR
665 | RIO_PORT_N_CTL_EN_TX_PAR;
666 }
667
668 if (local) {
669 rio_local_write_config_32(port, ext_ftr_ptr +
670 RIO_PORT_N_CTL_CSR(0), regval);
671 } else {
672 if (rio_mport_write_config_32(port, destid, hopcount,
673 ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0)
674 return -EIO;
675 }
676#endif
677 return 0;
678}
679EXPORT_SYMBOL_GPL(rio_enable_rx_tx_port);
680
548 681
549/** 682/**
550 * rio_chk_dev_route - Validate route to the specified device. 683 * rio_chk_dev_route - Validate route to the specified device.
@@ -610,6 +743,7 @@ rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount)
610 743
611 return 0; 744 return 0;
612} 745}
746EXPORT_SYMBOL_GPL(rio_mport_chk_dev_access);
613 747
614/** 748/**
615 * rio_chk_dev_access - Validate access to the specified device. 749 * rio_chk_dev_access - Validate access to the specified device.
@@ -941,6 +1075,7 @@ rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
941 return RIO_GET_BLOCK_ID(reg_val); 1075 return RIO_GET_BLOCK_ID(reg_val);
942 } 1076 }
943} 1077}
1078EXPORT_SYMBOL_GPL(rio_mport_get_efb);
944 1079
945/** 1080/**
946 * rio_mport_get_feature - query for devices' extended features 1081 * rio_mport_get_feature - query for devices' extended features
@@ -997,6 +1132,7 @@ rio_mport_get_feature(struct rio_mport * port, int local, u16 destid,
997 1132
998 return 0; 1133 return 0;
999} 1134}
1135EXPORT_SYMBOL_GPL(rio_mport_get_feature);
1000 1136
1001/** 1137/**
1002 * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did 1138 * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did
@@ -1246,6 +1382,71 @@ EXPORT_SYMBOL_GPL(rio_dma_prep_slave_sg);
1246 1382
1247#endif /* CONFIG_RAPIDIO_DMA_ENGINE */ 1383#endif /* CONFIG_RAPIDIO_DMA_ENGINE */
1248 1384
1385/**
1386 * rio_register_scan - enumeration/discovery method registration interface
1387 * @mport_id: mport device ID for which fabric scan routine has to be set
1388 * (RIO_MPORT_ANY = set for all available mports)
1389 * @scan_ops: enumeration/discovery control structure
1390 *
1391 * Assigns enumeration or discovery method to the specified mport device (or all
1392 * available mports if RIO_MPORT_ANY is specified).
1393 * Returns error if the mport already has an enumerator attached to it.
1394 * In case of RIO_MPORT_ANY ignores ports with valid scan routines and returns
1395 * an error if was unable to find at least one available mport.
1396 */
1397int rio_register_scan(int mport_id, struct rio_scan *scan_ops)
1398{
1399 struct rio_mport *port;
1400 int rc = -EBUSY;
1401
1402 mutex_lock(&rio_mport_list_lock);
1403 list_for_each_entry(port, &rio_mports, node) {
1404 if (port->id == mport_id || mport_id == RIO_MPORT_ANY) {
1405 if (port->nscan && mport_id == RIO_MPORT_ANY)
1406 continue;
1407 else if (port->nscan)
1408 break;
1409
1410 port->nscan = scan_ops;
1411 rc = 0;
1412
1413 if (mport_id != RIO_MPORT_ANY)
1414 break;
1415 }
1416 }
1417 mutex_unlock(&rio_mport_list_lock);
1418
1419 return rc;
1420}
1421EXPORT_SYMBOL_GPL(rio_register_scan);
1422
1423/**
1424 * rio_unregister_scan - removes enumeration/discovery method from mport
1425 * @mport_id: mport device ID for which fabric scan routine has to be
1426 * unregistered (RIO_MPORT_ANY = set for all available mports)
1427 *
1428 * Removes enumeration or discovery method assigned to the specified mport
1429 * device (or all available mports if RIO_MPORT_ANY is specified).
1430 */
1431int rio_unregister_scan(int mport_id)
1432{
1433 struct rio_mport *port;
1434
1435 mutex_lock(&rio_mport_list_lock);
1436 list_for_each_entry(port, &rio_mports, node) {
1437 if (port->id == mport_id || mport_id == RIO_MPORT_ANY) {
1438 if (port->nscan)
1439 port->nscan = NULL;
1440 if (mport_id != RIO_MPORT_ANY)
1441 break;
1442 }
1443 }
1444 mutex_unlock(&rio_mport_list_lock);
1445
1446 return 0;
1447}
1448EXPORT_SYMBOL_GPL(rio_unregister_scan);
1449
1249static void rio_fixup_device(struct rio_dev *dev) 1450static void rio_fixup_device(struct rio_dev *dev)
1250{ 1451{
1251} 1452}
@@ -1274,7 +1475,7 @@ static void disc_work_handler(struct work_struct *_work)
1274 work = container_of(_work, struct rio_disc_work, work); 1475 work = container_of(_work, struct rio_disc_work, work);
1275 pr_debug("RIO: discovery work for mport %d %s\n", 1476 pr_debug("RIO: discovery work for mport %d %s\n",
1276 work->mport->id, work->mport->name); 1477 work->mport->id, work->mport->name);
1277 rio_disc_mport(work->mport); 1478 work->mport->nscan->discover(work->mport);
1278} 1479}
1279 1480
1280int rio_init_mports(void) 1481int rio_init_mports(void)
@@ -1290,12 +1491,15 @@ int rio_init_mports(void)
1290 * First, run enumerations and check if we need to perform discovery 1491 * First, run enumerations and check if we need to perform discovery
1291 * on any of the registered mports. 1492 * on any of the registered mports.
1292 */ 1493 */
1494 mutex_lock(&rio_mport_list_lock);
1293 list_for_each_entry(port, &rio_mports, node) { 1495 list_for_each_entry(port, &rio_mports, node) {
1294 if (port->host_deviceid >= 0) 1496 if (port->host_deviceid >= 0) {
1295 rio_enum_mport(port); 1497 if (port->nscan)
1296 else 1498 port->nscan->enumerate(port);
1499 } else
1297 n++; 1500 n++;
1298 } 1501 }
1502 mutex_unlock(&rio_mport_list_lock);
1299 1503
1300 if (!n) 1504 if (!n)
1301 goto no_disc; 1505 goto no_disc;
@@ -1322,14 +1526,16 @@ int rio_init_mports(void)
1322 } 1526 }
1323 1527
1324 n = 0; 1528 n = 0;
1529 mutex_lock(&rio_mport_list_lock);
1325 list_for_each_entry(port, &rio_mports, node) { 1530 list_for_each_entry(port, &rio_mports, node) {
1326 if (port->host_deviceid < 0) { 1531 if (port->host_deviceid < 0 && port->nscan) {
1327 work[n].mport = port; 1532 work[n].mport = port;
1328 INIT_WORK(&work[n].work, disc_work_handler); 1533 INIT_WORK(&work[n].work, disc_work_handler);
1329 queue_work(rio_wq, &work[n].work); 1534 queue_work(rio_wq, &work[n].work);
1330 n++; 1535 n++;
1331 } 1536 }
1332 } 1537 }
1538 mutex_unlock(&rio_mport_list_lock);
1333 1539
1334 flush_workqueue(rio_wq); 1540 flush_workqueue(rio_wq);
1335 pr_debug("RIO: destroy discovery workqueue\n"); 1541 pr_debug("RIO: destroy discovery workqueue\n");
@@ -1342,8 +1548,6 @@ no_disc:
1342 return 0; 1548 return 0;
1343} 1549}
1344 1550
1345device_initcall_sync(rio_init_mports);
1346
1347static int hdids[RIO_MAX_MPORTS + 1]; 1551static int hdids[RIO_MAX_MPORTS + 1];
1348 1552
1349static int rio_get_hdid(int index) 1553static int rio_get_hdid(int index)
@@ -1371,7 +1575,10 @@ int rio_register_mport(struct rio_mport *port)
1371 1575
1372 port->id = next_portid++; 1576 port->id = next_portid++;
1373 port->host_deviceid = rio_get_hdid(port->id); 1577 port->host_deviceid = rio_get_hdid(port->id);
1578 port->nscan = NULL;
1579 mutex_lock(&rio_mport_list_lock);
1374 list_add_tail(&port->node, &rio_mports); 1580 list_add_tail(&port->node, &rio_mports);
1581 mutex_unlock(&rio_mport_list_lock);
1375 return 0; 1582 return 0;
1376} 1583}
1377 1584
@@ -1386,3 +1593,4 @@ EXPORT_SYMBOL_GPL(rio_request_inb_mbox);
1386EXPORT_SYMBOL_GPL(rio_release_inb_mbox); 1593EXPORT_SYMBOL_GPL(rio_release_inb_mbox);
1387EXPORT_SYMBOL_GPL(rio_request_outb_mbox); 1594EXPORT_SYMBOL_GPL(rio_request_outb_mbox);
1388EXPORT_SYMBOL_GPL(rio_release_outb_mbox); 1595EXPORT_SYMBOL_GPL(rio_release_outb_mbox);
1596EXPORT_SYMBOL_GPL(rio_init_mports);