Commit 315bbae9c5cb1f54a6d6fd47b9cf325fbedccf05
Committed by
Rafael J. Wysocki
1 parent
19387b27e4
ACPI / memhotplug: deal with eject request in hotplug queue
The memory device can be removed by 2 ways: 1. send eject request by SCI 2. echo 1 >/sys/bus/pci/devices/PNP0C80:XX/eject We handle the 1st case in the module acpi_memhotplug, and handle the 2nd case in ACPI eject notification. This 2 events may happen at the same time, so we may touch acpi_memory_device.res_list at the same time. This patch reimplements memory-hotremove support through an ACPI eject notification. Now the memory device is offlined and hotremoved only in the function acpi_memory_device_remove() which is protected by device_lock(). Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> Reviewed-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com> Reviewed-by: Toshi Kani <toshi.kani@hp.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Showing 1 changed file with 9 additions and 79 deletions Side-by-side Diff
drivers/acpi/acpi_memhotplug.c
... | ... | @@ -272,40 +272,6 @@ |
272 | 272 | return 0; |
273 | 273 | } |
274 | 274 | |
275 | -static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device) | |
276 | -{ | |
277 | - acpi_status status; | |
278 | - struct acpi_object_list arg_list; | |
279 | - union acpi_object arg; | |
280 | - unsigned long long current_status; | |
281 | - | |
282 | - | |
283 | - /* Issue the _EJ0 command */ | |
284 | - arg_list.count = 1; | |
285 | - arg_list.pointer = &arg; | |
286 | - arg.type = ACPI_TYPE_INTEGER; | |
287 | - arg.integer.value = 1; | |
288 | - status = acpi_evaluate_object(mem_device->device->handle, | |
289 | - "_EJ0", &arg_list, NULL); | |
290 | - /* Return on _EJ0 failure */ | |
291 | - if (ACPI_FAILURE(status)) { | |
292 | - ACPI_EXCEPTION((AE_INFO, status, "_EJ0 failed")); | |
293 | - return -ENODEV; | |
294 | - } | |
295 | - | |
296 | - /* Evalute _STA to check if the device is disabled */ | |
297 | - status = acpi_evaluate_integer(mem_device->device->handle, "_STA", | |
298 | - NULL, ¤t_status); | |
299 | - if (ACPI_FAILURE(status)) | |
300 | - return -ENODEV; | |
301 | - | |
302 | - /* Check for device status. Device should be disabled */ | |
303 | - if (current_status & ACPI_STA_DEVICE_ENABLED) | |
304 | - return -EINVAL; | |
305 | - | |
306 | - return 0; | |
307 | -} | |
308 | - | |
309 | 275 | static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) |
310 | 276 | { |
311 | 277 | int result; |
312 | 278 | |
... | ... | @@ -325,34 +291,11 @@ |
325 | 291 | return 0; |
326 | 292 | } |
327 | 293 | |
328 | -static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) | |
329 | -{ | |
330 | - int result; | |
331 | - | |
332 | - /* | |
333 | - * Ask the VM to offline this memory range. | |
334 | - * Note: Assume that this function returns zero on success | |
335 | - */ | |
336 | - result = acpi_memory_remove_memory(mem_device); | |
337 | - if (result) | |
338 | - return result; | |
339 | - | |
340 | - /* Power-off and eject the device */ | |
341 | - result = acpi_memory_powerdown_device(mem_device); | |
342 | - if (result) { | |
343 | - /* Set the status of the device to invalid */ | |
344 | - mem_device->state = MEMORY_INVALID_STATE; | |
345 | - return result; | |
346 | - } | |
347 | - | |
348 | - mem_device->state = MEMORY_POWER_OFF_STATE; | |
349 | - return result; | |
350 | -} | |
351 | - | |
352 | 294 | static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) |
353 | 295 | { |
354 | 296 | struct acpi_memory_device *mem_device; |
355 | 297 | struct acpi_device *device; |
298 | + struct acpi_eject_event *ej_event = NULL; | |
356 | 299 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ |
357 | 300 | |
358 | 301 | switch (event) { |
359 | 302 | |
360 | 303 | |
361 | 304 | |
... | ... | @@ -394,32 +337,19 @@ |
394 | 337 | break; |
395 | 338 | } |
396 | 339 | |
397 | - /* | |
398 | - * Currently disabling memory device from kernel mode | |
399 | - * TBD: Can also be disabled from user mode scripts | |
400 | - * TBD: Can also be disabled by Callback registration | |
401 | - * with generic sysfs driver | |
402 | - */ | |
403 | - if (acpi_memory_disable_device(mem_device)) { | |
404 | - printk(KERN_ERR PREFIX "Disable memory device\n"); | |
405 | - /* | |
406 | - * If _EJ0 was called but failed, _OST is not | |
407 | - * necessary. | |
408 | - */ | |
409 | - if (mem_device->state == MEMORY_INVALID_STATE) | |
410 | - return; | |
411 | - | |
340 | + ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); | |
341 | + if (!ej_event) { | |
342 | + pr_err(PREFIX "No memory, dropping EJECT\n"); | |
412 | 343 | break; |
413 | 344 | } |
414 | 345 | |
415 | - /* | |
416 | - * Invoke acpi_bus_trim() to remove memory device | |
417 | - */ | |
418 | - acpi_bus_trim(device, 1); | |
346 | + ej_event->handle = handle; | |
347 | + ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; | |
348 | + acpi_os_hotplug_execute(acpi_bus_hot_remove_device, | |
349 | + (void *)ej_event); | |
419 | 350 | |
420 | - /* _EJ0 succeeded; _OST is not necessary */ | |
351 | + /* eject is performed asynchronously */ | |
421 | 352 | return; |
422 | - | |
423 | 353 | default: |
424 | 354 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
425 | 355 | "Unsupported event [0x%x]\n", event)); |