diff options
author | Alexandre Bounine <alexandre.bounine@idt.com> | 2010-10-27 18:34:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-27 21:03:16 -0400 |
commit | af84ca38aff94061dd0711edbb99b0900a9c28fd (patch) | |
tree | 31f51e9106c0a0944ec168dc25399f12ab2fa527 /drivers | |
parent | a3725c45c114bd06e091802f90533332d1e93819 (diff) |
rapidio: add handling of redundant routes
Detects RIO link to the already enumerated device and properly sets links
between device objects. Changes to the enumeration/discovery logic:
1. Use Master Enable bit to signal end of the enumeration - agents may
start their discovery process as soon as they see this bit set
(Component Tag register was used before for this purpose).
2. Enumerator sets Component Tag (!= 0) immediately during device
setup. This allows to identify the device if the redundant route
exists in a RIO system.
Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Cc: 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>
Cc: Micha Nelissen <micha@neli.hopto.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.c | 88 | ||||
-rw-r--r-- | drivers/rapidio/rio.c | 16 | ||||
-rw-r--r-- | drivers/rapidio/rio.h | 1 |
3 files changed, 54 insertions, 51 deletions
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index e3efdf93df5a..1eb82c4c712e 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c | |||
@@ -48,7 +48,7 @@ DEFINE_SPINLOCK(rio_global_list_lock); | |||
48 | static int next_destid = 0; | 48 | static int next_destid = 0; |
49 | static int next_switchid = 0; | 49 | static int next_switchid = 0; |
50 | static int next_net = 0; | 50 | static int next_net = 0; |
51 | static int next_comptag; | 51 | static int next_comptag = 1; |
52 | 52 | ||
53 | static struct timer_list rio_enum_timer = | 53 | static struct timer_list rio_enum_timer = |
54 | TIMER_INITIALIZER(rio_enum_timeout, 0, 0); | 54 | TIMER_INITIALIZER(rio_enum_timeout, 0, 0); |
@@ -121,27 +121,6 @@ static int rio_clear_locks(struct rio_mport *port) | |||
121 | u32 result; | 121 | u32 result; |
122 | int ret = 0; | 122 | int ret = 0; |
123 | 123 | ||
124 | /* Assign component tag to all devices */ | ||
125 | next_comptag = 1; | ||
126 | rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, next_comptag++); | ||
127 | |||
128 | list_for_each_entry(rdev, &rio_devices, global_list) { | ||
129 | /* Mark device as discovered */ | ||
130 | rio_read_config_32(rdev, | ||
131 | rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, | ||
132 | &result); | ||
133 | rio_write_config_32(rdev, | ||
134 | rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, | ||
135 | result | RIO_PORT_GEN_DISCOVERED); | ||
136 | |||
137 | rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, next_comptag); | ||
138 | rdev->comp_tag = next_comptag++; | ||
139 | if (next_comptag >= 0x10000) { | ||
140 | pr_err("RIO: Component Tag Counter Overflow\n"); | ||
141 | break; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | /* Release host device id locks */ | 124 | /* Release host device id locks */ |
146 | rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, | 125 | rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, |
147 | port->host_deviceid); | 126 | port->host_deviceid); |
@@ -162,6 +141,15 @@ static int rio_clear_locks(struct rio_mport *port) | |||
162 | rdev->vid, rdev->did); | 141 | rdev->vid, rdev->did); |
163 | ret = -EINVAL; | 142 | ret = -EINVAL; |
164 | } | 143 | } |
144 | |||
145 | /* Mark device as discovered and enable master */ | ||
146 | rio_read_config_32(rdev, | ||
147 | rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, | ||
148 | &result); | ||
149 | result |= RIO_PORT_GEN_DISCOVERED | RIO_PORT_GEN_MASTER; | ||
150 | rio_write_config_32(rdev, | ||
151 | rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, | ||
152 | result); | ||
165 | } | 153 | } |
166 | 154 | ||
167 | return ret; | 155 | return ret; |
@@ -430,6 +418,17 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
430 | rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, | 418 | rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, |
431 | &rdev->dst_ops); | 419 | &rdev->dst_ops); |
432 | 420 | ||
421 | if (do_enum) { | ||
422 | /* Assign component tag to device */ | ||
423 | if (next_comptag >= 0x10000) { | ||
424 | pr_err("RIO: Component Tag Counter Overflow\n"); | ||
425 | goto cleanup; | ||
426 | } | ||
427 | rio_mport_write_config_32(port, destid, hopcount, | ||
428 | RIO_COMPONENT_TAG_CSR, next_comptag); | ||
429 | rdev->comp_tag = next_comptag++; | ||
430 | } | ||
431 | |||
433 | if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { | 432 | if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { |
434 | if (do_enum) { | 433 | if (do_enum) { |
435 | rio_set_device_id(port, destid, hopcount, next_destid); | 434 | rio_set_device_id(port, destid, hopcount, next_destid); |
@@ -726,21 +725,6 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) | |||
726 | } | 725 | } |
727 | 726 | ||
728 | /** | 727 | /** |
729 | * rio_net_add_mport- Add a master port to a RIO network | ||
730 | * @net: RIO network | ||
731 | * @port: Master port to add | ||
732 | * | ||
733 | * Adds a master port to the network list of associated master | ||
734 | * ports.. | ||
735 | */ | ||
736 | static void rio_net_add_mport(struct rio_net *net, struct rio_mport *port) | ||
737 | { | ||
738 | spin_lock(&rio_global_list_lock); | ||
739 | list_add_tail(&port->nnode, &net->mports); | ||
740 | spin_unlock(&rio_global_list_lock); | ||
741 | } | ||
742 | |||
743 | /** | ||
744 | * rio_enum_peer- Recursively enumerate a RIO network through a master port | 728 | * rio_enum_peer- Recursively enumerate a RIO network through a master port |
745 | * @net: RIO network being enumerated | 729 | * @net: RIO network being enumerated |
746 | * @port: Master port to send transactions | 730 | * @port: Master port to send transactions |
@@ -760,6 +744,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | |||
760 | int sw_inport; | 744 | int sw_inport; |
761 | struct rio_dev *rdev; | 745 | struct rio_dev *rdev; |
762 | u16 destid; | 746 | u16 destid; |
747 | u32 regval; | ||
763 | int tmp; | 748 | int tmp; |
764 | 749 | ||
765 | if (rio_mport_chk_dev_access(port, | 750 | if (rio_mport_chk_dev_access(port, |
@@ -772,9 +757,21 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | |||
772 | pr_debug("RIO: PE already discovered by this host\n"); | 757 | pr_debug("RIO: PE already discovered by this host\n"); |
773 | /* | 758 | /* |
774 | * Already discovered by this host. Add it as another | 759 | * Already discovered by this host. Add it as another |
775 | * master port for the current network. | 760 | * link to the existing device. |
776 | */ | 761 | */ |
777 | rio_net_add_mport(net, port); | 762 | rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), |
763 | hopcount, RIO_COMPONENT_TAG_CSR, ®val); | ||
764 | |||
765 | if (regval) { | ||
766 | rdev = rio_get_comptag((regval & 0xffff), NULL); | ||
767 | |||
768 | if (rdev && prev && rio_is_switch(prev)) { | ||
769 | pr_debug("RIO: redundant path to %s\n", | ||
770 | rio_name(rdev)); | ||
771 | prev->rswitch->nextdev[prev_port] = rdev; | ||
772 | } | ||
773 | } | ||
774 | |||
778 | return 0; | 775 | return 0; |
779 | } | 776 | } |
780 | 777 | ||
@@ -925,10 +922,11 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | |||
925 | */ | 922 | */ |
926 | static int rio_enum_complete(struct rio_mport *port) | 923 | static int rio_enum_complete(struct rio_mport *port) |
927 | { | 924 | { |
928 | u32 tag_csr; | 925 | u32 regval; |
929 | 926 | ||
930 | rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr); | 927 | rio_local_read_config_32(port, port->phys_efptr + RIO_PORT_GEN_CTL_CSR, |
931 | return (tag_csr & 0xffff) ? 1 : 0; | 928 | ®val); |
929 | return (regval & RIO_PORT_GEN_MASTER) ? 1 : 0; | ||
932 | } | 930 | } |
933 | 931 | ||
934 | /** | 932 | /** |
@@ -991,6 +989,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, | |||
991 | break; | 989 | break; |
992 | } | 990 | } |
993 | 991 | ||
992 | if (ndestid == RIO_ANY_DESTID(port->sys_size)) | ||
993 | continue; | ||
994 | rio_unlock_device(port, destid, hopcount); | 994 | rio_unlock_device(port, destid, hopcount); |
995 | if (rio_disc_peer | 995 | if (rio_disc_peer |
996 | (net, port, ndestid, hopcount + 1) < 0) | 996 | (net, port, ndestid, hopcount + 1) < 0) |
@@ -1163,6 +1163,10 @@ int __devinit rio_enum_mport(struct rio_mport *mport) | |||
1163 | /* Enable Input Output Port (transmitter reviever) */ | 1163 | /* Enable Input Output Port (transmitter reviever) */ |
1164 | rio_enable_rx_tx_port(mport, 1, 0, 0, 0); | 1164 | rio_enable_rx_tx_port(mport, 1, 0, 0, 0); |
1165 | 1165 | ||
1166 | /* Set component tag for host */ | ||
1167 | rio_local_write_config_32(mport, RIO_COMPONENT_TAG_CSR, | ||
1168 | next_comptag++); | ||
1169 | |||
1166 | if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) { | 1170 | if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) { |
1167 | /* A higher priority host won enumeration, bail. */ | 1171 | /* A higher priority host won enumeration, bail. */ |
1168 | printk(KERN_INFO | 1172 | printk(KERN_INFO |
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index fa5e3cbe4c83..7f18a65c4ed0 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c | |||
@@ -443,7 +443,7 @@ rio_mport_get_physefb(struct rio_mport *port, int local, | |||
443 | * @from is not %NULL, searches continue from next device on the global | 443 | * @from is not %NULL, searches continue from next device on the global |
444 | * list. | 444 | * list. |
445 | */ | 445 | */ |
446 | static struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) | 446 | struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) |
447 | { | 447 | { |
448 | struct list_head *n; | 448 | struct list_head *n; |
449 | struct rio_dev *rdev; | 449 | struct rio_dev *rdev; |
@@ -507,7 +507,7 @@ static int | |||
507 | rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) | 507 | rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) |
508 | { | 508 | { |
509 | u32 result; | 509 | u32 result; |
510 | int p_port, rc = -EIO; | 510 | int p_port, dstid, rc = -EIO; |
511 | struct rio_dev *prev = NULL; | 511 | struct rio_dev *prev = NULL; |
512 | 512 | ||
513 | /* Find switch with failed RIO link */ | 513 | /* Find switch with failed RIO link */ |
@@ -522,20 +522,18 @@ rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) | |||
522 | if (prev == NULL) | 522 | if (prev == NULL) |
523 | goto err_out; | 523 | goto err_out; |
524 | 524 | ||
525 | /* Find port with failed RIO link */ | 525 | dstid = (rdev->pef & RIO_PEF_SWITCH) ? |
526 | for (p_port = 0; | 526 | rdev->rswitch->destid : rdev->destid; |
527 | p_port < RIO_GET_TOTAL_PORTS(prev->swpinfo); p_port++) | 527 | p_port = prev->rswitch->route_table[dstid]; |
528 | if (prev->rswitch->nextdev[p_port] == rdev) | ||
529 | break; | ||
530 | 528 | ||
531 | if (p_port < RIO_GET_TOTAL_PORTS(prev->swpinfo)) { | 529 | if (p_port != RIO_INVALID_ROUTE) { |
532 | pr_debug("RIO: link failed on [%s]-P%d\n", | 530 | pr_debug("RIO: link failed on [%s]-P%d\n", |
533 | rio_name(prev), p_port); | 531 | rio_name(prev), p_port); |
534 | *nrdev = prev; | 532 | *nrdev = prev; |
535 | *npnum = p_port; | 533 | *npnum = p_port; |
536 | rc = 0; | 534 | rc = 0; |
537 | } else | 535 | } else |
538 | pr_debug("RIO: failed to trace route to %s\n", rio_name(prev)); | 536 | pr_debug("RIO: failed to trace route to %s\n", rio_name(rdev)); |
539 | err_out: | 537 | err_out: |
540 | return rc; | 538 | return rc; |
541 | } | 539 | } |
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index d249a1205c7d..b1af414f15e6 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h | |||
@@ -38,6 +38,7 @@ extern int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, | |||
38 | extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, | 38 | extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, |
39 | u8 hopcount, u16 table); | 39 | u8 hopcount, u16 table); |
40 | extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock); | 40 | extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock); |
41 | extern struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from); | ||
41 | 42 | ||
42 | /* Structures internal to the RIO core code */ | 43 | /* Structures internal to the RIO core code */ |
43 | extern struct device_attribute rio_dev_attrs[]; | 44 | extern struct device_attribute rio_dev_attrs[]; |