From: James Morse <james.morse@xxxxxxx> struct acpi_scan_handler has a detach callback that is used to remove a driver when a bus is changed. When interacting with an eject-request, the detach callback is called before _EJ0. This means the ACPI processor driver can't use _STA to determine if a CPU has been made not-present, or some of the other _STA bits have been changed. acpi_processor_remove() needs to know the value of _STA after _EJ0 has been called. Add a post_eject callback to struct acpi_scan_handler. This is called after acpi_scan_hot_remove() has successfully called _EJ0. Because acpi_scan_check_and_detach() also clears the handler pointer, it needs to be told if the caller will go on to call acpi_bus_post_eject(), so that acpi_device_clear_enumerated() and clearing the handler pointer can be deferred. The extra eject flag added in the previous patch is used for this purpose. Signed-off-by: James Morse <james.morse@xxxxxxx> Reviewed-by: Joanthan Cameron <Jonathan.Cameron@xxxxxxxxxx> Reviewed-by: Gavin Shan <gshan@xxxxxxxxxx> Tested-by: Miguel Luis <miguel.luis@xxxxxxxxxx> Tested-by: Vishnu Pajjuri <vishnu@xxxxxxxxxxxxxxxxxxxxxx> Tested-by: Jianyong Wu <jianyong.wu@xxxxxxx> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@xxxxxxxxxx> ---- Russell, you hadn't signed off on this when posting last time. Do you want to insert a suitable tag now? v5: - Rebase to take into account the changes to scan handling in the meantime. --- drivers/acpi/acpi_processor.c | 4 ++-- drivers/acpi/scan.c | 32 +++++++++++++++++++++++++++++--- include/acpi/acpi_bus.h | 1 + 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 3aa43dee4391..6b2ee0643d11 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -463,7 +463,7 @@ static int acpi_processor_add(struct acpi_device *device, #ifdef CONFIG_ACPI_HOTPLUG_CPU /* Removal */ -static void acpi_processor_remove(struct acpi_device *device) +static void acpi_processor_post_eject(struct acpi_device *device) { struct acpi_processor *pr; @@ -631,7 +631,7 @@ static struct acpi_scan_handler processor_handler = { .ids = processor_device_ids, .attach = acpi_processor_add, #ifdef CONFIG_ACPI_HOTPLUG_CPU - .detach = acpi_processor_remove, + .post_eject = acpi_processor_post_eject, #endif .hotplug = { .enabled = true, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 79b1f4d2b6bd..992779ac31d4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -276,8 +276,6 @@ static int acpi_scan_check_and_detach(struct acpi_device *adev, void *p) if (handler) { if (handler->detach) handler->detach(adev); - - adev->handler = NULL; } else { device_release_driver(&adev->dev); } @@ -287,6 +285,28 @@ static int acpi_scan_check_and_detach(struct acpi_device *adev, void *p) */ acpi_device_set_power(adev, ACPI_STATE_D3_COLD); adev->flags.initialized = false; + + /* For eject this is deferred to acpi_bus_post_eject() */ + if (!param->eject) { + adev->handler = NULL; + acpi_device_clear_enumerated(adev); + } + return 0; +} + +static int acpi_bus_post_eject(struct acpi_device *adev, void *not_used) +{ + struct acpi_scan_handler *handler = adev->handler; + + acpi_dev_for_each_child_reverse(adev, acpi_bus_post_eject, NULL); + + if (handler) { + if (handler->post_eject) + handler->post_eject(adev); + + adev->handler = NULL; + } + acpi_device_clear_enumerated(adev); return 0; @@ -306,6 +326,10 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_handle handle = device->handle; unsigned long long sta; acpi_status status; + struct acpi_scan_c_and_d_param p = { + .check_status = false, /* Not update until after ej0 */ + .eject = true, + }; if (device->handler && device->handler->hotplug.demand_offline) { if (!acpi_scan_is_offline(device, true)) @@ -318,7 +342,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_handle_debug(handle, "Ejecting\n"); - acpi_bus_trim(device); + acpi_scan_check_and_detach(device, &p); acpi_evaluate_lck(handle, 0); /* @@ -341,6 +365,8 @@ static int acpi_scan_hot_remove(struct acpi_device *device) } else if (sta & ACPI_STA_DEVICE_ENABLED) { acpi_handle_warn(handle, "Eject incomplete - status 0x%llx\n", sta); + } else { + acpi_bus_post_eject(device, NULL); } return 0; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index e193507fd743..27fdef17abe5 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -130,6 +130,7 @@ struct acpi_scan_handler { bool (*match)(const char *idstr, const struct acpi_device_id **matchid); int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id); void (*detach)(struct acpi_device *dev); + void (*post_eject)(struct acpi_device *dev); void (*bind)(struct device *phys_dev); void (*unbind)(struct device *phys_dev); struct acpi_hotplug_profile hotplug; -- 2.39.2