diff options
author | Alexandre Bounine <alexandre.bounine@idt.com> | 2012-10-04 20:16:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-05 14:05:22 -0400 |
commit | a7071efc20567f4b6c454ff93ca80daf51bf93e9 (patch) | |
tree | 3c59852343f27c89ab7f3527f1fd8e4ba0fc8833 /drivers/rapidio | |
parent | fa3dbaa0109d9fff23f7fd28c245bee880757ecd (diff) |
rapidio: use device lists handling on per-net basis
Modify handling of device lists to resolve issues caused by using single
global list of RIO devices during enumeration/discovery. The most common
sign of existing issue is incorrect contents of switch routing tables in
systems with multiple mport controllers while single-port configuration
performs as expected.
Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Cc: Matt Porter <mporter@kernel.crashing.org>
Cc: Li Yang <leoli@freescale.com>
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.c | 60 |
1 files changed, 31 insertions, 29 deletions
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 0a27253c9215..8b7c4bce7a4a 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include "rio.h" | 38 | #include "rio.h" |
39 | 39 | ||
40 | LIST_HEAD(rio_devices); | 40 | LIST_HEAD(rio_devices); |
41 | static LIST_HEAD(rio_switches); | ||
42 | 41 | ||
43 | static void rio_init_em(struct rio_dev *rdev); | 42 | static void rio_init_em(struct rio_dev *rdev); |
44 | 43 | ||
@@ -104,14 +103,15 @@ static void rio_local_set_device_id(struct rio_mport *port, u16 did) | |||
104 | 103 | ||
105 | /** | 104 | /** |
106 | * rio_clear_locks- Release all host locks and signal enumeration complete | 105 | * rio_clear_locks- Release all host locks and signal enumeration complete |
107 | * @port: Master port to issue transaction | 106 | * @net: RIO network to run on |
108 | * | 107 | * |
109 | * Marks the component tag CSR on each device with the enumeration | 108 | * Marks the component tag CSR on each device with the enumeration |
110 | * complete flag. When complete, it then release the host locks on | 109 | * complete flag. When complete, it then release the host locks on |
111 | * each device. Returns 0 on success or %-EINVAL on failure. | 110 | * each device. Returns 0 on success or %-EINVAL on failure. |
112 | */ | 111 | */ |
113 | static int rio_clear_locks(struct rio_mport *port) | 112 | static int rio_clear_locks(struct rio_net *net) |
114 | { | 113 | { |
114 | struct rio_mport *port = net->hport; | ||
115 | struct rio_dev *rdev; | 115 | struct rio_dev *rdev; |
116 | u32 result; | 116 | u32 result; |
117 | int ret = 0; | 117 | int ret = 0; |
@@ -126,7 +126,7 @@ static int rio_clear_locks(struct rio_mport *port) | |||
126 | result); | 126 | result); |
127 | ret = -EINVAL; | 127 | ret = -EINVAL; |
128 | } | 128 | } |
129 | list_for_each_entry(rdev, &rio_devices, global_list) { | 129 | list_for_each_entry(rdev, &net->devices, net_list) { |
130 | rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR, | 130 | rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR, |
131 | port->host_deviceid); | 131 | port->host_deviceid); |
132 | rio_read_config_32(rdev, RIO_HOST_DID_LOCK_CSR, &result); | 132 | rio_read_config_32(rdev, RIO_HOST_DID_LOCK_CSR, &result); |
@@ -479,7 +479,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
479 | rswitch->clr_table(port, destid, hopcount, | 479 | rswitch->clr_table(port, destid, hopcount, |
480 | RIO_GLOBAL_TABLE); | 480 | RIO_GLOBAL_TABLE); |
481 | 481 | ||
482 | list_add_tail(&rswitch->node, &rio_switches); | 482 | list_add_tail(&rswitch->node, &net->switches); |
483 | 483 | ||
484 | } else { | 484 | } else { |
485 | if (do_enum) | 485 | if (do_enum) |
@@ -1058,6 +1058,7 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) | |||
1058 | if (net) { | 1058 | if (net) { |
1059 | INIT_LIST_HEAD(&net->node); | 1059 | INIT_LIST_HEAD(&net->node); |
1060 | INIT_LIST_HEAD(&net->devices); | 1060 | INIT_LIST_HEAD(&net->devices); |
1061 | INIT_LIST_HEAD(&net->switches); | ||
1061 | INIT_LIST_HEAD(&net->mports); | 1062 | INIT_LIST_HEAD(&net->mports); |
1062 | list_add_tail(&port->nnode, &net->mports); | 1063 | list_add_tail(&port->nnode, &net->mports); |
1063 | net->hport = port; | 1064 | net->hport = port; |
@@ -1068,24 +1069,24 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) | |||
1068 | 1069 | ||
1069 | /** | 1070 | /** |
1070 | * rio_update_route_tables- Updates route tables in switches | 1071 | * rio_update_route_tables- Updates route tables in switches |
1071 | * @port: Master port associated with the RIO network | 1072 | * @net: RIO network to run update on |
1072 | * | 1073 | * |
1073 | * For each enumerated device, ensure that each switch in a system | 1074 | * For each enumerated device, ensure that each switch in a system |
1074 | * has correct routing entries. Add routes for devices that where | 1075 | * has correct routing entries. Add routes for devices that where |
1075 | * unknown dirung the first enumeration pass through the switch. | 1076 | * unknown dirung the first enumeration pass through the switch. |
1076 | */ | 1077 | */ |
1077 | static void rio_update_route_tables(struct rio_mport *port) | 1078 | static void rio_update_route_tables(struct rio_net *net) |
1078 | { | 1079 | { |
1079 | struct rio_dev *rdev, *swrdev; | 1080 | struct rio_dev *rdev, *swrdev; |
1080 | struct rio_switch *rswitch; | 1081 | struct rio_switch *rswitch; |
1081 | u8 sport; | 1082 | u8 sport; |
1082 | u16 destid; | 1083 | u16 destid; |
1083 | 1084 | ||
1084 | list_for_each_entry(rdev, &rio_devices, global_list) { | 1085 | list_for_each_entry(rdev, &net->devices, net_list) { |
1085 | 1086 | ||
1086 | destid = rdev->destid; | 1087 | destid = rdev->destid; |
1087 | 1088 | ||
1088 | list_for_each_entry(rswitch, &rio_switches, node) { | 1089 | list_for_each_entry(rswitch, &net->switches, node) { |
1089 | 1090 | ||
1090 | if (rio_is_switch(rdev) && (rdev->rswitch == rswitch)) | 1091 | if (rio_is_switch(rdev) && (rdev->rswitch == rswitch)) |
1091 | continue; | 1092 | continue; |
@@ -1181,12 +1182,12 @@ int __devinit rio_enum_mport(struct rio_mport *mport) | |||
1181 | printk(KERN_INFO | 1182 | printk(KERN_INFO |
1182 | "RIO: master port %d device has lost enumeration to a remote host\n", | 1183 | "RIO: master port %d device has lost enumeration to a remote host\n", |
1183 | mport->id); | 1184 | mport->id); |
1184 | rio_clear_locks(mport); | 1185 | rio_clear_locks(net); |
1185 | rc = -EBUSY; | 1186 | rc = -EBUSY; |
1186 | goto out; | 1187 | goto out; |
1187 | } | 1188 | } |
1188 | rio_update_route_tables(mport); | 1189 | rio_update_route_tables(net); |
1189 | rio_clear_locks(mport); | 1190 | rio_clear_locks(net); |
1190 | rio_pw_enable(mport, 1); | 1191 | rio_pw_enable(mport, 1); |
1191 | } else { | 1192 | } else { |
1192 | printk(KERN_INFO "RIO: master port %d link inactive\n", | 1193 | printk(KERN_INFO "RIO: master port %d link inactive\n", |
@@ -1200,33 +1201,34 @@ int __devinit rio_enum_mport(struct rio_mport *mport) | |||
1200 | 1201 | ||
1201 | /** | 1202 | /** |
1202 | * rio_build_route_tables- Generate route tables from switch route entries | 1203 | * rio_build_route_tables- Generate route tables from switch route entries |
1204 | * @net: RIO network to run route tables scan on | ||
1203 | * | 1205 | * |
1204 | * For each switch device, generate a route table by copying existing | 1206 | * For each switch device, generate a route table by copying existing |
1205 | * route entries from the switch. | 1207 | * route entries from the switch. |
1206 | */ | 1208 | */ |
1207 | static void rio_build_route_tables(void) | 1209 | static void rio_build_route_tables(struct rio_net *net) |
1208 | { | 1210 | { |
1211 | struct rio_switch *rswitch; | ||
1209 | struct rio_dev *rdev; | 1212 | struct rio_dev *rdev; |
1210 | int i; | 1213 | int i; |
1211 | u8 sport; | 1214 | u8 sport; |
1212 | 1215 | ||
1213 | list_for_each_entry(rdev, &rio_devices, global_list) | 1216 | list_for_each_entry(rswitch, &net->switches, node) { |
1214 | if (rio_is_switch(rdev)) { | 1217 | rdev = sw_to_rio_dev(rswitch); |
1215 | rio_lock_device(rdev->net->hport, rdev->destid, | ||
1216 | rdev->hopcount, 1000); | ||
1217 | for (i = 0; | ||
1218 | i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); | ||
1219 | i++) { | ||
1220 | if (rio_route_get_entry(rdev, | ||
1221 | RIO_GLOBAL_TABLE, i, &sport, 0) < 0) | ||
1222 | continue; | ||
1223 | rdev->rswitch->route_table[i] = sport; | ||
1224 | } | ||
1225 | 1218 | ||
1226 | rio_unlock_device(rdev->net->hport, | 1219 | rio_lock_device(net->hport, rdev->destid, |
1227 | rdev->destid, | 1220 | rdev->hopcount, 1000); |
1228 | rdev->hopcount); | 1221 | for (i = 0; |
1222 | i < RIO_MAX_ROUTE_ENTRIES(net->hport->sys_size); | ||
1223 | i++) { | ||
1224 | if (rio_route_get_entry(rdev, RIO_GLOBAL_TABLE, | ||
1225 | i, &sport, 0) < 0) | ||
1226 | continue; | ||
1227 | rswitch->route_table[i] = sport; | ||
1229 | } | 1228 | } |
1229 | |||
1230 | rio_unlock_device(net->hport, rdev->destid, rdev->hopcount); | ||
1231 | } | ||
1230 | } | 1232 | } |
1231 | 1233 | ||
1232 | /** | 1234 | /** |
@@ -1284,7 +1286,7 @@ enum_done: | |||
1284 | goto bail; | 1286 | goto bail; |
1285 | } | 1287 | } |
1286 | 1288 | ||
1287 | rio_build_route_tables(); | 1289 | rio_build_route_tables(net); |
1288 | } | 1290 | } |
1289 | 1291 | ||
1290 | return 0; | 1292 | return 0; |