diff options
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 176 |
1 files changed, 73 insertions, 103 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fee8a297c7d9..55f9dedbbf9f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -125,8 +125,8 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha | |||
125 | } | 125 | } |
126 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); | 126 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); |
127 | 127 | ||
128 | static acpi_status acpi_bus_offline_companions(acpi_handle handle, u32 lvl, | 128 | static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, |
129 | void *data, void **ret_p) | 129 | void **ret_p) |
130 | { | 130 | { |
131 | struct acpi_device *device = NULL; | 131 | struct acpi_device *device = NULL; |
132 | struct acpi_device_physical_node *pn; | 132 | struct acpi_device_physical_node *pn; |
@@ -136,6 +136,11 @@ static acpi_status acpi_bus_offline_companions(acpi_handle handle, u32 lvl, | |||
136 | if (acpi_bus_get_device(handle, &device)) | 136 | if (acpi_bus_get_device(handle, &device)) |
137 | return AE_OK; | 137 | return AE_OK; |
138 | 138 | ||
139 | if (device->handler && !device->handler->hotplug.enabled) { | ||
140 | *ret_p = &device->dev; | ||
141 | return AE_SUPPORT; | ||
142 | } | ||
143 | |||
139 | mutex_lock(&device->physical_node_lock); | 144 | mutex_lock(&device->physical_node_lock); |
140 | 145 | ||
141 | list_for_each_entry(pn, &device->physical_node_list, node) { | 146 | list_for_each_entry(pn, &device->physical_node_list, node) { |
@@ -168,8 +173,8 @@ static acpi_status acpi_bus_offline_companions(acpi_handle handle, u32 lvl, | |||
168 | return status; | 173 | return status; |
169 | } | 174 | } |
170 | 175 | ||
171 | static acpi_status acpi_bus_online_companions(acpi_handle handle, u32 lvl, | 176 | static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data, |
172 | void *data, void **ret_p) | 177 | void **ret_p) |
173 | { | 178 | { |
174 | struct acpi_device *device = NULL; | 179 | struct acpi_device *device = NULL; |
175 | struct acpi_device_physical_node *pn; | 180 | struct acpi_device_physical_node *pn; |
@@ -214,26 +219,32 @@ static int acpi_scan_hot_remove(struct acpi_device *device) | |||
214 | * If the first pass is successful, the second one isn't needed, though. | 219 | * If the first pass is successful, the second one isn't needed, though. |
215 | */ | 220 | */ |
216 | errdev = NULL; | 221 | errdev = NULL; |
217 | acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, | 222 | status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, |
218 | NULL, acpi_bus_offline_companions, | 223 | NULL, acpi_bus_offline, (void *)false, |
219 | (void *)false, (void **)&errdev); | 224 | (void **)&errdev); |
220 | acpi_bus_offline_companions(handle, 0, (void *)false, (void **)&errdev); | 225 | if (status == AE_SUPPORT) { |
226 | dev_warn(errdev, "Offline disabled.\n"); | ||
227 | acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, | ||
228 | acpi_bus_online, NULL, NULL, NULL); | ||
229 | put_device(&device->dev); | ||
230 | return -EPERM; | ||
231 | } | ||
232 | acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev); | ||
221 | if (errdev) { | 233 | if (errdev) { |
222 | errdev = NULL; | 234 | errdev = NULL; |
223 | acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, | 235 | acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, |
224 | NULL, acpi_bus_offline_companions, | 236 | NULL, acpi_bus_offline, (void *)true, |
225 | (void *)true , (void **)&errdev); | 237 | (void **)&errdev); |
226 | if (!errdev || acpi_force_hot_remove) | 238 | if (!errdev || acpi_force_hot_remove) |
227 | acpi_bus_offline_companions(handle, 0, (void *)true, | 239 | acpi_bus_offline(handle, 0, (void *)true, |
228 | (void **)&errdev); | 240 | (void **)&errdev); |
229 | 241 | ||
230 | if (errdev && !acpi_force_hot_remove) { | 242 | if (errdev && !acpi_force_hot_remove) { |
231 | dev_warn(errdev, "Offline failed.\n"); | 243 | dev_warn(errdev, "Offline failed.\n"); |
232 | acpi_bus_online_companions(handle, 0, NULL, NULL); | 244 | acpi_bus_online(handle, 0, NULL, NULL); |
233 | acpi_walk_namespace(ACPI_TYPE_ANY, handle, | 245 | acpi_walk_namespace(ACPI_TYPE_ANY, handle, |
234 | ACPI_UINT32_MAX, | 246 | ACPI_UINT32_MAX, acpi_bus_online, |
235 | acpi_bus_online_companions, NULL, | 247 | NULL, NULL, NULL); |
236 | NULL, NULL); | ||
237 | put_device(&device->dev); | 248 | put_device(&device->dev); |
238 | return -EBUSY; | 249 | return -EBUSY; |
239 | } | 250 | } |
@@ -274,10 +285,10 @@ static int acpi_scan_hot_remove(struct acpi_device *device) | |||
274 | return 0; | 285 | return 0; |
275 | } | 286 | } |
276 | 287 | ||
277 | static void acpi_bus_device_eject(void *context) | 288 | void acpi_bus_device_eject(void *data, u32 ost_src) |
278 | { | 289 | { |
279 | acpi_handle handle = context; | 290 | struct acpi_device *device = data; |
280 | struct acpi_device *device = NULL; | 291 | acpi_handle handle = device->handle; |
281 | struct acpi_scan_handler *handler; | 292 | struct acpi_scan_handler *handler; |
282 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | 293 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; |
283 | int error; | 294 | int error; |
@@ -285,38 +296,41 @@ static void acpi_bus_device_eject(void *context) | |||
285 | lock_device_hotplug(); | 296 | lock_device_hotplug(); |
286 | mutex_lock(&acpi_scan_lock); | 297 | mutex_lock(&acpi_scan_lock); |
287 | 298 | ||
288 | acpi_bus_get_device(handle, &device); | ||
289 | if (!device) | ||
290 | goto err_out; | ||
291 | |||
292 | handler = device->handler; | 299 | handler = device->handler; |
293 | if (!handler || !handler->hotplug.enabled) { | 300 | if (!handler || !handler->hotplug.enabled) { |
294 | ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; | 301 | put_device(&device->dev); |
295 | goto err_out; | 302 | goto err_support; |
296 | } | 303 | } |
297 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, | 304 | |
298 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | 305 | if (ost_src == ACPI_NOTIFY_EJECT_REQUEST) |
306 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, | ||
307 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | ||
308 | |||
299 | if (handler->hotplug.mode == AHM_CONTAINER) | 309 | if (handler->hotplug.mode == AHM_CONTAINER) |
300 | kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); | 310 | kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); |
301 | 311 | ||
302 | get_device(&device->dev); | ||
303 | error = acpi_scan_hot_remove(device); | 312 | error = acpi_scan_hot_remove(device); |
304 | if (error) | 313 | if (error == -EPERM) { |
314 | goto err_support; | ||
315 | } else if (error) { | ||
305 | goto err_out; | 316 | goto err_out; |
317 | } | ||
306 | 318 | ||
307 | out: | 319 | out: |
308 | mutex_unlock(&acpi_scan_lock); | 320 | mutex_unlock(&acpi_scan_lock); |
309 | unlock_device_hotplug(); | 321 | unlock_device_hotplug(); |
310 | return; | 322 | return; |
311 | 323 | ||
324 | err_support: | ||
325 | ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; | ||
312 | err_out: | 326 | err_out: |
313 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ost_code, | 327 | acpi_evaluate_hotplug_ost(handle, ost_src, ost_code, NULL); |
314 | NULL); | ||
315 | goto out; | 328 | goto out; |
316 | } | 329 | } |
317 | 330 | ||
318 | static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source) | 331 | static void acpi_scan_bus_device_check(void *data, u32 ost_source) |
319 | { | 332 | { |
333 | acpi_handle handle = data; | ||
320 | struct acpi_device *device = NULL; | 334 | struct acpi_device *device = NULL; |
321 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | 335 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; |
322 | int error; | 336 | int error; |
@@ -331,8 +345,6 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source) | |||
331 | goto out; | 345 | goto out; |
332 | } | 346 | } |
333 | } | 347 | } |
334 | acpi_evaluate_hotplug_ost(handle, ost_source, | ||
335 | ACPI_OST_SC_INSERT_IN_PROGRESS, NULL); | ||
336 | error = acpi_bus_scan(handle); | 348 | error = acpi_bus_scan(handle); |
337 | if (error) { | 349 | if (error) { |
338 | acpi_handle_warn(handle, "Namespace scan failure\n"); | 350 | acpi_handle_warn(handle, "Namespace scan failure\n"); |
@@ -353,18 +365,6 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source) | |||
353 | unlock_device_hotplug(); | 365 | unlock_device_hotplug(); |
354 | } | 366 | } |
355 | 367 | ||
356 | static void acpi_scan_bus_check(void *context) | ||
357 | { | ||
358 | acpi_scan_bus_device_check((acpi_handle)context, | ||
359 | ACPI_NOTIFY_BUS_CHECK); | ||
360 | } | ||
361 | |||
362 | static void acpi_scan_device_check(void *context) | ||
363 | { | ||
364 | acpi_scan_bus_device_check((acpi_handle)context, | ||
365 | ACPI_NOTIFY_DEVICE_CHECK); | ||
366 | } | ||
367 | |||
368 | static void acpi_hotplug_unsupported(acpi_handle handle, u32 type) | 368 | static void acpi_hotplug_unsupported(acpi_handle handle, u32 type) |
369 | { | 369 | { |
370 | u32 ost_status; | 370 | u32 ost_status; |
@@ -395,8 +395,8 @@ static void acpi_hotplug_unsupported(acpi_handle handle, u32 type) | |||
395 | 395 | ||
396 | static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) | 396 | static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) |
397 | { | 397 | { |
398 | acpi_osd_exec_callback callback; | ||
399 | struct acpi_scan_handler *handler = data; | 398 | struct acpi_scan_handler *handler = data; |
399 | struct acpi_device *adev; | ||
400 | acpi_status status; | 400 | acpi_status status; |
401 | 401 | ||
402 | if (!handler->hotplug.enabled) | 402 | if (!handler->hotplug.enabled) |
@@ -405,56 +405,35 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) | |||
405 | switch (type) { | 405 | switch (type) { |
406 | case ACPI_NOTIFY_BUS_CHECK: | 406 | case ACPI_NOTIFY_BUS_CHECK: |
407 | acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); | 407 | acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); |
408 | callback = acpi_scan_bus_check; | ||
409 | break; | 408 | break; |
410 | case ACPI_NOTIFY_DEVICE_CHECK: | 409 | case ACPI_NOTIFY_DEVICE_CHECK: |
411 | acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); | 410 | acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); |
412 | callback = acpi_scan_device_check; | ||
413 | break; | 411 | break; |
414 | case ACPI_NOTIFY_EJECT_REQUEST: | 412 | case ACPI_NOTIFY_EJECT_REQUEST: |
415 | acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); | 413 | acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); |
416 | callback = acpi_bus_device_eject; | 414 | status = acpi_bus_get_device(handle, &adev); |
417 | break; | 415 | if (ACPI_FAILURE(status)) |
416 | goto err_out; | ||
417 | |||
418 | get_device(&adev->dev); | ||
419 | status = acpi_hotplug_execute(acpi_bus_device_eject, adev, type); | ||
420 | if (ACPI_SUCCESS(status)) | ||
421 | return; | ||
422 | |||
423 | put_device(&adev->dev); | ||
424 | goto err_out; | ||
418 | default: | 425 | default: |
419 | /* non-hotplug event; possibly handled by other handler */ | 426 | /* non-hotplug event; possibly handled by other handler */ |
420 | return; | 427 | return; |
421 | } | 428 | } |
422 | status = acpi_os_hotplug_execute(callback, handle); | 429 | status = acpi_hotplug_execute(acpi_scan_bus_device_check, handle, type); |
423 | if (ACPI_FAILURE(status)) | 430 | if (ACPI_SUCCESS(status)) |
424 | acpi_evaluate_hotplug_ost(handle, type, | 431 | return; |
425 | ACPI_OST_SC_NON_SPECIFIC_FAILURE, | ||
426 | NULL); | ||
427 | } | ||
428 | |||
429 | /** | ||
430 | * acpi_bus_hot_remove_device: hot-remove a device and its children | ||
431 | * @context: struct acpi_eject_event pointer (freed in this func) | ||
432 | * | ||
433 | * Hot-remove a device and its children. This function frees up the | ||
434 | * memory space passed by arg context, so that the caller may call | ||
435 | * this function asynchronously through acpi_os_hotplug_execute(). | ||
436 | */ | ||
437 | void acpi_bus_hot_remove_device(void *context) | ||
438 | { | ||
439 | struct acpi_eject_event *ej_event = context; | ||
440 | struct acpi_device *device = ej_event->device; | ||
441 | acpi_handle handle = device->handle; | ||
442 | int error; | ||
443 | |||
444 | lock_device_hotplug(); | ||
445 | mutex_lock(&acpi_scan_lock); | ||
446 | |||
447 | error = acpi_scan_hot_remove(device); | ||
448 | if (error && handle) | ||
449 | acpi_evaluate_hotplug_ost(handle, ej_event->event, | ||
450 | ACPI_OST_SC_NON_SPECIFIC_FAILURE, | ||
451 | NULL); | ||
452 | 432 | ||
453 | mutex_unlock(&acpi_scan_lock); | 433 | err_out: |
454 | unlock_device_hotplug(); | 434 | acpi_evaluate_hotplug_ost(handle, type, |
455 | kfree(context); | 435 | ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); |
456 | } | 436 | } |
457 | EXPORT_SYMBOL(acpi_bus_hot_remove_device); | ||
458 | 437 | ||
459 | static ssize_t real_power_state_show(struct device *dev, | 438 | static ssize_t real_power_state_show(struct device *dev, |
460 | struct device_attribute *attr, char *buf) | 439 | struct device_attribute *attr, char *buf) |
@@ -487,10 +466,8 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, | |||
487 | const char *buf, size_t count) | 466 | const char *buf, size_t count) |
488 | { | 467 | { |
489 | struct acpi_device *acpi_device = to_acpi_device(d); | 468 | struct acpi_device *acpi_device = to_acpi_device(d); |
490 | struct acpi_eject_event *ej_event; | ||
491 | acpi_object_type not_used; | 469 | acpi_object_type not_used; |
492 | acpi_status status; | 470 | acpi_status status; |
493 | int ret; | ||
494 | 471 | ||
495 | if (!count || buf[0] != '1') | 472 | if (!count || buf[0] != '1') |
496 | return -EINVAL; | 473 | return -EINVAL; |
@@ -503,28 +480,18 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, | |||
503 | if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) | 480 | if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) |
504 | return -ENODEV; | 481 | return -ENODEV; |
505 | 482 | ||
506 | ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); | ||
507 | if (!ej_event) { | ||
508 | ret = -ENOMEM; | ||
509 | goto err_out; | ||
510 | } | ||
511 | acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, | 483 | acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, |
512 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | 484 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); |
513 | ej_event->device = acpi_device; | ||
514 | ej_event->event = ACPI_OST_EC_OSPM_EJECT; | ||
515 | get_device(&acpi_device->dev); | 485 | get_device(&acpi_device->dev); |
516 | status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event); | 486 | status = acpi_hotplug_execute(acpi_bus_device_eject, acpi_device, |
487 | ACPI_OST_EC_OSPM_EJECT); | ||
517 | if (ACPI_SUCCESS(status)) | 488 | if (ACPI_SUCCESS(status)) |
518 | return count; | 489 | return count; |
519 | 490 | ||
520 | put_device(&acpi_device->dev); | 491 | put_device(&acpi_device->dev); |
521 | kfree(ej_event); | ||
522 | ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; | ||
523 | |||
524 | err_out: | ||
525 | acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, | 492 | acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, |
526 | ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); | 493 | ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); |
527 | return ret; | 494 | return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; |
528 | } | 495 | } |
529 | 496 | ||
530 | static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); | 497 | static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); |
@@ -1676,7 +1643,6 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, | |||
1676 | 1643 | ||
1677 | void acpi_device_add_finalize(struct acpi_device *device) | 1644 | void acpi_device_add_finalize(struct acpi_device *device) |
1678 | { | 1645 | { |
1679 | device->flags.match_driver = true; | ||
1680 | dev_set_uevent_suppress(&device->dev, false); | 1646 | dev_set_uevent_suppress(&device->dev, false); |
1681 | kobject_uevent(&device->dev.kobj, KOBJ_ADD); | 1647 | kobject_uevent(&device->dev.kobj, KOBJ_ADD); |
1682 | } | 1648 | } |
@@ -1915,8 +1881,12 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, | |||
1915 | return AE_OK; | 1881 | return AE_OK; |
1916 | 1882 | ||
1917 | ret = acpi_scan_attach_handler(device); | 1883 | ret = acpi_scan_attach_handler(device); |
1918 | if (ret) | 1884 | if (ret < 0) |
1919 | return ret > 0 ? AE_OK : AE_CTRL_DEPTH; | 1885 | return AE_CTRL_DEPTH; |
1886 | |||
1887 | device->flags.match_driver = true; | ||
1888 | if (ret > 0) | ||
1889 | return AE_OK; | ||
1920 | 1890 | ||
1921 | ret = device_attach(&device->dev); | 1891 | ret = device_attach(&device->dev); |
1922 | return ret >= 0 ? AE_OK : AE_CTRL_DEPTH; | 1892 | return ret >= 0 ? AE_OK : AE_CTRL_DEPTH; |