From: Huang jun huangjun61@huawei.com
If we want acpi ged to support wake from freeze, we need to implement the suspend/resume function. In these two methods, ACPI's _GPO, GPP method is called to realize the setting of sleep flag and anti-shake.
Signed-off-by: Huangjun huangjun63@huawei.com --- drivers/acpi/evged.c | 108 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+)
diff --git a/drivers/acpi/evged.c b/drivers/acpi/evged.c index f13ba2c07667..dde8fbff8d19 100644 --- a/drivers/acpi/evged.c +++ b/drivers/acpi/evged.c @@ -46,11 +46,20 @@ #include <linux/list.h> #include <linux/platform_device.h> #include <linux/acpi.h> +#include <linux/timer.h> +#include <linux/jiffies.h>
#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 acpi_ged_handle *wakeup_handle; struct list_head event_list; };
@@ -131,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; @@ -149,6 +186,9 @@ static int ged_probe(struct platform_device *pdev) return -EINVAL; } platform_set_drvdata(pdev, geddev); +#ifdef CONFIG_PM_SLEEP + init_ged_handle(geddev); +#endif
return 0; } @@ -164,6 +204,10 @@ 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) @@ -172,6 +216,67 @@ static int ged_remove(struct platform_device *pdev) return 0; }
+#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_event *event, *next; + acpi_status acpi_ret; + + /* _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; + } + } + + list_for_each_entry_safe(event, next, &geddev->event_list, node) + enable_irq_wake(event->irq); + + return 0; +} + +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); + } + + list_for_each_entry_safe(event, next, &geddev->event_list, node) + disable_irq_wake(event->irq); + + return 0; +} + +static const struct dev_pm_ops ged_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ged_suspend, ged_resume) +}; +#endif + + static const struct acpi_device_id ged_acpi_ids[] = { {"ACPI0013"}, {}, @@ -184,6 +289,9 @@ static struct platform_driver ged_driver = { .driver = { .name = MODULE_NAME, .acpi_match_table = ACPI_PTR(ged_acpi_ids), +#ifdef CONFIG_PM_SLEEP + .pm = &ged_pm_ops, +#endif }, }; builtin_platform_driver(ged_driver);
From: louchaoquan louchaoquan1@huawei.com
Signed-off-by: Louchaoquan louchaoquan1@huawei.com --- kernel/power/swap.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index d7f6c1a288d3..ac20064c9e52 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -649,10 +649,12 @@ static int lzo_compress_threadfn(void *data) break; } atomic_set(&d->ready, 0); + mb();
d->ret = lzo1x_1_compress(d->unc, d->unc_len, d->cmp + LZO_HEADER, &d->cmp_len, d->wrk); + mb(); atomic_set(&d->stop, 1); wake_up(&d->done); } @@ -790,6 +792,7 @@ static int save_image_lzo(struct swap_map_handle *handle, break;
data[thr].unc_len = off; + mb();
atomic_set(&data[thr].ready, 1); wake_up(&data[thr].go); @@ -806,6 +809,7 @@ static int save_image_lzo(struct swap_map_handle *handle, wait_event(data[thr].done, atomic_read(&data[thr].stop)); atomic_set(&data[thr].stop, 0); + mb();
ret = data[thr].ret;