Commit af84ca38aff94061dd0711edbb99b0900a9c28fd
Committed by
Linus Torvalds
1 parent
a3725c45c1
Exists in
master
and in
4 other branches
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>
Showing 5 changed files with 64 additions and 51 deletions Side-by-side Diff
arch/powerpc/sysdev/fsl_rio.c
... | ... | @@ -50,6 +50,7 @@ |
50 | 50 | #define RIO_ATMU_REGS_OFFSET 0x10c00 |
51 | 51 | #define RIO_P_MSG_REGS_OFFSET 0x11000 |
52 | 52 | #define RIO_S_MSG_REGS_OFFSET 0x13000 |
53 | +#define RIO_GCCSR 0x13c | |
53 | 54 | #define RIO_ESCSR 0x158 |
54 | 55 | #define RIO_CCSR 0x15c |
55 | 56 | #define RIO_LTLEDCSR 0x0608 |
... | ... | @@ -1471,6 +1472,7 @@ |
1471 | 1472 | port->host_deviceid = fsl_rio_get_hdid(port->id); |
1472 | 1473 | |
1473 | 1474 | port->priv = priv; |
1475 | + port->phys_efptr = 0x100; | |
1474 | 1476 | rio_register_mport(port); |
1475 | 1477 | |
1476 | 1478 | priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1); |
... | ... | @@ -1517,6 +1519,12 @@ |
1517 | 1519 | & RIO_PEF_CTLS) >> 4; |
1518 | 1520 | dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n", |
1519 | 1521 | port->sys_size ? 65536 : 256); |
1522 | + | |
1523 | + if (port->host_deviceid >= 0) | |
1524 | + out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST | | |
1525 | + RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED); | |
1526 | + else | |
1527 | + out_be32(priv->regs_win + RIO_GCCSR, 0x00000000); | |
1520 | 1528 | |
1521 | 1529 | priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win |
1522 | 1530 | + RIO_ATMU_REGS_OFFSET); |
drivers/rapidio/rio-scan.c
... | ... | @@ -48,7 +48,7 @@ |
48 | 48 | static int next_destid = 0; |
49 | 49 | static int next_switchid = 0; |
50 | 50 | static int next_net = 0; |
51 | -static int next_comptag; | |
51 | +static int next_comptag = 1; | |
52 | 52 | |
53 | 53 | static struct timer_list rio_enum_timer = |
54 | 54 | TIMER_INITIALIZER(rio_enum_timeout, 0, 0); |
... | ... | @@ -121,27 +121,6 @@ |
121 | 121 | u32 result; |
122 | 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 | 124 | /* Release host device id locks */ |
146 | 125 | rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, |
147 | 126 | port->host_deviceid); |
... | ... | @@ -162,6 +141,15 @@ |
162 | 141 | rdev->vid, rdev->did); |
163 | 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 | 155 | return ret; |
... | ... | @@ -430,6 +418,17 @@ |
430 | 418 | rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, |
431 | 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 | 432 | if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { |
434 | 433 | if (do_enum) { |
435 | 434 | rio_set_device_id(port, destid, hopcount, next_destid); |
... | ... | @@ -726,21 +725,6 @@ |
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 | 728 | * rio_enum_peer- Recursively enumerate a RIO network through a master port |
745 | 729 | * @net: RIO network being enumerated |
746 | 730 | * @port: Master port to send transactions |
... | ... | @@ -760,6 +744,7 @@ |
760 | 744 | int sw_inport; |
761 | 745 | struct rio_dev *rdev; |
762 | 746 | u16 destid; |
747 | + u32 regval; | |
763 | 748 | int tmp; |
764 | 749 | |
765 | 750 | if (rio_mport_chk_dev_access(port, |
766 | 751 | |
... | ... | @@ -772,9 +757,21 @@ |
772 | 757 | pr_debug("RIO: PE already discovered by this host\n"); |
773 | 758 | /* |
774 | 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 | 775 | return 0; |
779 | 776 | } |
780 | 777 | |
781 | 778 | |
... | ... | @@ -925,10 +922,11 @@ |
925 | 922 | */ |
926 | 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); | |
931 | - return (tag_csr & 0xffff) ? 1 : 0; | |
927 | + rio_local_read_config_32(port, port->phys_efptr + RIO_PORT_GEN_CTL_CSR, | |
928 | + ®val); | |
929 | + return (regval & RIO_PORT_GEN_MASTER) ? 1 : 0; | |
932 | 930 | } |
933 | 931 | |
934 | 932 | /** |
... | ... | @@ -991,6 +989,8 @@ |
991 | 989 | break; |
992 | 990 | } |
993 | 991 | |
992 | + if (ndestid == RIO_ANY_DESTID(port->sys_size)) | |
993 | + continue; | |
994 | 994 | rio_unlock_device(port, destid, hopcount); |
995 | 995 | if (rio_disc_peer |
996 | 996 | (net, port, ndestid, hopcount + 1) < 0) |
... | ... | @@ -1162,6 +1162,10 @@ |
1162 | 1162 | |
1163 | 1163 | /* Enable Input Output Port (transmitter reviever) */ |
1164 | 1164 | rio_enable_rx_tx_port(mport, 1, 0, 0, 0); |
1165 | + | |
1166 | + /* Set component tag for host */ | |
1167 | + rio_local_write_config_32(mport, RIO_COMPONENT_TAG_CSR, | |
1168 | + next_comptag++); | |
1165 | 1169 | |
1166 | 1170 | if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) { |
1167 | 1171 | /* A higher priority host won enumeration, bail. */ |
drivers/rapidio/rio.c
... | ... | @@ -443,7 +443,7 @@ |
443 | 443 | * @from is not %NULL, searches continue from next device on the global |
444 | 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 | 448 | struct list_head *n; |
449 | 449 | struct rio_dev *rdev; |
... | ... | @@ -507,7 +507,7 @@ |
507 | 507 | rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) |
508 | 508 | { |
509 | 509 | u32 result; |
510 | - int p_port, rc = -EIO; | |
510 | + int p_port, dstid, rc = -EIO; | |
511 | 511 | struct rio_dev *prev = NULL; |
512 | 512 | |
513 | 513 | /* Find switch with failed RIO link */ |
514 | 514 | |
515 | 515 | |
... | ... | @@ -522,20 +522,18 @@ |
522 | 522 | if (prev == NULL) |
523 | 523 | goto err_out; |
524 | 524 | |
525 | - /* Find port with failed RIO link */ | |
526 | - for (p_port = 0; | |
527 | - p_port < RIO_GET_TOTAL_PORTS(prev->swpinfo); p_port++) | |
528 | - if (prev->rswitch->nextdev[p_port] == rdev) | |
529 | - break; | |
525 | + dstid = (rdev->pef & RIO_PEF_SWITCH) ? | |
526 | + rdev->rswitch->destid : rdev->destid; | |
527 | + p_port = prev->rswitch->route_table[dstid]; | |
530 | 528 | |
531 | - if (p_port < RIO_GET_TOTAL_PORTS(prev->swpinfo)) { | |
529 | + if (p_port != RIO_INVALID_ROUTE) { | |
532 | 530 | pr_debug("RIO: link failed on [%s]-P%d\n", |
533 | 531 | rio_name(prev), p_port); |
534 | 532 | *nrdev = prev; |
535 | 533 | *npnum = p_port; |
536 | 534 | rc = 0; |
537 | 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 | 537 | err_out: |
540 | 538 | return rc; |
541 | 539 | } |
drivers/rapidio/rio.h
... | ... | @@ -38,6 +38,7 @@ |
38 | 38 | extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, |
39 | 39 | u8 hopcount, u16 table); |
40 | 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 | 43 | /* Structures internal to the RIO core code */ |
43 | 44 | extern struct device_attribute rio_dev_attrs[]; |
include/linux/rio.h
... | ... | @@ -177,6 +177,7 @@ |
177 | 177 | * @index: Port index, unique among all port interfaces of the same type |
178 | 178 | * @sys_size: RapidIO common transport system size |
179 | 179 | * @phy_type: RapidIO phy type |
180 | + * @phys_efptr: RIO port extended features pointer | |
180 | 181 | * @name: Port name string |
181 | 182 | * @priv: Master port private data |
182 | 183 | */ |
... | ... | @@ -198,6 +199,7 @@ |
198 | 199 | * 1 - Large size, 65536 devices. |
199 | 200 | */ |
200 | 201 | enum rio_phy_type phy_type; /* RapidIO phy type */ |
202 | + u32 phys_efptr; | |
201 | 203 | unsigned char name[40]; |
202 | 204 | void *priv; /* Master port private data */ |
203 | 205 | }; |