aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2010-05-26 17:43:58 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-27 12:12:50 -0400
commit818a04a0bb93643d57dd8935815de2ff307b58a3 (patch)
tree8b21086dea9e3667bdb8f0843a3b50464d61e62f /drivers
parent07590ff03935a2efbc03bc7861f20c059576a479 (diff)
rapidio: add switch locking during discovery
Add switch access locking during RapidIO discovery. Access lock is required when reading switch routing table contents due to indexed mechanism of RT addressing. Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Tested-by: Thomas Moll <thomas.moll@sysgo.com> Cc: Matt Porter <mporter@kernel.crashing.org> Cc: Li Yang <leoli@freescale.com> Cc: Kumar Gala <galak@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/rapidio/rio-scan.c164
1 files changed, 144 insertions, 20 deletions
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 7f1a675d835d..cbf0d5f4fba8 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -457,12 +457,87 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
457} 457}
458 458
459/** 459/**
460 * rio_lock_device - Acquires host device lock for specified device
461 * @port: Master port to send transaction
462 * @destid: Destination ID for device/switch
463 * @hopcount: Hopcount to reach switch
464 * @wait_ms: Max wait time in msec (0 = no timeout)
465 *
466 * Attepts to acquire host device lock for specified device
467 * Returns 0 if device lock acquired or EINVAL if timeout expires.
468 */
469static int
470rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms)
471{
472 u32 result;
473 int tcnt = 0;
474
475 /* Attempt to acquire device lock */
476 rio_mport_write_config_32(port, destid, hopcount,
477 RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
478 rio_mport_read_config_32(port, destid, hopcount,
479 RIO_HOST_DID_LOCK_CSR, &result);
480
481 while (result != port->host_deviceid) {
482 if (wait_ms != 0 && tcnt == wait_ms) {
483 pr_debug("RIO: timeout when locking device %x:%x\n",
484 destid, hopcount);
485 return -EINVAL;
486 }
487
488 /* Delay a bit */
489 mdelay(1);
490 tcnt++;
491 /* Try to acquire device lock again */
492 rio_mport_write_config_32(port, destid,
493 hopcount,
494 RIO_HOST_DID_LOCK_CSR,
495 port->host_deviceid);
496 rio_mport_read_config_32(port, destid,
497 hopcount,
498 RIO_HOST_DID_LOCK_CSR, &result);
499 }
500
501 return 0;
502}
503
504/**
505 * rio_unlock_device - Releases host device lock for specified device
506 * @port: Master port to send transaction
507 * @destid: Destination ID for device/switch
508 * @hopcount: Hopcount to reach switch
509 *
510 * Returns 0 if device lock released or EINVAL if fails.
511 */
512static int
513rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
514{
515 u32 result;
516
517 /* Release device lock */
518 rio_mport_write_config_32(port, destid,
519 hopcount,
520 RIO_HOST_DID_LOCK_CSR,
521 port->host_deviceid);
522 rio_mport_read_config_32(port, destid, hopcount,
523 RIO_HOST_DID_LOCK_CSR, &result);
524 if ((result & 0xffff) != 0xffff) {
525 pr_debug("RIO: badness when releasing device lock %x:%x\n",
526 destid, hopcount);
527 return -EINVAL;
528 }
529
530 return 0;
531}
532
533/**
460 * rio_route_add_entry- Add a route entry to a switch routing table 534 * rio_route_add_entry- Add a route entry to a switch routing table
461 * @mport: Master port to send transaction 535 * @mport: Master port to send transaction
462 * @rswitch: Switch device 536 * @rswitch: Switch device
463 * @table: Routing table ID 537 * @table: Routing table ID
464 * @route_destid: Destination ID to be routed 538 * @route_destid: Destination ID to be routed
465 * @route_port: Port number to be routed 539 * @route_port: Port number to be routed
540 * @lock: lock switch device flag
466 * 541 *
467 * Calls the switch specific add_entry() method to add a route entry 542 * Calls the switch specific add_entry() method to add a route entry
468 * on a switch. The route table can be specified using the @table 543 * on a switch. The route table can be specified using the @table
@@ -471,12 +546,26 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
471 * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL 546 * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
472 * on failure. 547 * on failure.
473 */ 548 */
474static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, 549static int
475 u16 table, u16 route_destid, u8 route_port) 550rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch,
551 u16 table, u16 route_destid, u8 route_port, int lock)
476{ 552{
477 return rswitch->add_entry(mport, rswitch->destid, 553 int rc;
554
555 if (lock) {
556 rc = rio_lock_device(mport, rswitch->destid,
557 rswitch->hopcount, 1000);
558 if (rc)
559 return rc;
560 }
561
562 rc = rswitch->add_entry(mport, rswitch->destid,
478 rswitch->hopcount, table, 563 rswitch->hopcount, table,
479 route_destid, route_port); 564 route_destid, route_port);
565 if (lock)
566 rio_unlock_device(mport, rswitch->destid, rswitch->hopcount);
567
568 return rc;
480} 569}
481 570
482/** 571/**
@@ -486,6 +575,7 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit
486 * @table: Routing table ID 575 * @table: Routing table ID
487 * @route_destid: Destination ID to be routed 576 * @route_destid: Destination ID to be routed
488 * @route_port: Pointer to read port number into 577 * @route_port: Pointer to read port number into
578 * @lock: lock switch device flag
489 * 579 *
490 * Calls the switch specific get_entry() method to read a route entry 580 * Calls the switch specific get_entry() method to read a route entry
491 * in a switch. The route table can be specified using the @table 581 * in a switch. The route table can be specified using the @table
@@ -496,11 +586,24 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit
496 */ 586 */
497static int 587static int
498rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table, 588rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table,
499 u16 route_destid, u8 * route_port) 589 u16 route_destid, u8 *route_port, int lock)
500{ 590{
501 return rswitch->get_entry(mport, rswitch->destid, 591 int rc;
592
593 if (lock) {
594 rc = rio_lock_device(mport, rswitch->destid,
595 rswitch->hopcount, 1000);
596 if (rc)
597 return rc;
598 }
599
600 rc = rswitch->get_entry(mport, rswitch->destid,
502 rswitch->hopcount, table, 601 rswitch->hopcount, table,
503 route_destid, route_port); 602 route_destid, route_port);
603 if (lock)
604 rio_unlock_device(mport, rswitch->destid, rswitch->hopcount);
605
606 return rc;
504} 607}
505 608
506/** 609/**
@@ -640,14 +743,14 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
640 sw_inport = rio_get_swpinfo_inport(port, 743 sw_inport = rio_get_swpinfo_inport(port,
641 RIO_ANY_DESTID(port->sys_size), hopcount); 744 RIO_ANY_DESTID(port->sys_size), hopcount);
642 rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, 745 rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
643 port->host_deviceid, sw_inport); 746 port->host_deviceid, sw_inport, 0);
644 rdev->rswitch->route_table[port->host_deviceid] = sw_inport; 747 rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
645 748
646 for (destid = 0; destid < next_destid; destid++) { 749 for (destid = 0; destid < next_destid; destid++) {
647 if (destid == port->host_deviceid) 750 if (destid == port->host_deviceid)
648 continue; 751 continue;
649 rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, 752 rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
650 destid, sw_inport); 753 destid, sw_inport, 0);
651 rdev->rswitch->route_table[destid] = sw_inport; 754 rdev->rswitch->route_table[destid] = sw_inport;
652 } 755 }
653 756
@@ -673,7 +776,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
673 rio_route_add_entry(port, rdev->rswitch, 776 rio_route_add_entry(port, rdev->rswitch,
674 RIO_GLOBAL_TABLE, 777 RIO_GLOBAL_TABLE,
675 RIO_ANY_DESTID(port->sys_size), 778 RIO_ANY_DESTID(port->sys_size),
676 port_num); 779 port_num, 0);
677 780
678 if (rio_enum_peer(net, port, hopcount + 1) < 0) 781 if (rio_enum_peer(net, port, hopcount + 1) < 0)
679 return -1; 782 return -1;
@@ -687,7 +790,8 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
687 rio_route_add_entry(port, rdev->rswitch, 790 rio_route_add_entry(port, rdev->rswitch,
688 RIO_GLOBAL_TABLE, 791 RIO_GLOBAL_TABLE,
689 destid, 792 destid,
690 port_num); 793 port_num,
794 0);
691 rdev->rswitch-> 795 rdev->rswitch->
692 route_table[destid] = 796 route_table[destid] =
693 port_num; 797 port_num;
@@ -778,17 +882,21 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
778 pr_debug( 882 pr_debug(
779 "RIO: scanning device on port %d\n", 883 "RIO: scanning device on port %d\n",
780 port_num); 884 port_num);
885
886 rio_lock_device(port, destid, hopcount, 1000);
887
781 for (ndestid = 0; 888 for (ndestid = 0;
782 ndestid < RIO_ANY_DESTID(port->sys_size); 889 ndestid < RIO_ANY_DESTID(port->sys_size);
783 ndestid++) { 890 ndestid++) {
784 rio_route_get_entry(port, rdev->rswitch, 891 rio_route_get_entry(port, rdev->rswitch,
785 RIO_GLOBAL_TABLE, 892 RIO_GLOBAL_TABLE,
786 ndestid, 893 ndestid,
787 &route_port); 894 &route_port, 0);
788 if (route_port == port_num) 895 if (route_port == port_num)
789 break; 896 break;
790 } 897 }
791 898
899 rio_unlock_device(port, destid, hopcount);
792 if (rio_disc_peer 900 if (rio_disc_peer
793 (net, port, ndestid, hopcount + 1) < 0) 901 (net, port, ndestid, hopcount + 1) < 0)
794 return -1; 902 return -1;
@@ -889,7 +997,9 @@ static void rio_update_route_tables(struct rio_mport *port)
889 rswitch->destid, rswitch->hopcount); 997 rswitch->destid, rswitch->hopcount);
890 998
891 if (rswitch->add_entry) { 999 if (rswitch->add_entry) {
892 rio_route_add_entry(port, rswitch, RIO_GLOBAL_TABLE, destid, sport); 1000 rio_route_add_entry(port, rswitch,
1001 RIO_GLOBAL_TABLE, destid,
1002 sport, 0);
893 rswitch->route_table[destid] = sport; 1003 rswitch->route_table[destid] = sport;
894 } 1004 }
895 } 1005 }
@@ -963,15 +1073,22 @@ static void rio_build_route_tables(void)
963 u8 sport; 1073 u8 sport;
964 1074
965 list_for_each_entry(rdev, &rio_devices, global_list) 1075 list_for_each_entry(rdev, &rio_devices, global_list)
966 if (rio_is_switch(rdev)) 1076 if (rio_is_switch(rdev)) {
967 for (i = 0; 1077 rio_lock_device(rdev->net->hport, rdev->rswitch->destid,
968 i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); 1078 rdev->rswitch->hopcount, 1000);
969 i++) { 1079 for (i = 0;
970 if (rio_route_get_entry 1080 i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
971 (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE, 1081 i++) {
972 i, &sport) < 0) 1082 if (rio_route_get_entry
973 continue; 1083 (rdev->net->hport, rdev->rswitch,
974 rdev->rswitch->route_table[i] = sport; 1084 RIO_GLOBAL_TABLE, i, &sport, 0) < 0)
1085 continue;
1086 rdev->rswitch->route_table[i] = sport;
1087 }
1088
1089 rio_unlock_device(rdev->net->hport,
1090 rdev->rswitch->destid,
1091 rdev->rswitch->hopcount);
975 } 1092 }
976} 1093}
977 1094
@@ -1030,6 +1147,13 @@ int __devinit rio_disc_mport(struct rio_mport *mport)
1030 del_timer_sync(&rio_enum_timer); 1147 del_timer_sync(&rio_enum_timer);
1031 1148
1032 pr_debug("done\n"); 1149 pr_debug("done\n");
1150
1151 /* Read DestID assigned by enumerator */
1152 rio_local_read_config_32(mport, RIO_DID_CSR,
1153 &mport->host_deviceid);
1154 mport->host_deviceid = RIO_GET_DID(mport->sys_size,
1155 mport->host_deviceid);
1156
1033 if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), 1157 if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size),
1034 0) < 0) { 1158 0) < 0) {
1035 printk(KERN_INFO 1159 printk(KERN_INFO