diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-02-12 06:56:56 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-02-12 06:56:56 -0500 |
commit | 4b49b9fe2b5220374ddc1c122cc31e00cc20365f (patch) | |
tree | d8c3c3ff835da7238cc0b1d6817f7bcf5b735ecd | |
parent | 7282059489868e0ed1b0d79765730c6b233a8399 (diff) | |
parent | 21369c77477a7f937174833c8094154f0f995710 (diff) |
Merge back earlier 'acpi-pci-hotplug' material.
Conflicts:
drivers/pci/hotplug/acpiphp_glue.c
-rw-r--r-- | drivers/acpi/acpica/nsxfeval.c | 33 | ||||
-rw-r--r-- | drivers/acpi/bus.c | 61 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 1 | ||||
-rw-r--r-- | drivers/acpi/pci_root.c | 2 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 181 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 16 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 405 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 27 | ||||
-rw-r--r-- | include/acpi/acpixf.h | 4 | ||||
-rw-r--r-- | include/linux/pci-acpi.h | 4 |
10 files changed, 332 insertions, 402 deletions
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 1f0c28ba50df..d6b33bc7bab0 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c | |||
@@ -923,19 +923,22 @@ ACPI_EXPORT_SYMBOL(acpi_detach_data) | |||
923 | 923 | ||
924 | /******************************************************************************* | 924 | /******************************************************************************* |
925 | * | 925 | * |
926 | * FUNCTION: acpi_get_data | 926 | * FUNCTION: acpi_get_data_full |
927 | * | 927 | * |
928 | * PARAMETERS: obj_handle - Namespace node | 928 | * PARAMETERS: obj_handle - Namespace node |
929 | * handler - Handler used in call to attach_data | 929 | * handler - Handler used in call to attach_data |
930 | * data - Where the data is returned | 930 | * data - Where the data is returned |
931 | * callback - function to execute before returning | ||
931 | * | 932 | * |
932 | * RETURN: Status | 933 | * RETURN: Status |
933 | * | 934 | * |
934 | * DESCRIPTION: Retrieve data that was previously attached to a namespace node. | 935 | * DESCRIPTION: Retrieve data that was previously attached to a namespace node |
936 | * and execute a callback before returning. | ||
935 | * | 937 | * |
936 | ******************************************************************************/ | 938 | ******************************************************************************/ |
937 | acpi_status | 939 | acpi_status |
938 | acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) | 940 | acpi_get_data_full(acpi_handle obj_handle, acpi_object_handler handler, |
941 | void **data, void (*callback)(void *)) | ||
939 | { | 942 | { |
940 | struct acpi_namespace_node *node; | 943 | struct acpi_namespace_node *node; |
941 | acpi_status status; | 944 | acpi_status status; |
@@ -960,10 +963,34 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) | |||
960 | } | 963 | } |
961 | 964 | ||
962 | status = acpi_ns_get_attached_data(node, handler, data); | 965 | status = acpi_ns_get_attached_data(node, handler, data); |
966 | if (ACPI_SUCCESS(status) && callback) { | ||
967 | callback(*data); | ||
968 | } | ||
963 | 969 | ||
964 | unlock_and_exit: | 970 | unlock_and_exit: |
965 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 971 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
966 | return (status); | 972 | return (status); |
967 | } | 973 | } |
968 | 974 | ||
975 | ACPI_EXPORT_SYMBOL(acpi_get_data_full) | ||
976 | |||
977 | /******************************************************************************* | ||
978 | * | ||
979 | * FUNCTION: acpi_get_data | ||
980 | * | ||
981 | * PARAMETERS: obj_handle - Namespace node | ||
982 | * handler - Handler used in call to attach_data | ||
983 | * data - Where the data is returned | ||
984 | * | ||
985 | * RETURN: Status | ||
986 | * | ||
987 | * DESCRIPTION: Retrieve data that was previously attached to a namespace node. | ||
988 | * | ||
989 | ******************************************************************************/ | ||
990 | acpi_status | ||
991 | acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) | ||
992 | { | ||
993 | return acpi_get_data_full(obj_handle, handler, data, NULL); | ||
994 | } | ||
995 | |||
969 | ACPI_EXPORT_SYMBOL(acpi_get_data) | 996 | ACPI_EXPORT_SYMBOL(acpi_get_data) |
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index fcb59c21c68d..e61e7b8a2eaf 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -340,60 +340,77 @@ static void acpi_bus_osc_support(void) | |||
340 | */ | 340 | */ |
341 | static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) | 341 | static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) |
342 | { | 342 | { |
343 | struct acpi_device *device = NULL; | 343 | struct acpi_device *adev; |
344 | struct acpi_driver *driver; | 344 | struct acpi_driver *driver; |
345 | 345 | acpi_status status; | |
346 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", | 346 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; |
347 | type, handle)); | ||
348 | 347 | ||
349 | switch (type) { | 348 | switch (type) { |
350 | |||
351 | case ACPI_NOTIFY_BUS_CHECK: | 349 | case ACPI_NOTIFY_BUS_CHECK: |
352 | /* TBD */ | 350 | acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); |
353 | break; | 351 | break; |
354 | 352 | ||
355 | case ACPI_NOTIFY_DEVICE_CHECK: | 353 | case ACPI_NOTIFY_DEVICE_CHECK: |
356 | /* TBD */ | 354 | acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); |
357 | break; | 355 | break; |
358 | 356 | ||
359 | case ACPI_NOTIFY_DEVICE_WAKE: | 357 | case ACPI_NOTIFY_DEVICE_WAKE: |
360 | /* TBD */ | 358 | acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n"); |
361 | break; | 359 | break; |
362 | 360 | ||
363 | case ACPI_NOTIFY_EJECT_REQUEST: | 361 | case ACPI_NOTIFY_EJECT_REQUEST: |
364 | /* TBD */ | 362 | acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); |
365 | break; | 363 | break; |
366 | 364 | ||
367 | case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: | 365 | case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: |
366 | acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n"); | ||
368 | /* TBD: Exactly what does 'light' mean? */ | 367 | /* TBD: Exactly what does 'light' mean? */ |
369 | break; | 368 | break; |
370 | 369 | ||
371 | case ACPI_NOTIFY_FREQUENCY_MISMATCH: | 370 | case ACPI_NOTIFY_FREQUENCY_MISMATCH: |
372 | /* TBD */ | 371 | acpi_handle_err(handle, "Device cannot be configured due " |
372 | "to a frequency mismatch\n"); | ||
373 | break; | 373 | break; |
374 | 374 | ||
375 | case ACPI_NOTIFY_BUS_MODE_MISMATCH: | 375 | case ACPI_NOTIFY_BUS_MODE_MISMATCH: |
376 | /* TBD */ | 376 | acpi_handle_err(handle, "Device cannot be configured due " |
377 | "to a bus mode mismatch\n"); | ||
377 | break; | 378 | break; |
378 | 379 | ||
379 | case ACPI_NOTIFY_POWER_FAULT: | 380 | case ACPI_NOTIFY_POWER_FAULT: |
380 | /* TBD */ | 381 | acpi_handle_err(handle, "Device has suffered a power fault\n"); |
381 | break; | 382 | break; |
382 | 383 | ||
383 | default: | 384 | default: |
384 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 385 | acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); |
385 | "Received unknown/unsupported notification [%08x]\n", | 386 | ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; |
386 | type)); | 387 | goto err; |
387 | break; | ||
388 | } | 388 | } |
389 | 389 | ||
390 | acpi_bus_get_device(handle, &device); | 390 | adev = acpi_bus_get_acpi_device(handle); |
391 | if (device) { | 391 | if (!adev) |
392 | driver = device->driver; | 392 | goto err; |
393 | if (driver && driver->ops.notify && | 393 | |
394 | (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) | 394 | driver = adev->driver; |
395 | driver->ops.notify(device, type); | 395 | if (driver && driver->ops.notify && |
396 | (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) | ||
397 | driver->ops.notify(adev, type); | ||
398 | |||
399 | switch (type) { | ||
400 | case ACPI_NOTIFY_BUS_CHECK: | ||
401 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
402 | case ACPI_NOTIFY_EJECT_REQUEST: | ||
403 | status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); | ||
404 | if (ACPI_SUCCESS(status)) | ||
405 | return; | ||
406 | default: | ||
407 | break; | ||
396 | } | 408 | } |
409 | acpi_bus_put_acpi_device(adev); | ||
410 | return; | ||
411 | |||
412 | err: | ||
413 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); | ||
397 | } | 414 | } |
398 | 415 | ||
399 | /* -------------------------------------------------------------------------- | 416 | /* -------------------------------------------------------------------------- |
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index dedbb2d802f1..143d5df5ec32 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
@@ -73,6 +73,7 @@ static inline void acpi_lpss_init(void) {} | |||
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | bool acpi_queue_hotplug_work(struct work_struct *work); | 75 | bool acpi_queue_hotplug_work(struct work_struct *work); |
76 | void acpi_device_hotplug(void *data, u32 src); | ||
76 | bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); | 77 | bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); |
77 | 78 | ||
78 | /* -------------------------------------------------------------------------- | 79 | /* -------------------------------------------------------------------------- |
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index c1c4102e6478..c288ff3c6998 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
@@ -51,7 +51,7 @@ static void acpi_pci_root_remove(struct acpi_device *device); | |||
51 | 51 | ||
52 | static int acpi_pci_root_scan_dependent(struct acpi_device *adev) | 52 | static int acpi_pci_root_scan_dependent(struct acpi_device *adev) |
53 | { | 53 | { |
54 | acpiphp_check_host_bridge(adev->handle); | 54 | acpiphp_check_host_bridge(adev); |
55 | return 0; | 55 | return 0; |
56 | } | 56 | } |
57 | 57 | ||
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 57b053f424d1..8bb48bfab1df 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -41,6 +41,7 @@ static DEFINE_MUTEX(acpi_scan_lock); | |||
41 | static LIST_HEAD(acpi_scan_handlers_list); | 41 | static LIST_HEAD(acpi_scan_handlers_list); |
42 | DEFINE_MUTEX(acpi_device_lock); | 42 | DEFINE_MUTEX(acpi_device_lock); |
43 | LIST_HEAD(acpi_wakeup_device_list); | 43 | LIST_HEAD(acpi_wakeup_device_list); |
44 | static DEFINE_MUTEX(acpi_hp_context_lock); | ||
44 | 45 | ||
45 | struct acpi_device_bus_id{ | 46 | struct acpi_device_bus_id{ |
46 | char bus_id[15]; | 47 | char bus_id[15]; |
@@ -60,6 +61,16 @@ void acpi_scan_lock_release(void) | |||
60 | } | 61 | } |
61 | EXPORT_SYMBOL_GPL(acpi_scan_lock_release); | 62 | EXPORT_SYMBOL_GPL(acpi_scan_lock_release); |
62 | 63 | ||
64 | void acpi_lock_hp_context(void) | ||
65 | { | ||
66 | mutex_lock(&acpi_hp_context_lock); | ||
67 | } | ||
68 | |||
69 | void acpi_unlock_hp_context(void) | ||
70 | { | ||
71 | mutex_unlock(&acpi_hp_context_lock); | ||
72 | } | ||
73 | |||
63 | int acpi_scan_add_handler(struct acpi_scan_handler *handler) | 74 | int acpi_scan_add_handler(struct acpi_scan_handler *handler) |
64 | { | 75 | { |
65 | if (!handler || !handler->attach) | 76 | if (!handler || !handler->attach) |
@@ -439,90 +450,74 @@ static int acpi_scan_bus_check(struct acpi_device *adev) | |||
439 | return 0; | 450 | return 0; |
440 | } | 451 | } |
441 | 452 | ||
442 | static void acpi_device_hotplug(void *data, u32 src) | 453 | static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) |
454 | { | ||
455 | switch (type) { | ||
456 | case ACPI_NOTIFY_BUS_CHECK: | ||
457 | return acpi_scan_bus_check(adev); | ||
458 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
459 | return acpi_scan_device_check(adev); | ||
460 | case ACPI_NOTIFY_EJECT_REQUEST: | ||
461 | case ACPI_OST_EC_OSPM_EJECT: | ||
462 | if (adev->handler && !adev->handler->hotplug.enabled) { | ||
463 | dev_info(&adev->dev, "Eject disabled\n"); | ||
464 | return -EPERM; | ||
465 | } | ||
466 | acpi_evaluate_hotplug_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST, | ||
467 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | ||
468 | return acpi_scan_hot_remove(adev); | ||
469 | } | ||
470 | return -EINVAL; | ||
471 | } | ||
472 | |||
473 | void acpi_device_hotplug(void *data, u32 src) | ||
443 | { | 474 | { |
444 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | 475 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; |
445 | struct acpi_device *adev = data; | 476 | struct acpi_device *adev = data; |
446 | int error; | 477 | int error = -ENODEV; |
447 | 478 | ||
448 | lock_device_hotplug(); | 479 | lock_device_hotplug(); |
449 | mutex_lock(&acpi_scan_lock); | 480 | mutex_lock(&acpi_scan_lock); |
450 | 481 | ||
451 | /* | 482 | /* |
452 | * The device object's ACPI handle cannot become invalid as long as we | 483 | * The device object's ACPI handle cannot become invalid as long as we |
453 | * are holding acpi_scan_lock, but it may have become invalid before | 484 | * are holding acpi_scan_lock, but it might have become invalid before |
454 | * that lock was acquired. | 485 | * that lock was acquired. |
455 | */ | 486 | */ |
456 | if (adev->handle == INVALID_ACPI_HANDLE) | 487 | if (adev->handle == INVALID_ACPI_HANDLE) |
457 | goto out; | ||
458 | |||
459 | switch (src) { | ||
460 | case ACPI_NOTIFY_BUS_CHECK: | ||
461 | error = acpi_scan_bus_check(adev); | ||
462 | break; | ||
463 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
464 | error = acpi_scan_device_check(adev); | ||
465 | break; | ||
466 | case ACPI_NOTIFY_EJECT_REQUEST: | ||
467 | case ACPI_OST_EC_OSPM_EJECT: | ||
468 | error = acpi_scan_hot_remove(adev); | ||
469 | break; | ||
470 | default: | ||
471 | error = -EINVAL; | ||
472 | break; | ||
473 | } | ||
474 | if (!error) | ||
475 | ost_code = ACPI_OST_SC_SUCCESS; | ||
476 | |||
477 | out: | ||
478 | acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); | ||
479 | put_device(&adev->dev); | ||
480 | mutex_unlock(&acpi_scan_lock); | ||
481 | unlock_device_hotplug(); | ||
482 | } | ||
483 | |||
484 | static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) | ||
485 | { | ||
486 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | ||
487 | struct acpi_device *adev; | ||
488 | acpi_status status; | ||
489 | |||
490 | if (acpi_bus_get_device(handle, &adev)) | ||
491 | goto err_out; | 488 | goto err_out; |
492 | 489 | ||
493 | switch (type) { | 490 | if (adev->flags.hotplug_notify) { |
494 | case ACPI_NOTIFY_BUS_CHECK: | 491 | error = acpi_generic_hotplug_event(adev, src); |
495 | acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); | 492 | if (error == -EPERM) { |
496 | break; | ||
497 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
498 | acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); | ||
499 | break; | ||
500 | case ACPI_NOTIFY_EJECT_REQUEST: | ||
501 | acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); | ||
502 | if (!adev->handler) | ||
503 | goto err_out; | ||
504 | |||
505 | if (!adev->handler->hotplug.enabled) { | ||
506 | acpi_handle_err(handle, "Eject disabled\n"); | ||
507 | ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; | 493 | ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; |
508 | goto err_out; | 494 | goto err_out; |
509 | } | 495 | } |
510 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, | 496 | } else { |
511 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | 497 | int (*event)(struct acpi_device *, u32); |
512 | break; | ||
513 | default: | ||
514 | /* non-hotplug event; possibly handled by other handler */ | ||
515 | return; | ||
516 | } | ||
517 | get_device(&adev->dev); | ||
518 | status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); | ||
519 | if (ACPI_SUCCESS(status)) | ||
520 | return; | ||
521 | 498 | ||
522 | put_device(&adev->dev); | 499 | acpi_lock_hp_context(); |
500 | event = adev->hp ? adev->hp->event : NULL; | ||
501 | acpi_unlock_hp_context(); | ||
502 | /* | ||
503 | * There may be additional notify handlers for device objects | ||
504 | * without the .event() callback, so ignore them here. | ||
505 | */ | ||
506 | if (event) | ||
507 | error = event(adev, src); | ||
508 | else | ||
509 | goto out; | ||
510 | } | ||
511 | if (!error) | ||
512 | ost_code = ACPI_OST_SC_SUCCESS; | ||
523 | 513 | ||
524 | err_out: | 514 | err_out: |
525 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); | 515 | acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); |
516 | |||
517 | out: | ||
518 | acpi_bus_put_acpi_device(adev); | ||
519 | mutex_unlock(&acpi_scan_lock); | ||
520 | unlock_device_hotplug(); | ||
526 | } | 521 | } |
527 | 522 | ||
528 | static ssize_t real_power_state_show(struct device *dev, | 523 | static ssize_t real_power_state_show(struct device *dev, |
@@ -570,8 +565,6 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, | |||
570 | if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) | 565 | if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) |
571 | return -ENODEV; | 566 | return -ENODEV; |
572 | 567 | ||
573 | acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, | ||
574 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | ||
575 | get_device(&acpi_device->dev); | 568 | get_device(&acpi_device->dev); |
576 | status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device, | 569 | status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device, |
577 | ACPI_OST_EC_OSPM_EJECT); | 570 | ACPI_OST_EC_OSPM_EJECT); |
@@ -1114,14 +1107,16 @@ static void acpi_scan_drop_device(acpi_handle handle, void *context) | |||
1114 | mutex_unlock(&acpi_device_del_lock); | 1107 | mutex_unlock(&acpi_device_del_lock); |
1115 | } | 1108 | } |
1116 | 1109 | ||
1117 | int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) | 1110 | static int acpi_get_device_data(acpi_handle handle, struct acpi_device **device, |
1111 | void (*callback)(void *)) | ||
1118 | { | 1112 | { |
1119 | acpi_status status; | 1113 | acpi_status status; |
1120 | 1114 | ||
1121 | if (!device) | 1115 | if (!device) |
1122 | return -EINVAL; | 1116 | return -EINVAL; |
1123 | 1117 | ||
1124 | status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device); | 1118 | status = acpi_get_data_full(handle, acpi_scan_drop_device, |
1119 | (void **)device, callback); | ||
1125 | if (ACPI_FAILURE(status) || !*device) { | 1120 | if (ACPI_FAILURE(status) || !*device) { |
1126 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", | 1121 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", |
1127 | handle)); | 1122 | handle)); |
@@ -1129,8 +1124,32 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) | |||
1129 | } | 1124 | } |
1130 | return 0; | 1125 | return 0; |
1131 | } | 1126 | } |
1127 | |||
1128 | int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) | ||
1129 | { | ||
1130 | return acpi_get_device_data(handle, device, NULL); | ||
1131 | } | ||
1132 | EXPORT_SYMBOL(acpi_bus_get_device); | 1132 | EXPORT_SYMBOL(acpi_bus_get_device); |
1133 | 1133 | ||
1134 | static void get_acpi_device(void *dev) | ||
1135 | { | ||
1136 | if (dev) | ||
1137 | get_device(&((struct acpi_device *)dev)->dev); | ||
1138 | } | ||
1139 | |||
1140 | struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle) | ||
1141 | { | ||
1142 | struct acpi_device *adev = NULL; | ||
1143 | |||
1144 | acpi_get_device_data(handle, &adev, get_acpi_device); | ||
1145 | return adev; | ||
1146 | } | ||
1147 | |||
1148 | void acpi_bus_put_acpi_device(struct acpi_device *adev) | ||
1149 | { | ||
1150 | put_device(&adev->dev); | ||
1151 | } | ||
1152 | |||
1134 | int acpi_device_add(struct acpi_device *device, | 1153 | int acpi_device_add(struct acpi_device *device, |
1135 | void (*release)(struct device *)) | 1154 | void (*release)(struct device *)) |
1136 | { | 1155 | { |
@@ -1941,33 +1960,19 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val) | |||
1941 | mutex_unlock(&acpi_scan_lock); | 1960 | mutex_unlock(&acpi_scan_lock); |
1942 | } | 1961 | } |
1943 | 1962 | ||
1944 | static void acpi_scan_init_hotplug(acpi_handle handle, int type) | 1963 | static void acpi_scan_init_hotplug(struct acpi_device *adev) |
1945 | { | 1964 | { |
1946 | struct acpi_device_pnp pnp = {}; | ||
1947 | struct acpi_hardware_id *hwid; | 1965 | struct acpi_hardware_id *hwid; |
1948 | struct acpi_scan_handler *handler; | ||
1949 | |||
1950 | INIT_LIST_HEAD(&pnp.ids); | ||
1951 | acpi_set_pnp_ids(handle, &pnp, type); | ||
1952 | 1966 | ||
1953 | if (!pnp.type.hardware_id) | 1967 | list_for_each_entry(hwid, &adev->pnp.ids, list) { |
1954 | goto out; | 1968 | struct acpi_scan_handler *handler; |
1955 | 1969 | ||
1956 | /* | ||
1957 | * This relies on the fact that acpi_install_notify_handler() will not | ||
1958 | * install the same notify handler routine twice for the same handle. | ||
1959 | */ | ||
1960 | list_for_each_entry(hwid, &pnp.ids, list) { | ||
1961 | handler = acpi_scan_match_handler(hwid->id, NULL); | 1970 | handler = acpi_scan_match_handler(hwid->id, NULL); |
1962 | if (handler) { | 1971 | if (handler) { |
1963 | acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | 1972 | adev->flags.hotplug_notify = true; |
1964 | acpi_hotplug_notify_cb, handler); | ||
1965 | break; | 1973 | break; |
1966 | } | 1974 | } |
1967 | } | 1975 | } |
1968 | |||
1969 | out: | ||
1970 | acpi_free_pnp_ids(&pnp); | ||
1971 | } | 1976 | } |
1972 | 1977 | ||
1973 | static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, | 1978 | static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, |
@@ -1991,12 +1996,12 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, | |||
1991 | return AE_OK; | 1996 | return AE_OK; |
1992 | } | 1997 | } |
1993 | 1998 | ||
1994 | acpi_scan_init_hotplug(handle, type); | ||
1995 | |||
1996 | acpi_add_single_object(&device, handle, type, sta); | 1999 | acpi_add_single_object(&device, handle, type, sta); |
1997 | if (!device) | 2000 | if (!device) |
1998 | return AE_CTRL_DEPTH; | 2001 | return AE_CTRL_DEPTH; |
1999 | 2002 | ||
2003 | acpi_scan_init_hotplug(device); | ||
2004 | |||
2000 | out: | 2005 | out: |
2001 | if (!*return_value) | 2006 | if (!*return_value) |
2002 | *return_value = device; | 2007 | *return_value = device; |
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index b6162be4df40..2b859249303b 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h | |||
@@ -93,7 +93,6 @@ struct acpiphp_slot { | |||
93 | struct list_head funcs; /* one slot may have different | 93 | struct list_head funcs; /* one slot may have different |
94 | objects (i.e. for each function) */ | 94 | objects (i.e. for each function) */ |
95 | struct slot *slot; | 95 | struct slot *slot; |
96 | struct mutex crit_sect; | ||
97 | 96 | ||
98 | u8 device; /* pci device# */ | 97 | u8 device; /* pci device# */ |
99 | u32 flags; /* see below */ | 98 | u32 flags; /* see below */ |
@@ -117,20 +116,30 @@ struct acpiphp_func { | |||
117 | }; | 116 | }; |
118 | 117 | ||
119 | struct acpiphp_context { | 118 | struct acpiphp_context { |
120 | acpi_handle handle; | 119 | struct acpi_hotplug_context hp; |
121 | struct acpiphp_func func; | 120 | struct acpiphp_func func; |
122 | struct acpiphp_bridge *bridge; | 121 | struct acpiphp_bridge *bridge; |
123 | unsigned int refcount; | 122 | unsigned int refcount; |
124 | }; | 123 | }; |
125 | 124 | ||
125 | static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp) | ||
126 | { | ||
127 | return container_of(hp, struct acpiphp_context, hp); | ||
128 | } | ||
129 | |||
126 | static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) | 130 | static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) |
127 | { | 131 | { |
128 | return container_of(func, struct acpiphp_context, func); | 132 | return container_of(func, struct acpiphp_context, func); |
129 | } | 133 | } |
130 | 134 | ||
135 | static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) | ||
136 | { | ||
137 | return func_to_context(func)->hp.self; | ||
138 | } | ||
139 | |||
131 | static inline acpi_handle func_to_handle(struct acpiphp_func *func) | 140 | static inline acpi_handle func_to_handle(struct acpiphp_func *func) |
132 | { | 141 | { |
133 | return func_to_context(func)->handle; | 142 | return func_to_acpi_device(func)->handle; |
134 | } | 143 | } |
135 | 144 | ||
136 | /* | 145 | /* |
@@ -158,7 +167,6 @@ struct acpiphp_attention_info | |||
158 | 167 | ||
159 | #define FUNC_HAS_STA (0x00000001) | 168 | #define FUNC_HAS_STA (0x00000001) |
160 | #define FUNC_HAS_EJ0 (0x00000002) | 169 | #define FUNC_HAS_EJ0 (0x00000002) |
161 | #define FUNC_HAS_DCK (0x00000004) | ||
162 | 170 | ||
163 | /* function prototypes */ | 171 | /* function prototypes */ |
164 | 172 | ||
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 7c7a388c85ab..91276f9fe268 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -58,71 +58,57 @@ | |||
58 | 58 | ||
59 | static LIST_HEAD(bridge_list); | 59 | static LIST_HEAD(bridge_list); |
60 | static DEFINE_MUTEX(bridge_mutex); | 60 | static DEFINE_MUTEX(bridge_mutex); |
61 | static DEFINE_MUTEX(acpiphp_context_lock); | ||
62 | 61 | ||
63 | static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); | 62 | static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); |
64 | static void acpiphp_sanitize_bus(struct pci_bus *bus); | 63 | static void acpiphp_sanitize_bus(struct pci_bus *bus); |
65 | static void acpiphp_set_hpp_values(struct pci_bus *bus); | 64 | static void acpiphp_set_hpp_values(struct pci_bus *bus); |
66 | static void hotplug_event(acpi_handle handle, u32 type, void *data); | 65 | static void hotplug_event(u32 type, struct acpiphp_context *context); |
67 | static void free_bridge(struct kref *kref); | 66 | static void free_bridge(struct kref *kref); |
68 | 67 | ||
69 | static void acpiphp_context_handler(acpi_handle handle, void *context) | ||
70 | { | ||
71 | /* Intentionally empty. */ | ||
72 | } | ||
73 | |||
74 | /** | 68 | /** |
75 | * acpiphp_init_context - Create hotplug context and grab a reference to it. | 69 | * acpiphp_init_context - Create hotplug context and grab a reference to it. |
76 | * @handle: ACPI object handle to create the context for. | 70 | * @adev: ACPI device object to create the context for. |
77 | * | 71 | * |
78 | * Call under acpiphp_context_lock. | 72 | * Call under acpi_hp_context_lock. |
79 | */ | 73 | */ |
80 | static struct acpiphp_context *acpiphp_init_context(acpi_handle handle) | 74 | static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) |
81 | { | 75 | { |
82 | struct acpiphp_context *context; | 76 | struct acpiphp_context *context; |
83 | acpi_status status; | ||
84 | 77 | ||
85 | context = kzalloc(sizeof(*context), GFP_KERNEL); | 78 | context = kzalloc(sizeof(*context), GFP_KERNEL); |
86 | if (!context) | 79 | if (!context) |
87 | return NULL; | 80 | return NULL; |
88 | 81 | ||
89 | context->handle = handle; | ||
90 | context->refcount = 1; | 82 | context->refcount = 1; |
91 | status = acpi_attach_data(handle, acpiphp_context_handler, context); | 83 | acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event); |
92 | if (ACPI_FAILURE(status)) { | ||
93 | kfree(context); | ||
94 | return NULL; | ||
95 | } | ||
96 | return context; | 84 | return context; |
97 | } | 85 | } |
98 | 86 | ||
99 | /** | 87 | /** |
100 | * acpiphp_get_context - Get hotplug context and grab a reference to it. | 88 | * acpiphp_get_context - Get hotplug context and grab a reference to it. |
101 | * @handle: ACPI object handle to get the context for. | 89 | * @adev: ACPI device object to get the context for. |
102 | * | 90 | * |
103 | * Call under acpiphp_context_lock. | 91 | * Call under acpi_hp_context_lock. |
104 | */ | 92 | */ |
105 | static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) | 93 | static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) |
106 | { | 94 | { |
107 | struct acpiphp_context *context = NULL; | 95 | struct acpiphp_context *context; |
108 | acpi_status status; | ||
109 | void *data; | ||
110 | 96 | ||
111 | status = acpi_get_data(handle, acpiphp_context_handler, &data); | 97 | if (!adev->hp) |
112 | if (ACPI_SUCCESS(status)) { | 98 | return NULL; |
113 | context = data; | 99 | |
114 | context->refcount++; | 100 | context = to_acpiphp_context(adev->hp); |
115 | } | 101 | context->refcount++; |
116 | return context; | 102 | return context; |
117 | } | 103 | } |
118 | 104 | ||
119 | /** | 105 | /** |
120 | * acpiphp_put_context - Drop a reference to ACPI hotplug context. | 106 | * acpiphp_put_context - Drop a reference to ACPI hotplug context. |
121 | * @handle: ACPI object handle to put the context for. | 107 | * @context: ACPI hotplug context to drop a reference to. |
122 | * | 108 | * |
123 | * The context object is removed if there are no more references to it. | 109 | * The context object is removed if there are no more references to it. |
124 | * | 110 | * |
125 | * Call under acpiphp_context_lock. | 111 | * Call under acpi_hp_context_lock. |
126 | */ | 112 | */ |
127 | static void acpiphp_put_context(struct acpiphp_context *context) | 113 | static void acpiphp_put_context(struct acpiphp_context *context) |
128 | { | 114 | { |
@@ -130,7 +116,7 @@ static void acpiphp_put_context(struct acpiphp_context *context) | |||
130 | return; | 116 | return; |
131 | 117 | ||
132 | WARN_ON(context->bridge); | 118 | WARN_ON(context->bridge); |
133 | acpi_detach_data(context->handle, acpiphp_context_handler); | 119 | context->hp.self->hp = NULL; |
134 | kfree(context); | 120 | kfree(context); |
135 | } | 121 | } |
136 | 122 | ||
@@ -151,7 +137,7 @@ static void free_bridge(struct kref *kref) | |||
151 | struct acpiphp_slot *slot, *next; | 137 | struct acpiphp_slot *slot, *next; |
152 | struct acpiphp_func *func, *tmp; | 138 | struct acpiphp_func *func, *tmp; |
153 | 139 | ||
154 | mutex_lock(&acpiphp_context_lock); | 140 | acpi_lock_hp_context(); |
155 | 141 | ||
156 | bridge = container_of(kref, struct acpiphp_bridge, ref); | 142 | bridge = container_of(kref, struct acpiphp_bridge, ref); |
157 | 143 | ||
@@ -175,7 +161,7 @@ static void free_bridge(struct kref *kref) | |||
175 | pci_dev_put(bridge->pci_dev); | 161 | pci_dev_put(bridge->pci_dev); |
176 | kfree(bridge); | 162 | kfree(bridge); |
177 | 163 | ||
178 | mutex_unlock(&acpiphp_context_lock); | 164 | acpi_unlock_hp_context(); |
179 | } | 165 | } |
180 | 166 | ||
181 | /* | 167 | /* |
@@ -212,22 +198,13 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) | |||
212 | 198 | ||
213 | static void dock_event(acpi_handle handle, u32 type, void *data) | 199 | static void dock_event(acpi_handle handle, u32 type, void *data) |
214 | { | 200 | { |
215 | struct acpiphp_context *context; | 201 | struct acpi_device *adev; |
216 | 202 | ||
217 | mutex_lock(&acpiphp_context_lock); | 203 | adev = acpi_bus_get_acpi_device(handle); |
218 | context = acpiphp_get_context(handle); | 204 | if (adev) { |
219 | if (!context || WARN_ON(context->handle != handle) | 205 | acpiphp_hotplug_event(adev, type); |
220 | || context->func.parent->is_going_away) { | 206 | acpi_bus_put_acpi_device(adev); |
221 | mutex_unlock(&acpiphp_context_lock); | ||
222 | return; | ||
223 | } | 207 | } |
224 | get_bridge(context->func.parent); | ||
225 | acpiphp_put_context(context); | ||
226 | mutex_unlock(&acpiphp_context_lock); | ||
227 | |||
228 | hotplug_event(handle, type, data); | ||
229 | |||
230 | put_bridge(context->func.parent); | ||
231 | } | 208 | } |
232 | 209 | ||
233 | static const struct acpi_dock_ops acpiphp_dock_ops = { | 210 | static const struct acpi_dock_ops acpiphp_dock_ops = { |
@@ -284,6 +261,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, | |||
284 | { | 261 | { |
285 | struct acpiphp_bridge *bridge = data; | 262 | struct acpiphp_bridge *bridge = data; |
286 | struct acpiphp_context *context; | 263 | struct acpiphp_context *context; |
264 | struct acpi_device *adev; | ||
287 | struct acpiphp_slot *slot; | 265 | struct acpiphp_slot *slot; |
288 | struct acpiphp_func *newfunc; | 266 | struct acpiphp_func *newfunc; |
289 | acpi_status status = AE_OK; | 267 | acpi_status status = AE_OK; |
@@ -303,21 +281,22 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, | |||
303 | "can't evaluate _ADR (%#x)\n", status); | 281 | "can't evaluate _ADR (%#x)\n", status); |
304 | return AE_OK; | 282 | return AE_OK; |
305 | } | 283 | } |
284 | if (acpi_bus_get_device(handle, &adev)) | ||
285 | return AE_OK; | ||
306 | 286 | ||
307 | device = (adr >> 16) & 0xffff; | 287 | device = (adr >> 16) & 0xffff; |
308 | function = adr & 0xffff; | 288 | function = adr & 0xffff; |
309 | 289 | ||
310 | mutex_lock(&acpiphp_context_lock); | 290 | acpi_lock_hp_context(); |
311 | context = acpiphp_init_context(handle); | 291 | context = acpiphp_init_context(adev); |
312 | if (!context) { | 292 | if (!context) { |
313 | mutex_unlock(&acpiphp_context_lock); | 293 | acpi_unlock_hp_context(); |
314 | acpi_handle_err(handle, "No hotplug context\n"); | 294 | acpi_handle_err(handle, "No hotplug context\n"); |
315 | return AE_NOT_EXIST; | 295 | return AE_NOT_EXIST; |
316 | } | 296 | } |
317 | newfunc = &context->func; | 297 | newfunc = &context->func; |
318 | newfunc->function = function; | 298 | newfunc->function = function; |
319 | newfunc->parent = bridge; | 299 | newfunc->parent = bridge; |
320 | mutex_unlock(&acpiphp_context_lock); | ||
321 | 300 | ||
322 | if (acpi_has_method(handle, "_EJ0")) | 301 | if (acpi_has_method(handle, "_EJ0")) |
323 | newfunc->flags = FUNC_HAS_EJ0; | 302 | newfunc->flags = FUNC_HAS_EJ0; |
@@ -325,8 +304,14 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, | |||
325 | if (acpi_has_method(handle, "_STA")) | 304 | if (acpi_has_method(handle, "_STA")) |
326 | newfunc->flags |= FUNC_HAS_STA; | 305 | newfunc->flags |= FUNC_HAS_STA; |
327 | 306 | ||
307 | /* | ||
308 | * Dock stations' notify handler should be used for dock devices instead | ||
309 | * of the common one, so clear hp.event in their contexts. | ||
310 | */ | ||
328 | if (acpi_has_method(handle, "_DCK")) | 311 | if (acpi_has_method(handle, "_DCK")) |
329 | newfunc->flags |= FUNC_HAS_DCK; | 312 | context->hp.event = NULL; |
313 | |||
314 | acpi_unlock_hp_context(); | ||
330 | 315 | ||
331 | /* search for objects that share the same slot */ | 316 | /* search for objects that share the same slot */ |
332 | list_for_each_entry(slot, &bridge->slots, node) | 317 | list_for_each_entry(slot, &bridge->slots, node) |
@@ -335,14 +320,15 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, | |||
335 | 320 | ||
336 | slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); | 321 | slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); |
337 | if (!slot) { | 322 | if (!slot) { |
338 | status = AE_NO_MEMORY; | 323 | acpi_lock_hp_context(); |
339 | goto err; | 324 | acpiphp_put_context(context); |
325 | acpi_unlock_hp_context(); | ||
326 | return AE_NO_MEMORY; | ||
340 | } | 327 | } |
341 | 328 | ||
342 | slot->bus = bridge->pci_bus; | 329 | slot->bus = bridge->pci_bus; |
343 | slot->device = device; | 330 | slot->device = device; |
344 | INIT_LIST_HEAD(&slot->funcs); | 331 | INIT_LIST_HEAD(&slot->funcs); |
345 | mutex_init(&slot->crit_sect); | ||
346 | 332 | ||
347 | list_add_tail(&slot->node, &bridge->slots); | 333 | list_add_tail(&slot->node, &bridge->slots); |
348 | 334 | ||
@@ -393,32 +379,16 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, | |||
393 | pr_debug("failed to register dock device\n"); | 379 | pr_debug("failed to register dock device\n"); |
394 | } | 380 | } |
395 | 381 | ||
396 | /* install notify handler */ | ||
397 | if (!(newfunc->flags & FUNC_HAS_DCK)) { | ||
398 | status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
399 | handle_hotplug_event, | ||
400 | context); | ||
401 | if (ACPI_FAILURE(status)) | ||
402 | acpi_handle_err(handle, | ||
403 | "failed to install notify handler\n"); | ||
404 | } | ||
405 | |||
406 | return AE_OK; | 382 | return AE_OK; |
407 | |||
408 | err: | ||
409 | mutex_lock(&acpiphp_context_lock); | ||
410 | acpiphp_put_context(context); | ||
411 | mutex_unlock(&acpiphp_context_lock); | ||
412 | return status; | ||
413 | } | 383 | } |
414 | 384 | ||
415 | static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) | 385 | static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev) |
416 | { | 386 | { |
417 | struct acpiphp_context *context; | 387 | struct acpiphp_context *context; |
418 | struct acpiphp_bridge *bridge = NULL; | 388 | struct acpiphp_bridge *bridge = NULL; |
419 | 389 | ||
420 | mutex_lock(&acpiphp_context_lock); | 390 | acpi_lock_hp_context(); |
421 | context = acpiphp_get_context(handle); | 391 | context = acpiphp_get_context(adev); |
422 | if (context) { | 392 | if (context) { |
423 | bridge = context->bridge; | 393 | bridge = context->bridge; |
424 | if (bridge) | 394 | if (bridge) |
@@ -426,7 +396,7 @@ static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) | |||
426 | 396 | ||
427 | acpiphp_put_context(context); | 397 | acpiphp_put_context(context); |
428 | } | 398 | } |
429 | mutex_unlock(&acpiphp_context_lock); | 399 | acpi_unlock_hp_context(); |
430 | return bridge; | 400 | return bridge; |
431 | } | 401 | } |
432 | 402 | ||
@@ -434,22 +404,17 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
434 | { | 404 | { |
435 | struct acpiphp_slot *slot; | 405 | struct acpiphp_slot *slot; |
436 | struct acpiphp_func *func; | 406 | struct acpiphp_func *func; |
437 | acpi_status status; | ||
438 | 407 | ||
439 | list_for_each_entry(slot, &bridge->slots, node) { | 408 | list_for_each_entry(slot, &bridge->slots, node) { |
440 | list_for_each_entry(func, &slot->funcs, sibling) { | 409 | list_for_each_entry(func, &slot->funcs, sibling) { |
441 | acpi_handle handle = func_to_handle(func); | 410 | struct acpi_device *adev = func_to_acpi_device(func); |
442 | 411 | ||
443 | if (is_dock_device(handle)) | 412 | if (is_dock_device(adev->handle)) |
444 | unregister_hotplug_dock_device(handle); | 413 | unregister_hotplug_dock_device(adev->handle); |
445 | 414 | ||
446 | if (!(func->flags & FUNC_HAS_DCK)) { | 415 | acpi_lock_hp_context(); |
447 | status = acpi_remove_notify_handler(handle, | 416 | adev->hp->event = NULL; |
448 | ACPI_SYSTEM_NOTIFY, | 417 | acpi_unlock_hp_context(); |
449 | handle_hotplug_event); | ||
450 | if (ACPI_FAILURE(status)) | ||
451 | pr_err("failed to remove notify handler\n"); | ||
452 | } | ||
453 | } | 418 | } |
454 | slot->flags |= SLOT_IS_GOING_AWAY; | 419 | slot->flags |= SLOT_IS_GOING_AWAY; |
455 | if (slot->slot) | 420 | if (slot->slot) |
@@ -460,9 +425,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
460 | list_del(&bridge->list); | 425 | list_del(&bridge->list); |
461 | mutex_unlock(&bridge_mutex); | 426 | mutex_unlock(&bridge_mutex); |
462 | 427 | ||
463 | mutex_lock(&acpiphp_context_lock); | 428 | acpi_lock_hp_context(); |
464 | bridge->is_going_away = true; | 429 | bridge->is_going_away = true; |
465 | mutex_unlock(&acpiphp_context_lock); | 430 | acpi_unlock_hp_context(); |
466 | } | 431 | } |
467 | 432 | ||
468 | /** | 433 | /** |
@@ -492,33 +457,6 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) | |||
492 | return max; | 457 | return max; |
493 | } | 458 | } |
494 | 459 | ||
495 | /** | ||
496 | * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree. | ||
497 | * @handle: ACPI device object handle to start from. | ||
498 | */ | ||
499 | static void acpiphp_bus_trim(acpi_handle handle) | ||
500 | { | ||
501 | struct acpi_device *adev = NULL; | ||
502 | |||
503 | acpi_bus_get_device(handle, &adev); | ||
504 | if (adev) | ||
505 | acpi_bus_trim(adev); | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * acpiphp_bus_add - Scan ACPI namespace subtree. | ||
510 | * @handle: ACPI object handle to start the scan from. | ||
511 | */ | ||
512 | static void acpiphp_bus_add(acpi_handle handle) | ||
513 | { | ||
514 | struct acpi_device *adev = NULL; | ||
515 | |||
516 | acpi_bus_scan(handle); | ||
517 | acpi_bus_get_device(handle, &adev); | ||
518 | if (acpi_device_enumerated(adev)) | ||
519 | acpi_device_set_power(adev, ACPI_STATE_D0); | ||
520 | } | ||
521 | |||
522 | static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) | 460 | static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) |
523 | { | 461 | { |
524 | struct acpiphp_func *func; | 462 | struct acpiphp_func *func; |
@@ -558,9 +496,13 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot) | |||
558 | { | 496 | { |
559 | struct acpiphp_func *func; | 497 | struct acpiphp_func *func; |
560 | 498 | ||
561 | list_for_each_entry(func, &slot->funcs, sibling) | 499 | list_for_each_entry(func, &slot->funcs, sibling) { |
562 | acpiphp_bus_add(func_to_handle(func)); | 500 | struct acpi_device *adev = func_to_acpi_device(func); |
563 | 501 | ||
502 | acpi_bus_scan(adev->handle); | ||
503 | if (acpi_device_enumerated(adev)) | ||
504 | acpi_device_set_power(adev, ACPI_STATE_D0); | ||
505 | } | ||
564 | return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0)); | 506 | return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0)); |
565 | } | 507 | } |
566 | 508 | ||
@@ -625,32 +567,15 @@ static void __ref enable_slot(struct acpiphp_slot *slot) | |||
625 | } | 567 | } |
626 | } | 568 | } |
627 | 569 | ||
628 | /* return first device in slot, acquiring a reference on it */ | ||
629 | static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) | ||
630 | { | ||
631 | struct pci_bus *bus = slot->bus; | ||
632 | struct pci_dev *dev; | ||
633 | struct pci_dev *ret = NULL; | ||
634 | |||
635 | down_read(&pci_bus_sem); | ||
636 | list_for_each_entry(dev, &bus->devices, bus_list) | ||
637 | if (PCI_SLOT(dev->devfn) == slot->device) { | ||
638 | ret = pci_dev_get(dev); | ||
639 | break; | ||
640 | } | ||
641 | up_read(&pci_bus_sem); | ||
642 | |||
643 | return ret; | ||
644 | } | ||
645 | |||
646 | /** | 570 | /** |
647 | * disable_slot - disable a slot | 571 | * disable_slot - disable a slot |
648 | * @slot: ACPI PHP slot | 572 | * @slot: ACPI PHP slot |
649 | */ | 573 | */ |
650 | static void disable_slot(struct acpiphp_slot *slot) | 574 | static void disable_slot(struct acpiphp_slot *slot) |
651 | { | 575 | { |
576 | struct pci_bus *bus = slot->bus; | ||
577 | struct pci_dev *dev, *prev; | ||
652 | struct acpiphp_func *func; | 578 | struct acpiphp_func *func; |
653 | struct pci_dev *pdev; | ||
654 | 579 | ||
655 | /* | 580 | /* |
656 | * enable_slot() enumerates all functions in this device via | 581 | * enable_slot() enumerates all functions in this device via |
@@ -658,22 +583,18 @@ static void disable_slot(struct acpiphp_slot *slot) | |||
658 | * methods (_EJ0, etc.) or not. Therefore, we remove all functions | 583 | * methods (_EJ0, etc.) or not. Therefore, we remove all functions |
659 | * here. | 584 | * here. |
660 | */ | 585 | */ |
661 | while ((pdev = dev_in_slot(slot))) { | 586 | list_for_each_entry_safe_reverse(dev, prev, &bus->devices, bus_list) |
662 | pci_stop_and_remove_bus_device(pdev); | 587 | if (PCI_SLOT(dev->devfn) == slot->device) |
663 | pci_dev_put(pdev); | 588 | pci_stop_and_remove_bus_device(dev); |
664 | } | ||
665 | 589 | ||
666 | list_for_each_entry(func, &slot->funcs, sibling) | 590 | list_for_each_entry(func, &slot->funcs, sibling) |
667 | acpiphp_bus_trim(func_to_handle(func)); | 591 | acpi_bus_trim(func_to_acpi_device(func)); |
668 | 592 | ||
669 | slot->flags &= (~SLOT_ENABLED); | 593 | slot->flags &= (~SLOT_ENABLED); |
670 | } | 594 | } |
671 | 595 | ||
672 | static bool acpiphp_no_hotplug(acpi_handle handle) | 596 | static bool acpiphp_no_hotplug(struct acpi_device *adev) |
673 | { | 597 | { |
674 | struct acpi_device *adev = NULL; | ||
675 | |||
676 | acpi_bus_get_device(handle, &adev); | ||
677 | return adev && adev->flags.no_hotplug; | 598 | return adev && adev->flags.no_hotplug; |
678 | } | 599 | } |
679 | 600 | ||
@@ -682,7 +603,7 @@ static bool slot_no_hotplug(struct acpiphp_slot *slot) | |||
682 | struct acpiphp_func *func; | 603 | struct acpiphp_func *func; |
683 | 604 | ||
684 | list_for_each_entry(func, &slot->funcs, sibling) | 605 | list_for_each_entry(func, &slot->funcs, sibling) |
685 | if (acpiphp_no_hotplug(func_to_handle(func))) | 606 | if (acpiphp_no_hotplug(func_to_acpi_device(func))) |
686 | return true; | 607 | return true; |
687 | 608 | ||
688 | return false; | 609 | return false; |
@@ -747,17 +668,17 @@ static inline bool device_status_valid(unsigned int sta) | |||
747 | */ | 668 | */ |
748 | static void trim_stale_devices(struct pci_dev *dev) | 669 | static void trim_stale_devices(struct pci_dev *dev) |
749 | { | 670 | { |
750 | acpi_handle handle = ACPI_HANDLE(&dev->dev); | 671 | struct acpi_device *adev = ACPI_COMPANION(&dev->dev); |
751 | struct pci_bus *bus = dev->subordinate; | 672 | struct pci_bus *bus = dev->subordinate; |
752 | bool alive = false; | 673 | bool alive = false; |
753 | 674 | ||
754 | if (handle) { | 675 | if (adev) { |
755 | acpi_status status; | 676 | acpi_status status; |
756 | unsigned long long sta; | 677 | unsigned long long sta; |
757 | 678 | ||
758 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); | 679 | status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); |
759 | alive = (ACPI_SUCCESS(status) && device_status_valid(sta)) | 680 | alive = (ACPI_SUCCESS(status) && device_status_valid(sta)) |
760 | || acpiphp_no_hotplug(handle); | 681 | || acpiphp_no_hotplug(adev); |
761 | } | 682 | } |
762 | if (!alive) { | 683 | if (!alive) { |
763 | u32 v; | 684 | u32 v; |
@@ -767,8 +688,8 @@ static void trim_stale_devices(struct pci_dev *dev) | |||
767 | } | 688 | } |
768 | if (!alive) { | 689 | if (!alive) { |
769 | pci_stop_and_remove_bus_device(dev); | 690 | pci_stop_and_remove_bus_device(dev); |
770 | if (handle) | 691 | if (adev) |
771 | acpiphp_bus_trim(handle); | 692 | acpi_bus_trim(adev); |
772 | } else if (bus) { | 693 | } else if (bus) { |
773 | struct pci_dev *child, *tmp; | 694 | struct pci_dev *child, *tmp; |
774 | 695 | ||
@@ -800,7 +721,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) | |||
800 | struct pci_bus *bus = slot->bus; | 721 | struct pci_bus *bus = slot->bus; |
801 | struct pci_dev *dev, *tmp; | 722 | struct pci_dev *dev, *tmp; |
802 | 723 | ||
803 | mutex_lock(&slot->crit_sect); | ||
804 | if (slot_no_hotplug(slot)) { | 724 | if (slot_no_hotplug(slot)) { |
805 | ; /* do nothing */ | 725 | ; /* do nothing */ |
806 | } else if (device_status_valid(get_slot_status(slot))) { | 726 | } else if (device_status_valid(get_slot_status(slot))) { |
@@ -815,7 +735,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) | |||
815 | } else { | 735 | } else { |
816 | disable_slot(slot); | 736 | disable_slot(slot); |
817 | } | 737 | } |
818 | mutex_unlock(&slot->crit_sect); | ||
819 | } | 738 | } |
820 | } | 739 | } |
821 | 740 | ||
@@ -855,11 +774,11 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) | |||
855 | * ACPI event handlers | 774 | * ACPI event handlers |
856 | */ | 775 | */ |
857 | 776 | ||
858 | void acpiphp_check_host_bridge(acpi_handle handle) | 777 | void acpiphp_check_host_bridge(struct acpi_device *adev) |
859 | { | 778 | { |
860 | struct acpiphp_bridge *bridge; | 779 | struct acpiphp_bridge *bridge; |
861 | 780 | ||
862 | bridge = acpiphp_handle_to_bridge(handle); | 781 | bridge = acpiphp_dev_to_bridge(adev); |
863 | if (bridge) { | 782 | if (bridge) { |
864 | pci_lock_rescan_remove(); | 783 | pci_lock_rescan_remove(); |
865 | 784 | ||
@@ -872,73 +791,52 @@ void acpiphp_check_host_bridge(acpi_handle handle) | |||
872 | 791 | ||
873 | static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); | 792 | static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); |
874 | 793 | ||
875 | static void hotplug_event(acpi_handle handle, u32 type, void *data) | 794 | static void hotplug_event(u32 type, struct acpiphp_context *context) |
876 | { | 795 | { |
877 | struct acpiphp_context *context = data; | 796 | acpi_handle handle = context->hp.self->handle; |
878 | struct acpiphp_func *func = &context->func; | 797 | struct acpiphp_func *func = &context->func; |
798 | struct acpiphp_slot *slot = func->slot; | ||
879 | struct acpiphp_bridge *bridge; | 799 | struct acpiphp_bridge *bridge; |
880 | char objname[64]; | ||
881 | struct acpi_buffer buffer = { .length = sizeof(objname), | ||
882 | .pointer = objname }; | ||
883 | 800 | ||
884 | mutex_lock(&acpiphp_context_lock); | 801 | acpi_lock_hp_context(); |
885 | bridge = context->bridge; | 802 | bridge = context->bridge; |
886 | if (bridge) | 803 | if (bridge) |
887 | get_bridge(bridge); | 804 | get_bridge(bridge); |
888 | 805 | ||
889 | mutex_unlock(&acpiphp_context_lock); | 806 | acpi_unlock_hp_context(); |
890 | 807 | ||
891 | pci_lock_rescan_remove(); | 808 | pci_lock_rescan_remove(); |
892 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | ||
893 | 809 | ||
894 | switch (type) { | 810 | switch (type) { |
895 | case ACPI_NOTIFY_BUS_CHECK: | 811 | case ACPI_NOTIFY_BUS_CHECK: |
896 | /* bus re-enumerate */ | 812 | /* bus re-enumerate */ |
897 | pr_debug("%s: Bus check notify on %s\n", __func__, objname); | 813 | acpi_handle_debug(handle, "Bus check in %s()\n", __func__); |
898 | pr_debug("%s: re-enumerating slots under %s\n", | 814 | if (bridge) |
899 | __func__, objname); | ||
900 | if (bridge) { | ||
901 | acpiphp_check_bridge(bridge); | 815 | acpiphp_check_bridge(bridge); |
902 | } else { | 816 | else if (!(slot->flags & SLOT_IS_GOING_AWAY)) |
903 | struct acpiphp_slot *slot = func->slot; | ||
904 | |||
905 | if (slot->flags & SLOT_IS_GOING_AWAY) | ||
906 | break; | ||
907 | |||
908 | mutex_lock(&slot->crit_sect); | ||
909 | enable_slot(slot); | 817 | enable_slot(slot); |
910 | mutex_unlock(&slot->crit_sect); | 818 | |
911 | } | ||
912 | break; | 819 | break; |
913 | 820 | ||
914 | case ACPI_NOTIFY_DEVICE_CHECK: | 821 | case ACPI_NOTIFY_DEVICE_CHECK: |
915 | /* device check */ | 822 | /* device check */ |
916 | pr_debug("%s: Device check notify on %s\n", __func__, objname); | 823 | acpi_handle_debug(handle, "Device check in %s()\n", __func__); |
917 | if (bridge) { | 824 | if (bridge) { |
918 | acpiphp_check_bridge(bridge); | 825 | acpiphp_check_bridge(bridge); |
919 | } else { | 826 | } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) { |
920 | struct acpiphp_slot *slot = func->slot; | ||
921 | int ret; | ||
922 | |||
923 | if (slot->flags & SLOT_IS_GOING_AWAY) | ||
924 | break; | ||
925 | |||
926 | /* | 827 | /* |
927 | * Check if anything has changed in the slot and rescan | 828 | * Check if anything has changed in the slot and rescan |
928 | * from the parent if that's the case. | 829 | * from the parent if that's the case. |
929 | */ | 830 | */ |
930 | mutex_lock(&slot->crit_sect); | 831 | if (acpiphp_rescan_slot(slot)) |
931 | ret = acpiphp_rescan_slot(slot); | ||
932 | mutex_unlock(&slot->crit_sect); | ||
933 | if (ret) | ||
934 | acpiphp_check_bridge(func->parent); | 832 | acpiphp_check_bridge(func->parent); |
935 | } | 833 | } |
936 | break; | 834 | break; |
937 | 835 | ||
938 | case ACPI_NOTIFY_EJECT_REQUEST: | 836 | case ACPI_NOTIFY_EJECT_REQUEST: |
939 | /* request device eject */ | 837 | /* request device eject */ |
940 | pr_debug("%s: Device eject notify on %s\n", __func__, objname); | 838 | acpi_handle_debug(handle, "Eject request in %s()\n", __func__); |
941 | acpiphp_disable_and_eject_slot(func->slot); | 839 | acpiphp_disable_and_eject_slot(slot); |
942 | break; | 840 | break; |
943 | } | 841 | } |
944 | 842 | ||
@@ -947,106 +845,48 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) | |||
947 | put_bridge(bridge); | 845 | put_bridge(bridge); |
948 | } | 846 | } |
949 | 847 | ||
950 | static void hotplug_event_work(void *data, u32 type) | 848 | static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type) |
951 | { | ||
952 | struct acpiphp_context *context = data; | ||
953 | acpi_handle handle = context->handle; | ||
954 | |||
955 | acpi_scan_lock_acquire(); | ||
956 | |||
957 | hotplug_event(handle, type, context); | ||
958 | |||
959 | acpi_scan_lock_release(); | ||
960 | acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); | ||
961 | put_bridge(context->func.parent); | ||
962 | } | ||
963 | |||
964 | /** | ||
965 | * handle_hotplug_event - handle ACPI hotplug event | ||
966 | * @handle: Notify()'ed acpi_handle | ||
967 | * @type: Notify code | ||
968 | * @data: pointer to acpiphp_context structure | ||
969 | * | ||
970 | * Handles ACPI event notification on slots. | ||
971 | */ | ||
972 | static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) | ||
973 | { | 849 | { |
974 | struct acpiphp_context *context; | 850 | struct acpiphp_context *context; |
975 | u32 ost_code = ACPI_OST_SC_SUCCESS; | ||
976 | acpi_status status; | ||
977 | 851 | ||
978 | switch (type) { | 852 | acpi_lock_hp_context(); |
979 | case ACPI_NOTIFY_BUS_CHECK: | 853 | context = acpiphp_get_context(adev); |
980 | case ACPI_NOTIFY_DEVICE_CHECK: | 854 | if (!context || context->func.parent->is_going_away) { |
981 | break; | 855 | acpi_unlock_hp_context(); |
982 | case ACPI_NOTIFY_EJECT_REQUEST: | 856 | return -ENODATA; |
983 | ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; | ||
984 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); | ||
985 | break; | ||
986 | |||
987 | case ACPI_NOTIFY_DEVICE_WAKE: | ||
988 | return; | ||
989 | |||
990 | case ACPI_NOTIFY_FREQUENCY_MISMATCH: | ||
991 | acpi_handle_err(handle, "Device cannot be configured due " | ||
992 | "to a frequency mismatch\n"); | ||
993 | goto out; | ||
994 | |||
995 | case ACPI_NOTIFY_BUS_MODE_MISMATCH: | ||
996 | acpi_handle_err(handle, "Device cannot be configured due " | ||
997 | "to a bus mode mismatch\n"); | ||
998 | goto out; | ||
999 | |||
1000 | case ACPI_NOTIFY_POWER_FAULT: | ||
1001 | acpi_handle_err(handle, "Device has suffered a power fault\n"); | ||
1002 | goto out; | ||
1003 | |||
1004 | default: | ||
1005 | acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); | ||
1006 | ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; | ||
1007 | goto out; | ||
1008 | } | 857 | } |
1009 | |||
1010 | mutex_lock(&acpiphp_context_lock); | ||
1011 | context = acpiphp_get_context(handle); | ||
1012 | if (!context || WARN_ON(context->handle != handle) | ||
1013 | || context->func.parent->is_going_away) | ||
1014 | goto err_out; | ||
1015 | |||
1016 | get_bridge(context->func.parent); | 858 | get_bridge(context->func.parent); |
1017 | acpiphp_put_context(context); | 859 | acpiphp_put_context(context); |
1018 | status = acpi_hotplug_execute(hotplug_event_work, context, type); | 860 | acpi_unlock_hp_context(); |
1019 | if (ACPI_SUCCESS(status)) { | ||
1020 | mutex_unlock(&acpiphp_context_lock); | ||
1021 | return; | ||
1022 | } | ||
1023 | put_bridge(context->func.parent); | ||
1024 | 861 | ||
1025 | err_out: | 862 | hotplug_event(type, context); |
1026 | mutex_unlock(&acpiphp_context_lock); | ||
1027 | ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | ||
1028 | 863 | ||
1029 | out: | 864 | put_bridge(context->func.parent); |
1030 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); | 865 | return 0; |
1031 | } | 866 | } |
1032 | 867 | ||
1033 | /* | 868 | /** |
1034 | * Create hotplug slots for the PCI bus. | 869 | * acpiphp_enumerate_slots - Enumerate PCI slots for a given bus. |
1035 | * It should always return 0 to avoid skipping following notifiers. | 870 | * @bus: PCI bus to enumerate the slots for. |
871 | * | ||
872 | * A "slot" is an object associated with a PCI device number. All functions | ||
873 | * (PCI devices) with the same bus and device number belong to the same slot. | ||
1036 | */ | 874 | */ |
1037 | void acpiphp_enumerate_slots(struct pci_bus *bus) | 875 | void acpiphp_enumerate_slots(struct pci_bus *bus) |
1038 | { | 876 | { |
1039 | struct acpiphp_bridge *bridge; | 877 | struct acpiphp_bridge *bridge; |
878 | struct acpi_device *adev; | ||
1040 | acpi_handle handle; | 879 | acpi_handle handle; |
1041 | acpi_status status; | 880 | acpi_status status; |
1042 | 881 | ||
1043 | if (acpiphp_disabled) | 882 | if (acpiphp_disabled) |
1044 | return; | 883 | return; |
1045 | 884 | ||
1046 | handle = ACPI_HANDLE(bus->bridge); | 885 | adev = ACPI_COMPANION(bus->bridge); |
1047 | if (!handle) | 886 | if (!adev) |
1048 | return; | 887 | return; |
1049 | 888 | ||
889 | handle = adev->handle; | ||
1050 | bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); | 890 | bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); |
1051 | if (!bridge) { | 891 | if (!bridge) { |
1052 | acpi_handle_err(handle, "No memory for bridge object\n"); | 892 | acpi_handle_err(handle, "No memory for bridge object\n"); |
@@ -1074,10 +914,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) | |||
1074 | * parent is going to be handled by pciehp, in which case this | 914 | * parent is going to be handled by pciehp, in which case this |
1075 | * bridge is not interesting to us either. | 915 | * bridge is not interesting to us either. |
1076 | */ | 916 | */ |
1077 | mutex_lock(&acpiphp_context_lock); | 917 | acpi_lock_hp_context(); |
1078 | context = acpiphp_get_context(handle); | 918 | context = acpiphp_get_context(adev); |
1079 | if (!context) { | 919 | if (!context) { |
1080 | mutex_unlock(&acpiphp_context_lock); | 920 | acpi_unlock_hp_context(); |
1081 | put_device(&bus->dev); | 921 | put_device(&bus->dev); |
1082 | pci_dev_put(bridge->pci_dev); | 922 | pci_dev_put(bridge->pci_dev); |
1083 | kfree(bridge); | 923 | kfree(bridge); |
@@ -1087,7 +927,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) | |||
1087 | context->bridge = bridge; | 927 | context->bridge = bridge; |
1088 | /* Get a reference to the parent bridge. */ | 928 | /* Get a reference to the parent bridge. */ |
1089 | get_bridge(context->func.parent); | 929 | get_bridge(context->func.parent); |
1090 | mutex_unlock(&acpiphp_context_lock); | 930 | acpi_unlock_hp_context(); |
1091 | } | 931 | } |
1092 | 932 | ||
1093 | /* must be added to the list prior to calling register_slot */ | 933 | /* must be added to the list prior to calling register_slot */ |
@@ -1105,7 +945,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) | |||
1105 | } | 945 | } |
1106 | } | 946 | } |
1107 | 947 | ||
1108 | /* Destroy hotplug slots associated with the PCI bus */ | 948 | /** |
949 | * acpiphp_remove_slots - Remove slot objects associated with a given bus. | ||
950 | * @bus: PCI bus to remove the slot objects for. | ||
951 | */ | ||
1109 | void acpiphp_remove_slots(struct pci_bus *bus) | 952 | void acpiphp_remove_slots(struct pci_bus *bus) |
1110 | { | 953 | { |
1111 | struct acpiphp_bridge *bridge; | 954 | struct acpiphp_bridge *bridge; |
@@ -1136,13 +979,10 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) | |||
1136 | if (slot->flags & SLOT_IS_GOING_AWAY) | 979 | if (slot->flags & SLOT_IS_GOING_AWAY) |
1137 | return -ENODEV; | 980 | return -ENODEV; |
1138 | 981 | ||
1139 | mutex_lock(&slot->crit_sect); | ||
1140 | /* configure all functions */ | 982 | /* configure all functions */ |
1141 | if (!(slot->flags & SLOT_ENABLED)) | 983 | if (!(slot->flags & SLOT_ENABLED)) |
1142 | enable_slot(slot); | 984 | enable_slot(slot); |
1143 | 985 | ||
1144 | mutex_unlock(&slot->crit_sect); | ||
1145 | |||
1146 | pci_unlock_rescan_remove(); | 986 | pci_unlock_rescan_remove(); |
1147 | return 0; | 987 | return 0; |
1148 | } | 988 | } |
@@ -1158,8 +998,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) | |||
1158 | if (slot->flags & SLOT_IS_GOING_AWAY) | 998 | if (slot->flags & SLOT_IS_GOING_AWAY) |
1159 | return -ENODEV; | 999 | return -ENODEV; |
1160 | 1000 | ||
1161 | mutex_lock(&slot->crit_sect); | ||
1162 | |||
1163 | /* unconfigure all functions */ | 1001 | /* unconfigure all functions */ |
1164 | disable_slot(slot); | 1002 | disable_slot(slot); |
1165 | 1003 | ||
@@ -1173,7 +1011,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) | |||
1173 | break; | 1011 | break; |
1174 | } | 1012 | } |
1175 | 1013 | ||
1176 | mutex_unlock(&slot->crit_sect); | ||
1177 | return 0; | 1014 | return 0; |
1178 | } | 1015 | } |
1179 | 1016 | ||
@@ -1181,9 +1018,15 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) | |||
1181 | { | 1018 | { |
1182 | int ret; | 1019 | int ret; |
1183 | 1020 | ||
1021 | /* | ||
1022 | * Acquire acpi_scan_lock to ensure that the execution of _EJ0 in | ||
1023 | * acpiphp_disable_and_eject_slot() will be synchronized properly. | ||
1024 | */ | ||
1025 | acpi_scan_lock_acquire(); | ||
1184 | pci_lock_rescan_remove(); | 1026 | pci_lock_rescan_remove(); |
1185 | ret = acpiphp_disable_and_eject_slot(slot); | 1027 | ret = acpiphp_disable_and_eject_slot(slot); |
1186 | pci_unlock_rescan_remove(); | 1028 | pci_unlock_rescan_remove(); |
1029 | acpi_scan_lock_release(); | ||
1187 | return ret; | 1030 | return ret; |
1188 | } | 1031 | } |
1189 | 1032 | ||
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 8256eb4ad057..32f90c7bcb03 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
@@ -137,6 +137,16 @@ struct acpi_scan_handler { | |||
137 | }; | 137 | }; |
138 | 138 | ||
139 | /* | 139 | /* |
140 | * ACPI Hotplug Context | ||
141 | * -------------------- | ||
142 | */ | ||
143 | |||
144 | struct acpi_hotplug_context { | ||
145 | struct acpi_device *self; | ||
146 | int (*event)(struct acpi_device *, u32); | ||
147 | }; | ||
148 | |||
149 | /* | ||
140 | * ACPI Driver | 150 | * ACPI Driver |
141 | * ----------- | 151 | * ----------- |
142 | */ | 152 | */ |
@@ -190,7 +200,8 @@ struct acpi_device_flags { | |||
190 | u32 initialized:1; | 200 | u32 initialized:1; |
191 | u32 visited:1; | 201 | u32 visited:1; |
192 | u32 no_hotplug:1; | 202 | u32 no_hotplug:1; |
193 | u32 reserved:24; | 203 | u32 hotplug_notify:1; |
204 | u32 reserved:23; | ||
194 | }; | 205 | }; |
195 | 206 | ||
196 | /* File System */ | 207 | /* File System */ |
@@ -329,6 +340,7 @@ struct acpi_device { | |||
329 | struct acpi_device_perf performance; | 340 | struct acpi_device_perf performance; |
330 | struct acpi_device_dir dir; | 341 | struct acpi_device_dir dir; |
331 | struct acpi_scan_handler *handler; | 342 | struct acpi_scan_handler *handler; |
343 | struct acpi_hotplug_context *hp; | ||
332 | struct acpi_driver *driver; | 344 | struct acpi_driver *driver; |
333 | void *driver_data; | 345 | void *driver_data; |
334 | struct device dev; | 346 | struct device dev; |
@@ -351,6 +363,15 @@ static inline void acpi_set_device_status(struct acpi_device *adev, u32 sta) | |||
351 | *((u32 *)&adev->status) = sta; | 363 | *((u32 *)&adev->status) = sta; |
352 | } | 364 | } |
353 | 365 | ||
366 | static inline void acpi_set_hp_context(struct acpi_device *adev, | ||
367 | struct acpi_hotplug_context *hp, | ||
368 | int (*event)(struct acpi_device *, u32)) | ||
369 | { | ||
370 | hp->self = adev; | ||
371 | hp->event = event; | ||
372 | adev->hp = hp; | ||
373 | } | ||
374 | |||
354 | /* acpi_device.dev.bus == &acpi_bus_type */ | 375 | /* acpi_device.dev.bus == &acpi_bus_type */ |
355 | extern struct bus_type acpi_bus_type; | 376 | extern struct bus_type acpi_bus_type; |
356 | 377 | ||
@@ -381,6 +402,8 @@ extern int unregister_acpi_notifier(struct notifier_block *); | |||
381 | */ | 402 | */ |
382 | 403 | ||
383 | int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device); | 404 | int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device); |
405 | struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle); | ||
406 | void acpi_bus_put_acpi_device(struct acpi_device *adev); | ||
384 | acpi_status acpi_bus_get_status_handle(acpi_handle handle, | 407 | acpi_status acpi_bus_get_status_handle(acpi_handle handle, |
385 | unsigned long long *sta); | 408 | unsigned long long *sta); |
386 | int acpi_bus_get_status(struct acpi_device *device); | 409 | int acpi_bus_get_status(struct acpi_device *device); |
@@ -402,6 +425,8 @@ static inline bool acpi_bus_can_wakeup(acpi_handle handle) { return false; } | |||
402 | 425 | ||
403 | void acpi_scan_lock_acquire(void); | 426 | void acpi_scan_lock_acquire(void); |
404 | void acpi_scan_lock_release(void); | 427 | void acpi_scan_lock_release(void); |
428 | void acpi_lock_hp_context(void); | ||
429 | void acpi_unlock_hp_context(void); | ||
405 | int acpi_scan_add_handler(struct acpi_scan_handler *handler); | 430 | int acpi_scan_add_handler(struct acpi_scan_handler *handler); |
406 | int acpi_bus_register_driver(struct acpi_driver *driver); | 431 | int acpi_bus_register_driver(struct acpi_driver *driver); |
407 | void acpi_bus_unregister_driver(struct acpi_driver *driver); | 432 | void acpi_bus_unregister_driver(struct acpi_driver *driver); |
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index fea6773f87fc..34bad459c11b 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h | |||
@@ -230,6 +230,10 @@ acpi_attach_data(acpi_handle object, acpi_object_handler handler, void *data); | |||
230 | acpi_status acpi_detach_data(acpi_handle object, acpi_object_handler handler); | 230 | acpi_status acpi_detach_data(acpi_handle object, acpi_object_handler handler); |
231 | 231 | ||
232 | acpi_status | 232 | acpi_status |
233 | acpi_get_data_full(acpi_handle object, acpi_object_handler handler, void **data, | ||
234 | void (*callback)(void *)); | ||
235 | |||
236 | acpi_status | ||
233 | acpi_get_data(acpi_handle object, acpi_object_handler handler, void **data); | 237 | acpi_get_data(acpi_handle object, acpi_object_handler handler, void **data); |
234 | 238 | ||
235 | acpi_status | 239 | acpi_status |
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 5a462c4e5009..637a608ded0b 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h | |||
@@ -59,12 +59,12 @@ static inline void acpi_pci_slot_remove(struct pci_bus *bus) { } | |||
59 | void acpiphp_init(void); | 59 | void acpiphp_init(void); |
60 | void acpiphp_enumerate_slots(struct pci_bus *bus); | 60 | void acpiphp_enumerate_slots(struct pci_bus *bus); |
61 | void acpiphp_remove_slots(struct pci_bus *bus); | 61 | void acpiphp_remove_slots(struct pci_bus *bus); |
62 | void acpiphp_check_host_bridge(acpi_handle handle); | 62 | void acpiphp_check_host_bridge(struct acpi_device *adev); |
63 | #else | 63 | #else |
64 | static inline void acpiphp_init(void) { } | 64 | static inline void acpiphp_init(void) { } |
65 | static inline void acpiphp_enumerate_slots(struct pci_bus *bus) { } | 65 | static inline void acpiphp_enumerate_slots(struct pci_bus *bus) { } |
66 | static inline void acpiphp_remove_slots(struct pci_bus *bus) { } | 66 | static inline void acpiphp_remove_slots(struct pci_bus *bus) { } |
67 | static inline void acpiphp_check_host_bridge(acpi_handle handle) { } | 67 | static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { } |
68 | #endif | 68 | #endif |
69 | 69 | ||
70 | #else /* CONFIG_ACPI */ | 70 | #else /* CONFIG_ACPI */ |