From: huangjun huangjun63@huawei.com
The acpi_get_handle function uses a mutex, so it cannot be called in the timer. We put the initialization of acpi_handle in init_ged_handle which will be called in the ged_probe.
Signed-off-by: Huangjun huangjun63@huawei.com --- drivers/acpi/evged.c | 123 ++++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 48 deletions(-)
diff --git a/drivers/acpi/evged.c b/drivers/acpi/evged.c index 84656fc09d15..ef5167c0aa87 100644 --- a/drivers/acpi/evged.c +++ b/drivers/acpi/evged.c @@ -51,9 +51,15 @@
#define MODULE_NAME "acpi-ged"
+struct acpi_ged_handle { + struct timer_list timer; /* For 4s anti-shake of power button */ + acpi_handle gpp_handle; /* ACPI Handle: enable shutdown */ + acpi_handle gpo_handle; /* ACPI Handle: set sleep flag */ +}; + struct acpi_ged_device { struct device *dev; - struct timer_list timer; + struct acpi_ged_handle *wakeup_handle; struct list_head event_list; };
@@ -134,6 +140,34 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, return AE_OK; }
+#ifdef CONFIG_PM_SLEEP +static void init_ged_handle(struct acpi_ged_device *geddev) { + struct acpi_ged_handle *wakeup_handle; + acpi_handle gpo_handle = NULL; + acpi_handle gpp_handle = NULL; + acpi_status acpi_ret; + + wakeup_handle = devm_kzalloc(geddev->dev, sizeof(*wakeup_handle), GFP_KERNEL); + if (!wakeup_handle) + return; + + geddev->wakeup_handle = wakeup_handle; + + /* Initialize wakeup_handle, prepare for ged suspend and resume */ + timer_setup(&wakeup_handle->timer, NULL, 0); + + acpi_ret = acpi_get_handle(ACPI_HANDLE(geddev->dev), "_GPO", &gpo_handle); + if (ACPI_FAILURE(acpi_ret)) + dev_info(geddev->dev, "cannot locate _GPO method\n"); + wakeup_handle->gpo_handle = gpo_handle; + + acpi_ret = acpi_get_handle(ACPI_HANDLE(geddev->dev), "_GPP", &gpp_handle); + if (ACPI_FAILURE(acpi_ret)) + dev_info(geddev->dev, "cannot locate _GPP method\n"); + wakeup_handle->gpp_handle = gpp_handle; +} +#endif + static int ged_probe(struct platform_device *pdev) { struct acpi_ged_device *geddev; @@ -152,8 +186,10 @@ static int ged_probe(struct platform_device *pdev) return -EINVAL; }
- timer_setup(&geddev->timer, NULL, 0); platform_set_drvdata(pdev, geddev); +#ifdef CONFIG_PM_SLEEP + init_ged_handle(geddev); +#endif
return 0; } @@ -169,7 +205,9 @@ static void ged_shutdown(struct platform_device *pdev) dev_dbg(geddev->dev, "GED releasing GSI %u @ IRQ %u\n", event->gsi, event->irq); } - del_timer(&geddev->timer); + if (geddev->wakeup_handle) + del_timer(&geddev->wakeup_handle->timer); + }
static int ged_remove(struct platform_device *pdev) @@ -184,67 +222,56 @@ static const struct acpi_device_id ged_acpi_ids[] = { };
#ifdef CONFIG_PM_SLEEP -static acpi_status ged_acpi_execute(struct device *dev, char* method, u64 arg) -{ - acpi_status acpi_ret; - acpi_handle method_handle; - - acpi_ret = acpi_get_handle(ACPI_HANDLE(dev), method, &method_handle); - - if (ACPI_FAILURE(acpi_ret)) { - dev_err(dev, "cannot locate %s method\n", method); - return AE_NOT_FOUND; - } - - acpi_ret = acpi_execute_simple_method(method_handle, NULL, arg); - if (ACPI_FAILURE(acpi_ret)) { - dev_err(dev, "%s method execution failed\n", method); - return AE_ERROR; - } - - return AE_OK; -} - static void ged_timer_callback(struct timer_list *t) { - struct acpi_ged_device *geddev = from_timer(geddev, t, timer); - struct acpi_ged_event *event, *next; + struct acpi_ged_handle *wakeup_handle = from_timer(wakeup_handle, t, timer); + acpi_status acpi_ret;
- list_for_each_entry_safe(event, next, &geddev->event_list, node) { - ged_acpi_execute(geddev->dev, "_GPP", event->gsi); - } + /* _GPP method enable power button */ + if (wakeup_handle && wakeup_handle->gpp_handle) { + acpi_ret = acpi_execute_simple_method(wakeup_handle->gpp_handle, NULL, ACPI_IRQ_MODEL_GIC); + if (ACPI_FAILURE(acpi_ret)) + pr_warn("_GPP method execution failed\n"); + } }
static int ged_suspend(struct device *dev) { - struct acpi_ged_device *geddev = dev_get_drvdata(dev); - struct acpi_ged_event *event, *next; - acpi_status acpi_ret; + struct acpi_ged_device *geddev = dev_get_drvdata(dev); + struct acpi_ged_handle *wakeup_handle = geddev->wakeup_handle; + struct acpi_ged_event *event, *next; + acpi_status acpi_ret;
- list_for_each_entry_safe(event, next, &geddev->event_list, node) { - acpi_ret = ged_acpi_execute(dev, "_GPO", event->gsi); + /* _GPO method set sleep flag */ + if (wakeup_handle && wakeup_handle->gpo_handle) { + acpi_ret = acpi_execute_simple_method(wakeup_handle->gpo_handle, NULL, ACPI_IRQ_MODEL_GIC); + if (ACPI_FAILURE(acpi_ret)) { + pr_warn("_GPO method execution failed\n"); + return AE_ERROR; + } + }
- if (acpi_ret == AE_ERROR) - return -EINVAL; + list_for_each_entry_safe(event, next, &geddev->event_list, node) + enable_irq_wake(event->irq);
- enable_irq_wake(event->irq); - } - return 0; + return 0; }
static int ged_resume(struct device *dev) { - struct acpi_ged_device *geddev = dev_get_drvdata(dev); - struct acpi_ged_event *event, *next; - - list_for_each_entry_safe(event, next, &geddev->event_list, node) { - disable_irq_wake(event->irq); - } + struct acpi_ged_device *geddev = dev_get_drvdata(dev); + struct acpi_ged_handle *wakeup_handle = geddev->wakeup_handle; + struct acpi_ged_event *event, *next;
/* use timer to complete 4s anti-shake */ - geddev->timer.expires = jiffies + (4 * HZ); - geddev->timer.function = ged_timer_callback; - add_timer(&geddev->timer); + if (wakeup_handle && wakeup_handle->gpp_handle) { + wakeup_handle->timer.expires = jiffies + (4 * HZ); + wakeup_handle->timer.function = ged_timer_callback; + add_timer(&wakeup_handle->timer); + } + + list_for_each_entry_safe(event, next, &geddev->event_list, node) + disable_irq_wake(event->irq);
return 0; }