diff options
Diffstat (limited to 'drivers/rapidio')
-rw-r--r-- | drivers/rapidio/rio-scan.c | 205 |
1 files changed, 170 insertions, 35 deletions
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 745670f535e8..48e9041dd1e2 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c | |||
@@ -54,6 +54,114 @@ static int rio_mport_phys_table[] = { | |||
54 | -1, | 54 | -1, |
55 | }; | 55 | }; |
56 | 56 | ||
57 | |||
58 | /* | ||
59 | * rio_destid_alloc - Allocate next available destID for given network | ||
60 | * net: RIO network | ||
61 | * | ||
62 | * Returns next available device destination ID for the specified RIO network. | ||
63 | * Marks allocated ID as one in use. | ||
64 | * Returns RIO_INVALID_DESTID if new destID is not available. | ||
65 | */ | ||
66 | static u16 rio_destid_alloc(struct rio_net *net) | ||
67 | { | ||
68 | int destid; | ||
69 | struct rio_id_table *idtab = &net->destid_table; | ||
70 | |||
71 | spin_lock(&idtab->lock); | ||
72 | destid = find_next_zero_bit(idtab->table, idtab->max, idtab->next); | ||
73 | if (destid >= idtab->max) | ||
74 | destid = find_first_zero_bit(idtab->table, idtab->max); | ||
75 | |||
76 | if (destid < idtab->max) { | ||
77 | idtab->next = destid + 1; | ||
78 | if (idtab->next >= idtab->max) | ||
79 | idtab->next = 0; | ||
80 | set_bit(destid, idtab->table); | ||
81 | destid += idtab->start; | ||
82 | } else | ||
83 | destid = RIO_INVALID_DESTID; | ||
84 | |||
85 | spin_unlock(&idtab->lock); | ||
86 | return (u16)destid; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * rio_destid_reserve - Reserve the specivied destID | ||
91 | * net: RIO network | ||
92 | * destid: destID to reserve | ||
93 | * | ||
94 | * Tries to reserve the specified destID. | ||
95 | * Returns 0 if successfull. | ||
96 | */ | ||
97 | static int rio_destid_reserve(struct rio_net *net, u16 destid) | ||
98 | { | ||
99 | int oldbit; | ||
100 | struct rio_id_table *idtab = &net->destid_table; | ||
101 | |||
102 | destid -= idtab->start; | ||
103 | spin_lock(&idtab->lock); | ||
104 | oldbit = test_and_set_bit(destid, idtab->table); | ||
105 | spin_unlock(&idtab->lock); | ||
106 | return oldbit; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * rio_destid_free - free a previously allocated destID | ||
111 | * net: RIO network | ||
112 | * destid: destID to free | ||
113 | * | ||
114 | * Makes the specified destID available for use. | ||
115 | */ | ||
116 | static void rio_destid_free(struct rio_net *net, u16 destid) | ||
117 | { | ||
118 | struct rio_id_table *idtab = &net->destid_table; | ||
119 | |||
120 | destid -= idtab->start; | ||
121 | spin_lock(&idtab->lock); | ||
122 | clear_bit(destid, idtab->table); | ||
123 | spin_unlock(&idtab->lock); | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * rio_destid_first - return first destID in use | ||
128 | * net: RIO network | ||
129 | */ | ||
130 | static u16 rio_destid_first(struct rio_net *net) | ||
131 | { | ||
132 | int destid; | ||
133 | struct rio_id_table *idtab = &net->destid_table; | ||
134 | |||
135 | spin_lock(&idtab->lock); | ||
136 | destid = find_first_bit(idtab->table, idtab->max); | ||
137 | if (destid >= idtab->max) | ||
138 | destid = RIO_INVALID_DESTID; | ||
139 | else | ||
140 | destid += idtab->start; | ||
141 | spin_unlock(&idtab->lock); | ||
142 | return (u16)destid; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * rio_destid_next - return next destID in use | ||
147 | * net: RIO network | ||
148 | * from: destination ID from which search shall continue | ||
149 | */ | ||
150 | static u16 rio_destid_next(struct rio_net *net, u16 from) | ||
151 | { | ||
152 | int destid; | ||
153 | struct rio_id_table *idtab = &net->destid_table; | ||
154 | |||
155 | spin_lock(&idtab->lock); | ||
156 | destid = find_next_bit(idtab->table, idtab->max, from); | ||
157 | if (destid >= idtab->max) | ||
158 | destid = RIO_INVALID_DESTID; | ||
159 | else | ||
160 | destid += idtab->start; | ||
161 | spin_unlock(&idtab->lock); | ||
162 | return (u16)destid; | ||
163 | } | ||
164 | |||
57 | /** | 165 | /** |
58 | * rio_get_device_id - Get the base/extended device id for a device | 166 | * rio_get_device_id - Get the base/extended device id for a device |
59 | * @port: RIO master port | 167 | * @port: RIO master port |
@@ -171,10 +279,6 @@ static int rio_enum_host(struct rio_mport *port) | |||
171 | 279 | ||
172 | /* Set master port destid and init destid ctr */ | 280 | /* Set master port destid and init destid ctr */ |
173 | rio_local_set_device_id(port, port->host_deviceid); | 281 | rio_local_set_device_id(port, port->host_deviceid); |
174 | |||
175 | if (next_destid == port->host_deviceid) | ||
176 | next_destid++; | ||
177 | |||
178 | return 0; | 282 | return 0; |
179 | } | 283 | } |
180 | 284 | ||
@@ -441,9 +545,8 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
441 | if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { | 545 | if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { |
442 | if (do_enum) { | 546 | if (do_enum) { |
443 | rio_set_device_id(port, destid, hopcount, next_destid); | 547 | rio_set_device_id(port, destid, hopcount, next_destid); |
444 | rdev->destid = next_destid++; | 548 | rdev->destid = next_destid; |
445 | if (next_destid == port->host_deviceid) | 549 | next_destid = rio_destid_alloc(net); |
446 | next_destid++; | ||
447 | } else | 550 | } else |
448 | rdev->destid = rio_get_device_id(port, destid, hopcount); | 551 | rdev->destid = rio_get_device_id(port, destid, hopcount); |
449 | 552 | ||
@@ -742,12 +845,7 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) | |||
742 | static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | 845 | static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, |
743 | u8 hopcount, struct rio_dev *prev, int prev_port) | 846 | u8 hopcount, struct rio_dev *prev, int prev_port) |
744 | { | 847 | { |
745 | int port_num; | ||
746 | int cur_destid; | ||
747 | int sw_destid; | ||
748 | int sw_inport; | ||
749 | struct rio_dev *rdev; | 848 | struct rio_dev *rdev; |
750 | u16 destid; | ||
751 | u32 regval; | 849 | u32 regval; |
752 | int tmp; | 850 | int tmp; |
753 | 851 | ||
@@ -813,19 +911,26 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | |||
813 | return -1; | 911 | return -1; |
814 | 912 | ||
815 | if (rio_is_switch(rdev)) { | 913 | if (rio_is_switch(rdev)) { |
914 | int sw_destid; | ||
915 | int cur_destid; | ||
916 | int sw_inport; | ||
917 | u16 destid; | ||
918 | int port_num; | ||
919 | |||
816 | sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo); | 920 | sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo); |
817 | rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, | 921 | rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, |
818 | port->host_deviceid, sw_inport, 0); | 922 | port->host_deviceid, sw_inport, 0); |
819 | rdev->rswitch->route_table[port->host_deviceid] = sw_inport; | 923 | rdev->rswitch->route_table[port->host_deviceid] = sw_inport; |
820 | 924 | ||
821 | for (destid = 0; destid < next_destid; destid++) { | 925 | destid = rio_destid_first(net); |
822 | if (destid == port->host_deviceid) | 926 | while (destid != RIO_INVALID_DESTID && destid < next_destid) { |
823 | continue; | 927 | if (destid != port->host_deviceid) { |
824 | rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, | 928 | rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, |
825 | destid, sw_inport, 0); | 929 | destid, sw_inport, 0); |
826 | rdev->rswitch->route_table[destid] = sw_inport; | 930 | rdev->rswitch->route_table[destid] = sw_inport; |
931 | } | ||
932 | destid = rio_destid_next(net, destid + 1); | ||
827 | } | 933 | } |
828 | |||
829 | pr_debug( | 934 | pr_debug( |
830 | "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", | 935 | "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", |
831 | rio_name(rdev), rdev->vid, rdev->did, | 936 | rio_name(rdev), rdev->vid, rdev->did, |
@@ -863,19 +968,22 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | |||
863 | return -1; | 968 | return -1; |
864 | 969 | ||
865 | /* Update routing tables */ | 970 | /* Update routing tables */ |
866 | if (next_destid > cur_destid) { | 971 | destid = rio_destid_next(net, cur_destid + 1); |
972 | if (destid != RIO_INVALID_DESTID) { | ||
867 | for (destid = cur_destid; | 973 | for (destid = cur_destid; |
868 | destid < next_destid; destid++) { | 974 | destid < next_destid;) { |
869 | if (destid == port->host_deviceid) | 975 | if (destid != port->host_deviceid) { |
870 | continue; | 976 | rio_route_add_entry(rdev, |
871 | rio_route_add_entry(rdev, | ||
872 | RIO_GLOBAL_TABLE, | 977 | RIO_GLOBAL_TABLE, |
873 | destid, | 978 | destid, |
874 | port_num, | 979 | port_num, |
875 | 0); | 980 | 0); |
876 | rdev->rswitch-> | 981 | rdev->rswitch-> |
877 | route_table[destid] = | 982 | route_table[destid] = |
878 | port_num; | 983 | port_num; |
984 | } | ||
985 | destid = rio_destid_next(net, | ||
986 | destid + 1); | ||
879 | } | 987 | } |
880 | } | 988 | } |
881 | } else { | 989 | } else { |
@@ -901,11 +1009,8 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | |||
901 | rio_init_em(rdev); | 1009 | rio_init_em(rdev); |
902 | 1010 | ||
903 | /* Check for empty switch */ | 1011 | /* Check for empty switch */ |
904 | if (next_destid == sw_destid) { | 1012 | if (next_destid == sw_destid) |
905 | next_destid++; | 1013 | next_destid = rio_destid_alloc(net); |
906 | if (next_destid == port->host_deviceid) | ||
907 | next_destid++; | ||
908 | } | ||
909 | 1014 | ||
910 | rdev->destid = sw_destid; | 1015 | rdev->destid = sw_destid; |
911 | } else | 1016 | } else |
@@ -1043,17 +1148,39 @@ static int rio_mport_is_active(struct rio_mport *port) | |||
1043 | /** | 1148 | /** |
1044 | * rio_alloc_net- Allocate and configure a new RIO network | 1149 | * rio_alloc_net- Allocate and configure a new RIO network |
1045 | * @port: Master port associated with the RIO network | 1150 | * @port: Master port associated with the RIO network |
1151 | * @do_enum: Enumeration/Discovery mode flag | ||
1152 | * @start: logical minimal start id for new net | ||
1046 | * | 1153 | * |
1047 | * Allocates a RIO network structure, initializes per-network | 1154 | * Allocates a RIO network structure, initializes per-network |
1048 | * list heads, and adds the associated master port to the | 1155 | * list heads, and adds the associated master port to the |
1049 | * network list of associated master ports. Returns a | 1156 | * network list of associated master ports. Returns a |
1050 | * RIO network pointer on success or %NULL on failure. | 1157 | * RIO network pointer on success or %NULL on failure. |
1051 | */ | 1158 | */ |
1052 | static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) | 1159 | static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port, |
1160 | int do_enum, u16 start) | ||
1053 | { | 1161 | { |
1054 | struct rio_net *net; | 1162 | struct rio_net *net; |
1055 | 1163 | ||
1056 | net = kzalloc(sizeof(struct rio_net), GFP_KERNEL); | 1164 | net = kzalloc(sizeof(struct rio_net), GFP_KERNEL); |
1165 | if (net && do_enum) { | ||
1166 | net->destid_table.table = kzalloc( | ||
1167 | BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)) * | ||
1168 | sizeof(long), | ||
1169 | GFP_KERNEL); | ||
1170 | |||
1171 | if (net->destid_table.table == NULL) { | ||
1172 | pr_err("RIO: failed to allocate destID table\n"); | ||
1173 | kfree(net); | ||
1174 | net = NULL; | ||
1175 | } else { | ||
1176 | net->destid_table.start = start; | ||
1177 | net->destid_table.next = 0; | ||
1178 | net->destid_table.max = | ||
1179 | RIO_MAX_ROUTE_ENTRIES(port->sys_size); | ||
1180 | spin_lock_init(&net->destid_table.lock); | ||
1181 | } | ||
1182 | } | ||
1183 | |||
1057 | if (net) { | 1184 | if (net) { |
1058 | INIT_LIST_HEAD(&net->node); | 1185 | INIT_LIST_HEAD(&net->node); |
1059 | INIT_LIST_HEAD(&net->devices); | 1186 | INIT_LIST_HEAD(&net->devices); |
@@ -1163,12 +1290,16 @@ int __devinit rio_enum_mport(struct rio_mport *mport) | |||
1163 | 1290 | ||
1164 | /* If master port has an active link, allocate net and enum peers */ | 1291 | /* If master port has an active link, allocate net and enum peers */ |
1165 | if (rio_mport_is_active(mport)) { | 1292 | if (rio_mport_is_active(mport)) { |
1166 | if (!(net = rio_alloc_net(mport))) { | 1293 | net = rio_alloc_net(mport, 1, 0); |
1294 | if (!net) { | ||
1167 | printk(KERN_ERR "RIO: failed to allocate new net\n"); | 1295 | printk(KERN_ERR "RIO: failed to allocate new net\n"); |
1168 | rc = -ENOMEM; | 1296 | rc = -ENOMEM; |
1169 | goto out; | 1297 | goto out; |
1170 | } | 1298 | } |
1171 | 1299 | ||
1300 | /* reserve mport destID in new net */ | ||
1301 | rio_destid_reserve(net, mport->host_deviceid); | ||
1302 | |||
1172 | /* Enable Input Output Port (transmitter reviever) */ | 1303 | /* Enable Input Output Port (transmitter reviever) */ |
1173 | rio_enable_rx_tx_port(mport, 1, 0, 0, 0); | 1304 | rio_enable_rx_tx_port(mport, 1, 0, 0, 0); |
1174 | 1305 | ||
@@ -1176,6 +1307,8 @@ int __devinit rio_enum_mport(struct rio_mport *mport) | |||
1176 | rio_local_write_config_32(mport, RIO_COMPONENT_TAG_CSR, | 1307 | rio_local_write_config_32(mport, RIO_COMPONENT_TAG_CSR, |
1177 | next_comptag++); | 1308 | next_comptag++); |
1178 | 1309 | ||
1310 | next_destid = rio_destid_alloc(net); | ||
1311 | |||
1179 | if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) { | 1312 | if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) { |
1180 | /* A higher priority host won enumeration, bail. */ | 1313 | /* A higher priority host won enumeration, bail. */ |
1181 | printk(KERN_INFO | 1314 | printk(KERN_INFO |
@@ -1185,6 +1318,8 @@ int __devinit rio_enum_mport(struct rio_mport *mport) | |||
1185 | rc = -EBUSY; | 1318 | rc = -EBUSY; |
1186 | goto out; | 1319 | goto out; |
1187 | } | 1320 | } |
1321 | /* free the last allocated destID (unused) */ | ||
1322 | rio_destid_free(net, next_destid); | ||
1188 | rio_update_route_tables(net); | 1323 | rio_update_route_tables(net); |
1189 | rio_clear_locks(net); | 1324 | rio_clear_locks(net); |
1190 | rio_pw_enable(mport, 1); | 1325 | rio_pw_enable(mport, 1); |
@@ -1265,7 +1400,7 @@ int __devinit rio_disc_mport(struct rio_mport *mport) | |||
1265 | enum_done: | 1400 | enum_done: |
1266 | pr_debug("RIO: ... enumeration done\n"); | 1401 | pr_debug("RIO: ... enumeration done\n"); |
1267 | 1402 | ||
1268 | net = rio_alloc_net(mport); | 1403 | net = rio_alloc_net(mport, 0, 0); |
1269 | if (!net) { | 1404 | if (!net) { |
1270 | printk(KERN_ERR "RIO: Failed to allocate new net\n"); | 1405 | printk(KERN_ERR "RIO: Failed to allocate new net\n"); |
1271 | goto bail; | 1406 | goto bail; |