From: Jun Huang huangjun63@huawei.com
The acpi_execute_simple_method function uses a mutex, so it cannot be called in the timer. We replace timer with delayed work.
Signed-off-by: Jun Huang huangjun63@huawei.com --- drivers/acpi/evged.c | 60 ++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 33 deletions(-)
diff --git a/drivers/acpi/evged.c b/drivers/acpi/evged.c index 7354d8d..5bf65b1 100644 --- a/drivers/acpi/evged.c +++ b/drivers/acpi/evged.c @@ -34,7 +34,7 @@ * Method (_EVT, 1) { * if (Lequal(123, Arg0)) * { - * } + * }# * } * } * @@ -46,20 +46,23 @@ #include <linux/list.h> #include <linux/platform_device.h> #include <linux/acpi.h> -#include <linux/timer.h> #include <linux/jiffies.h> +#include <linux/workqueue.h>
#define MODULE_NAME "acpi-ged"
+static void gpp_enable_pwd(struct work_struct *private_); + +static DECLARE_DELAYED_WORK(gpp_work, gpp_enable_pwd); + 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 acpi_ged_handle *wakeup_handle; + struct acpi_ged_handle *ged_handle; struct list_head event_list; };
@@ -71,6 +74,8 @@ struct acpi_ged_event { acpi_handle handle; };
+static struct acpi_ged_handle *wakeup_handle; + static irqreturn_t acpi_ged_irq_handler(int irq, void *data) { struct acpi_ged_event *event = data; @@ -142,7 +147,6 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares,
#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; @@ -151,10 +155,7 @@ static void init_ged_handle(struct acpi_ged_device *geddev) { 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); + geddev->ged_handle = wakeup_handle; acpi_ret = acpi_get_handle(ACPI_HANDLE(geddev->dev), "_GPO", &gpo_handle); if (ACPI_FAILURE(acpi_ret)) @@ -204,8 +205,6 @@ static void ged_shutdown(struct platform_device *pdev) dev_dbg(geddev->dev, "GED releasing GSI %u @ IRQ %u\n", event->gsi, event->irq); } - if (geddev->wakeup_handle) - del_timer(&geddev->wakeup_handle->timer); }
static int ged_remove(struct platform_device *pdev) @@ -220,23 +219,10 @@ static const struct acpi_device_id ged_acpi_ids[] = { };
#ifdef CONFIG_PM_SLEEP -static void ged_timer_callback(struct timer_list *t) -{ - struct acpi_ged_handle *wakeup_handle = from_timer(wakeup_handle, t, timer); - acpi_status acpi_ret; - - /* _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_handle *wakeup_handle = geddev->wakeup_handle; + //struct acpi_ged_handle *wakeup_handle = geddev->wakeup_handle; struct acpi_ged_event *event, *next; acpi_status acpi_ret;
@@ -255,18 +241,26 @@ static int ged_suspend(struct device *dev) return 0; }
+static void gpp_enable_pwd(struct work_struct *private_) +{ + acpi_status acpi_ret; + + /* _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_resume(struct device *dev) { 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 */ - 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); - } + + /* use delayed_work to complete 4s anti-shake */ + schedule_delayed_work(&gpp_work, 4 * HZ);
list_for_each_entry_safe(event, next, &geddev->event_list, node) disable_irq_wake(event->irq);