From: Jun Huang <huangjun63(a)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(a)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);
--
2.23.0.windows.1