aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rapidio
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2010-10-27 18:34:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-27 21:03:16 -0400
commitaf84ca38aff94061dd0711edbb99b0900a9c28fd (patch)
tree31f51e9106c0a0944ec168dc25399f12ab2fa527 /drivers/rapidio
parenta3725c45c114bd06e091802f90533332d1e93819 (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/rapidio')
-rw-r--r--drivers/rapidio/rio-scan.c88
-rw-r--r--drivers/rapidio/rio.c16
-rw-r--r--drivers/rapidio/rio.h1
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);
48static int next_destid = 0; 48static int next_destid = 0;
49static int next_switchid = 0; 49static int next_switchid = 0;
50static int next_net = 0; 50static int next_net = 0;
51static int next_comptag; 51static int next_comptag = 1;
52 52
53static struct timer_list rio_enum_timer = 53static struct timer_list rio_enum_timer =
54TIMER_INITIALIZER(rio_enum_timeout, 0, 0); 54TIMER_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 */
736static 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, &regval);
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 */
926static int rio_enum_complete(struct rio_mport *port) 923static 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 &regval);
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 */
446static struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) 446struct 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
507rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) 507rio_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));
539err_out: 537err_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,
38extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, 38extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
39 u8 hopcount, u16 table); 39 u8 hopcount, u16 table);
40extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock); 40extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock);
41extern 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 */
43extern struct device_attribute rio_dev_attrs[]; 44extern struct device_attribute rio_dev_attrs[];