From patchwork Wed Aug 19 07:24:21 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shaohua Li X-Patchwork-Id: 42532 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n7J7OFtR019226 for ; Wed, 19 Aug 2009 07:24:26 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751455AbZHSHYX (ORCPT ); Wed, 19 Aug 2009 03:24:23 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751509AbZHSHYX (ORCPT ); Wed, 19 Aug 2009 03:24:23 -0400 Received: from mga14.intel.com ([143.182.124.37]:16829 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751455AbZHSHYX (ORCPT ); Wed, 19 Aug 2009 03:24:23 -0400 Received: from azsmga001.ch.intel.com ([10.2.17.19]) by azsmga102.ch.intel.com with ESMTP; 19 Aug 2009 00:24:24 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.43,407,1246863600"; d="scan'208";a="177580327" Received: from sli10-conroe.sh.intel.com (HELO [10.239.13.175]) ([10.239.13.175]) by azsmga001.ch.intel.com with ESMTP; 19 Aug 2009 00:24:23 -0700 Subject: [PATCH 5/5] acpi-based wakeup event detection From: Shaohua Li To: linux acpi , linux-pm Cc: "Rafael J. Wysocki" , Alan Stern , mjg59 Date: Wed, 19 Aug 2009 15:24:21 +0800 Message-Id: <1250666661.23178.120.camel@sli10-desk.sh.intel.com> Mime-Version: 1.0 X-Mailer: Evolution 2.26.1 Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org In ACPI platform, if native PME isn't enabled, GPE is used to report wakeup event. --- drivers/acpi/Kconfig | 9 ++++++ drivers/acpi/bus.c | 15 +++++++++++ drivers/acpi/sleep/wakeup.c | 60 ++++++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 4 ++ 4 files changed, 88 insertions(+) -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Index: linux/drivers/acpi/Kconfig =================================================================== --- linux.orig/drivers/acpi/Kconfig 2009-08-05 11:00:06.000000000 +0800 +++ linux/drivers/acpi/Kconfig 2009-08-19 10:07:05.000000000 +0800 @@ -45,6 +45,15 @@ config ACPI_SLEEP depends on SUSPEND || HIBERNATION default y +config ACPI_GPE_WAKEUP + bool "ACPI wakeup event support" + depends on PM_SLEEP && EXPERIMENTAL + help + Enable ACPI to detect wakeup event. For example, PCI device can + invoke PME, and in ACPI platform, the PME will invoke a GPE. With + the option, we can detect which device invokes wakeup event. + + config ACPI_PROCFS bool "Deprecated /proc/acpi files" depends on PROC_FS Index: linux/drivers/acpi/wakeup.c =================================================================== --- linux.orig/drivers/acpi/wakeup.c 2009-07-24 11:31:05.000000000 +0800 +++ linux/drivers/acpi/wakeup.c 2009-08-19 10:16:27.000000000 +0800 @@ -124,6 +124,63 @@ void acpi_disable_wakeup_device(u8 sleep } } +#ifdef CONFIG_ACPI_GPE_WAKEUP +static int acpi_gpe_pme_check(struct acpi_device *dev) +{ + struct device *ldev; + + ldev = acpi_get_physical_device(dev->handle); + if (!ldev) + return -ENODEV; + /* + * AML code might already clear the event, so ignore the return value. + * Actually we can't correctly detect which device invokes GPE if the + * event is cleared. + */ + if (ldev->bus->pm && ldev->bus->pm->wakeup_event) + ldev->bus->pm->wakeup_event(ldev); + + put_device(ldev); + return 0; +} + +static int acpi_gpe_pme_handler(struct notifier_block *nb, + unsigned long type, void *data) +{ + int ret; + acpi_handle handle = data; + struct acpi_device *dev; + + if (type != ACPI_NOTIFY_DEVICE_WAKE) + return NOTIFY_DONE; + + if (acpi_bus_get_device(handle, &dev)) + return NOTIFY_DONE; + + ret = acpi_gpe_pme_check(dev); + + acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); + + /* FIXME: spurious interrupt, disables it? */ + if (ret) + printk(KERN_ERR"Spurious GPE %d detected\n", + dev->wakeup.gpe_number); + + return NOTIFY_OK; +} + +static struct notifier_block acpi_gpe_pme_nb = { + .notifier_call = acpi_gpe_pme_handler, +}; + +static void acpi_init_gpe_pme(void) +{ + register_acpi_bus_notifier(&acpi_gpe_pme_nb); +} +#else +static inline void acpi_init_gpe_pme(void) {} +#endif + int __init acpi_wakeup_device_init(void) { struct list_head *node, *next; @@ -144,5 +201,7 @@ int __init acpi_wakeup_device_init(void) dev->wakeup.state.enabled = 1; } mutex_unlock(&acpi_device_lock); + + acpi_init_gpe_pme(); return 0; }