diff options
Diffstat (limited to 'drivers/rapidio/rio.c')
-rw-r--r-- | drivers/rapidio/rio.c | 246 |
1 files changed, 239 insertions, 7 deletions
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index d553b5d13722..cb1c08996fbb 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 | ||
34 | static LIST_HEAD(rio_devices); | ||
35 | static DEFINE_SPINLOCK(rio_global_list_lock); | ||
36 | |||
34 | static LIST_HEAD(rio_mports); | 37 | static LIST_HEAD(rio_mports); |
38 | static DEFINE_MUTEX(rio_mport_list_lock); | ||
35 | static unsigned char next_portid; | 39 | static unsigned char next_portid; |
36 | static DEFINE_SPINLOCK(rio_mmap_lock); | 40 | static 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 | */ | ||
67 | int 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 | } | ||
83 | EXPORT_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 | } |
522 | EXPORT_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 | } |
555 | EXPORT_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 | } |
580 | EXPORT_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 | */ | ||
591 | void 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 | } | ||
618 | EXPORT_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 | */ | ||
632 | int 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 | ®val); | ||
652 | } else { | ||
653 | if (rio_mport_read_config_32(port, destid, hopcount, | ||
654 | ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), ®val) < 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 | } | ||
679 | EXPORT_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 | } |
746 | EXPORT_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 | } |
1078 | EXPORT_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 | } |
1135 | EXPORT_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,95 @@ 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_find_mport - find RIO mport by its ID | ||
1387 | * @mport_id: number (ID) of mport device | ||
1388 | * | ||
1389 | * Given a RIO mport number, the desired mport is located | ||
1390 | * in the global list of mports. If the mport is found, a pointer to its | ||
1391 | * data structure is returned. If no mport is found, %NULL is returned. | ||
1392 | */ | ||
1393 | struct rio_mport *rio_find_mport(int mport_id) | ||
1394 | { | ||
1395 | struct rio_mport *port; | ||
1396 | |||
1397 | mutex_lock(&rio_mport_list_lock); | ||
1398 | list_for_each_entry(port, &rio_mports, node) { | ||
1399 | if (port->id == mport_id) | ||
1400 | goto found; | ||
1401 | } | ||
1402 | port = NULL; | ||
1403 | found: | ||
1404 | mutex_unlock(&rio_mport_list_lock); | ||
1405 | |||
1406 | return port; | ||
1407 | } | ||
1408 | |||
1409 | /** | ||
1410 | * rio_register_scan - enumeration/discovery method registration interface | ||
1411 | * @mport_id: mport device ID for which fabric scan routine has to be set | ||
1412 | * (RIO_MPORT_ANY = set for all available mports) | ||
1413 | * @scan_ops: enumeration/discovery control structure | ||
1414 | * | ||
1415 | * Assigns enumeration or discovery method to the specified mport device (or all | ||
1416 | * available mports if RIO_MPORT_ANY is specified). | ||
1417 | * Returns error if the mport already has an enumerator attached to it. | ||
1418 | * In case of RIO_MPORT_ANY ignores ports with valid scan routines and returns | ||
1419 | * an error if was unable to find at least one available mport. | ||
1420 | */ | ||
1421 | int rio_register_scan(int mport_id, struct rio_scan *scan_ops) | ||
1422 | { | ||
1423 | struct rio_mport *port; | ||
1424 | int rc = -EBUSY; | ||
1425 | |||
1426 | mutex_lock(&rio_mport_list_lock); | ||
1427 | list_for_each_entry(port, &rio_mports, node) { | ||
1428 | if (port->id == mport_id || mport_id == RIO_MPORT_ANY) { | ||
1429 | if (port->nscan && mport_id == RIO_MPORT_ANY) | ||
1430 | continue; | ||
1431 | else if (port->nscan) | ||
1432 | break; | ||
1433 | |||
1434 | port->nscan = scan_ops; | ||
1435 | rc = 0; | ||
1436 | |||
1437 | if (mport_id != RIO_MPORT_ANY) | ||
1438 | break; | ||
1439 | } | ||
1440 | } | ||
1441 | mutex_unlock(&rio_mport_list_lock); | ||
1442 | |||
1443 | return rc; | ||
1444 | } | ||
1445 | EXPORT_SYMBOL_GPL(rio_register_scan); | ||
1446 | |||
1447 | /** | ||
1448 | * rio_unregister_scan - removes enumeration/discovery method from mport | ||
1449 | * @mport_id: mport device ID for which fabric scan routine has to be | ||
1450 | * unregistered (RIO_MPORT_ANY = set for all available mports) | ||
1451 | * | ||
1452 | * Removes enumeration or discovery method assigned to the specified mport | ||
1453 | * device (or all available mports if RIO_MPORT_ANY is specified). | ||
1454 | */ | ||
1455 | int rio_unregister_scan(int mport_id) | ||
1456 | { | ||
1457 | struct rio_mport *port; | ||
1458 | |||
1459 | mutex_lock(&rio_mport_list_lock); | ||
1460 | list_for_each_entry(port, &rio_mports, node) { | ||
1461 | if (port->id == mport_id || mport_id == RIO_MPORT_ANY) { | ||
1462 | if (port->nscan) | ||
1463 | port->nscan = NULL; | ||
1464 | if (mport_id != RIO_MPORT_ANY) | ||
1465 | break; | ||
1466 | } | ||
1467 | } | ||
1468 | mutex_unlock(&rio_mport_list_lock); | ||
1469 | |||
1470 | return 0; | ||
1471 | } | ||
1472 | EXPORT_SYMBOL_GPL(rio_unregister_scan); | ||
1473 | |||
1249 | static void rio_fixup_device(struct rio_dev *dev) | 1474 | static void rio_fixup_device(struct rio_dev *dev) |
1250 | { | 1475 | { |
1251 | } | 1476 | } |
@@ -1274,7 +1499,7 @@ static void disc_work_handler(struct work_struct *_work) | |||
1274 | work = container_of(_work, struct rio_disc_work, work); | 1499 | work = container_of(_work, struct rio_disc_work, work); |
1275 | pr_debug("RIO: discovery work for mport %d %s\n", | 1500 | pr_debug("RIO: discovery work for mport %d %s\n", |
1276 | work->mport->id, work->mport->name); | 1501 | work->mport->id, work->mport->name); |
1277 | rio_disc_mport(work->mport); | 1502 | work->mport->nscan->discover(work->mport, 0); |
1278 | } | 1503 | } |
1279 | 1504 | ||
1280 | int rio_init_mports(void) | 1505 | int rio_init_mports(void) |
@@ -1290,12 +1515,15 @@ int rio_init_mports(void) | |||
1290 | * First, run enumerations and check if we need to perform discovery | 1515 | * First, run enumerations and check if we need to perform discovery |
1291 | * on any of the registered mports. | 1516 | * on any of the registered mports. |
1292 | */ | 1517 | */ |
1518 | mutex_lock(&rio_mport_list_lock); | ||
1293 | list_for_each_entry(port, &rio_mports, node) { | 1519 | list_for_each_entry(port, &rio_mports, node) { |
1294 | if (port->host_deviceid >= 0) | 1520 | if (port->host_deviceid >= 0) { |
1295 | rio_enum_mport(port); | 1521 | if (port->nscan) |
1296 | else | 1522 | port->nscan->enumerate(port, 0); |
1523 | } else | ||
1297 | n++; | 1524 | n++; |
1298 | } | 1525 | } |
1526 | mutex_unlock(&rio_mport_list_lock); | ||
1299 | 1527 | ||
1300 | if (!n) | 1528 | if (!n) |
1301 | goto no_disc; | 1529 | goto no_disc; |
@@ -1322,14 +1550,16 @@ int rio_init_mports(void) | |||
1322 | } | 1550 | } |
1323 | 1551 | ||
1324 | n = 0; | 1552 | n = 0; |
1553 | mutex_lock(&rio_mport_list_lock); | ||
1325 | list_for_each_entry(port, &rio_mports, node) { | 1554 | list_for_each_entry(port, &rio_mports, node) { |
1326 | if (port->host_deviceid < 0) { | 1555 | if (port->host_deviceid < 0 && port->nscan) { |
1327 | work[n].mport = port; | 1556 | work[n].mport = port; |
1328 | INIT_WORK(&work[n].work, disc_work_handler); | 1557 | INIT_WORK(&work[n].work, disc_work_handler); |
1329 | queue_work(rio_wq, &work[n].work); | 1558 | queue_work(rio_wq, &work[n].work); |
1330 | n++; | 1559 | n++; |
1331 | } | 1560 | } |
1332 | } | 1561 | } |
1562 | mutex_unlock(&rio_mport_list_lock); | ||
1333 | 1563 | ||
1334 | flush_workqueue(rio_wq); | 1564 | flush_workqueue(rio_wq); |
1335 | pr_debug("RIO: destroy discovery workqueue\n"); | 1565 | pr_debug("RIO: destroy discovery workqueue\n"); |
@@ -1342,8 +1572,6 @@ no_disc: | |||
1342 | return 0; | 1572 | return 0; |
1343 | } | 1573 | } |
1344 | 1574 | ||
1345 | device_initcall_sync(rio_init_mports); | ||
1346 | |||
1347 | static int hdids[RIO_MAX_MPORTS + 1]; | 1575 | static int hdids[RIO_MAX_MPORTS + 1]; |
1348 | 1576 | ||
1349 | static int rio_get_hdid(int index) | 1577 | static int rio_get_hdid(int index) |
@@ -1371,7 +1599,10 @@ int rio_register_mport(struct rio_mport *port) | |||
1371 | 1599 | ||
1372 | port->id = next_portid++; | 1600 | port->id = next_portid++; |
1373 | port->host_deviceid = rio_get_hdid(port->id); | 1601 | port->host_deviceid = rio_get_hdid(port->id); |
1602 | port->nscan = NULL; | ||
1603 | mutex_lock(&rio_mport_list_lock); | ||
1374 | list_add_tail(&port->node, &rio_mports); | 1604 | list_add_tail(&port->node, &rio_mports); |
1605 | mutex_unlock(&rio_mport_list_lock); | ||
1375 | return 0; | 1606 | return 0; |
1376 | } | 1607 | } |
1377 | 1608 | ||
@@ -1386,3 +1617,4 @@ EXPORT_SYMBOL_GPL(rio_request_inb_mbox); | |||
1386 | EXPORT_SYMBOL_GPL(rio_release_inb_mbox); | 1617 | EXPORT_SYMBOL_GPL(rio_release_inb_mbox); |
1387 | EXPORT_SYMBOL_GPL(rio_request_outb_mbox); | 1618 | EXPORT_SYMBOL_GPL(rio_request_outb_mbox); |
1388 | EXPORT_SYMBOL_GPL(rio_release_outb_mbox); | 1619 | EXPORT_SYMBOL_GPL(rio_release_outb_mbox); |
1620 | EXPORT_SYMBOL_GPL(rio_init_mports); | ||