diff options
-rw-r--r-- | drivers/acpi/scan.c | 137 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 9 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 168 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 25 |
4 files changed, 158 insertions, 181 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index d64a5826ef35..984eaff235df 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -450,43 +450,61 @@ static int acpi_scan_bus_check(struct acpi_device *adev) | |||
450 | return 0; | 450 | return 0; |
451 | } | 451 | } |
452 | 452 | ||
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 | return acpi_scan_hot_remove(adev); | ||
463 | } | ||
464 | return -EINVAL; | ||
465 | } | ||
466 | |||
453 | static void acpi_device_hotplug(void *data, u32 src) | 467 | static void acpi_device_hotplug(void *data, u32 src) |
454 | { | 468 | { |
455 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | 469 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; |
456 | struct acpi_device *adev = data; | 470 | struct acpi_device *adev = data; |
457 | int error; | 471 | int error = -ENODEV; |
458 | 472 | ||
459 | lock_device_hotplug(); | 473 | lock_device_hotplug(); |
460 | mutex_lock(&acpi_scan_lock); | 474 | mutex_lock(&acpi_scan_lock); |
461 | 475 | ||
462 | /* | 476 | /* |
463 | * The device object's ACPI handle cannot become invalid as long as we | 477 | * The device object's ACPI handle cannot become invalid as long as we |
464 | * are holding acpi_scan_lock, but it may have become invalid before | 478 | * are holding acpi_scan_lock, but it might have become invalid before |
465 | * that lock was acquired. | 479 | * that lock was acquired. |
466 | */ | 480 | */ |
467 | if (adev->handle == INVALID_ACPI_HANDLE) | 481 | if (adev->handle == INVALID_ACPI_HANDLE) |
468 | goto out; | 482 | goto err_out; |
469 | 483 | ||
470 | switch (src) { | 484 | if (adev->flags.hotplug_notify) { |
471 | case ACPI_NOTIFY_BUS_CHECK: | 485 | error = acpi_generic_hotplug_event(adev, src); |
472 | error = acpi_scan_bus_check(adev); | 486 | } else { |
473 | break; | 487 | int (*event)(struct acpi_device *, u32); |
474 | case ACPI_NOTIFY_DEVICE_CHECK: | 488 | |
475 | error = acpi_scan_device_check(adev); | 489 | acpi_lock_hp_context(); |
476 | break; | 490 | event = adev->hp ? adev->hp->event : NULL; |
477 | case ACPI_NOTIFY_EJECT_REQUEST: | 491 | acpi_unlock_hp_context(); |
478 | case ACPI_OST_EC_OSPM_EJECT: | 492 | /* |
479 | error = acpi_scan_hot_remove(adev); | 493 | * There may be additional notify handlers for device objects |
480 | break; | 494 | * without the .event() callback, so ignore them here. |
481 | default: | 495 | */ |
482 | error = -EINVAL; | 496 | if (event) |
483 | break; | 497 | error = event(adev, src); |
498 | else | ||
499 | goto out; | ||
484 | } | 500 | } |
485 | if (!error) | 501 | if (!error) |
486 | ost_code = ACPI_OST_SC_SUCCESS; | 502 | ost_code = ACPI_OST_SC_SUCCESS; |
487 | 503 | ||
488 | out: | 504 | err_out: |
489 | acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); | 505 | acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); |
506 | |||
507 | out: | ||
490 | acpi_bus_put_acpi_device(adev); | 508 | acpi_bus_put_acpi_device(adev); |
491 | mutex_unlock(&acpi_scan_lock); | 509 | mutex_unlock(&acpi_scan_lock); |
492 | unlock_device_hotplug(); | 510 | unlock_device_hotplug(); |
@@ -494,8 +512,8 @@ static void acpi_device_hotplug(void *data, u32 src) | |||
494 | 512 | ||
495 | static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) | 513 | static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) |
496 | { | 514 | { |
497 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | ||
498 | struct acpi_scan_handler *handler = data; | 515 | struct acpi_scan_handler *handler = data; |
516 | u32 ost_code = ACPI_OST_SC_SUCCESS; | ||
499 | struct acpi_device *adev; | 517 | struct acpi_device *adev; |
500 | acpi_status status; | 518 | acpi_status status; |
501 | 519 | ||
@@ -503,26 +521,49 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) | |||
503 | case ACPI_NOTIFY_BUS_CHECK: | 521 | case ACPI_NOTIFY_BUS_CHECK: |
504 | acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); | 522 | acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); |
505 | break; | 523 | break; |
524 | |||
506 | case ACPI_NOTIFY_DEVICE_CHECK: | 525 | case ACPI_NOTIFY_DEVICE_CHECK: |
507 | acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); | 526 | acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); |
508 | break; | 527 | break; |
528 | |||
509 | case ACPI_NOTIFY_EJECT_REQUEST: | 529 | case ACPI_NOTIFY_EJECT_REQUEST: |
510 | acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); | 530 | acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); |
511 | if (!handler->hotplug.enabled) { | 531 | if (handler && !handler->hotplug.enabled) { |
512 | acpi_handle_err(handle, "Eject disabled\n"); | 532 | acpi_handle_err(handle, "Eject disabled\n"); |
513 | ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; | 533 | ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; |
514 | goto err_out; | 534 | goto out; |
515 | } | 535 | } |
516 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, | 536 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, |
517 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | 537 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); |
518 | break; | 538 | break; |
519 | default: | 539 | |
520 | /* non-hotplug event; possibly handled by other handler */ | 540 | case ACPI_NOTIFY_DEVICE_WAKE: |
521 | return; | 541 | return; |
542 | |||
543 | case ACPI_NOTIFY_FREQUENCY_MISMATCH: | ||
544 | acpi_handle_err(handle, "Device cannot be configured due " | ||
545 | "to a frequency mismatch\n"); | ||
546 | goto out; | ||
547 | |||
548 | case ACPI_NOTIFY_BUS_MODE_MISMATCH: | ||
549 | acpi_handle_err(handle, "Device cannot be configured due " | ||
550 | "to a bus mode mismatch\n"); | ||
551 | goto out; | ||
552 | |||
553 | case ACPI_NOTIFY_POWER_FAULT: | ||
554 | acpi_handle_err(handle, "Device has suffered a power fault\n"); | ||
555 | goto out; | ||
556 | |||
557 | default: | ||
558 | acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); | ||
559 | ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; | ||
560 | goto out; | ||
522 | } | 561 | } |
562 | |||
563 | ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | ||
523 | adev = acpi_bus_get_acpi_device(handle); | 564 | adev = acpi_bus_get_acpi_device(handle); |
524 | if (!adev) | 565 | if (!adev) |
525 | goto err_out; | 566 | goto out; |
526 | 567 | ||
527 | status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); | 568 | status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); |
528 | if (ACPI_SUCCESS(status)) | 569 | if (ACPI_SUCCESS(status)) |
@@ -530,10 +571,22 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) | |||
530 | 571 | ||
531 | acpi_bus_put_acpi_device(adev); | 572 | acpi_bus_put_acpi_device(adev); |
532 | 573 | ||
533 | err_out: | 574 | out: |
534 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); | 575 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); |
535 | } | 576 | } |
536 | 577 | ||
578 | void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) | ||
579 | { | ||
580 | acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
581 | acpi_hotplug_notify_cb, data); | ||
582 | } | ||
583 | |||
584 | void acpi_remove_hotplug_notify_handler(acpi_handle handle) | ||
585 | { | ||
586 | acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
587 | acpi_hotplug_notify_cb); | ||
588 | } | ||
589 | |||
537 | static ssize_t real_power_state_show(struct device *dev, | 590 | static ssize_t real_power_state_show(struct device *dev, |
538 | struct device_attribute *attr, char *buf) | 591 | struct device_attribute *attr, char *buf) |
539 | { | 592 | { |
@@ -1976,33 +2029,21 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val) | |||
1976 | mutex_unlock(&acpi_scan_lock); | 2029 | mutex_unlock(&acpi_scan_lock); |
1977 | } | 2030 | } |
1978 | 2031 | ||
1979 | static void acpi_scan_init_hotplug(acpi_handle handle, int type) | 2032 | static void acpi_scan_init_hotplug(struct acpi_device *adev) |
1980 | { | 2033 | { |
1981 | struct acpi_device_pnp pnp = {}; | ||
1982 | struct acpi_hardware_id *hwid; | 2034 | struct acpi_hardware_id *hwid; |
1983 | struct acpi_scan_handler *handler; | ||
1984 | 2035 | ||
1985 | INIT_LIST_HEAD(&pnp.ids); | 2036 | list_for_each_entry(hwid, &adev->pnp.ids, list) { |
1986 | acpi_set_pnp_ids(handle, &pnp, type); | 2037 | struct acpi_scan_handler *handler; |
1987 | |||
1988 | if (!pnp.type.hardware_id) | ||
1989 | goto out; | ||
1990 | 2038 | ||
1991 | /* | ||
1992 | * This relies on the fact that acpi_install_notify_handler() will not | ||
1993 | * install the same notify handler routine twice for the same handle. | ||
1994 | */ | ||
1995 | list_for_each_entry(hwid, &pnp.ids, list) { | ||
1996 | handler = acpi_scan_match_handler(hwid->id, NULL); | 2039 | handler = acpi_scan_match_handler(hwid->id, NULL); |
1997 | if (handler) { | 2040 | if (!handler) |
1998 | acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | 2041 | continue; |
1999 | acpi_hotplug_notify_cb, handler); | ||
2000 | break; | ||
2001 | } | ||
2002 | } | ||
2003 | 2042 | ||
2004 | out: | 2043 | acpi_install_hotplug_notify_handler(adev->handle, handler); |
2005 | acpi_free_pnp_ids(&pnp); | 2044 | adev->flags.hotplug_notify = true; |
2045 | break; | ||
2046 | } | ||
2006 | } | 2047 | } |
2007 | 2048 | ||
2008 | static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, | 2049 | static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, |
@@ -2026,12 +2067,12 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, | |||
2026 | return AE_OK; | 2067 | return AE_OK; |
2027 | } | 2068 | } |
2028 | 2069 | ||
2029 | acpi_scan_init_hotplug(handle, type); | ||
2030 | |||
2031 | acpi_add_single_object(&device, handle, type, sta); | 2070 | acpi_add_single_object(&device, handle, type, sta); |
2032 | if (!device) | 2071 | if (!device) |
2033 | return AE_CTRL_DEPTH; | 2072 | return AE_CTRL_DEPTH; |
2034 | 2073 | ||
2074 | acpi_scan_init_hotplug(device); | ||
2075 | |||
2035 | out: | 2076 | out: |
2036 | if (!*return_value) | 2077 | if (!*return_value) |
2037 | *return_value = device; | 2078 | *return_value = device; |
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 373c7aa3b4a6..d7c1fc9712ad 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h | |||
@@ -116,12 +116,17 @@ struct acpiphp_func { | |||
116 | }; | 116 | }; |
117 | 117 | ||
118 | struct acpiphp_context { | 118 | struct acpiphp_context { |
119 | struct acpi_hotplug_context hp; | ||
119 | struct acpiphp_func func; | 120 | struct acpiphp_func func; |
120 | struct acpi_device *adev; | ||
121 | struct acpiphp_bridge *bridge; | 121 | struct acpiphp_bridge *bridge; |
122 | unsigned int refcount; | 122 | unsigned int refcount; |
123 | }; | 123 | }; |
124 | 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 | |||
125 | 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) |
126 | { | 131 | { |
127 | return container_of(func, struct acpiphp_context, func); | 132 | return container_of(func, struct acpiphp_context, func); |
@@ -129,7 +134,7 @@ static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) | |||
129 | 134 | ||
130 | static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) | 135 | static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) |
131 | { | 136 | { |
132 | return func_to_context(func)->adev; | 137 | return func_to_context(func)->hp.self; |
133 | } | 138 | } |
134 | 139 | ||
135 | static inline acpi_handle func_to_handle(struct acpiphp_func *func) | 140 | static inline acpi_handle func_to_handle(struct acpiphp_func *func) |
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 8139a4b0d389..7c498d663eb3 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -59,17 +59,12 @@ | |||
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 | 61 | ||
62 | static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); | 62 | static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); |
63 | static void acpiphp_sanitize_bus(struct pci_bus *bus); | 63 | static void acpiphp_sanitize_bus(struct pci_bus *bus); |
64 | static void acpiphp_set_hpp_values(struct pci_bus *bus); | 64 | static void acpiphp_set_hpp_values(struct pci_bus *bus); |
65 | static void hotplug_event(u32 type, struct acpiphp_context *context); | 65 | static void hotplug_event(u32 type, struct acpiphp_context *context); |
66 | static void free_bridge(struct kref *kref); | 66 | static void free_bridge(struct kref *kref); |
67 | 67 | ||
68 | static void acpiphp_context_handler(acpi_handle handle, void *context) | ||
69 | { | ||
70 | /* Intentionally empty. */ | ||
71 | } | ||
72 | |||
73 | /** | 68 | /** |
74 | * 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. |
75 | * @adev: ACPI device object to create the context for. | 70 | * @adev: ACPI device object to create the context for. |
@@ -79,39 +74,31 @@ static void acpiphp_context_handler(acpi_handle handle, void *context) | |||
79 | static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) | 74 | static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) |
80 | { | 75 | { |
81 | struct acpiphp_context *context; | 76 | struct acpiphp_context *context; |
82 | acpi_status status; | ||
83 | 77 | ||
84 | context = kzalloc(sizeof(*context), GFP_KERNEL); | 78 | context = kzalloc(sizeof(*context), GFP_KERNEL); |
85 | if (!context) | 79 | if (!context) |
86 | return NULL; | 80 | return NULL; |
87 | 81 | ||
88 | context->adev = adev; | ||
89 | context->refcount = 1; | 82 | context->refcount = 1; |
90 | status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); | 83 | acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event); |
91 | if (ACPI_FAILURE(status)) { | ||
92 | kfree(context); | ||
93 | return NULL; | ||
94 | } | ||
95 | return context; | 84 | return context; |
96 | } | 85 | } |
97 | 86 | ||
98 | /** | 87 | /** |
99 | * 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. |
100 | * @handle: ACPI object handle to get the context for. | 89 | * @adev: ACPI device object to get the context for. |
101 | * | 90 | * |
102 | * Call under acpi_hp_context_lock. | 91 | * Call under acpi_hp_context_lock. |
103 | */ | 92 | */ |
104 | static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) | 93 | static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) |
105 | { | 94 | { |
106 | struct acpiphp_context *context = NULL; | 95 | struct acpiphp_context *context; |
107 | acpi_status status; | ||
108 | void *data; | ||
109 | 96 | ||
110 | status = acpi_get_data(handle, acpiphp_context_handler, &data); | 97 | if (!adev->hp) |
111 | if (ACPI_SUCCESS(status)) { | 98 | return NULL; |
112 | context = data; | 99 | |
113 | context->refcount++; | 100 | context = to_acpiphp_context(adev->hp); |
114 | } | 101 | context->refcount++; |
115 | return context; | 102 | return context; |
116 | } | 103 | } |
117 | 104 | ||
@@ -129,7 +116,7 @@ static void acpiphp_put_context(struct acpiphp_context *context) | |||
129 | return; | 116 | return; |
130 | 117 | ||
131 | WARN_ON(context->bridge); | 118 | WARN_ON(context->bridge); |
132 | acpi_detach_data(context->adev->handle, acpiphp_context_handler); | 119 | context->hp.self->hp = NULL; |
133 | kfree(context); | 120 | kfree(context); |
134 | } | 121 | } |
135 | 122 | ||
@@ -211,22 +198,13 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) | |||
211 | 198 | ||
212 | static void dock_event(acpi_handle handle, u32 type, void *data) | 199 | static void dock_event(acpi_handle handle, u32 type, void *data) |
213 | { | 200 | { |
214 | struct acpiphp_context *context; | 201 | struct acpi_device *adev; |
215 | 202 | ||
216 | acpi_lock_hp_context(); | 203 | adev = acpi_bus_get_acpi_device(handle); |
217 | context = acpiphp_get_context(handle); | 204 | if (adev) { |
218 | if (!context || WARN_ON(context->adev->handle != handle) | 205 | acpiphp_hotplug_event(adev, type); |
219 | || context->func.parent->is_going_away) { | 206 | acpi_bus_put_acpi_device(adev); |
220 | acpi_unlock_hp_context(); | ||
221 | return; | ||
222 | } | 207 | } |
223 | get_bridge(context->func.parent); | ||
224 | acpiphp_put_context(context); | ||
225 | acpi_unlock_hp_context(); | ||
226 | |||
227 | hotplug_event(type, context); | ||
228 | |||
229 | put_bridge(context->func.parent); | ||
230 | } | 208 | } |
231 | 209 | ||
232 | static const struct acpi_dock_ops acpiphp_dock_ops = { | 210 | static const struct acpi_dock_ops acpiphp_dock_ops = { |
@@ -397,25 +375,23 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, | |||
397 | } | 375 | } |
398 | 376 | ||
399 | /* install notify handler */ | 377 | /* install notify handler */ |
400 | if (!(newfunc->flags & FUNC_HAS_DCK)) { | 378 | if (!(newfunc->flags & FUNC_HAS_DCK)) |
401 | status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | 379 | acpi_install_hotplug_notify_handler(handle, NULL); |
402 | handle_hotplug_event, | ||
403 | context); | ||
404 | if (ACPI_FAILURE(status)) | ||
405 | acpi_handle_err(handle, | ||
406 | "failed to install notify handler\n"); | ||
407 | } | ||
408 | 380 | ||
409 | return AE_OK; | 381 | return AE_OK; |
410 | } | 382 | } |
411 | 383 | ||
412 | static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) | 384 | static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) |
413 | { | 385 | { |
386 | struct acpi_device *adev = acpi_bus_get_acpi_device(handle); | ||
414 | struct acpiphp_context *context; | 387 | struct acpiphp_context *context; |
415 | struct acpiphp_bridge *bridge = NULL; | 388 | struct acpiphp_bridge *bridge = NULL; |
416 | 389 | ||
390 | if (!adev) | ||
391 | return NULL; | ||
392 | |||
417 | acpi_lock_hp_context(); | 393 | acpi_lock_hp_context(); |
418 | context = acpiphp_get_context(handle); | 394 | context = acpiphp_get_context(adev); |
419 | if (context) { | 395 | if (context) { |
420 | bridge = context->bridge; | 396 | bridge = context->bridge; |
421 | if (bridge) | 397 | if (bridge) |
@@ -424,6 +400,7 @@ static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) | |||
424 | acpiphp_put_context(context); | 400 | acpiphp_put_context(context); |
425 | } | 401 | } |
426 | acpi_unlock_hp_context(); | 402 | acpi_unlock_hp_context(); |
403 | acpi_bus_put_acpi_device(adev); | ||
427 | return bridge; | 404 | return bridge; |
428 | } | 405 | } |
429 | 406 | ||
@@ -431,7 +408,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
431 | { | 408 | { |
432 | struct acpiphp_slot *slot; | 409 | struct acpiphp_slot *slot; |
433 | struct acpiphp_func *func; | 410 | struct acpiphp_func *func; |
434 | acpi_status status; | ||
435 | 411 | ||
436 | list_for_each_entry(slot, &bridge->slots, node) { | 412 | list_for_each_entry(slot, &bridge->slots, node) { |
437 | list_for_each_entry(func, &slot->funcs, sibling) { | 413 | list_for_each_entry(func, &slot->funcs, sibling) { |
@@ -440,13 +416,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
440 | if (is_dock_device(handle)) | 416 | if (is_dock_device(handle)) |
441 | unregister_hotplug_dock_device(handle); | 417 | unregister_hotplug_dock_device(handle); |
442 | 418 | ||
443 | if (!(func->flags & FUNC_HAS_DCK)) { | 419 | if (!(func->flags & FUNC_HAS_DCK)) |
444 | status = acpi_remove_notify_handler(handle, | 420 | acpi_remove_hotplug_notify_handler(handle); |
445 | ACPI_SYSTEM_NOTIFY, | ||
446 | handle_hotplug_event); | ||
447 | if (ACPI_FAILURE(status)) | ||
448 | pr_err("failed to remove notify handler\n"); | ||
449 | } | ||
450 | } | 421 | } |
451 | slot->flags |= SLOT_IS_GOING_AWAY; | 422 | slot->flags |= SLOT_IS_GOING_AWAY; |
452 | if (slot->slot) | 423 | if (slot->slot) |
@@ -814,7 +785,7 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); | |||
814 | 785 | ||
815 | static void hotplug_event(u32 type, struct acpiphp_context *context) | 786 | static void hotplug_event(u32 type, struct acpiphp_context *context) |
816 | { | 787 | { |
817 | acpi_handle handle = context->adev->handle; | 788 | acpi_handle handle = context->hp.self->handle; |
818 | struct acpiphp_func *func = &context->func; | 789 | struct acpiphp_func *func = &context->func; |
819 | struct acpiphp_slot *slot = func->slot; | 790 | struct acpiphp_slot *slot = func->slot; |
820 | struct acpiphp_bridge *bridge; | 791 | struct acpiphp_bridge *bridge; |
@@ -866,87 +837,24 @@ static void hotplug_event(u32 type, struct acpiphp_context *context) | |||
866 | put_bridge(bridge); | 837 | put_bridge(bridge); |
867 | } | 838 | } |
868 | 839 | ||
869 | static void hotplug_event_work(void *data, u32 type) | 840 | static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type) |
870 | { | ||
871 | struct acpiphp_context *context = data; | ||
872 | |||
873 | acpi_scan_lock_acquire(); | ||
874 | |||
875 | hotplug_event(type, context); | ||
876 | |||
877 | acpi_scan_lock_release(); | ||
878 | acpi_evaluate_hotplug_ost(context->adev->handle, type, | ||
879 | ACPI_OST_SC_SUCCESS, NULL); | ||
880 | put_bridge(context->func.parent); | ||
881 | } | ||
882 | |||
883 | /** | ||
884 | * handle_hotplug_event - handle ACPI hotplug event | ||
885 | * @handle: Notify()'ed acpi_handle | ||
886 | * @type: Notify code | ||
887 | * @data: pointer to acpiphp_context structure | ||
888 | * | ||
889 | * Handles ACPI event notification on slots. | ||
890 | */ | ||
891 | static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) | ||
892 | { | 841 | { |
893 | struct acpiphp_context *context; | 842 | struct acpiphp_context *context; |
894 | u32 ost_code = ACPI_OST_SC_SUCCESS; | ||
895 | acpi_status status; | ||
896 | |||
897 | switch (type) { | ||
898 | case ACPI_NOTIFY_BUS_CHECK: | ||
899 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
900 | break; | ||
901 | case ACPI_NOTIFY_EJECT_REQUEST: | ||
902 | ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; | ||
903 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); | ||
904 | break; | ||
905 | |||
906 | case ACPI_NOTIFY_DEVICE_WAKE: | ||
907 | return; | ||
908 | |||
909 | case ACPI_NOTIFY_FREQUENCY_MISMATCH: | ||
910 | acpi_handle_err(handle, "Device cannot be configured due " | ||
911 | "to a frequency mismatch\n"); | ||
912 | goto out; | ||
913 | |||
914 | case ACPI_NOTIFY_BUS_MODE_MISMATCH: | ||
915 | acpi_handle_err(handle, "Device cannot be configured due " | ||
916 | "to a bus mode mismatch\n"); | ||
917 | goto out; | ||
918 | |||
919 | case ACPI_NOTIFY_POWER_FAULT: | ||
920 | acpi_handle_err(handle, "Device has suffered a power fault\n"); | ||
921 | goto out; | ||
922 | |||
923 | default: | ||
924 | acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); | ||
925 | ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; | ||
926 | goto out; | ||
927 | } | ||
928 | 843 | ||
929 | acpi_lock_hp_context(); | 844 | acpi_lock_hp_context(); |
930 | context = acpiphp_get_context(handle); | 845 | context = acpiphp_get_context(adev); |
931 | if (!context || WARN_ON(context->adev->handle != handle) | 846 | if (!context || context->func.parent->is_going_away) { |
932 | || context->func.parent->is_going_away) | ||
933 | goto err_out; | ||
934 | |||
935 | get_bridge(context->func.parent); | ||
936 | acpiphp_put_context(context); | ||
937 | status = acpi_hotplug_execute(hotplug_event_work, context, type); | ||
938 | if (ACPI_SUCCESS(status)) { | ||
939 | acpi_unlock_hp_context(); | 847 | acpi_unlock_hp_context(); |
940 | return; | 848 | return -ENODATA; |
941 | } | 849 | } |
942 | put_bridge(context->func.parent); | 850 | get_bridge(context->func.parent); |
943 | 851 | acpiphp_put_context(context); | |
944 | err_out: | ||
945 | acpi_unlock_hp_context(); | 852 | acpi_unlock_hp_context(); |
946 | ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | ||
947 | 853 | ||
948 | out: | 854 | hotplug_event(type, context); |
949 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); | 855 | |
856 | put_bridge(context->func.parent); | ||
857 | return 0; | ||
950 | } | 858 | } |
951 | 859 | ||
952 | /** | 860 | /** |
@@ -999,7 +907,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) | |||
999 | * bridge is not interesting to us either. | 907 | * bridge is not interesting to us either. |
1000 | */ | 908 | */ |
1001 | acpi_lock_hp_context(); | 909 | acpi_lock_hp_context(); |
1002 | context = acpiphp_get_context(handle); | 910 | context = acpiphp_get_context(adev); |
1003 | if (!context) { | 911 | if (!context) { |
1004 | acpi_unlock_hp_context(); | 912 | acpi_unlock_hp_context(); |
1005 | put_device(&bus->dev); | 913 | put_device(&bus->dev); |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 0c82708ff08a..53ce357f6335 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 | ||
@@ -425,6 +446,8 @@ static inline bool acpi_device_enumerated(struct acpi_device *adev) | |||
425 | typedef void (*acpi_hp_callback)(void *data, u32 src); | 446 | typedef void (*acpi_hp_callback)(void *data, u32 src); |
426 | 447 | ||
427 | acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); | 448 | acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); |
449 | void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); | ||
450 | void acpi_remove_hotplug_notify_handler(acpi_handle handle); | ||
428 | 451 | ||
429 | /** | 452 | /** |
430 | * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver | 453 | * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver |