diff options
-rw-r--r-- | drivers/acpi/internal.h | 2 | ||||
-rw-r--r-- | drivers/acpi/pci_root.c | 4 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 141 |
3 files changed, 68 insertions, 79 deletions
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 809b8082c134..a0d42cf5b0c5 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
@@ -89,7 +89,7 @@ void acpi_device_add_finalize(struct acpi_device *device); | |||
89 | void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); | 89 | void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); |
90 | int acpi_bind_one(struct device *dev, acpi_handle handle); | 90 | int acpi_bind_one(struct device *dev, acpi_handle handle); |
91 | int acpi_unbind_one(struct device *dev); | 91 | int acpi_unbind_one(struct device *dev); |
92 | void acpi_bus_device_eject(void *data, u32 ost_src); | 92 | void acpi_device_hotplug(void *data, u32 ost_src); |
93 | bool acpi_device_is_present(struct acpi_device *adev); | 93 | bool acpi_device_is_present(struct acpi_device *adev); |
94 | 94 | ||
95 | /* -------------------------------------------------------------------------- | 95 | /* -------------------------------------------------------------------------- |
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 4076491c6ded..ca05064f3ff7 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
@@ -683,11 +683,13 @@ static void hotplug_event_root(void *data, u32 type) | |||
683 | if (!root) | 683 | if (!root) |
684 | break; | 684 | break; |
685 | 685 | ||
686 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, | ||
687 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | ||
686 | get_device(&root->device->dev); | 688 | get_device(&root->device->dev); |
687 | 689 | ||
688 | acpi_scan_lock_release(); | 690 | acpi_scan_lock_release(); |
689 | 691 | ||
690 | acpi_bus_device_eject(root->device, ACPI_NOTIFY_EJECT_REQUEST); | 692 | acpi_device_hotplug(root->device, ACPI_NOTIFY_EJECT_REQUEST); |
691 | return; | 693 | return; |
692 | default: | 694 | default: |
693 | acpi_handle_warn(handle, | 695 | acpi_handle_warn(handle, |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 4fa416f94f52..dd0ff9de9277 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -206,12 +206,8 @@ static int acpi_scan_hot_remove(struct acpi_device *device) | |||
206 | acpi_status status; | 206 | acpi_status status; |
207 | unsigned long long sta; | 207 | unsigned long long sta; |
208 | 208 | ||
209 | /* If there is no handle, the device node has been unregistered. */ | 209 | if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER) |
210 | if (!handle) { | 210 | kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); |
211 | dev_dbg(&device->dev, "ACPI handle missing\n"); | ||
212 | put_device(&device->dev); | ||
213 | return -EINVAL; | ||
214 | } | ||
215 | 211 | ||
216 | /* | 212 | /* |
217 | * Carry out two passes here and ignore errors in the first pass, | 213 | * Carry out two passes here and ignore errors in the first pass, |
@@ -230,7 +226,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) | |||
230 | dev_warn(errdev, "Offline disabled.\n"); | 226 | dev_warn(errdev, "Offline disabled.\n"); |
231 | acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, | 227 | acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, |
232 | acpi_bus_online, NULL, NULL, NULL); | 228 | acpi_bus_online, NULL, NULL, NULL); |
233 | put_device(&device->dev); | ||
234 | return -EPERM; | 229 | return -EPERM; |
235 | } | 230 | } |
236 | acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev); | 231 | acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev); |
@@ -249,7 +244,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) | |||
249 | acpi_walk_namespace(ACPI_TYPE_ANY, handle, | 244 | acpi_walk_namespace(ACPI_TYPE_ANY, handle, |
250 | ACPI_UINT32_MAX, acpi_bus_online, | 245 | ACPI_UINT32_MAX, acpi_bus_online, |
251 | NULL, NULL, NULL); | 246 | NULL, NULL, NULL); |
252 | put_device(&device->dev); | ||
253 | return -EBUSY; | 247 | return -EBUSY; |
254 | } | 248 | } |
255 | } | 249 | } |
@@ -259,9 +253,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) | |||
259 | 253 | ||
260 | acpi_bus_trim(device); | 254 | acpi_bus_trim(device); |
261 | 255 | ||
262 | put_device(&device->dev); | ||
263 | device = NULL; | ||
264 | |||
265 | acpi_evaluate_lck(handle, 0); | 256 | acpi_evaluate_lck(handle, 0); |
266 | /* | 257 | /* |
267 | * TBD: _EJD support. | 258 | * TBD: _EJD support. |
@@ -288,77 +279,74 @@ static int acpi_scan_hot_remove(struct acpi_device *device) | |||
288 | return 0; | 279 | return 0; |
289 | } | 280 | } |
290 | 281 | ||
291 | void acpi_bus_device_eject(void *data, u32 ost_src) | 282 | static int acpi_scan_device_check(struct acpi_device *adev) |
292 | { | 283 | { |
293 | struct acpi_device *device = data; | ||
294 | acpi_handle handle = device->handle; | ||
295 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | ||
296 | int error; | 284 | int error; |
297 | 285 | ||
298 | lock_device_hotplug(); | 286 | /* |
299 | mutex_lock(&acpi_scan_lock); | 287 | * This function is only called for device objects for which matching |
300 | 288 | * scan handlers exist. The only situation in which the scan handler is | |
301 | if (ost_src == ACPI_NOTIFY_EJECT_REQUEST) | 289 | * not attached to this device object yet is when the device has just |
302 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, | 290 | * appeared (either it wasn't present at all before or it was removed |
303 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | 291 | * and then added again). |
304 | 292 | */ | |
305 | if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER) | 293 | if (adev->handler) { |
306 | kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); | 294 | dev_warn(&adev->dev, "Already enumerated\n"); |
307 | 295 | return -EBUSY; | |
308 | error = acpi_scan_hot_remove(device); | ||
309 | if (error == -EPERM) { | ||
310 | goto err_support; | ||
311 | } else if (error) { | ||
312 | goto err_out; | ||
313 | } | 296 | } |
314 | 297 | error = acpi_bus_scan(adev->handle); | |
315 | out: | 298 | if (error) { |
316 | mutex_unlock(&acpi_scan_lock); | 299 | dev_warn(&adev->dev, "Namespace scan failure\n"); |
317 | unlock_device_hotplug(); | 300 | return error; |
318 | return; | 301 | } |
319 | 302 | if (adev->handler) { | |
320 | err_support: | 303 | if (adev->handler->hotplug.mode == AHM_CONTAINER) |
321 | ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; | 304 | kobject_uevent(&adev->dev.kobj, KOBJ_ONLINE); |
322 | err_out: | 305 | } else { |
323 | acpi_evaluate_hotplug_ost(handle, ost_src, ost_code, NULL); | 306 | dev_warn(&adev->dev, "Enumeration failure\n"); |
324 | goto out; | 307 | return -ENODEV; |
308 | } | ||
309 | return 0; | ||
325 | } | 310 | } |
326 | 311 | ||
327 | static void acpi_scan_bus_device_check(void *data, u32 ost_source) | 312 | void acpi_device_hotplug(void *data, u32 src) |
328 | { | 313 | { |
329 | acpi_handle handle = data; | ||
330 | struct acpi_device *device; | ||
331 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | 314 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; |
315 | struct acpi_device *adev = data; | ||
332 | int error; | 316 | int error; |
333 | 317 | ||
334 | lock_device_hotplug(); | 318 | lock_device_hotplug(); |
335 | mutex_lock(&acpi_scan_lock); | 319 | mutex_lock(&acpi_scan_lock); |
336 | 320 | ||
337 | if (ost_source != ACPI_NOTIFY_BUS_CHECK) { | 321 | /* |
338 | device = NULL; | 322 | * The device object's ACPI handle cannot become invalid as long as we |
339 | acpi_bus_get_device(handle, &device); | 323 | * are holding acpi_scan_lock, but it may have become invalid before |
340 | if (acpi_device_enumerated(device)) { | 324 | * that lock was acquired. |
341 | dev_warn(&device->dev, "Attempt to re-insert\n"); | 325 | */ |
342 | goto out; | 326 | if (adev->handle == INVALID_ACPI_HANDLE) |
343 | } | ||
344 | } | ||
345 | error = acpi_bus_scan(handle); | ||
346 | if (error) { | ||
347 | acpi_handle_warn(handle, "Namespace scan failure\n"); | ||
348 | goto out; | ||
349 | } | ||
350 | device = NULL; | ||
351 | acpi_bus_get_device(handle, &device); | ||
352 | if (!acpi_device_enumerated(device)) { | ||
353 | acpi_handle_warn(handle, "Device not enumerated\n"); | ||
354 | goto out; | 327 | goto out; |
328 | |||
329 | switch (src) { | ||
330 | case ACPI_NOTIFY_BUS_CHECK: | ||
331 | error = acpi_bus_scan(adev->handle); | ||
332 | break; | ||
333 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
334 | error = acpi_scan_device_check(adev); | ||
335 | break; | ||
336 | case ACPI_NOTIFY_EJECT_REQUEST: | ||
337 | case ACPI_OST_EC_OSPM_EJECT: | ||
338 | error = acpi_scan_hot_remove(adev); | ||
339 | break; | ||
340 | default: | ||
341 | error = -EINVAL; | ||
342 | break; | ||
355 | } | 343 | } |
356 | ost_code = ACPI_OST_SC_SUCCESS; | 344 | if (!error) |
357 | if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER) | 345 | ost_code = ACPI_OST_SC_SUCCESS; |
358 | kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); | ||
359 | 346 | ||
360 | out: | 347 | out: |
361 | acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL); | 348 | acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); |
349 | put_device(&adev->dev); | ||
362 | mutex_unlock(&acpi_scan_lock); | 350 | mutex_unlock(&acpi_scan_lock); |
363 | unlock_device_hotplug(); | 351 | unlock_device_hotplug(); |
364 | } | 352 | } |
@@ -370,6 +358,9 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) | |||
370 | struct acpi_device *adev; | 358 | struct acpi_device *adev; |
371 | acpi_status status; | 359 | acpi_status status; |
372 | 360 | ||
361 | if (acpi_bus_get_device(handle, &adev)) | ||
362 | goto err_out; | ||
363 | |||
373 | switch (type) { | 364 | switch (type) { |
374 | case ACPI_NOTIFY_BUS_CHECK: | 365 | case ACPI_NOTIFY_BUS_CHECK: |
375 | acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); | 366 | acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); |
@@ -384,24 +375,20 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) | |||
384 | ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; | 375 | ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; |
385 | goto err_out; | 376 | goto err_out; |
386 | } | 377 | } |
387 | if (acpi_bus_get_device(handle, &adev)) | 378 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, |
388 | goto err_out; | 379 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); |
389 | 380 | break; | |
390 | get_device(&adev->dev); | ||
391 | status = acpi_hotplug_execute(acpi_bus_device_eject, adev, type); | ||
392 | if (ACPI_SUCCESS(status)) | ||
393 | return; | ||
394 | |||
395 | put_device(&adev->dev); | ||
396 | goto err_out; | ||
397 | default: | 381 | default: |
398 | /* non-hotplug event; possibly handled by other handler */ | 382 | /* non-hotplug event; possibly handled by other handler */ |
399 | return; | 383 | return; |
400 | } | 384 | } |
401 | status = acpi_hotplug_execute(acpi_scan_bus_device_check, handle, type); | 385 | get_device(&adev->dev); |
386 | status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); | ||
402 | if (ACPI_SUCCESS(status)) | 387 | if (ACPI_SUCCESS(status)) |
403 | return; | 388 | return; |
404 | 389 | ||
390 | put_device(&adev->dev); | ||
391 | |||
405 | err_out: | 392 | err_out: |
406 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); | 393 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); |
407 | } | 394 | } |
@@ -454,7 +441,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, | |||
454 | acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, | 441 | acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, |
455 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | 442 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); |
456 | get_device(&acpi_device->dev); | 443 | get_device(&acpi_device->dev); |
457 | status = acpi_hotplug_execute(acpi_bus_device_eject, acpi_device, | 444 | status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device, |
458 | ACPI_OST_EC_OSPM_EJECT); | 445 | ACPI_OST_EC_OSPM_EJECT); |
459 | if (ACPI_SUCCESS(status)) | 446 | if (ACPI_SUCCESS(status)) |
460 | return count; | 447 | return count; |