diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 8 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_core.c | 129 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 48 |
3 files changed, 87 insertions, 98 deletions
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 885838a2e93f..de9df80ffb50 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h | |||
@@ -60,10 +60,7 @@ struct acpiphp_slot; | |||
60 | * struct slot - slot information for each *physical* slot | 60 | * struct slot - slot information for each *physical* slot |
61 | */ | 61 | */ |
62 | struct slot { | 62 | struct slot { |
63 | u8 number; | ||
64 | struct hotplug_slot *hotplug_slot; | 63 | struct hotplug_slot *hotplug_slot; |
65 | struct list_head slot_list; | ||
66 | |||
67 | struct acpiphp_slot *acpi_slot; | 64 | struct acpiphp_slot *acpi_slot; |
68 | }; | 65 | }; |
69 | 66 | ||
@@ -119,9 +116,9 @@ struct acpiphp_slot { | |||
119 | struct acpiphp_bridge *bridge; /* parent */ | 116 | struct acpiphp_bridge *bridge; /* parent */ |
120 | struct list_head funcs; /* one slot may have different | 117 | struct list_head funcs; /* one slot may have different |
121 | objects (i.e. for each function) */ | 118 | objects (i.e. for each function) */ |
119 | struct slot *slot; | ||
122 | struct mutex crit_sect; | 120 | struct mutex crit_sect; |
123 | 121 | ||
124 | u32 id; /* slot id (serial #) for hotplug core */ | ||
125 | u8 device; /* pci device# */ | 122 | u8 device; /* pci device# */ |
126 | 123 | ||
127 | u32 sun; /* ACPI _SUN (slot unique number) */ | 124 | u32 sun; /* ACPI _SUN (slot unique number) */ |
@@ -229,12 +226,13 @@ struct acpiphp_dock_station { | |||
229 | /* acpiphp_core.c */ | 226 | /* acpiphp_core.c */ |
230 | extern int acpiphp_register_attention(struct acpiphp_attention_info*info); | 227 | extern int acpiphp_register_attention(struct acpiphp_attention_info*info); |
231 | extern int acpiphp_unregister_attention(struct acpiphp_attention_info *info); | 228 | extern int acpiphp_unregister_attention(struct acpiphp_attention_info *info); |
229 | extern int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot); | ||
230 | extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); | ||
232 | 231 | ||
233 | /* acpiphp_glue.c */ | 232 | /* acpiphp_glue.c */ |
234 | extern int acpiphp_glue_init (void); | 233 | extern int acpiphp_glue_init (void); |
235 | extern void acpiphp_glue_exit (void); | 234 | extern void acpiphp_glue_exit (void); |
236 | extern int acpiphp_get_num_slots (void); | 235 | extern int acpiphp_get_num_slots (void); |
237 | extern struct acpiphp_slot *get_slot_from_id (int id); | ||
238 | typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); | 236 | typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); |
239 | void handle_hotplug_event_func(acpi_handle, u32, void*); | 237 | void handle_hotplug_event_func(acpi_handle, u32, void*); |
240 | 238 | ||
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index bce71c933478..4f1b0da8e47e 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c | |||
@@ -44,8 +44,6 @@ | |||
44 | #include "pci_hotplug.h" | 44 | #include "pci_hotplug.h" |
45 | #include "acpiphp.h" | 45 | #include "acpiphp.h" |
46 | 46 | ||
47 | static LIST_HEAD(slot_list); | ||
48 | |||
49 | #define MY_NAME "acpiphp" | 47 | #define MY_NAME "acpiphp" |
50 | 48 | ||
51 | static int debug; | 49 | static int debug; |
@@ -341,62 +339,53 @@ static void release_slot(struct hotplug_slot *hotplug_slot) | |||
341 | kfree(slot); | 339 | kfree(slot); |
342 | } | 340 | } |
343 | 341 | ||
344 | /** | 342 | /* callback routine to initialize 'struct slot' for each slot */ |
345 | * init_slots - initialize 'struct slot' structures for each slot | 343 | int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) |
346 | * | ||
347 | */ | ||
348 | static int __init init_slots(void) | ||
349 | { | 344 | { |
350 | struct slot *slot; | 345 | struct slot *slot; |
346 | struct hotplug_slot *hotplug_slot; | ||
347 | struct hotplug_slot_info *hotplug_slot_info; | ||
351 | int retval = -ENOMEM; | 348 | int retval = -ENOMEM; |
352 | int i; | 349 | |
353 | 350 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | |
354 | for (i = 0; i < num_slots; ++i) { | 351 | if (!slot) |
355 | slot = kmalloc(sizeof(struct slot), GFP_KERNEL); | 352 | goto error; |
356 | if (!slot) | 353 | |
357 | goto error; | 354 | slot->hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); |
358 | memset(slot, 0, sizeof(struct slot)); | 355 | if (!slot->hotplug_slot) |
359 | 356 | goto error_slot; | |
360 | slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL); | 357 | |
361 | if (!slot->hotplug_slot) | 358 | slot->hotplug_slot->info = kzalloc(sizeof(*hotplug_slot_info), |
362 | goto error_slot; | 359 | GFP_KERNEL); |
363 | memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); | 360 | if (!slot->hotplug_slot->info) |
364 | 361 | goto error_hpslot; | |
365 | slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); | 362 | |
366 | if (!slot->hotplug_slot->info) | 363 | slot->hotplug_slot->name = kzalloc(SLOT_NAME_SIZE, GFP_KERNEL); |
367 | goto error_hpslot; | 364 | if (!slot->hotplug_slot->name) |
368 | memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info)); | 365 | goto error_info; |
369 | 366 | ||
370 | slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); | 367 | slot->hotplug_slot->private = slot; |
371 | if (!slot->hotplug_slot->name) | 368 | slot->hotplug_slot->release = &release_slot; |
372 | goto error_info; | 369 | slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; |
373 | 370 | ||
374 | slot->number = i; | 371 | slot->acpi_slot = acpiphp_slot; |
375 | 372 | slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); | |
376 | slot->hotplug_slot->private = slot; | 373 | slot->hotplug_slot->info->attention_status = 0; |
377 | slot->hotplug_slot->release = &release_slot; | 374 | slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); |
378 | slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; | 375 | slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); |
379 | 376 | slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; | |
380 | slot->acpi_slot = get_slot_from_id(i); | 377 | slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; |
381 | slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); | 378 | |
382 | slot->hotplug_slot->info->attention_status = 0; | 379 | acpiphp_slot->slot = slot; |
383 | slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); | 380 | make_slot_name(slot); |
384 | slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); | 381 | |
385 | slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; | 382 | retval = pci_hp_register(slot->hotplug_slot); |
386 | slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; | 383 | if (retval) { |
387 | 384 | err("pci_hp_register failed with error %d\n", retval); | |
388 | make_slot_name(slot); | 385 | goto error_name; |
389 | 386 | } | |
390 | retval = pci_hp_register(slot->hotplug_slot); | 387 | |
391 | if (retval) { | 388 | info("Slot [%s] registered\n", slot->hotplug_slot->name); |
392 | err("pci_hp_register failed with error %d\n", retval); | ||
393 | goto error_name; | ||
394 | } | ||
395 | |||
396 | /* add slot to our internal list */ | ||
397 | list_add(&slot->slot_list, &slot_list); | ||
398 | info("Slot [%s] registered\n", slot->hotplug_slot->name); | ||
399 | } | ||
400 | 389 | ||
401 | return 0; | 390 | return 0; |
402 | error_name: | 391 | error_name: |
@@ -412,17 +401,16 @@ error: | |||
412 | } | 401 | } |
413 | 402 | ||
414 | 403 | ||
415 | static void __exit cleanup_slots (void) | 404 | void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot) |
416 | { | 405 | { |
417 | struct list_head *tmp, *n; | 406 | struct slot *slot = acpiphp_slot->slot; |
418 | struct slot *slot; | 407 | int retval = 0; |
419 | 408 | ||
420 | list_for_each_safe (tmp, n, &slot_list) { | 409 | info ("Slot [%s] unregistered\n", slot->hotplug_slot->name); |
421 | /* memory will be freed in release_slot callback */ | 410 | |
422 | slot = list_entry(tmp, struct slot, slot_list); | 411 | retval = pci_hp_deregister(slot->hotplug_slot); |
423 | list_del(&slot->slot_list); | 412 | if (retval) |
424 | pci_hp_deregister(slot->hotplug_slot); | 413 | err("pci_hp_deregister failed with error %d\n", retval); |
425 | } | ||
426 | } | 414 | } |
427 | 415 | ||
428 | 416 | ||
@@ -439,16 +427,21 @@ static int __init acpiphp_init(void) | |||
439 | 427 | ||
440 | /* read all the ACPI info from the system */ | 428 | /* read all the ACPI info from the system */ |
441 | retval = init_acpi(); | 429 | retval = init_acpi(); |
442 | if (retval && !(docking_station)) | ||
443 | return retval; | ||
444 | 430 | ||
445 | return init_slots(); | 431 | /* if we have found a docking station, we should |
432 | * go ahead and load even if init_acpi has found | ||
433 | * no slots. This handles the case when the _DCK | ||
434 | * method not defined under the actual dock bridge | ||
435 | */ | ||
436 | if (docking_station) | ||
437 | return 0; | ||
438 | else | ||
439 | return retval; | ||
446 | } | 440 | } |
447 | 441 | ||
448 | 442 | ||
449 | static void __exit acpiphp_exit(void) | 443 | static void __exit acpiphp_exit(void) |
450 | { | 444 | { |
451 | cleanup_slots(); | ||
452 | /* deallocate internal data structures etc. */ | 445 | /* deallocate internal data structures etc. */ |
453 | acpiphp_glue_exit(); | 446 | acpiphp_glue_exit(); |
454 | 447 | ||
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 22d0f1cf1362..dbfdac63cb49 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -128,8 +128,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
128 | acpi_handle tmp; | 128 | acpi_handle tmp; |
129 | acpi_status status = AE_OK; | 129 | acpi_status status = AE_OK; |
130 | unsigned long adr, sun; | 130 | unsigned long adr, sun; |
131 | int device, function; | 131 | int device, function, retval; |
132 | static int num_slots = 0; /* XXX if we support I/O node hotplug... */ | ||
133 | 132 | ||
134 | status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); | 133 | status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); |
135 | 134 | ||
@@ -198,7 +197,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
198 | 197 | ||
199 | memset(slot, 0, sizeof(struct acpiphp_slot)); | 198 | memset(slot, 0, sizeof(struct acpiphp_slot)); |
200 | slot->bridge = bridge; | 199 | slot->bridge = bridge; |
201 | slot->id = num_slots++; | ||
202 | slot->device = device; | 200 | slot->device = device; |
203 | slot->sun = sun; | 201 | slot->sun = sun; |
204 | INIT_LIST_HEAD(&slot->funcs); | 202 | INIT_LIST_HEAD(&slot->funcs); |
@@ -212,6 +210,11 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
212 | dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n", | 210 | dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n", |
213 | slot->sun, pci_domain_nr(bridge->pci_bus), | 211 | slot->sun, pci_domain_nr(bridge->pci_bus), |
214 | bridge->pci_bus->number, slot->device); | 212 | bridge->pci_bus->number, slot->device); |
213 | retval = acpiphp_register_hotplug_slot(slot); | ||
214 | if (retval) { | ||
215 | warn("acpiphp_register_hotplug_slot failed(err code = 0x%x)\n", retval); | ||
216 | goto err_exit; | ||
217 | } | ||
215 | } | 218 | } |
216 | 219 | ||
217 | newfunc->slot = slot; | 220 | newfunc->slot = slot; |
@@ -253,6 +256,14 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
253 | status = AE_OK; | 256 | status = AE_OK; |
254 | 257 | ||
255 | return status; | 258 | return status; |
259 | |||
260 | err_exit: | ||
261 | bridge->nr_slots--; | ||
262 | bridge->slots = slot->next; | ||
263 | kfree(slot); | ||
264 | kfree(newfunc); | ||
265 | |||
266 | return AE_OK; | ||
256 | } | 267 | } |
257 | 268 | ||
258 | 269 | ||
@@ -335,9 +346,16 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) | |||
335 | /* decode ACPI 2.0 _HPP (hot plug parameters) */ | 346 | /* decode ACPI 2.0 _HPP (hot plug parameters) */ |
336 | decode_hpp(bridge); | 347 | decode_hpp(bridge); |
337 | 348 | ||
349 | /* must be added to the list prior to calling register_slot */ | ||
350 | list_add(&bridge->list, &bridge_list); | ||
351 | |||
338 | /* register all slot objects under this bridge */ | 352 | /* register all slot objects under this bridge */ |
339 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, | 353 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, |
340 | register_slot, bridge, NULL); | 354 | register_slot, bridge, NULL); |
355 | if (ACPI_FAILURE(status)) { | ||
356 | list_del(&bridge->list); | ||
357 | return; | ||
358 | } | ||
341 | 359 | ||
342 | /* install notify handler */ | 360 | /* install notify handler */ |
343 | if (bridge->type != BRIDGE_TYPE_HOST) { | 361 | if (bridge->type != BRIDGE_TYPE_HOST) { |
@@ -350,8 +368,6 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) | |||
350 | err("failed to register interrupt notify handler\n"); | 368 | err("failed to register interrupt notify handler\n"); |
351 | } | 369 | } |
352 | } | 370 | } |
353 | |||
354 | list_add(&bridge->list, &bridge_list); | ||
355 | } | 371 | } |
356 | 372 | ||
357 | 373 | ||
@@ -555,6 +571,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
555 | list_del(list); | 571 | list_del(list); |
556 | kfree(func); | 572 | kfree(func); |
557 | } | 573 | } |
574 | acpiphp_unregister_hotplug_slot(slot); | ||
575 | list_del(&slot->funcs); | ||
558 | kfree(slot); | 576 | kfree(slot); |
559 | slot = next; | 577 | slot = next; |
560 | } | 578 | } |
@@ -1521,26 +1539,6 @@ static int acpiphp_for_each_slot(acpiphp_callback fn, void *data) | |||
1521 | } | 1539 | } |
1522 | #endif | 1540 | #endif |
1523 | 1541 | ||
1524 | /* search matching slot from id */ | ||
1525 | struct acpiphp_slot *get_slot_from_id(int id) | ||
1526 | { | ||
1527 | struct list_head *node; | ||
1528 | struct acpiphp_bridge *bridge; | ||
1529 | struct acpiphp_slot *slot; | ||
1530 | |||
1531 | list_for_each (node, &bridge_list) { | ||
1532 | bridge = (struct acpiphp_bridge *)node; | ||
1533 | for (slot = bridge->slots; slot; slot = slot->next) | ||
1534 | if (slot->id == id) | ||
1535 | return slot; | ||
1536 | } | ||
1537 | |||
1538 | /* should never happen! */ | ||
1539 | err("%s: no object for id %d\n", __FUNCTION__, id); | ||
1540 | WARN_ON(1); | ||
1541 | return NULL; | ||
1542 | } | ||
1543 | |||
1544 | 1542 | ||
1545 | /** | 1543 | /** |
1546 | * acpiphp_enable_slot - power on slot | 1544 | * acpiphp_enable_slot - power on slot |