diff options
| -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 |
