# This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/03/19 00:15:48-05:00 len.brown@intel.com # [ACPI] PCI can now get suspend state from firmware # # pci_choose_state() can now call # platform_pci_choose_state() # and ACPI can answer # # http://bugzilla.kernel.org/show_bug.cgi?id=4277 # # Signed-off-by: David Shaohua Li # Signed-off-by: Len Brown # # drivers/pci/pci.h # 2005/03/19 00:15:24-05:00 len.brown@intel.com +3 -0 # add platform_pci_choose_state() # # drivers/pci/pci.c # 2005/03/19 00:15:24-05:00 len.brown@intel.com +7 -0 # add platform_pci_choose_state() # # drivers/pci/pci-acpi.c # 2005/03/19 00:15:24-05:00 len.brown@intel.com +46 -1 # add platform_pci_choose_state() # Index: linux-2.6.12/drivers/pci/pci-acpi.c =================================================================== --- linux-2.6.12.orig/drivers/pci/pci-acpi.c 2005-07-10 00:08:10.000000000 -0400 +++ linux-2.6.12/drivers/pci/pci-acpi.c 2005-07-10 00:08:23.000000000 -0400 @@ -1,6 +1,6 @@ /* * File: pci-acpi.c - * Purpose: Provide PCI support in ACPI + * Purpose: Provde PCI support in ACPI * * Copyright (C) 2005 David Shaohua Li * Copyright (C) 2004 Tom Long Nguyen @@ -17,6 +17,7 @@ #include #include +#include "pci.h" static u32 ctrlset_buf[3] = {0, 0, 0}; static u32 global_ctrlsets = 0; @@ -209,6 +210,49 @@ } EXPORT_SYMBOL(pci_osc_control_set); +/* + * _SxD returns the D-state with the highest power + * (lowest D-state number) supported in the S-state "x". + * + * If the devices does not have a _PRW + * (Power Resources for Wake) supporting system wakeup from "x" + * then the OS is free to choose a lower power (higher number + * D-state) than the return value from _SxD. + * + * But if _PRW is enabled at S-state "x", the OS + * must not choose a power lower than _SxD -- + * unless the device has an _SxW method specifying + * the lowest power (highest D-state number) the device + * may enter while still able to wake the system. + * + * ie. depending on global OS policy: + * + * if (_PRW at S-state x) + * choose from highest power _SxD to lowest power _SxW + * else // no _PRW at S-state x + * choose highest power _SxD or any lower power + * + * currently we simply return _SxD, if present. + */ + +static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) +{ + char dstate_str[] = "_S0D"; + acpi_status status; + unsigned long val; + struct device *dev = &pdev->dev; + + /* Fixme: the check is wrong after pm_message_t is a struct */ + if ((state >= PM_SUSPEND_MAX) || !DEVICE_ACPI_HANDLE(dev)) + return -EINVAL; + dstate_str[2] += state; /* _S1D, _S2D, _S3D, _S4D */ + status = acpi_evaluate_integer(DEVICE_ACPI_HANDLE(dev), dstate_str, + NULL, &val); + if (ACPI_SUCCESS(status)) + return val; + return -ENODEV; +} + /* ACPI bus type */ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) { @@ -255,6 +299,7 @@ ret = register_acpi_bus_type(&pci_acpi_bus); if (ret) return 0; + platform_pci_choose_state = acpi_pci_choose_state; return 0; } arch_initcall(pci_acpi_init); Index: linux-2.6.12/drivers/pci/pci.c =================================================================== --- linux-2.6.12.orig/drivers/pci/pci.c 2005-07-09 23:35:03.000000000 -0400 +++ linux-2.6.12/drivers/pci/pci.c 2005-07-10 00:11:00.000000000 -0400 @@ -304,6 +304,8 @@ return 0; } +int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state) = NULL; + /** * pci_choose_state - Choose the power state of a PCI device * @dev: PCI device to be suspended @@ -316,10 +318,17 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { + int ret; + if (!pci_find_capability(dev, PCI_CAP_ID_PM)) return PCI_D0; - switch (state) { + if (platform_pci_choose_state) { + ret = platform_pci_choose_state(dev, state); + if (ret >= 0) + state = ret; + } + switch (state) { case 0: return PCI_D0; case 3: return PCI_D3hot; default: Index: linux-2.6.12/drivers/pci/pci.h =================================================================== --- linux-2.6.12.orig/drivers/pci/pci.h 2005-07-09 23:35:17.000000000 -0400 +++ linux-2.6.12/drivers/pci/pci.h 2005-07-10 00:08:23.000000000 -0400 @@ -11,6 +11,9 @@ void (*alignf)(void *, struct resource *, unsigned long, unsigned long), void *alignf_data); +/* Firmware callbacks */ +extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); + /* PCI /proc functions */ #ifdef CONFIG_PROC_FS extern int pci_proc_attach_device(struct pci_dev *dev);