aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Bounine <Alexandre.Bounine@tundra.com>2007-02-10 04:46:47 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-11 14:18:07 -0500
commitc70555b051f2a32bf94a7e1c75b6b6759031b989 (patch)
treeb0ab2e8cd1402e98a85b4303e5f14f39a3e71fc2
parentd5698c28b6e4711e4747bf155f69936208d60e28 (diff)
[PATCH] rapidio: fix multi-switch enumeration
This patch contains two fixes for RapisIO enumeration logic: 1. Fix enumeration in configurations with multiple switches. The patch adds: a. Enumeration of an empty switch. Empty switch is a switch that does not have any endpoint devices attached to it (except host device or previous switch in a chain). New code assigns a phony destination ID associated with the switch and sets up corresponding routes. b. Adds a second pass to the enumeration to setup routes to devices discovered after switch was scanned. 2. Fix enumeration failure when riohdid parameter has non-zero value. Current version fails to setup response path to the host when it has destination ID other that 0. Signed-off-by: Alexandre Bounine <alexandreb@tundra.com> Acked-by: Matt Porter <mporter@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/rapidio/rio-scan.c118
-rw-r--r--include/linux/rio.h1
2 files changed, 88 insertions, 31 deletions
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 7bf7b2c88245..f935c1f71a58 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -326,14 +326,17 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
326 rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, 326 rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR,
327 &rdev->dst_ops); 327 &rdev->dst_ops);
328 328
329 if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops) 329 if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) {
330 && do_enum) { 330 if (do_enum) {
331 rio_set_device_id(port, destid, hopcount, next_destid); 331 rio_set_device_id(port, destid, hopcount, next_destid);
332 rdev->destid = next_destid++; 332 rdev->destid = next_destid++;
333 if (next_destid == port->host_deviceid) 333 if (next_destid == port->host_deviceid)
334 next_destid++; 334 next_destid++;
335 } else
336 rdev->destid = rio_get_device_id(port, destid, hopcount);
335 } else 337 } else
336 rdev->destid = rio_get_device_id(port, destid, hopcount); 338 /* Switch device has an associated destID */
339 rdev->destid = RIO_INVALID_DESTID;
337 340
338 /* If a PE has both switch and other functions, show it as a switch */ 341 /* If a PE has both switch and other functions, show it as a switch */
339 if (rio_is_switch(rdev)) { 342 if (rio_is_switch(rdev)) {
@@ -347,7 +350,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
347 } 350 }
348 rswitch->switchid = next_switchid; 351 rswitch->switchid = next_switchid;
349 rswitch->hopcount = hopcount; 352 rswitch->hopcount = hopcount;
350 rswitch->destid = 0xffff; 353 rswitch->destid = destid;
351 /* Initialize switch route table */ 354 /* Initialize switch route table */
352 for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES; rdid++) 355 for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES; rdid++)
353 rswitch->route_table[rdid] = RIO_INVALID_ROUTE; 356 rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
@@ -422,7 +425,7 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
422/** 425/**
423 * rio_route_add_entry- Add a route entry to a switch routing table 426 * rio_route_add_entry- Add a route entry to a switch routing table
424 * @mport: Master port to send transaction 427 * @mport: Master port to send transaction
425 * @rdev: Switch device 428 * @rswitch: Switch device
426 * @table: Routing table ID 429 * @table: Routing table ID
427 * @route_destid: Destination ID to be routed 430 * @route_destid: Destination ID to be routed
428 * @route_port: Port number to be routed 431 * @route_port: Port number to be routed
@@ -434,18 +437,18 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
434 * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL 437 * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
435 * on failure. 438 * on failure.
436 */ 439 */
437static int rio_route_add_entry(struct rio_mport *mport, struct rio_dev *rdev, 440static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch,
438 u16 table, u16 route_destid, u8 route_port) 441 u16 table, u16 route_destid, u8 route_port)
439{ 442{
440 return rdev->rswitch->add_entry(mport, rdev->rswitch->destid, 443 return rswitch->add_entry(mport, rswitch->destid,
441 rdev->rswitch->hopcount, table, 444 rswitch->hopcount, table,
442 route_destid, route_port); 445 route_destid, route_port);
443} 446}
444 447
445/** 448/**
446 * rio_route_get_entry- Read a route entry in a switch routing table 449 * rio_route_get_entry- Read a route entry in a switch routing table
447 * @mport: Master port to send transaction 450 * @mport: Master port to send transaction
448 * @rdev: Switch device 451 * @rswitch: Switch device
449 * @table: Routing table ID 452 * @table: Routing table ID
450 * @route_destid: Destination ID to be routed 453 * @route_destid: Destination ID to be routed
451 * @route_port: Pointer to read port number into 454 * @route_port: Pointer to read port number into
@@ -458,11 +461,11 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_dev *rdev,
458 * on failure. 461 * on failure.
459 */ 462 */
460static int 463static int
461rio_route_get_entry(struct rio_mport *mport, struct rio_dev *rdev, u16 table, 464rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table,
462 u16 route_destid, u8 * route_port) 465 u16 route_destid, u8 * route_port)
463{ 466{
464 return rdev->rswitch->get_entry(mport, rdev->rswitch->destid, 467 return rswitch->get_entry(mport, rswitch->destid,
465 rdev->rswitch->hopcount, table, 468 rswitch->hopcount, table,
466 route_destid, route_port); 469 route_destid, route_port);
467} 470}
468 471
@@ -552,6 +555,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
552 int port_num; 555 int port_num;
553 int num_ports; 556 int num_ports;
554 int cur_destid; 557 int cur_destid;
558 int sw_destid;
559 int sw_inport;
555 struct rio_dev *rdev; 560 struct rio_dev *rdev;
556 u16 destid; 561 u16 destid;
557 int tmp; 562 int tmp;
@@ -594,15 +599,17 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
594 599
595 if (rio_is_switch(rdev)) { 600 if (rio_is_switch(rdev)) {
596 next_switchid++; 601 next_switchid++;
602 sw_inport = rio_get_swpinfo_inport(port, RIO_ANY_DESTID, hopcount);
603 rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
604 port->host_deviceid, sw_inport);
605 rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
597 606
598 for (destid = 0; destid < next_destid; destid++) { 607 for (destid = 0; destid < next_destid; destid++) {
599 rio_route_add_entry(port, rdev, RIO_GLOBAL_TABLE, 608 if (destid == port->host_deviceid)
600 destid, rio_get_swpinfo_inport(port, 609 continue;
601 RIO_ANY_DESTID, 610 rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
602 hopcount)); 611 destid, sw_inport);
603 rdev->rswitch->route_table[destid] = 612 rdev->rswitch->route_table[destid] = sw_inport;
604 rio_get_swpinfo_inport(port, RIO_ANY_DESTID,
605 hopcount);
606 } 613 }
607 614
608 num_ports = 615 num_ports =
@@ -610,9 +617,9 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
610 pr_debug( 617 pr_debug(
611 "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", 618 "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
612 rio_name(rdev), rdev->vid, rdev->did, num_ports); 619 rio_name(rdev), rdev->vid, rdev->did, num_ports);
620 sw_destid = next_destid;
613 for (port_num = 0; port_num < num_ports; port_num++) { 621 for (port_num = 0; port_num < num_ports; port_num++) {
614 if (rio_get_swpinfo_inport 622 if (sw_inport == port_num)
615 (port, RIO_ANY_DESTID, hopcount) == port_num)
616 continue; 623 continue;
617 624
618 cur_destid = next_destid; 625 cur_destid = next_destid;
@@ -622,7 +629,7 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
622 pr_debug( 629 pr_debug(
623 "RIO: scanning device on port %d\n", 630 "RIO: scanning device on port %d\n",
624 port_num); 631 port_num);
625 rio_route_add_entry(port, rdev, 632 rio_route_add_entry(port, rdev->rswitch,
626 RIO_GLOBAL_TABLE, 633 RIO_GLOBAL_TABLE,
627 RIO_ANY_DESTID, port_num); 634 RIO_ANY_DESTID, port_num);
628 635
@@ -633,7 +640,9 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
633 if (next_destid > cur_destid) { 640 if (next_destid > cur_destid) {
634 for (destid = cur_destid; 641 for (destid = cur_destid;
635 destid < next_destid; destid++) { 642 destid < next_destid; destid++) {
636 rio_route_add_entry(port, rdev, 643 if (destid == port->host_deviceid)
644 continue;
645 rio_route_add_entry(port, rdev->rswitch,
637 RIO_GLOBAL_TABLE, 646 RIO_GLOBAL_TABLE,
638 destid, 647 destid,
639 port_num); 648 port_num);
@@ -641,10 +650,18 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
641 route_table[destid] = 650 route_table[destid] =
642 port_num; 651 port_num;
643 } 652 }
644 rdev->rswitch->destid = cur_destid;
645 } 653 }
646 } 654 }
647 } 655 }
656
657 /* Check for empty switch */
658 if (next_destid == sw_destid) {
659 next_destid++;
660 if (next_destid == port->host_deviceid)
661 next_destid++;
662 }
663
664 rdev->rswitch->destid = sw_destid;
648 } else 665 } else
649 pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", 666 pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n",
650 rio_name(rdev), rdev->vid, rdev->did); 667 rio_name(rdev), rdev->vid, rdev->did);
@@ -721,7 +738,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
721 port_num); 738 port_num);
722 for (ndestid = 0; ndestid < RIO_ANY_DESTID; 739 for (ndestid = 0; ndestid < RIO_ANY_DESTID;
723 ndestid++) { 740 ndestid++) {
724 rio_route_get_entry(port, rdev, 741 rio_route_get_entry(port, rdev->rswitch,
725 RIO_GLOBAL_TABLE, 742 RIO_GLOBAL_TABLE,
726 ndestid, 743 ndestid,
727 &route_port); 744 &route_port);
@@ -798,6 +815,44 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port)
798} 815}
799 816
800/** 817/**
818 * rio_update_route_tables- Updates route tables in switches
819 * @port: Master port associated with the RIO network
820 *
821 * For each enumerated device, ensure that each switch in a system
822 * has correct routing entries. Add routes for devices that where
823 * unknown dirung the first enumeration pass through the switch.
824 */
825static void rio_update_route_tables(struct rio_mport *port)
826{
827 struct rio_dev *rdev;
828 struct rio_switch *rswitch;
829 u8 sport;
830 u16 destid;
831
832 list_for_each_entry(rdev, &rio_devices, global_list) {
833
834 destid = (rio_is_switch(rdev))?rdev->rswitch->destid:rdev->destid;
835
836 list_for_each_entry(rswitch, &rio_switches, node) {
837
838 if (rio_is_switch(rdev) && (rdev->rswitch == rswitch))
839 continue;
840
841 if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) {
842
843 sport = rio_get_swpinfo_inport(port,
844 rswitch->destid, rswitch->hopcount);
845
846 if (rswitch->add_entry) {
847 rio_route_add_entry(port, rswitch, RIO_GLOBAL_TABLE, destid, sport);
848 rswitch->route_table[destid] = sport;
849 }
850 }
851 }
852 }
853}
854
855/**
801 * rio_enum_mport- Start enumeration through a master port 856 * rio_enum_mport- Start enumeration through a master port
802 * @mport: Master port to send transactions 857 * @mport: Master port to send transactions
803 * 858 *
@@ -838,6 +893,7 @@ int rio_enum_mport(struct rio_mport *mport)
838 rc = -EBUSY; 893 rc = -EBUSY;
839 goto out; 894 goto out;
840 } 895 }
896 rio_update_route_tables(mport);
841 rio_clear_locks(mport); 897 rio_clear_locks(mport);
842 } else { 898 } else {
843 printk(KERN_INFO "RIO: master port %d link inactive\n", 899 printk(KERN_INFO "RIO: master port %d link inactive\n",
@@ -865,8 +921,8 @@ static void rio_build_route_tables(void)
865 if (rio_is_switch(rdev)) 921 if (rio_is_switch(rdev))
866 for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) { 922 for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) {
867 if (rio_route_get_entry 923 if (rio_route_get_entry
868 (rdev->net->hport, rdev, RIO_GLOBAL_TABLE, i, 924 (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE,
869 &sport) < 0) 925 i, &sport) < 0)
870 continue; 926 continue;
871 rdev->rswitch->route_table[i] = sport; 927 rdev->rswitch->route_table[i] = sport;
872 } 928 }
diff --git a/include/linux/rio.h b/include/linux/rio.h
index d93857056cb9..68e3f6853fa6 100644
--- a/include/linux/rio.h
+++ b/include/linux/rio.h
@@ -25,6 +25,7 @@
25 25
26#define RIO_ANY_DESTID 0xff 26#define RIO_ANY_DESTID 0xff
27#define RIO_NO_HOPCOUNT -1 27#define RIO_NO_HOPCOUNT -1
28#define RIO_INVALID_DESTID 0xffff
28 29
29#define RIO_MAX_MPORT_RESOURCES 16 30#define RIO_MAX_MPORT_RESOURCES 16
30#define RIO_MAX_DEV_RESOURCES 16 31#define RIO_MAX_DEV_RESOURCES 16