diff options
-rw-r--r-- | drivers/pci/hotplug/shpchp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 7 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 48 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_pci.c | 314 |
4 files changed, 32 insertions, 338 deletions
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 1b345ae81ddb..5e99260987e8 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h | |||
@@ -63,7 +63,6 @@ struct pci_func { | |||
63 | u8 switch_save; | 63 | u8 switch_save; |
64 | u8 presence_save; | 64 | u8 presence_save; |
65 | u8 pwr_save; | 65 | u8 pwr_save; |
66 | u32 config_space[0x20]; | ||
67 | struct pci_dev* pci_dev; | 66 | struct pci_dev* pci_dev; |
68 | }; | 67 | }; |
69 | 68 | ||
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 3132d60a79f5..5d4fc28969d0 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c | |||
@@ -424,13 +424,6 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
424 | first_device_num = ctrl->slot_device_offset; | 424 | first_device_num = ctrl->slot_device_offset; |
425 | num_ctlr_slots = ctrl->num_slots; | 425 | num_ctlr_slots = ctrl->num_slots; |
426 | 426 | ||
427 | /* Store PCI Config Space for all devices on this bus */ | ||
428 | rc = shpchp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num); | ||
429 | if (rc) { | ||
430 | err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); | ||
431 | goto err_out_free_ctrl_bus; | ||
432 | } | ||
433 | |||
434 | ctrl->add_support = 1; | 427 | ctrl->add_support = 1; |
435 | 428 | ||
436 | /* Setup the slot information structures */ | 429 | /* Setup the slot information structures */ |
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 23dd61c4c66c..c55103f3cebd 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c | |||
@@ -328,21 +328,20 @@ static int slot_remove(struct pci_func * old_slot) | |||
328 | /** | 328 | /** |
329 | * bridge_slot_remove - Removes a node from the linked list of slots. | 329 | * bridge_slot_remove - Removes a node from the linked list of slots. |
330 | * @bridge: bridge to remove | 330 | * @bridge: bridge to remove |
331 | * @secondaryBus: secondary PCI bus number for bridge being removed | ||
332 | * @subordinateBus: subordinate PCI bus number for bridge being removed | ||
331 | * | 333 | * |
332 | * Returns 0 if successful, !0 otherwise. | 334 | * Returns 0 if successful, !0 otherwise. |
333 | */ | 335 | */ |
334 | static int bridge_slot_remove(struct pci_func *bridge) | 336 | static int bridge_slot_remove(struct pci_func *bridge, u8 secondaryBus, |
337 | u8 subordinateBus) | ||
335 | { | 338 | { |
336 | u8 subordinateBus, secondaryBus; | ||
337 | u8 tempBus; | 339 | u8 tempBus; |
338 | struct pci_func *next; | 340 | struct pci_func *next; |
339 | 341 | ||
340 | if (bridge == NULL) | 342 | if (bridge == NULL) |
341 | return(1); | 343 | return(1); |
342 | 344 | ||
343 | secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; | ||
344 | subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; | ||
345 | |||
346 | for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { | 345 | for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { |
347 | next = shpchp_slot_list[tempBus]; | 346 | next = shpchp_slot_list[tempBus]; |
348 | 347 | ||
@@ -410,16 +409,23 @@ struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index) | |||
410 | return(NULL); | 409 | return(NULL); |
411 | } | 410 | } |
412 | 411 | ||
413 | static int is_bridge(struct pci_func * func) | 412 | static int is_bridge(struct pci_func *func, struct controller *ctrl) |
414 | { | 413 | { |
415 | /* Check the header type */ | 414 | u8 hdr_type; |
416 | if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) | 415 | struct pci_bus *bus = ctrl->pci_dev->subordinate; |
416 | |||
417 | /* | ||
418 | * Note: device may have just been hot-added and not yet scanned | ||
419 | * by the pci core, so its pci_dev structure may not exist yet | ||
420 | */ | ||
421 | pci_bus_read_config_byte(bus, PCI_DEVFN(func->device, func->function), | ||
422 | PCI_HEADER_TYPE, &hdr_type); | ||
423 | if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) | ||
417 | return 1; | 424 | return 1; |
418 | else | 425 | else |
419 | return 0; | 426 | return 0; |
420 | } | 427 | } |
421 | 428 | ||
422 | |||
423 | /* The following routines constitute the bulk of the | 429 | /* The following routines constitute the bulk of the |
424 | hotplug controller logic | 430 | hotplug controller logic |
425 | */ | 431 | */ |
@@ -709,8 +715,6 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) | |||
709 | goto err_exit; | 715 | goto err_exit; |
710 | } | 716 | } |
711 | 717 | ||
712 | shpchp_save_slot_config(ctrl, func); | ||
713 | |||
714 | func->status = 0; | 718 | func->status = 0; |
715 | func->switch_save = 0x10; | 719 | func->switch_save = 0x10; |
716 | func->is_a_board = 0x01; | 720 | func->is_a_board = 0x01; |
@@ -769,10 +773,18 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) | |||
769 | u8 hp_slot; | 773 | u8 hp_slot; |
770 | u32 rc; | 774 | u32 rc; |
771 | struct slot *p_slot; | 775 | struct slot *p_slot; |
776 | u8 secondary = 0, subordinate = 0; | ||
777 | int remove_bridge; | ||
772 | 778 | ||
773 | if (func == NULL) | 779 | if (func == NULL) |
774 | return(1); | 780 | return(1); |
775 | 781 | ||
782 | if ((remove_bridge = is_bridge(func, ctrl))) { | ||
783 | /* Stash away bus information before we destroy it */ | ||
784 | secondary = func->pci_dev->subordinate->secondary; | ||
785 | subordinate = func->pci_dev->subordinate->subordinate; | ||
786 | } | ||
787 | |||
776 | if (shpchp_unconfigure_device(func)) | 788 | if (shpchp_unconfigure_device(func)) |
777 | return(1); | 789 | return(1); |
778 | 790 | ||
@@ -825,10 +837,11 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) | |||
825 | 837 | ||
826 | if (ctrl->add_support) { | 838 | if (ctrl->add_support) { |
827 | while (func) { | 839 | while (func) { |
828 | if (is_bridge(func)) { | 840 | if (remove_bridge) { |
829 | dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, | 841 | dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, |
830 | func->device, func->function); | 842 | func->device, func->function); |
831 | bridge_slot_remove(func); | 843 | bridge_slot_remove(func, secondary, |
844 | subordinate); | ||
832 | } else | 845 | } else |
833 | dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, | 846 | dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, |
834 | func->device, func->function); | 847 | func->device, func->function); |
@@ -1185,9 +1198,12 @@ int shpchp_enable_slot (struct slot *p_slot) | |||
1185 | 1198 | ||
1186 | rc = board_added(func, p_slot->ctrl); | 1199 | rc = board_added(func, p_slot->ctrl); |
1187 | if (rc) { | 1200 | if (rc) { |
1188 | if (is_bridge(func)) | 1201 | if (is_bridge(func, p_slot->ctrl)) { |
1189 | bridge_slot_remove(func); | 1202 | u8 secondary = func->pci_dev->subordinate->secondary; |
1190 | else | 1203 | u8 subordinate = |
1204 | func->pci_dev->subordinate->subordinate; | ||
1205 | bridge_slot_remove(func, secondary, subordinate); | ||
1206 | } else | ||
1191 | slot_remove(func); | 1207 | slot_remove(func); |
1192 | 1208 | ||
1193 | /* Setup slot structure with entry for empty slot */ | 1209 | /* Setup slot structure with entry for empty slot */ |
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index 6209972313f3..f51a97d7611f 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c | |||
@@ -166,317 +166,3 @@ int shpchp_unconfigure_device(struct pci_func* func) | |||
166 | return rc; | 166 | return rc; |
167 | } | 167 | } |
168 | 168 | ||
169 | /* More PCI configuration routines; this time centered around hotplug controller */ | ||
170 | |||
171 | |||
172 | /* | ||
173 | * shpchp_save_config | ||
174 | * | ||
175 | * Reads configuration for all slots in a PCI bus and saves info. | ||
176 | * | ||
177 | * Note: For non-hot plug busses, the slot # saved is the device # | ||
178 | * | ||
179 | * returns 0 if success | ||
180 | */ | ||
181 | int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num) | ||
182 | { | ||
183 | int rc; | ||
184 | u8 class_code; | ||
185 | u8 header_type; | ||
186 | u32 ID; | ||
187 | u8 secondary_bus; | ||
188 | struct pci_func *new_slot; | ||
189 | int sub_bus; | ||
190 | int FirstSupported; | ||
191 | int LastSupported; | ||
192 | int max_functions; | ||
193 | int function; | ||
194 | u8 DevError; | ||
195 | int device = 0; | ||
196 | int cloop = 0; | ||
197 | int stop_it; | ||
198 | int index; | ||
199 | int is_hot_plug = num_ctlr_slots || first_device_num; | ||
200 | struct pci_bus lpci_bus, *pci_bus; | ||
201 | |||
202 | dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, | ||
203 | num_ctlr_slots, first_device_num); | ||
204 | |||
205 | memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); | ||
206 | pci_bus = &lpci_bus; | ||
207 | |||
208 | dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, | ||
209 | num_ctlr_slots, first_device_num); | ||
210 | |||
211 | /* Decide which slots are supported */ | ||
212 | if (is_hot_plug) { | ||
213 | /********************************* | ||
214 | * is_hot_plug is the slot mask | ||
215 | *********************************/ | ||
216 | FirstSupported = first_device_num; | ||
217 | LastSupported = FirstSupported + num_ctlr_slots - 1; | ||
218 | } else { | ||
219 | FirstSupported = 0; | ||
220 | LastSupported = 0x1F; | ||
221 | } | ||
222 | |||
223 | dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, | ||
224 | LastSupported); | ||
225 | |||
226 | /* Save PCI configuration space for all devices in supported slots */ | ||
227 | pci_bus->number = busnumber; | ||
228 | for (device = FirstSupported; device <= LastSupported; device++) { | ||
229 | ID = 0xFFFFFFFF; | ||
230 | rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), | ||
231 | PCI_VENDOR_ID, &ID); | ||
232 | |||
233 | if (ID != 0xFFFFFFFF) { /* device in slot */ | ||
234 | rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), | ||
235 | 0x0B, &class_code); | ||
236 | if (rc) | ||
237 | return rc; | ||
238 | |||
239 | rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), | ||
240 | PCI_HEADER_TYPE, &header_type); | ||
241 | if (rc) | ||
242 | return rc; | ||
243 | |||
244 | dbg("class_code = %x, header_type = %x\n", class_code, header_type); | ||
245 | |||
246 | /* If multi-function device, set max_functions to 8 */ | ||
247 | if (header_type & 0x80) | ||
248 | max_functions = 8; | ||
249 | else | ||
250 | max_functions = 1; | ||
251 | |||
252 | function = 0; | ||
253 | |||
254 | do { | ||
255 | DevError = 0; | ||
256 | |||
257 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* P-P Bridge */ | ||
258 | /* Recurse the subordinate bus | ||
259 | * get the subordinate bus number | ||
260 | */ | ||
261 | rc = pci_bus_read_config_byte(pci_bus, | ||
262 | PCI_DEVFN(device, function), | ||
263 | PCI_SECONDARY_BUS, &secondary_bus); | ||
264 | if (rc) { | ||
265 | return rc; | ||
266 | } else { | ||
267 | sub_bus = (int) secondary_bus; | ||
268 | |||
269 | /* Save secondary bus cfg spc with this recursive call. */ | ||
270 | rc = shpchp_save_config(ctrl, sub_bus, 0, 0); | ||
271 | if (rc) | ||
272 | return rc; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | index = 0; | ||
277 | new_slot = shpchp_slot_find(busnumber, device, index++); | ||
278 | |||
279 | dbg("new_slot = %p\n", new_slot); | ||
280 | |||
281 | while (new_slot && (new_slot->function != (u8) function)) { | ||
282 | new_slot = shpchp_slot_find(busnumber, device, index++); | ||
283 | dbg("new_slot = %p\n", new_slot); | ||
284 | } | ||
285 | if (!new_slot) { | ||
286 | /* Setup slot structure. */ | ||
287 | new_slot = shpchp_slot_create(busnumber); | ||
288 | dbg("new_slot = %p\n", new_slot); | ||
289 | |||
290 | if (new_slot == NULL) | ||
291 | return(1); | ||
292 | } | ||
293 | |||
294 | new_slot->bus = (u8) busnumber; | ||
295 | new_slot->device = (u8) device; | ||
296 | new_slot->function = (u8) function; | ||
297 | new_slot->is_a_board = 1; | ||
298 | new_slot->switch_save = 0x10; | ||
299 | new_slot->pwr_save = 1; | ||
300 | /* In case of unsupported board */ | ||
301 | new_slot->status = DevError; | ||
302 | new_slot->pci_dev = pci_find_slot(new_slot->bus, | ||
303 | (new_slot->device << 3) | new_slot->function); | ||
304 | dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev); | ||
305 | |||
306 | for (cloop = 0; cloop < 0x20; cloop++) { | ||
307 | rc = pci_bus_read_config_dword(pci_bus, | ||
308 | PCI_DEVFN(device, function), | ||
309 | cloop << 2, | ||
310 | (u32 *) &(new_slot->config_space [cloop])); | ||
311 | /* dbg("new_slot->config_space[%x] = %x\n", | ||
312 | cloop, new_slot->config_space[cloop]); */ | ||
313 | if (rc) | ||
314 | return rc; | ||
315 | } | ||
316 | |||
317 | function++; | ||
318 | |||
319 | stop_it = 0; | ||
320 | |||
321 | /* this loop skips to the next present function | ||
322 | * reading in Class Code and Header type. | ||
323 | */ | ||
324 | |||
325 | while ((function < max_functions)&&(!stop_it)) { | ||
326 | rc = pci_bus_read_config_dword(pci_bus, | ||
327 | PCI_DEVFN(device, function), | ||
328 | PCI_VENDOR_ID, &ID); | ||
329 | |||
330 | if (ID == 0xFFFFFFFF) { /* nothing there. */ | ||
331 | function++; | ||
332 | dbg("Nothing there\n"); | ||
333 | } else { /* Something there */ | ||
334 | rc = pci_bus_read_config_byte(pci_bus, | ||
335 | PCI_DEVFN(device, function), | ||
336 | 0x0B, &class_code); | ||
337 | if (rc) | ||
338 | return rc; | ||
339 | |||
340 | rc = pci_bus_read_config_byte(pci_bus, | ||
341 | PCI_DEVFN(device, function), | ||
342 | PCI_HEADER_TYPE, &header_type); | ||
343 | if (rc) | ||
344 | return rc; | ||
345 | |||
346 | dbg("class_code = %x, header_type = %x\n", | ||
347 | class_code, header_type); | ||
348 | stop_it++; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | } while (function < max_functions); | ||
353 | /* End of IF (device in slot?) */ | ||
354 | } else if (is_hot_plug) { | ||
355 | /* Setup slot structure with entry for empty slot */ | ||
356 | new_slot = shpchp_slot_create(busnumber); | ||
357 | |||
358 | if (new_slot == NULL) { | ||
359 | return(1); | ||
360 | } | ||
361 | dbg("new_slot = %p\n", new_slot); | ||
362 | |||
363 | new_slot->bus = (u8) busnumber; | ||
364 | new_slot->device = (u8) device; | ||
365 | new_slot->function = 0; | ||
366 | new_slot->is_a_board = 0; | ||
367 | new_slot->presence_save = 0; | ||
368 | new_slot->switch_save = 0; | ||
369 | } | ||
370 | } /* End of FOR loop */ | ||
371 | |||
372 | return(0); | ||
373 | } | ||
374 | |||
375 | |||
376 | /* | ||
377 | * shpchp_save_slot_config | ||
378 | * | ||
379 | * Saves configuration info for all PCI devices in a given slot | ||
380 | * including subordinate busses. | ||
381 | * | ||
382 | * returns 0 if success | ||
383 | */ | ||
384 | int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot) | ||
385 | { | ||
386 | int rc; | ||
387 | u8 class_code; | ||
388 | u8 header_type; | ||
389 | u32 ID; | ||
390 | u8 secondary_bus; | ||
391 | int sub_bus; | ||
392 | int max_functions; | ||
393 | int function; | ||
394 | int cloop = 0; | ||
395 | int stop_it; | ||
396 | struct pci_bus lpci_bus, *pci_bus; | ||
397 | memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); | ||
398 | pci_bus = &lpci_bus; | ||
399 | pci_bus->number = new_slot->bus; | ||
400 | |||
401 | ID = 0xFFFFFFFF; | ||
402 | |||
403 | pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0), | ||
404 | PCI_VENDOR_ID, &ID); | ||
405 | |||
406 | if (ID != 0xFFFFFFFF) { /* device in slot */ | ||
407 | pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), | ||
408 | 0x0B, &class_code); | ||
409 | |||
410 | pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), | ||
411 | PCI_HEADER_TYPE, &header_type); | ||
412 | |||
413 | if (header_type & 0x80) /* Multi-function device */ | ||
414 | max_functions = 8; | ||
415 | else | ||
416 | max_functions = 1; | ||
417 | |||
418 | function = 0; | ||
419 | |||
420 | do { | ||
421 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ | ||
422 | /* Recurse the subordinate bus */ | ||
423 | pci_bus_read_config_byte(pci_bus, | ||
424 | PCI_DEVFN(new_slot->device, function), | ||
425 | PCI_SECONDARY_BUS, &secondary_bus); | ||
426 | |||
427 | sub_bus = (int) secondary_bus; | ||
428 | |||
429 | /* Save the config headers for the secondary bus. */ | ||
430 | rc = shpchp_save_config(ctrl, sub_bus, 0, 0); | ||
431 | |||
432 | if (rc) | ||
433 | return rc; | ||
434 | |||
435 | } /* End of IF */ | ||
436 | |||
437 | new_slot->status = 0; | ||
438 | |||
439 | for (cloop = 0; cloop < 0x20; cloop++) { | ||
440 | pci_bus_read_config_dword(pci_bus, | ||
441 | PCI_DEVFN(new_slot->device, function), | ||
442 | cloop << 2, | ||
443 | (u32 *) &(new_slot->config_space [cloop])); | ||
444 | } | ||
445 | |||
446 | function++; | ||
447 | |||
448 | stop_it = 0; | ||
449 | |||
450 | /* this loop skips to the next present function | ||
451 | * reading in the Class Code and the Header type. | ||
452 | */ | ||
453 | |||
454 | while ((function < max_functions) && (!stop_it)) { | ||
455 | pci_bus_read_config_dword(pci_bus, | ||
456 | PCI_DEVFN(new_slot->device, function), | ||
457 | PCI_VENDOR_ID, &ID); | ||
458 | |||
459 | if (ID == 0xFFFFFFFF) { /* nothing there. */ | ||
460 | function++; | ||
461 | } else { /* Something there */ | ||
462 | pci_bus_read_config_byte(pci_bus, | ||
463 | PCI_DEVFN(new_slot->device, function), | ||
464 | 0x0B, &class_code); | ||
465 | |||
466 | pci_bus_read_config_byte(pci_bus, | ||
467 | PCI_DEVFN(new_slot->device, function), | ||
468 | PCI_HEADER_TYPE, &header_type); | ||
469 | |||
470 | stop_it++; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | } while (function < max_functions); | ||
475 | } /* End of IF (device in slot?) */ | ||
476 | else { | ||
477 | return 2; | ||
478 | } | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||