diff options
author | Alexandre Bounine <Alexandre.Bounine@tundra.com> | 2007-02-10 04:46:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 14:18:07 -0500 |
commit | c70555b051f2a32bf94a7e1c75b6b6759031b989 (patch) | |
tree | b0ab2e8cd1402e98a85b4303e5f14f39a3e71fc2 | |
parent | d5698c28b6e4711e4747bf155f69936208d60e28 (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.c | 118 | ||||
-rw-r--r-- | include/linux/rio.h | 1 |
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 | */ |
437 | static int rio_route_add_entry(struct rio_mport *mport, struct rio_dev *rdev, | 440 | static 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 | */ |
460 | static int | 463 | static int |
461 | rio_route_get_entry(struct rio_mport *mport, struct rio_dev *rdev, u16 table, | 464 | rio_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 | */ | ||
825 | static 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 |