* [PATCH 0/11] PCI PM: Handling of PCI devices wake-up functionality
@ 2008-06-23 17:34 Rafael J. Wysocki
0 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:34 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
Hi,
The purpose of the following series of patches is to rework the power
management of PCI devices so that the handling of their wake-up functionality
is consistent with the other PM operations and so that the user space can
manage the wake-up functionality of PCI devices using the
/sys/devices/.../power/wakeup interface regardless of whether the wake-up
function is based on the native PCI mechanism (PME#), or it is handled by the
platform (eg. ACPI).
Apart from the ACPI and PCI changes necessary for this purpose, the series
includes some clean-ups that are not strictly required, but make the code more
straightforward and (IMHO) easier to follow.
Please review.
Thanks,
Rafael
--
"Premature optimization is the root of all evil." - Donald Knuth
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 10/11] PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep
[not found] <200806231934.08565.rjw@sisk.pl>
@ 2008-06-23 17:44 ` Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 01/11] ACPI: Introduce acpi_bus_power_manageable function Rafael J. Wysocki
` (16 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:44 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
From: Rafael J. Wysocki <rjw@sisk.pl>
PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep
Introduce functions pci_prepare_to_sleep() and pci_back_from_sleep(),
to be used by the PCI drivers that want to place their devices into
the lowest power state appropiate for them (PCI_D3hot, if the device
is not supposed to wake up the system, or the deepest state from
which the wake-up is possible, otherwise) while the system is being
prepared to go into a sleeping state and to put them back into D0
during the subsequent transition to the working state.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/pci/pci.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 2 +
2 files changed, 85 insertions(+)
Index: linux-next/drivers/pci/pci.c
===================================================================
--- linux-next.orig/drivers/pci/pci.c
+++ linux-next/drivers/pci/pci.c
@@ -1145,6 +1145,87 @@ int pci_enable_wake(struct pci_dev *dev,
}
/**
+ * pci_prepare_to_sleep - prepare PCI device for system-wide transition into
+ * a sleep state
+ * @dev: Device to handle.
+ *
+ * Choose the power state appropriate for the device depending on whether
+ * it can wake-up the system and/or is power manageable by the platform
+ * (PCI_D3hot is the default) and put the device into that state.
+ */
+int pci_prepare_to_sleep(struct pci_dev *dev)
+{
+ pci_power_t target_state = PCI_D3hot;
+ int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ int error;
+
+ if (platform_pci_power_manageable(dev)) {
+ /*
+ * Call the platform to choose the target state of the device
+ * and enable wake-up from this state if supported.
+ */
+ pci_power_t state = platform_pci_choose_state(dev);
+
+ switch (state) {
+ case PCI_POWER_ERROR:
+ case PCI_UNKNOWN:
+ break;
+ case PCI_D1:
+ case PCI_D2:
+ if (pci_no_d1d2(dev))
+ break;
+ default:
+ target_state = state;
+ pci_enable_wake(dev, target_state, true);
+ }
+ } else if (device_may_wakeup(&dev->dev)) {
+ /*
+ * Find the deepest state from which the device can generate
+ * wake-up events, make it the target state and enable device
+ * to generate PME#.
+ */
+ u16 pmc;
+
+ if (!pm)
+ return -EIO;
+
+ pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
+ if (pmc & PCI_PM_CAP_PME_MASK) {
+ if (!(pmc & PCI_PM_CAP_PME_D3)) {
+ /* Device cannot generate PME# from D3_hot */
+ if (pmc & PCI_PM_CAP_PME_D2)
+ target_state = PCI_D2;
+ else if (pmc & PCI_PM_CAP_PME_D1)
+ target_state = PCI_D1;
+ else
+ target_state = PCI_D0;
+ }
+ pci_pme_active(dev, pm, true);
+ }
+ }
+
+ error = pci_set_power_state(dev, target_state);
+
+ if (error)
+ pci_enable_wake(dev, target_state, false);
+
+ return error;
+}
+
+/**
+ * pci_back_from_sleep - turn PCI device on during system-wide transition into
+ * the working state a sleep state
+ * @dev: Device to handle.
+ *
+ * Disable device's sytem wake-up capability and put it into D0.
+ */
+int pci_back_from_sleep(struct pci_dev *dev)
+{
+ pci_enable_wake(dev, PCI_D0, false);
+ return pci_set_power_state(dev, PCI_D0);
+}
+
+/**
* pci_pm_init - Initialize PM functions of given PCI device
* @dev: PCI device to handle.
*/
@@ -1843,5 +1924,7 @@ EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_save_state);
EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_enable_wake);
+EXPORT_SYMBOL(pci_prepare_to_sleep);
+EXPORT_SYMBOL(pci_back_from_sleep);
EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
Index: linux-next/include/linux/pci.h
===================================================================
--- linux-next.orig/include/linux/pci.h
+++ linux-next/include/linux/pci.h
@@ -633,6 +633,8 @@ int pci_restore_state(struct pci_dev *de
int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable);
+int pci_prepare_to_sleep(struct pci_dev *dev);
+int pci_back_from_sleep(struct pci_dev *dev);
/* Functions for PCI Hotplug drivers to use */
int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 01/11] ACPI: Introduce acpi_bus_power_manageable function
[not found] <200806231934.08565.rjw@sisk.pl>
2008-06-23 17:44 ` [PATCH 10/11] PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep Rafael J. Wysocki
@ 2008-06-23 17:45 ` Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 02/11] PCI: Introduce platform_pci_power_manageable function Rafael J. Wysocki
` (15 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:45 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
From: Rafael J. Wysocki <rjw@sisk.pl>
ACPI: Introduce acpi_bus_power_manageable function
Introduce function acpi_bus_power_manageable() allowing other
(dependent) subsystems to check if ACPI is able to power manage given
device. This may be useful, for example, for PCI device power
management.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/acpi/bus.c | 11 +++++++++++
include/acpi/acpi_bus.h | 1 +
2 files changed, 12 insertions(+)
Index: linux-next/drivers/acpi/bus.c
===================================================================
--- linux-next.orig/drivers/acpi/bus.c
+++ linux-next/drivers/acpi/bus.c
@@ -295,6 +295,17 @@ int acpi_bus_set_power(acpi_handle handl
EXPORT_SYMBOL(acpi_bus_set_power);
+bool acpi_bus_power_manageable(acpi_handle handle)
+{
+ struct acpi_device *device;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ return result ? false : device->flags.power_manageable;
+}
+
+EXPORT_SYMBOL(acpi_bus_power_manageable);
+
/* --------------------------------------------------------------------------
Event Management
-------------------------------------------------------------------------- */
Index: linux-next/include/acpi/acpi_bus.h
===================================================================
--- linux-next.orig/include/acpi/acpi_bus.h
+++ linux-next/include/acpi/acpi_bus.h
@@ -335,6 +335,7 @@ void acpi_bus_data_handler(acpi_handle h
int acpi_bus_get_status(struct acpi_device *device);
int acpi_bus_get_power(acpi_handle handle, int *state);
int acpi_bus_set_power(acpi_handle handle, int state);
+bool acpi_bus_power_manageable(acpi_handle handle);
#ifdef CONFIG_ACPI_PROC_EVENT
int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data);
int acpi_bus_generate_proc_event4(const char *class, const char *bid, u8 type,
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 02/11] PCI: Introduce platform_pci_power_manageable function
[not found] <200806231934.08565.rjw@sisk.pl>
2008-06-23 17:44 ` [PATCH 10/11] PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 01/11] ACPI: Introduce acpi_bus_power_manageable function Rafael J. Wysocki
@ 2008-06-23 17:45 ` Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 03/11] PCI: Rework pci_set_power_state function (rev. 3) Rafael J. Wysocki
` (14 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:45 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
From: Rafael J. Wysocki <rjw@sisk.pl>
PCI: Introduce platform_pci_power_manageable function
Introduce function pointer platform_pci_power_manageable to be used
by the platform-related code to point to a function allowing us to
check if given device is power manageable by the platform.
Introduce acpi_pci_power_manageable() playing that role for ACPI.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/pci/pci-acpi.c | 19 +++++++++++++------
drivers/pci/pci.c | 40 ++++++++++++++++++++++++++++++----------
drivers/pci/pci.h | 26 ++++++++++++++++++++++----
3 files changed, 65 insertions(+), 20 deletions(-)
Index: linux-next/drivers/pci/pci-acpi.c
===================================================================
--- linux-next.orig/drivers/pci/pci-acpi.c
+++ linux-next/drivers/pci/pci-acpi.c
@@ -215,7 +215,6 @@ acpi_status pci_osc_control_set(acpi_han
}
EXPORT_SYMBOL(pci_osc_control_set);
-#ifdef CONFIG_ACPI_SLEEP
/*
* _SxD returns the D-state with the highest power
* (lowest D-state number) supported in the S-state "x".
@@ -259,7 +258,13 @@ static pci_power_t acpi_pci_choose_state
}
return PCI_POWER_ERROR;
}
-#endif
+
+static bool acpi_pci_power_manageable(struct pci_dev *dev)
+{
+ acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+
+ return handle ? acpi_bus_power_manageable(handle) : false;
+}
static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{
@@ -290,6 +295,11 @@ static int acpi_pci_set_power_state(stru
return -EINVAL;
}
+static struct pci_platform_pm_ops acpi_pci_platform_pm = {
+ .is_manageable = acpi_pci_power_manageable,
+ .set_state = acpi_pci_set_power_state,
+ .choose_state = acpi_pci_choose_state,
+};
/* ACPI bus type */
static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
@@ -341,10 +351,7 @@ static int __init acpi_pci_init(void)
ret = register_acpi_bus_type(&acpi_pci_bus);
if (ret)
return 0;
-#ifdef CONFIG_ACPI_SLEEP
- platform_pci_choose_state = acpi_pci_choose_state;
-#endif
- platform_pci_set_power_state = acpi_pci_set_power_state;
+ pci_set_platform_pm(&acpi_pci_platform_pm);
return 0;
}
arch_initcall(acpi_pci_init);
Index: linux-next/drivers/pci/pci.c
===================================================================
--- linux-next.orig/drivers/pci/pci.c
+++ linux-next/drivers/pci/pci.c
@@ -376,7 +376,32 @@ pci_restore_bars(struct pci_dev *dev)
pci_update_resource(dev, &dev->resource[i], i);
}
-int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t);
+static struct pci_platform_pm_ops *pci_platform_pm;
+
+int pci_set_platform_pm(struct pci_platform_pm_ops *ops)
+{
+ if (!ops->is_manageable || !ops->set_state || !ops->choose_state)
+ return -EINVAL;
+ pci_platform_pm = ops;
+ return 0;
+}
+
+static inline bool platform_pci_power_manageable(struct pci_dev *dev)
+{
+ return pci_platform_pm ? pci_platform_pm->is_manageable(dev) : false;
+}
+
+static inline int platform_pci_set_power_state(struct pci_dev *dev,
+ pci_power_t t)
+{
+ return pci_platform_pm ? pci_platform_pm->set_state(dev, t) : -ENOSYS;
+}
+
+static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
+{
+ return pci_platform_pm ?
+ pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR;
+}
/**
* pci_set_power_state - Set the power state of a PCI device
@@ -480,8 +505,7 @@ pci_set_power_state(struct pci_dev *dev,
* Give firmware a chance to be called, such as ACPI _PRx, _PSx
* Firmware method after native method ?
*/
- if (platform_pci_set_power_state)
- platform_pci_set_power_state(dev, state);
+ platform_pci_set_power_state(dev, state);
dev->current_state = state;
@@ -506,8 +530,6 @@ pci_set_power_state(struct pci_dev *dev,
return 0;
}
-pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev);
-
/**
* pci_choose_state - Choose the power state of a PCI device
* @dev: PCI device to be suspended
@@ -525,11 +547,9 @@ pci_power_t pci_choose_state(struct pci_
if (!pci_find_capability(dev, PCI_CAP_ID_PM))
return PCI_D0;
- if (platform_pci_choose_state) {
- ret = platform_pci_choose_state(dev);
- if (ret != PCI_POWER_ERROR)
- return ret;
- }
+ ret = platform_pci_choose_state(dev);
+ if (ret != PCI_POWER_ERROR)
+ return ret;
switch (state.event) {
case PM_EVENT_ON:
Index: linux-next/drivers/pci/pci.h
===================================================================
--- linux-next.orig/drivers/pci/pci.h
+++ linux-next/drivers/pci/pci.h
@@ -5,10 +5,28 @@ extern int pci_create_sysfs_dev_files(st
extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_cleanup_rom(struct pci_dev *dev);
-/* Firmware callbacks */
-extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev);
-extern int (*platform_pci_set_power_state)(struct pci_dev *dev,
- pci_power_t state);
+/**
+ * Firmware PM callbacks
+ *
+ * @is_manageable - returns 'true' if given device is power manageable by the
+ * platform firmware
+ *
+ * @set_state - invokes the platform firmware to set the device's power state
+ *
+ * @choose_state - returns PCI power state of given device preferred by the
+ * platform; to be used during system-wide transitions from a
+ * sleeping state to the working state and vice versa
+ *
+ * If given platform is generally capable of power managing PCI devices, all of
+ * these callbacks are mandatory.
+ */
+struct pci_platform_pm_ops {
+ bool (*is_manageable)(struct pci_dev *dev);
+ int (*set_state)(struct pci_dev *dev, pci_power_t state);
+ pci_power_t (*choose_state)(struct pci_dev *dev);
+};
+
+extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 03/11] PCI: Rework pci_set_power_state function (rev. 3)
[not found] <200806231934.08565.rjw@sisk.pl>
` (2 preceding siblings ...)
2008-06-23 17:45 ` [PATCH 02/11] PCI: Introduce platform_pci_power_manageable function Rafael J. Wysocki
@ 2008-06-23 17:45 ` Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 04/11] ACPI: Introduce acpi_device_sleep_wake function Rafael J. Wysocki
` (13 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:45 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
From: Rafael J. Wysocki <rjw@sisk.pl>
PCI: Rework pci_set_power_state function (rev. 3)
Rework pci_set_power_state() so that the platform callback is
invoked before the native mechanism, if necessary. Also, make
the function check if the device is power manageable by the
platform before invoking the platform callback.
This may matter if the device dependent on additional power
resources controlled by the platform is being put into D0, in which
case those power resources must be turned on before we attempt to
handle the device itself.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/pci/pci-acpi.c | 16 +++--
drivers/pci/pci.c | 152 +++++++++++++++++++++++++++++++++----------------
2 files changed, 115 insertions(+), 53 deletions(-)
Index: linux-next/drivers/pci/pci.c
===================================================================
--- linux-next.orig/drivers/pci/pci.c
+++ linux-next/drivers/pci/pci.c
@@ -404,68 +404,57 @@ static inline pci_power_t platform_pci_c
}
/**
- * pci_set_power_state - Set the power state of a PCI device
- * @dev: PCI device to be suspended
- * @state: PCI power state (D0, D1, D2, D3hot, D3cold) we're entering
- *
- * Transition a device to a new power state, using the Power Management
- * Capabilities in the device's config space.
- *
- * RETURN VALUE:
- * -EINVAL if trying to enter a lower state than we're already in.
- * 0 if we're already in the requested state.
- * -EIO if device does not support PCI PM.
- * 0 if we can successfully change the power state.
+ * pci_raw_set_power_state - Use PCI PM registers to set the power state of
+ * given PCI device
+ * @dev: PCI device to handle.
+ * @pm: PCI PM capability offset of the device.
+ * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
+ *
+ * RETURN VALUE:
+ * -EINVAL if the requested state is invalid.
+ * -EIO if device does not support PCI PM or its PM capabilities register has a
+ * wrong version, or device doesn't support the requested state.
+ * 0 if device already is in the requested state.
+ * 0 if device's power state has been successfully changed.
*/
-int
-pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+static int
+pci_raw_set_power_state(struct pci_dev *dev, int pm, pci_power_t state)
{
- int pm, need_restore = 0;
u16 pmcsr, pmc;
+ bool need_restore = false;
- /* bound the state we're entering */
- if (state > PCI_D3hot)
- state = PCI_D3hot;
-
- /*
- * If the device or the parent bridge can't support PCI PM, ignore
- * the request if we're doing anything besides putting it into D0
- * (which would only happen on boot).
- */
- if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
- return 0;
-
- /* find PCI PM capability in list */
- pm = pci_find_capability(dev, PCI_CAP_ID_PM);
-
- /* abort if the device doesn't support PM capabilities */
if (!pm)
return -EIO;
+ if (state < PCI_D0 || state > PCI_D3hot)
+ return -EINVAL;
+
/* Validate current state:
* Can enter D0 from any state, but if we can only go deeper
* to sleep if we're already in a low power state
*/
- if (state != PCI_D0 && dev->current_state > state) {
- printk(KERN_ERR "%s(): %s: state=%d, current state=%d\n",
+ if (dev->current_state == state) {
+ /* we're already there */
+ return 0;
+ } else if (state != PCI_D0 && dev->current_state <= PCI_D3cold
+ && dev->current_state > state) {
+ printk(KERN_ERR "%s(): %s: state=D%d, current state=D%d\n",
__func__, pci_name(dev), state, dev->current_state);
return -EINVAL;
- } else if (dev->current_state == state)
- return 0; /* we're already there */
+ }
+ pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
- pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc);
if ((pmc & PCI_PM_CAP_VER_MASK) > 3) {
- printk(KERN_DEBUG
+ printk(KERN_ERR
"PCI: %s has unsupported PM cap regs version (%u)\n",
pci_name(dev), pmc & PCI_PM_CAP_VER_MASK);
return -EIO;
}
/* check if this device supports the desired state */
- if (state == PCI_D1 && !(pmc & PCI_PM_CAP_D1))
- return -EIO;
- else if (state == PCI_D2 && !(pmc & PCI_PM_CAP_D2))
+ if ((state == PCI_D1 && !(pmc & PCI_PM_CAP_D1))
+ || (state == PCI_D2 && !(pmc & PCI_PM_CAP_D2)))
return -EIO;
pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
@@ -484,7 +473,7 @@ pci_set_power_state(struct pci_dev *dev,
case PCI_UNKNOWN: /* Boot-up */
if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot
&& !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
- need_restore = 1;
+ need_restore = true;
/* Fall-through: force to D0 */
default:
pmcsr = 0;
@@ -501,12 +490,6 @@ pci_set_power_state(struct pci_dev *dev,
else if (state == PCI_D2 || dev->current_state == PCI_D2)
udelay(200);
- /*
- * Give firmware a chance to be called, such as ACPI _PRx, _PSx
- * Firmware method after native method ?
- */
- platform_pci_set_power_state(dev, state);
-
dev->current_state = state;
/* According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT
@@ -531,6 +514,81 @@ pci_set_power_state(struct pci_dev *dev,
}
/**
+ * pci_update_current_state - Read PCI power state of given device from its
+ * PCI PM registers and cache it
+ * @dev: PCI device to handle.
+ * @pm: PCI PM capability offset of the device.
+ */
+static void pci_update_current_state(struct pci_dev *dev, int pm)
+{
+ if (pm) {
+ u16 pmcsr;
+
+ pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+ dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
+ }
+}
+
+/**
+ * pci_set_power_state - Set the power state of a PCI device
+ * @dev: PCI device to handle.
+ * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
+ *
+ * Transition a device to a new power state, using the platform formware and/or
+ * the device's PCI PM registers.
+ *
+ * RETURN VALUE:
+ * -EINVAL if the requested state is invalid.
+ * -EIO if device does not support PCI PM or its PM capabilities register has a
+ * wrong version, or device doesn't support the requested state.
+ * 0 if device already is in the requested state.
+ * 0 if device's power state has been successfully changed.
+ */
+int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+{
+ int pm, error;
+
+ /* bound the state we're entering */
+ if (state > PCI_D3hot)
+ state = PCI_D3hot;
+ else if (state < PCI_D0)
+ state = PCI_D0;
+ else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
+ /*
+ * If the device or the parent bridge do not support PCI PM,
+ * ignore the request if we're doing anything other than putting
+ * it into D0 (which would only happen on boot).
+ */
+ return 0;
+
+ /* Find PCI PM capability in the list */
+ pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+
+ if (state == PCI_D0 && platform_pci_power_manageable(dev)) {
+ /*
+ * Allow the platform to change the state, for example via ACPI
+ * _PR0, _PS0 and some such, but do not trust it.
+ */
+ int ret = platform_pci_set_power_state(dev, PCI_D0);
+ if (!ret)
+ pci_update_current_state(dev, pm);
+ }
+
+ error = pci_raw_set_power_state(dev, pm, state);
+
+ if (state > PCI_D0 && platform_pci_power_manageable(dev)) {
+ /* Allow the platform to finalize the transition */
+ int ret = platform_pci_set_power_state(dev, state);
+ if (!ret) {
+ pci_update_current_state(dev, pm);
+ error = 0;
+ }
+ }
+
+ return error;
+}
+
+/**
* pci_choose_state - Choose the power state of a PCI device
* @dev: PCI device to be suspended
* @state: target sleep state for the whole system. This is the value
Index: linux-next/drivers/pci/pci-acpi.c
===================================================================
--- linux-next.orig/drivers/pci/pci-acpi.c
+++ linux-next/drivers/pci/pci-acpi.c
@@ -277,12 +277,11 @@ static int acpi_pci_set_power_state(stru
[PCI_D3hot] = ACPI_STATE_D3,
[PCI_D3cold] = ACPI_STATE_D3
};
+ int error = -EINVAL;
- if (!handle)
- return -ENODEV;
/* If the ACPI device has _EJ0, ignore the device */
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
- return 0;
+ if (!handle || ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
+ return -ENODEV;
switch (state) {
case PCI_D0:
@@ -290,9 +289,14 @@ static int acpi_pci_set_power_state(stru
case PCI_D2:
case PCI_D3hot:
case PCI_D3cold:
- return acpi_bus_set_power(handle, state_conv[state]);
+ error = acpi_bus_set_power(handle, state_conv[state]);
}
- return -EINVAL;
+
+ if (!error)
+ printk(KERN_INFO "PCI: Power state of %s changed by ACPI\n",
+ pci_name(dev));
+
+ return error;
}
static struct pci_platform_pm_ops acpi_pci_platform_pm = {
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 04/11] ACPI: Introduce acpi_device_sleep_wake function
[not found] <200806231934.08565.rjw@sisk.pl>
` (3 preceding siblings ...)
2008-06-23 17:45 ` [PATCH 03/11] PCI: Rework pci_set_power_state function (rev. 3) Rafael J. Wysocki
@ 2008-06-23 17:45 ` Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 05/11] ACPI: Introduce new device wakeup flag 'prepared' Rafael J. Wysocki
` (12 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:45 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
From: Rafael J. Wysocki <rjw@sisk.pl>
ACPI: Introduce acpi_device_sleep_wake function
The currect ACPI code attempts to execute _PSW at three different
places and in one of them only it tries to execute _DSW before _PSW,
which is inconsistent with the other two cases.
Move the execution of _DSW and _PSW into a separate function called
acpi_device_sleep_wake() and call it wherever appropriate instead of
executing _DSW and/or _PSW directly.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/acpi/power.c | 118 ++++++++++++++++++++++++++++++--------------
drivers/acpi/scan.c | 42 ++-------------
drivers/acpi/sleep/wakeup.c | 2
include/acpi/acpi_drivers.h | 4 +
4 files changed, 92 insertions(+), 74 deletions(-)
Index: linux-next/drivers/acpi/power.c
===================================================================
--- linux-next.orig/drivers/acpi/power.c
+++ linux-next/drivers/acpi/power.c
@@ -292,69 +292,115 @@ static int acpi_power_off_device(acpi_ha
return 0;
}
+/**
+ * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
+ * ACPI 3.0) _PSW (Power State Wake)
+ * @dev: Device to handle.
+ * @enable: 0 - disable, 1 - enable the wake capabilities of the device.
+ * @sleep_state: Target sleep state of the system.
+ * @dev_state: Target power state of the device.
+ *
+ * Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
+ * State Wake) for the device, if present. On failure reset the device's
+ * wakeup.flags.valid flag.
+ *
+ * RETURN VALUE:
+ * 0 if either _DSW or _PSW has been successfully executed
+ * 0 if neither _DSW nor _PSW has been found
+ * -ENODEV if the execution of either _DSW or _PSW has failed
+ */
+int acpi_device_sleep_wake(struct acpi_device *dev,
+ int enable, int sleep_state, int dev_state)
+{
+ union acpi_object in_arg[3];
+ struct acpi_object_list arg_list = { 3, in_arg };
+ acpi_status status = AE_OK;
+
+ /*
+ * Try to execute _DSW first.
+ *
+ * Three agruments are needed for the _DSW object:
+ * Argument 0: enable/disable the wake capabilities
+ * Argument 1: target system state
+ * Argument 2: target device state
+ * When _DSW object is called to disable the wake capabilities, maybe
+ * the first argument is filled. The values of the other two agruments
+ * are meaningless.
+ */
+ in_arg[0].type = ACPI_TYPE_INTEGER;
+ in_arg[0].integer.value = enable;
+ in_arg[1].type = ACPI_TYPE_INTEGER;
+ in_arg[1].integer.value = sleep_state;
+ in_arg[2].type = ACPI_TYPE_INTEGER;
+ in_arg[2].integer.value = dev_state;
+ status = acpi_evaluate_object(dev->handle, "_DSW", &arg_list, NULL);
+ if (ACPI_SUCCESS(status)) {
+ return 0;
+ } else if (status != AE_NOT_FOUND) {
+ printk(KERN_ERR PREFIX "_DSW execution failed\n");
+ dev->wakeup.flags.valid = 0;
+ return -ENODEV;
+ }
+
+ /* Execute _PSW */
+ arg_list.count = 1;
+ in_arg[0].integer.value = enable;
+ status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
+ if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
+ printk(KERN_ERR PREFIX "_PSW execution failed\n");
+ dev->wakeup.flags.valid = 0;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
/*
* Prepare a wakeup device, two steps (Ref ACPI 2.0:P229):
* 1. Power on the power resources required for the wakeup device
- * 2. Enable _PSW (power state wake) for the device if present
+ * 2. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
+ * State Wake) for the device, if present
*/
-int acpi_enable_wakeup_device_power(struct acpi_device *dev)
+int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
{
- union acpi_object arg = { ACPI_TYPE_INTEGER };
- struct acpi_object_list arg_list = { 1, &arg };
- acpi_status status = AE_OK;
int i;
- int ret = 0;
if (!dev || !dev->wakeup.flags.valid)
- return -1;
+ return -EINVAL;
- arg.integer.value = 1;
/* Open power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
- ret = acpi_power_on(dev->wakeup.resources.handles[i], dev);
+ int ret = acpi_power_on(dev->wakeup.resources.handles[i], dev);
if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
- return -1;
+ return -ENODEV;
}
}
- /* Execute PSW */
- status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
- if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- printk(KERN_ERR PREFIX "Evaluate _PSW\n");
- dev->wakeup.flags.valid = 0;
- ret = -1;
- }
-
- return ret;
+ /*
+ * Passing 3 as the third argument below means the device may be placed
+ * in arbitrary power state afterwards.
+ */
+ return acpi_device_sleep_wake(dev, 1, sleep_state, 3);
}
/*
* Shutdown a wakeup device, counterpart of above method
- * 1. Disable _PSW (power state wake)
+ * 1. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
+ * State Wake) for the device, if present
* 2. Shutdown down the power resources
*/
int acpi_disable_wakeup_device_power(struct acpi_device *dev)
{
- union acpi_object arg = { ACPI_TYPE_INTEGER };
- struct acpi_object_list arg_list = { 1, &arg };
- acpi_status status = AE_OK;
- int i;
- int ret = 0;
-
+ int i, ret;
if (!dev || !dev->wakeup.flags.valid)
- return -1;
+ return -EINVAL;
- arg.integer.value = 0;
- /* Execute PSW */
- status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
- if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- printk(KERN_ERR PREFIX "Evaluate _PSW\n");
- dev->wakeup.flags.valid = 0;
- return -1;
- }
+ ret = acpi_device_sleep_wake(dev, 0, 0, 0);
+ if (ret)
+ return ret;
/* Close power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
@@ -362,7 +408,7 @@ int acpi_disable_wakeup_device_power(str
if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
- return -1;
+ return -ENODEV;
}
}
Index: linux-next/drivers/acpi/sleep/wakeup.c
===================================================================
--- linux-next.orig/drivers/acpi/sleep/wakeup.c
+++ linux-next/drivers/acpi/sleep/wakeup.c
@@ -42,7 +42,7 @@ void acpi_enable_wakeup_device_prep(u8 s
continue;
spin_unlock(&acpi_device_lock);
- acpi_enable_wakeup_device_power(dev);
+ acpi_enable_wakeup_device_power(dev, sleep_state);
spin_lock(&acpi_device_lock);
}
spin_unlock(&acpi_device_lock);
Index: linux-next/include/acpi/acpi_drivers.h
===================================================================
--- linux-next.orig/include/acpi/acpi_drivers.h
+++ linux-next/include/acpi/acpi_drivers.h
@@ -87,7 +87,9 @@ struct pci_bus *pci_acpi_scan_root(struc
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_POWER
-int acpi_enable_wakeup_device_power(struct acpi_device *dev);
+int acpi_device_sleep_wake(struct acpi_device *dev,
+ int enable, int sleep_state, int dev_state);
+int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state);
int acpi_disable_wakeup_device_power(struct acpi_device *dev);
int acpi_power_get_inferred_state(struct acpi_device *device);
int acpi_power_transition(struct acpi_device *device, int state);
Index: linux-next/drivers/acpi/scan.c
===================================================================
--- linux-next.orig/drivers/acpi/scan.c
+++ linux-next/drivers/acpi/scan.c
@@ -703,9 +703,7 @@ static int acpi_bus_get_wakeup_device_fl
acpi_status status = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package = NULL;
- union acpi_object in_arg[3];
- struct acpi_object_list arg_list = { 3, in_arg };
- acpi_status psw_status = AE_OK;
+ int psw_error;
struct acpi_device_id button_device_ids[] = {
{"PNP0C0D", 0},
@@ -737,39 +735,11 @@ static int acpi_bus_get_wakeup_device_fl
* So it is necessary to call _DSW object first. Only when it is not
* present will the _PSW object used.
*/
- /*
- * Three agruments are needed for the _DSW object.
- * Argument 0: enable/disable the wake capabilities
- * When _DSW object is called to disable the wake capabilities, maybe
- * the first argument is filled. The value of the other two agruments
- * is meaningless.
- */
- in_arg[0].type = ACPI_TYPE_INTEGER;
- in_arg[0].integer.value = 0;
- in_arg[1].type = ACPI_TYPE_INTEGER;
- in_arg[1].integer.value = 0;
- in_arg[2].type = ACPI_TYPE_INTEGER;
- in_arg[2].integer.value = 0;
- psw_status = acpi_evaluate_object(device->handle, "_DSW",
- &arg_list, NULL);
- if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in evaluate _DSW\n"));
- /*
- * When the _DSW object is not present, OSPM will call _PSW object.
- */
- if (psw_status == AE_NOT_FOUND) {
- /*
- * Only one agruments is required for the _PSW object.
- * agrument 0: enable/disable the wake capabilities
- */
- arg_list.count = 1;
- in_arg[0].integer.value = 0;
- psw_status = acpi_evaluate_object(device->handle, "_PSW",
- &arg_list, NULL);
- if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in "
- "evaluate _PSW\n"));
- }
+ psw_error = acpi_device_sleep_wake(device, 0, 0, 0);
+ if (psw_error)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "error in _DSW or _PSW evaluation\n"));
+
/* Power button, Lid switch always enable wakeup */
if (!acpi_match_device_ids(device, button_device_ids))
device->wakeup.flags.run_wake = 1;
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 05/11] ACPI: Introduce new device wakeup flag 'prepared'
[not found] <200806231934.08565.rjw@sisk.pl>
` (4 preceding siblings ...)
2008-06-23 17:45 ` [PATCH 04/11] ACPI: Introduce acpi_device_sleep_wake function Rafael J. Wysocki
@ 2008-06-23 17:45 ` Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 06/11] PCI ACPI: Introduce acpi_pm_device_sleep_wake function Rafael J. Wysocki
` (11 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:45 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
From: Rafael J. Wysocki <rjw@sisk.pl>
ACPI: Introduce new device wakeup flag 'prepared'
Introduce additional flag 'prepared' in
struct acpi_device_wakeup_flags and use it to prevent devices from
being enable/disabled do wake up the system multiple times in a row
(this does not happen currently, but will be possible after some of
the following patches).
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/acpi/power.c | 24 ++++++++++++++++++++++--
include/acpi/acpi_bus.h | 1 +
2 files changed, 23 insertions(+), 2 deletions(-)
Index: linux-next/drivers/acpi/power.c
===================================================================
--- linux-next.orig/drivers/acpi/power.c
+++ linux-next/drivers/acpi/power.c
@@ -363,11 +363,18 @@ int acpi_device_sleep_wake(struct acpi_d
*/
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
{
- int i;
+ int i, err;
if (!dev || !dev->wakeup.flags.valid)
return -EINVAL;
+ /*
+ * Do not execute the code below twice in a row without calling
+ * acpi_disable_wakeup_device_power() in between for the same device
+ */
+ if (dev->wakeup.flags.prepared)
+ return 0;
+
/* Open power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
int ret = acpi_power_on(dev->wakeup.resources.handles[i], dev);
@@ -382,7 +389,11 @@ int acpi_enable_wakeup_device_power(stru
* Passing 3 as the third argument below means the device may be placed
* in arbitrary power state afterwards.
*/
- return acpi_device_sleep_wake(dev, 1, sleep_state, 3);
+ err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
+ if (!err)
+ dev->wakeup.flags.prepared = 1;
+
+ return err;
}
/*
@@ -398,6 +409,15 @@ int acpi_disable_wakeup_device_power(str
if (!dev || !dev->wakeup.flags.valid)
return -EINVAL;
+ /*
+ * Do not execute the code below twice in a row without calling
+ * acpi_enable_wakeup_device_power() in between for the same device
+ */
+ if (!dev->wakeup.flags.prepared)
+ return 0;
+
+ dev->wakeup.flags.prepared = 0;
+
ret = acpi_device_sleep_wake(dev, 0, 0, 0);
if (ret)
return ret;
Index: linux-next/include/acpi/acpi_bus.h
===================================================================
--- linux-next.orig/include/acpi/acpi_bus.h
+++ linux-next/include/acpi/acpi_bus.h
@@ -259,6 +259,7 @@ struct acpi_device_perf {
/* Wakeup Management */
struct acpi_device_wakeup_flags {
u8 valid:1; /* Can successfully enable wakeup? */
+ u8 prepared:1; /* Has the wake-up capability been enabled? */
u8 run_wake:1; /* Run-Wake GPE devices */
};
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 06/11] PCI ACPI: Introduce acpi_pm_device_sleep_wake function
[not found] <200806231934.08565.rjw@sisk.pl>
` (5 preceding siblings ...)
2008-06-23 17:45 ` [PATCH 05/11] ACPI: Introduce new device wakeup flag 'prepared' Rafael J. Wysocki
@ 2008-06-23 17:45 ` Rafael J. Wysocki
2008-06-23 17:46 ` [PATCH 07/11] PCI ACPI: Introduce can_wakeup platform callback Rafael J. Wysocki
` (10 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:45 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
From: Rafael J. Wysocki <rjw@sisk.pl>
PCI ACPI: Introduce acpi_pm_device_sleep_wake function
Introduce function acpi_pm_device_sleep_wake() for enabling and
disabling the system wake-up capability of devices that are power
manageable by ACPI.
Introduce callback .sleep_wake() in struct pci_platform_pm_ops and
for the ACPI PCI 'driver' make it use acpi_pm_device_sleep_wake().
Modify pci_enable_wake() to use the new callback and drop the generic
.platform_enable_wakeup() callback that is not used any more.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/acpi/sleep/main.c | 25 +++++++++++++++++
drivers/base/power/sysfs.c | 3 --
drivers/pci/pci-acpi.c | 11 +++++++
drivers/pci/pci.c | 64 ++++++++++++++++++++++++++++++---------------
drivers/pci/pci.h | 3 ++
include/acpi/acpi_bus.h | 1
include/linux/pm_wakeup.h | 21 --------------
7 files changed, 84 insertions(+), 44 deletions(-)
Index: linux-next/drivers/acpi/sleep/main.c
===================================================================
--- linux-next.orig/drivers/acpi/sleep/main.c
+++ linux-next/drivers/acpi/sleep/main.c
@@ -468,6 +468,31 @@ int acpi_pm_device_sleep_state(struct de
*d_min_p = d_min;
return d_max;
}
+
+/**
+ * acpi_pm_device_sleep_wake - enable or disable the system wake-up
+ * capability of given device
+ * @dev: device to handle
+ * @enable: 'true' - enable, 'false' - disable the wake-up capability
+ */
+int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
+{
+ acpi_handle handle;
+ struct acpi_device *adev;
+
+ if (!device_may_wakeup(dev))
+ return -EINVAL;
+
+ handle = DEVICE_ACPI_HANDLE(dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
+ printk(KERN_DEBUG "ACPI handle has no context!\n");
+ return -ENODEV;
+ }
+
+ return enable ?
+ acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) :
+ acpi_disable_wakeup_device_power(adev);
+}
#endif
static void acpi_power_off_prepare(void)
Index: linux-next/drivers/pci/pci-acpi.c
===================================================================
--- linux-next.orig/drivers/pci/pci-acpi.c
+++ linux-next/drivers/pci/pci-acpi.c
@@ -299,10 +299,21 @@ static int acpi_pci_set_power_state(stru
return error;
}
+static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable)
+{
+ int error = acpi_pm_device_sleep_wake(&dev->dev, enable);
+
+ if (!error)
+ printk(KERN_INFO "PCI: Wake-up capability of %s %s by ACPI\n",
+ pci_name(dev), enable ? "enabled" : "disabled");
+ return error;
+}
+
static struct pci_platform_pm_ops acpi_pci_platform_pm = {
.is_manageable = acpi_pci_power_manageable,
.set_state = acpi_pci_set_power_state,
.choose_state = acpi_pci_choose_state,
+ .sleep_wake = acpi_pci_sleep_wake,
};
/* ACPI bus type */
Index: linux-next/drivers/pci/pci.h
===================================================================
--- linux-next.orig/drivers/pci/pci.h
+++ linux-next/drivers/pci/pci.h
@@ -17,6 +17,8 @@ extern void pci_cleanup_rom(struct pci_d
* platform; to be used during system-wide transitions from a
* sleeping state to the working state and vice versa
*
+ * @sleep_wake - enables/disables the system wake up capability of given device
+ *
* If given platform is generally capable of power managing PCI devices, all of
* these callbacks are mandatory.
*/
@@ -24,6 +26,7 @@ struct pci_platform_pm_ops {
bool (*is_manageable)(struct pci_dev *dev);
int (*set_state)(struct pci_dev *dev, pci_power_t state);
pci_power_t (*choose_state)(struct pci_dev *dev);
+ int (*sleep_wake)(struct pci_dev *dev, bool enable);
};
extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
Index: linux-next/include/acpi/acpi_bus.h
===================================================================
--- linux-next.orig/include/acpi/acpi_bus.h
+++ linux-next/include/acpi/acpi_bus.h
@@ -383,6 +383,7 @@ acpi_handle acpi_get_pci_rootbridge_hand
#ifdef CONFIG_PM_SLEEP
int acpi_pm_device_sleep_state(struct device *, int *);
+int acpi_pm_device_sleep_wake(struct device *, bool);
#else /* !CONFIG_PM_SLEEP */
static inline int acpi_pm_device_sleep_state(struct device *d, int *p)
{
Index: linux-next/drivers/pci/pci.c
===================================================================
--- linux-next.orig/drivers/pci/pci.c
+++ linux-next/drivers/pci/pci.c
@@ -380,7 +380,8 @@ static struct pci_platform_pm_ops *pci_p
int pci_set_platform_pm(struct pci_platform_pm_ops *ops)
{
- if (!ops->is_manageable || !ops->set_state || !ops->choose_state)
+ if (!ops->is_manageable || !ops->set_state || !ops->choose_state
+ || !ops->sleep_wake)
return -EINVAL;
pci_platform_pm = ops;
return 0;
@@ -403,6 +404,12 @@ static inline pci_power_t platform_pci_c
pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR;
}
+static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
+{
+ return pci_platform_pm ?
+ pci_platform_pm->sleep_wake(dev, enable) : -ENODEV;
+}
+
/**
* pci_raw_set_power_state - Use PCI PM registers to set the power state of
* given PCI device
@@ -1051,24 +1058,27 @@ int pci_set_pcie_reset_state(struct pci_
* supporting the standard PCI PME# signal may require such platform hooks;
* they always update bits in config space to allow PME# generation.
*
- * -EIO is returned if the device can't ever be a wakeup event source.
+ * -EIO is returned if the device can't be a wakeup event source.
* -EINVAL is returned if the device can't generate wakeup events from
* the specified PCI state. Returns zero if the operation is successful.
*/
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
{
int pm;
- int status;
- u16 value;
+ u16 value = 0;
+ bool platform_done = false;
- /* Note that drivers should verify device_may_wakeup(&dev->dev)
- * before calling this function. Platform code should report
- * errors when drivers try to enable wakeup on devices that
- * can't issue wakeups, or on which wakeups were disabled by
- * userspace updating the /sys/devices.../power/wakeup file.
- */
-
- status = call_platform_enable_wakeup(&dev->dev, enable);
+ if (enable && platform_pci_power_manageable(dev)) {
+ /* Allow the platform to handle the device */
+ int err = platform_pci_sleep_wake(dev, true);
+ if (!err)
+ /*
+ * The platform claims to have enabled the device's
+ * system wake-up capability as requested, but we are
+ * going to enable PME# anyway.
+ */
+ platform_done = true;
+ }
/* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM);
@@ -1077,23 +1087,27 @@ int pci_enable_wake(struct pci_dev *dev,
* disable wake events, it's a NOP. Otherwise fail unless the
* platform hooks handled this legacy device already.
*/
- if (!pm)
- return enable ? status : 0;
+ if (!pm) {
+ if (enable)
+ return platform_done ? 0 : -EIO;
+ else
+ goto Platform_disable;
+ }
/* Check device's ability to generate PME# */
- pci_read_config_word(dev,pm+PCI_PM_PMC,&value);
+ pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
value &= PCI_PM_CAP_PME_MASK;
value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
/* Check if it can generate PME# from requested state. */
if (!value || !(value & (1 << state))) {
- /* if it can't, revert what the platform hook changed,
- * always reporting the base "EINVAL, can't PME#" error
- */
- if (enable)
- call_platform_enable_wakeup(&dev->dev, 0);
- return enable ? -EINVAL : 0;
+ if (enable) {
+ return platform_done ? 0 : -EINVAL;
+ } else {
+ value = 0;
+ goto Platform_disable;
+ }
}
pci_read_config_word(dev, pm + PCI_PM_CTRL, &value);
@@ -1106,6 +1120,14 @@ int pci_enable_wake(struct pci_dev *dev,
pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
+ Platform_disable:
+ if (!enable && platform_pci_power_manageable(dev)) {
+ /* Allow the platform to finalize the operation */
+ int err = platform_pci_sleep_wake(dev, false);
+ if (err && !value)
+ return -EIO;
+ }
+
return 0;
}
Index: linux-next/include/linux/pm_wakeup.h
===================================================================
--- linux-next.orig/include/linux/pm_wakeup.h
+++ linux-next/include/linux/pm_wakeup.h
@@ -47,21 +47,7 @@ static inline void device_set_wakeup_ena
static inline int device_may_wakeup(struct device *dev)
{
- return dev->power.can_wakeup & dev->power.should_wakeup;
-}
-
-/*
- * Platform hook to activate device wakeup capability, if that's not already
- * handled by enable_irq_wake() etc.
- * Returns zero on success, else negative errno
- */
-extern int (*platform_enable_wakeup)(struct device *dev, int is_on);
-
-static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
-{
- if (platform_enable_wakeup)
- return (*platform_enable_wakeup)(dev, is_on);
- return 0;
+ return dev->power.can_wakeup && dev->power.should_wakeup;
}
#else /* !CONFIG_PM */
@@ -80,11 +66,6 @@ static inline int device_can_wakeup(stru
#define device_set_wakeup_enable(dev, val) do {} while (0)
#define device_may_wakeup(dev) 0
-static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
-{
- return 0;
-}
-
#endif /* !CONFIG_PM */
#endif /* _LINUX_PM_WAKEUP_H */
Index: linux-next/drivers/base/power/sysfs.c
===================================================================
--- linux-next.orig/drivers/base/power/sysfs.c
+++ linux-next/drivers/base/power/sysfs.c
@@ -6,9 +6,6 @@
#include <linux/string.h>
#include "power.h"
-int (*platform_enable_wakeup)(struct device *dev, int is_on);
-
-
/*
* wakeup - Report/change current wakeup option for device
*
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 07/11] PCI ACPI: Introduce can_wakeup platform callback
[not found] <200806231934.08565.rjw@sisk.pl>
` (6 preceding siblings ...)
2008-06-23 17:45 ` [PATCH 06/11] PCI ACPI: Introduce acpi_pm_device_sleep_wake function Rafael J. Wysocki
@ 2008-06-23 17:46 ` Rafael J. Wysocki
2008-06-23 17:46 ` [PATCH 08/11] PCI PM: Rework device PM initialization (rev. 3) Rafael J. Wysocki
` (9 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:46 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
From: Rafael J. Wysocki <rjw@sisk.pl>
PCI ACPI: Introduce can_wakeup platform callback
Introduce function acpi_bus_can_wakeup() allowing other (dependent)
subsystems to check if ACPI is able to enable the system wake-up
capability of given device.
Introduce callback .can_wakeup() in struct pci_platform_pm_ops and
for the ACPI 'driver' make it use acpi_bus_can_wakeup().
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/acpi/bus.c | 11 +++++++++++
drivers/pci/pci-acpi.c | 8 ++++++++
drivers/pci/pci.c | 11 ++++++++---
drivers/pci/pci.h | 4 ++++
include/acpi/acpi_bus.h | 1 +
5 files changed, 32 insertions(+), 3 deletions(-)
Index: linux-next/drivers/pci/pci.h
===================================================================
--- linux-next.orig/drivers/pci/pci.h
+++ linux-next/drivers/pci/pci.h
@@ -17,6 +17,9 @@ extern void pci_cleanup_rom(struct pci_d
* platform; to be used during system-wide transitions from a
* sleeping state to the working state and vice versa
*
+ * @can_wakeup - returns 'true' if given device is capable of waking up the
+ * system from a sleeping state
+ *
* @sleep_wake - enables/disables the system wake up capability of given device
*
* If given platform is generally capable of power managing PCI devices, all of
@@ -26,6 +29,7 @@ struct pci_platform_pm_ops {
bool (*is_manageable)(struct pci_dev *dev);
int (*set_state)(struct pci_dev *dev, pci_power_t state);
pci_power_t (*choose_state)(struct pci_dev *dev);
+ bool (*can_wakeup)(struct pci_dev *dev);
int (*sleep_wake)(struct pci_dev *dev, bool enable);
};
Index: linux-next/drivers/pci/pci.c
===================================================================
--- linux-next.orig/drivers/pci/pci.c
+++ linux-next/drivers/pci/pci.c
@@ -381,7 +381,7 @@ static struct pci_platform_pm_ops *pci_p
int pci_set_platform_pm(struct pci_platform_pm_ops *ops)
{
if (!ops->is_manageable || !ops->set_state || !ops->choose_state
- || !ops->sleep_wake)
+ || !ops->sleep_wake || !ops->can_wakeup)
return -EINVAL;
pci_platform_pm = ops;
return 0;
@@ -404,6 +404,11 @@ static inline pci_power_t platform_pci_c
pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR;
}
+static inline bool platform_pci_can_wakeup(struct pci_dev *dev)
+{
+ return pci_platform_pm ? pci_platform_pm->can_wakeup(dev) : false;
+}
+
static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
{
return pci_platform_pm ?
@@ -1068,7 +1073,7 @@ int pci_enable_wake(struct pci_dev *dev,
u16 value = 0;
bool platform_done = false;
- if (enable && platform_pci_power_manageable(dev)) {
+ if (enable && platform_pci_can_wakeup(dev)) {
/* Allow the platform to handle the device */
int err = platform_pci_sleep_wake(dev, true);
if (!err)
@@ -1121,7 +1126,7 @@ int pci_enable_wake(struct pci_dev *dev,
pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
Platform_disable:
- if (!enable && platform_pci_power_manageable(dev)) {
+ if (!enable && platform_pci_can_wakeup(dev)) {
/* Allow the platform to finalize the operation */
int err = platform_pci_sleep_wake(dev, false);
if (err && !value)
Index: linux-next/drivers/acpi/bus.c
===================================================================
--- linux-next.orig/drivers/acpi/bus.c
+++ linux-next/drivers/acpi/bus.c
@@ -306,6 +306,17 @@ bool acpi_bus_power_manageable(acpi_hand
EXPORT_SYMBOL(acpi_bus_power_manageable);
+bool acpi_bus_can_wakeup(acpi_handle handle)
+{
+ struct acpi_device *device;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ return result ? false : device->wakeup.flags.valid;
+}
+
+EXPORT_SYMBOL(acpi_bus_can_wakeup);
+
/* --------------------------------------------------------------------------
Event Management
-------------------------------------------------------------------------- */
Index: linux-next/drivers/pci/pci-acpi.c
===================================================================
--- linux-next.orig/drivers/pci/pci-acpi.c
+++ linux-next/drivers/pci/pci-acpi.c
@@ -299,6 +299,13 @@ static int acpi_pci_set_power_state(stru
return error;
}
+static bool acpi_pci_can_wakeup(struct pci_dev *dev)
+{
+ acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+
+ return handle ? acpi_bus_can_wakeup(handle) : false;
+}
+
static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable)
{
int error = acpi_pm_device_sleep_wake(&dev->dev, enable);
@@ -313,6 +320,7 @@ static struct pci_platform_pm_ops acpi_p
.is_manageable = acpi_pci_power_manageable,
.set_state = acpi_pci_set_power_state,
.choose_state = acpi_pci_choose_state,
+ .can_wakeup = acpi_pci_can_wakeup,
.sleep_wake = acpi_pci_sleep_wake,
};
Index: linux-next/include/acpi/acpi_bus.h
===================================================================
--- linux-next.orig/include/acpi/acpi_bus.h
+++ linux-next/include/acpi/acpi_bus.h
@@ -337,6 +337,7 @@ int acpi_bus_get_status(struct acpi_devi
int acpi_bus_get_power(acpi_handle handle, int *state);
int acpi_bus_set_power(acpi_handle handle, int state);
bool acpi_bus_power_manageable(acpi_handle handle);
+bool acpi_bus_can_wakeup(acpi_handle handle);
#ifdef CONFIG_ACPI_PROC_EVENT
int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data);
int acpi_bus_generate_proc_event4(const char *class, const char *bid, u8 type,
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 08/11] PCI PM: Rework device PM initialization (rev. 3)
[not found] <200806231934.08565.rjw@sisk.pl>
` (7 preceding siblings ...)
2008-06-23 17:46 ` [PATCH 07/11] PCI ACPI: Introduce can_wakeup platform callback Rafael J. Wysocki
@ 2008-06-23 17:46 ` Rafael J. Wysocki
2008-06-23 17:46 ` [PATCH 09/11] ACPI: Make ACPI update wake-up capability flag for devices that can wake up Rafael J. Wysocki
` (8 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:46 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
From: Rafael J. Wysocki <rjw@sisk.pl>
PCI PM: Rework device PM initialization (rev. 3)
Rework PCI device PM initialization so that if given device is capable
of generating wake-up events, either natively through the PME#
mechanism, or with the help of the platform, its power.can_wakeup
and power.should_wakeup flags are set as appropriate.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/pci/pci.c | 150 ++++++++++++++++++++++++++++++++--------------------
drivers/pci/pci.h | 1
drivers/pci/probe.c | 47 +---------------
3 files changed, 98 insertions(+), 100 deletions(-)
Index: linux-next/drivers/pci/pci.c
===================================================================
--- linux-next.orig/drivers/pci/pci.c
+++ linux-next/drivers/pci/pci.c
@@ -1049,6 +1049,53 @@ int pci_set_pcie_reset_state(struct pci_
}
/**
+ * pci_pme_capable - check the capability of PCI device to generate PME#
+ * @dev: PCI device to handle.
+ * @pm: PCI PM capability offset of the device.
+ * @state: PCI state from which device will issue PME#.
+ */
+static bool pci_pme_capable(struct pci_dev *dev, int pm, pci_power_t state)
+{
+ u16 pmc;
+
+ if (!pm)
+ return false;
+
+ /* Check device's ability to generate PME# from given state */
+ pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
+
+ pmc &= PCI_PM_CAP_PME_MASK;
+ pmc >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
+
+ return !!(pmc & (1 << state));
+}
+
+/**
+ * pci_pme_active - enable or disable PCI device's PME# function
+ * @dev: PCI device to handle.
+ * @pm: PCI PM capability offset of the device.
+ * @enable: 'true' to enable PME# generation; 'false' to disable it.
+ *
+ * The caller must verify that the device is capable of generating PME# before
+ * calling this function with @enable equal to 'true'.
+ */
+static void pci_pme_active(struct pci_dev *dev, int pm, bool enable)
+{
+ u16 pmcsr;
+
+ if (!pm)
+ return;
+
+ pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+ /* Clear PME_Status by writing 1 to it and enable PME# */
+ pmcsr |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE;
+ if (!enable)
+ pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
+
+ pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);
+}
+
+/**
* pci_enable_wake - enable PCI device as wakeup event source
* @dev: PCI device affected
* @state: PCI state from which device will issue wakeup events
@@ -1063,77 +1110,68 @@ int pci_set_pcie_reset_state(struct pci_
* supporting the standard PCI PME# signal may require such platform hooks;
* they always update bits in config space to allow PME# generation.
*
- * -EIO is returned if the device can't be a wakeup event source.
- * -EINVAL is returned if the device can't generate wakeup events from
- * the specified PCI state. Returns zero if the operation is successful.
+ * RETURN VALUE:
+ * 0 is returned on success
+ * -EINVAL is returned if device is not supposed to wake up the system
+ * Error code depending on the platform is returned if both the platform and the
+ * native mechanism fail to enable the generation of wake-up events
*/
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
{
int pm;
- u16 value = 0;
- bool platform_done = false;
+ int error = 0;
- if (enable && platform_pci_can_wakeup(dev)) {
- /* Allow the platform to handle the device */
- int err = platform_pci_sleep_wake(dev, true);
- if (!err)
- /*
- * The platform claims to have enabled the device's
- * system wake-up capability as requested, but we are
- * going to enable PME# anyway.
- */
- platform_done = true;
- }
+ if (!device_may_wakeup(&dev->dev))
+ return -EINVAL;
- /* find PCI PM capability in list */
- pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ if (enable && platform_pci_can_wakeup(dev))
+ error = platform_pci_sleep_wake(dev, true);
- /* If device doesn't support PM Capabilities, but caller wants to
- * disable wake events, it's a NOP. Otherwise fail unless the
- * platform hooks handled this legacy device already.
+ /*
+ * We are going to enable/disable the generation of PME# even if the
+ * platform claims to have handled the device as requested.
*/
- if (!pm) {
+ pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ if (!enable || pci_pme_capable(dev, pm, state)) {
+ pci_pme_active(dev, pm, enable);
if (enable)
- return platform_done ? 0 : -EIO;
- else
- goto Platform_disable;
- }
-
- /* Check device's ability to generate PME# */
- pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
-
- value &= PCI_PM_CAP_PME_MASK;
- value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
-
- /* Check if it can generate PME# from requested state. */
- if (!value || !(value & (1 << state))) {
- if (enable) {
- return platform_done ? 0 : -EINVAL;
- } else {
- value = 0;
- goto Platform_disable;
- }
+ return 0;
}
- pci_read_config_word(dev, pm + PCI_PM_CTRL, &value);
-
- /* Clear PME_Status by writing 1 to it and enable PME# */
- value |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE;
+ if (!enable && platform_pci_can_wakeup(dev))
+ error = platform_pci_sleep_wake(dev, false);
- if (!enable)
- value &= ~PCI_PM_CTRL_PME_ENABLE;
+ return error;
+}
- pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
+/**
+ * pci_pm_init - Initialize PM functions of given PCI device
+ * @dev: PCI device to handle.
+ */
+void pci_pm_init(struct pci_dev *dev)
+{
+ int pm;
+ u16 pmc;
- Platform_disable:
- if (!enable && platform_pci_can_wakeup(dev)) {
- /* Allow the platform to finalize the operation */
- int err = platform_pci_sleep_wake(dev, false);
- if (err && !value)
- return -EIO;
+ /* find PCI PM capability in list */
+ pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ if (!pm)
+ return;
+ /* Check device's ability to generate PME# */
+ pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
+ if (pmc & PCI_PM_CAP_PME_MASK) {
+ printk(KERN_INFO "PCI: Device %s supports PME# from"
+ "%s%s%s%s%s\n", pci_name(dev),
+ (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
+ (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
+ (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
+ (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "",
+ (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
+ /* Mak device's PM flags reflect the wake-up capability */
+ device_init_wakeup(&dev->dev, true);
+ /* Disable the PME# generation functionality */
+ pci_pme_active(dev, pm, false);
}
-
- return 0;
}
int
Index: linux-next/drivers/pci/pci.h
===================================================================
--- linux-next.orig/drivers/pci/pci.h
+++ linux-next/drivers/pci/pci.h
@@ -34,6 +34,7 @@ struct pci_platform_pm_ops {
};
extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
+extern void pci_pm_init(struct pci_dev *dev);
extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
Index: linux-next/drivers/pci/probe.c
===================================================================
--- linux-next.orig/drivers/pci/probe.c
+++ linux-next/drivers/pci/probe.c
@@ -858,49 +858,6 @@ int pci_cfg_space_size_ext(struct pci_de
return PCI_CFG_SPACE_SIZE;
}
-/**
- * pci_disable_pme - Disable the PME function of PCI device
- * @dev: PCI device affected
- * -EINVAL is returned if PCI device doesn't support PME.
- * Zero is returned if the PME is supported and can be disabled.
- */
-static int pci_disable_pme(struct pci_dev *dev)
-{
- int pm;
- u16 value;
-
- /* find PCI PM capability in list */
- pm = pci_find_capability(dev, PCI_CAP_ID_PM);
-
- /* If device doesn't support PM Capabilities, it means that PME is
- * not supported.
- */
- if (!pm)
- return -EINVAL;
- /* Check device's ability to generate PME# */
- pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
-
- value &= PCI_PM_CAP_PME_MASK;
- /* Check if it can generate PME# */
- if (!value) {
- /*
- * If it is zero, it means that PME is still unsupported
- * although there exists the PM capability.
- */
- return -EINVAL;
- }
-
- pci_read_config_word(dev, pm + PCI_PM_CTRL, &value);
-
- /* Clear PME_Status by writing 1 to it */
- value |= PCI_PM_CTRL_PME_STATUS ;
- /* Disable PME enable bit */
- value &= ~PCI_PM_CTRL_PME_ENABLE;
- pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
-
- return 0;
-}
-
int pci_cfg_space_size(struct pci_dev *dev)
{
int pos;
@@ -1008,7 +965,6 @@ static struct pci_dev *pci_scan_device(s
}
pci_vpd_pci22_init(dev);
- pci_disable_pme(dev);
return dev;
}
@@ -1029,6 +985,9 @@ void pci_device_add(struct pci_dev *dev,
/* Fix up broken headers */
pci_fixup_device(pci_fixup_header, dev);
+ /* Initialize power management of the device */
+ pci_pm_init(dev);
+
/*
* Add the device to our list of discovered devices
* and the bus list for fixup functions, etc.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 09/11] ACPI: Make ACPI update wake-up capability flag for devices that can wake up
[not found] <200806231934.08565.rjw@sisk.pl>
` (8 preceding siblings ...)
2008-06-23 17:46 ` [PATCH 08/11] PCI PM: Rework device PM initialization (rev. 3) Rafael J. Wysocki
@ 2008-06-23 17:46 ` Rafael J. Wysocki
2008-06-23 17:49 ` [PATCH 11/11] PCI: Simplify PCI device PM code Rafael J. Wysocki
` (7 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:46 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
From: Rafael J. Wysocki <rjw@sisk.pl>
ACPI: Make ACPI update wake-up capability flag for devices that can wake up
Make ACPI code set the dev->power.can_wakeup flag for devices that
are found to be wake-up capable by it.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/acpi/glue.c | 2 ++
drivers/acpi/sleep/proc.c | 5 ++++-
include/linux/pm_wakeup.h | 5 +++++
3 files changed, 11 insertions(+), 1 deletion(-)
Index: linux-next/include/linux/pm_wakeup.h
===================================================================
--- linux-next.orig/include/linux/pm_wakeup.h
+++ linux-next/include/linux/pm_wakeup.h
@@ -35,6 +35,11 @@ static inline void device_init_wakeup(st
dev->power.can_wakeup = dev->power.should_wakeup = !!val;
}
+static inline void device_set_wakeup_capable(struct device *dev, int val)
+{
+ dev->power.can_wakeup = !!val;
+}
+
static inline int device_can_wakeup(struct device *dev)
{
return dev->power.can_wakeup;
Index: linux-next/drivers/acpi/glue.c
===================================================================
--- linux-next.orig/drivers/acpi/glue.c
+++ linux-next/drivers/acpi/glue.c
@@ -165,6 +165,8 @@ static int acpi_bind_one(struct device *
"firmware_node");
ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
"physical_node");
+ if (acpi_dev->wakeup.flags.valid)
+ device_set_wakeup_capable(dev, true);
}
return 0;
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 11/11] PCI: Simplify PCI device PM code
[not found] <200806231934.08565.rjw@sisk.pl>
` (9 preceding siblings ...)
2008-06-23 17:46 ` [PATCH 09/11] ACPI: Make ACPI update wake-up capability flag for devices that can wake up Rafael J. Wysocki
@ 2008-06-23 17:49 ` Rafael J. Wysocki
2008-06-25 22:05 ` [PATCH 0/11] PCI PM: Handling of PCI devices wake-up functionality Jesse Barnes
` (6 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-23 17:49 UTC (permalink / raw)
To: ACPI Devel Maling List; +Cc: pm list, Jesse Barnes
From: Rafael J. Wysocki <rjw@sisk.pl>
PCI: Simplify PCI device PM code
If the offset of PCI device's PM capability in its configuration space and the
mask of states that the device supports PME# from are cached in the
corresponding struct pci_dev, the PCI device PM code can be simplified quite
a bit.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/pci/pci.c | 88 ++++++++++++++++++-----------------------------
include/linux/pci.h | 4 ++
include/linux/pci_regs.h | 1
3 files changed, 39 insertions(+), 54 deletions(-)
Index: linux-next/include/linux/pci.h
===================================================================
--- linux-next.orig/include/linux/pci.h
+++ linux-next/include/linux/pci.h
@@ -177,6 +177,10 @@ struct pci_dev {
pci_power_t current_state; /* Current operating state. In ACPI-speak,
this is D0-D3, D0 being fully functional,
and D3 being off. */
+ int pm_cap; /* PM capability offset in the
+ configuration space */
+ unsigned int pme_data:5; /* Bitmask of states from which PME#
+ can be generated */
#ifdef CONFIG_PCIEASPM
struct pcie_link_state *link_state; /* ASPM link state. */
Index: linux-next/drivers/pci/pci.c
===================================================================
--- linux-next.orig/drivers/pci/pci.c
+++ linux-next/drivers/pci/pci.c
@@ -419,7 +419,6 @@ static inline int platform_pci_sleep_wak
* pci_raw_set_power_state - Use PCI PM registers to set the power state of
* given PCI device
* @dev: PCI device to handle.
- * @pm: PCI PM capability offset of the device.
* @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
*
* RETURN VALUE:
@@ -430,12 +429,12 @@ static inline int platform_pci_sleep_wak
* 0 if device's power state has been successfully changed.
*/
static int
-pci_raw_set_power_state(struct pci_dev *dev, int pm, pci_power_t state)
+pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
{
u16 pmcsr, pmc;
bool need_restore = false;
- if (!pm)
+ if (!dev->pm_cap)
return -EIO;
if (state < PCI_D0 || state > PCI_D3hot)
@@ -455,7 +454,7 @@ pci_raw_set_power_state(struct pci_dev *
return -EINVAL;
}
- pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_PMC, &pmc);
if ((pmc & PCI_PM_CAP_VER_MASK) > 3) {
printk(KERN_ERR
@@ -469,7 +468,7 @@ pci_raw_set_power_state(struct pci_dev *
|| (state == PCI_D2 && !(pmc & PCI_PM_CAP_D2)))
return -EIO;
- pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
/* If we're (effectively) in D3, force entire word to 0.
* This doesn't affect PME_Status, disables PME_En, and
@@ -493,7 +492,7 @@ pci_raw_set_power_state(struct pci_dev *
}
/* enter specified state */
- pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);
+ pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
/* Mandatory power management transition delays */
/* see PCI PM 1.1 5.6.1 table 18 */
@@ -529,14 +528,13 @@ pci_raw_set_power_state(struct pci_dev *
* pci_update_current_state - Read PCI power state of given device from its
* PCI PM registers and cache it
* @dev: PCI device to handle.
- * @pm: PCI PM capability offset of the device.
*/
-static void pci_update_current_state(struct pci_dev *dev, int pm)
+static void pci_update_current_state(struct pci_dev *dev)
{
- if (pm) {
+ if (dev->pm_cap) {
u16 pmcsr;
- pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
}
}
@@ -558,7 +556,7 @@ static void pci_update_current_state(str
*/
int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{
- int pm, error;
+ int error;
/* bound the state we're entering */
if (state > PCI_D3hot)
@@ -573,9 +571,6 @@ int pci_set_power_state(struct pci_dev *
*/
return 0;
- /* Find PCI PM capability in the list */
- pm = pci_find_capability(dev, PCI_CAP_ID_PM);
-
if (state == PCI_D0 && platform_pci_power_manageable(dev)) {
/*
* Allow the platform to change the state, for example via ACPI
@@ -583,16 +578,16 @@ int pci_set_power_state(struct pci_dev *
*/
int ret = platform_pci_set_power_state(dev, PCI_D0);
if (!ret)
- pci_update_current_state(dev, pm);
+ pci_update_current_state(dev);
}
- error = pci_raw_set_power_state(dev, pm, state);
+ error = pci_raw_set_power_state(dev, state);
if (state > PCI_D0 && platform_pci_power_manageable(dev)) {
/* Allow the platform to finalize the transition */
int ret = platform_pci_set_power_state(dev, state);
if (!ret) {
- pci_update_current_state(dev, pm);
+ pci_update_current_state(dev);
error = 0;
}
}
@@ -1051,48 +1046,40 @@ int pci_set_pcie_reset_state(struct pci_
/**
* pci_pme_capable - check the capability of PCI device to generate PME#
* @dev: PCI device to handle.
- * @pm: PCI PM capability offset of the device.
* @state: PCI state from which device will issue PME#.
*/
-static bool pci_pme_capable(struct pci_dev *dev, int pm, pci_power_t state)
+static bool pci_pme_capable(struct pci_dev *dev, pci_power_t state)
{
u16 pmc;
- if (!pm)
+ if (!dev->pm_cap)
return false;
- /* Check device's ability to generate PME# from given state */
- pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
-
- pmc &= PCI_PM_CAP_PME_MASK;
- pmc >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
-
- return !!(pmc & (1 << state));
+ return !!(dev->pme_data & (1 << state));
}
/**
* pci_pme_active - enable or disable PCI device's PME# function
* @dev: PCI device to handle.
- * @pm: PCI PM capability offset of the device.
* @enable: 'true' to enable PME# generation; 'false' to disable it.
*
* The caller must verify that the device is capable of generating PME# before
* calling this function with @enable equal to 'true'.
*/
-static void pci_pme_active(struct pci_dev *dev, int pm, bool enable)
+static void pci_pme_active(struct pci_dev *dev, bool enable)
{
u16 pmcsr;
- if (!pm)
+ if (!dev->pm_cap)
return;
- pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
/* Clear PME_Status by writing 1 to it and enable PME# */
pmcsr |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE;
if (!enable)
pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
- pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);
+ pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
}
/**
@@ -1118,7 +1105,6 @@ static void pci_pme_active(struct pci_de
*/
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
{
- int pm;
int error = 0;
if (!device_may_wakeup(&dev->dev))
@@ -1131,9 +1117,8 @@ int pci_enable_wake(struct pci_dev *dev,
* We are going to enable/disable the generation of PME# even if the
* platform claims to have handled the device as requested.
*/
- pm = pci_find_capability(dev, PCI_CAP_ID_PM);
- if (!enable || pci_pme_capable(dev, pm, state)) {
- pci_pme_active(dev, pm, enable);
+ if (!enable || pci_pme_capable(dev, state)) {
+ pci_pme_active(dev, enable);
if (enable)
return 0;
}
@@ -1156,7 +1141,6 @@ int pci_enable_wake(struct pci_dev *dev,
int pci_prepare_to_sleep(struct pci_dev *dev)
{
pci_power_t target_state = PCI_D3hot;
- int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
int error;
if (platform_pci_power_manageable(dev)) {
@@ -1184,23 +1168,14 @@ int pci_prepare_to_sleep(struct pci_dev
* wake-up events, make it the target state and enable device
* to generate PME#.
*/
- u16 pmc;
-
- if (!pm)
+ if (!dev->pm_cap)
return -EIO;
- pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
- if (pmc & PCI_PM_CAP_PME_MASK) {
- if (!(pmc & PCI_PM_CAP_PME_D3)) {
- /* Device cannot generate PME# from D3_hot */
- if (pmc & PCI_PM_CAP_PME_D2)
- target_state = PCI_D2;
- else if (pmc & PCI_PM_CAP_PME_D1)
- target_state = PCI_D1;
- else
- target_state = PCI_D0;
- }
- pci_pme_active(dev, pm, true);
+ if (dev->pme_data) {
+ while (target_state
+ && !(dev->pme_data & (1 << target_state)))
+ target_state--;
+ pci_pme_active(dev, true);
}
}
@@ -1236,11 +1211,13 @@ void pci_pm_init(struct pci_dev *dev)
/* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ dev->pm_cap = pm;
if (!pm)
return;
/* Check device's ability to generate PME# */
pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
- if (pmc & PCI_PM_CAP_PME_MASK) {
+ pmc &= PCI_PM_CAP_PME_MASK;
+ if (pmc) {
printk(KERN_INFO "PCI: Device %s supports PME# from"
"%s%s%s%s%s\n", pci_name(dev),
(pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
@@ -1248,10 +1225,13 @@ void pci_pm_init(struct pci_dev *dev)
(pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
(pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "",
(pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
+ dev->pme_data = pmc >> PCI_PM_CAP_PME_SHIFT;
/* Mak device's PM flags reflect the wake-up capability */
device_init_wakeup(&dev->dev, true);
/* Disable the PME# generation functionality */
- pci_pme_active(dev, pm, false);
+ pci_pme_active(dev, false);
+ } else {
+ dev->pme_data = 0;
}
}
Index: linux-next/include/linux/pci_regs.h
===================================================================
--- linux-next.orig/include/linux/pci_regs.h
+++ linux-next/include/linux/pci_regs.h
@@ -231,6 +231,7 @@
#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */
#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */
#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */
+#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */
#define PCI_PM_CTRL 4 /* PM control and status register */
#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */
#define PCI_PM_CTRL_NO_SOFT_RESET 0x0004 /* No reset for D3hot->D0 */
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 0/11] PCI PM: Handling of PCI devices wake-up functionality
[not found] <200806231934.08565.rjw@sisk.pl>
` (10 preceding siblings ...)
2008-06-23 17:49 ` [PATCH 11/11] PCI: Simplify PCI device PM code Rafael J. Wysocki
@ 2008-06-25 22:05 ` Jesse Barnes
2008-06-25 22:24 ` Rafael J. Wysocki
[not found] ` <200806231945.00404.rjw@sisk.pl>
` (5 subsequent siblings)
17 siblings, 1 reply; 20+ messages in thread
From: Jesse Barnes @ 2008-06-25 22:05 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list
On Monday, June 23, 2008 10:34 am Rafael J. Wysocki wrote:
> Hi,
>
> The purpose of the following series of patches is to rework the power
> management of PCI devices so that the handling of their wake-up
> functionality is consistent with the other PM operations and so that the
> user space can manage the wake-up functionality of PCI devices using the
> /sys/devices/.../power/wakeup interface regardless of whether the wake-up
> function is based on the native PCI mechanism (PME#), or it is handled by
> the platform (eg. ACPI).
>
> Apart from the ACPI and PCI changes necessary for this purpose, the series
> includes some clean-ups that are not strictly required, but make the code
> more straightforward and (IMHO) easier to follow.
>
> Please review.
This patchset looks really nice, and makes pci_enable_wake and such much more
readable, IMO. How much testing has it seen? Do you think it's appropriate
for 2.6.27?
Thanks,
Jesse
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 0/11] PCI PM: Handling of PCI devices wake-up functionality
2008-06-25 22:05 ` [PATCH 0/11] PCI PM: Handling of PCI devices wake-up functionality Jesse Barnes
@ 2008-06-25 22:24 ` Rafael J. Wysocki
0 siblings, 0 replies; 20+ messages in thread
From: Rafael J. Wysocki @ 2008-06-25 22:24 UTC (permalink / raw)
To: Jesse Barnes; +Cc: ACPI Devel Maling List, pm list
On Thursday, 26 of June 2008, Jesse Barnes wrote:
> On Monday, June 23, 2008 10:34 am Rafael J. Wysocki wrote:
> > Hi,
> >
> > The purpose of the following series of patches is to rework the power
> > management of PCI devices so that the handling of their wake-up
> > functionality is consistent with the other PM operations and so that the
> > user space can manage the wake-up functionality of PCI devices using the
> > /sys/devices/.../power/wakeup interface regardless of whether the wake-up
> > function is based on the native PCI mechanism (PME#), or it is handled by
> > the platform (eg. ACPI).
> >
> > Apart from the ACPI and PCI changes necessary for this purpose, the series
> > includes some clean-ups that are not strictly required, but make the code
> > more straightforward and (IMHO) easier to follow.
> >
> > Please review.
>
> This patchset looks really nice, and makes pci_enable_wake and such much more
> readable, IMO.
Thanks!
> How much testing has it seen?
A little. I've been using it on my HP nx6325 for some days with no visible
problems.
> Do you think it's appropriate for 2.6.27?
Well, I think the patches need to be modified to handle the case of devices
that can wake up both through PME# and the ACPI-based mechanism.
Also, I need to make ACPI enable the wake-up GPEs for PCI devices that are
supposed to be handled by it.
For this reasons I'm not sure they will be sufficiently tested before the
2.6.27 merge window. Perhaps it's better to target the patchset at 2.6.28 and
make sure it gets some serious testing during the .27 cycle.
Thanks,
Rafael
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 10/11] PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep
[not found] ` <200806231945.00404.rjw@sisk.pl>
@ 2008-07-07 7:02 ` Pavel Machek
0 siblings, 0 replies; 20+ messages in thread
From: Pavel Machek @ 2008-07-07 7:02 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Jesse Barnes
On Mon 2008-06-23 19:44:59, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
>
> PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep
>
> Introduce functions pci_prepare_to_sleep() and pci_back_from_sleep(),
> to be used by the PCI drivers that want to place their devices into
> the lowest power state appropiate for them (PCI_D3hot, if the device
> is not supposed to wake up the system, or the deepest state from
> which the wake-up is possible, otherwise) while the system is being
> prepared to go into a sleeping state and to put them back into D0
> during the subsequent transition to the working state.
>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Looks ok to me, ACK.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 01/11] ACPI: Introduce acpi_bus_power_manageable function
[not found] ` <200806231945.19574.rjw@sisk.pl>
@ 2008-07-07 7:03 ` Pavel Machek
0 siblings, 0 replies; 20+ messages in thread
From: Pavel Machek @ 2008-07-07 7:03 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Jesse Barnes
On Mon 2008-06-23 19:45:18, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
>
> ACPI: Introduce acpi_bus_power_manageable function
>
> Introduce function acpi_bus_power_manageable() allowing other
> (dependent) subsystems to check if ACPI is able to power manage given
> device. This may be useful, for example, for PCI device power
> management.
>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
ACK.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 02/11] PCI: Introduce platform_pci_power_manageable function
[not found] ` <200806231945.26068.rjw@sisk.pl>
@ 2008-07-07 7:05 ` Pavel Machek
0 siblings, 0 replies; 20+ messages in thread
From: Pavel Machek @ 2008-07-07 7:05 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Jesse Barnes
On Mon 2008-06-23 19:45:25, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
>
> PCI: Introduce platform_pci_power_manageable function
>
> Introduce function pointer platform_pci_power_manageable to be used
> by the platform-related code to point to a function allowing us to
> check if given device is power manageable by the platform.
>
> Introduce acpi_pci_power_manageable() playing that role for ACPI.
>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
ACK.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 03/11] PCI: Rework pci_set_power_state function (rev. 3)
[not found] ` <200806231945.32682.rjw@sisk.pl>
@ 2008-07-07 7:15 ` Pavel Machek
0 siblings, 0 replies; 20+ messages in thread
From: Pavel Machek @ 2008-07-07 7:15 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Jesse Barnes
On Mon 2008-06-23 19:45:32, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
>
> PCI: Rework pci_set_power_state function (rev. 3)
>
> Rework pci_set_power_state() so that the platform callback is
> invoked before the native mechanism, if necessary. Also, make
> the function check if the device is power manageable by the
> platform before invoking the platform callback.
>
> This may matter if the device dependent on additional power
> resources controlled by the platform is being put into D0, in which
> case those power resources must be turned on before we attempt to
> handle the device itself.
>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Looks mostly ok to me...
> +/**
> + * pci_set_power_state - Set the power state of a PCI device
> + * @dev: PCI device to handle.
> + * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
> + *
> + * Transition a device to a new power state, using the platform formware and/or
> + * the device's PCI PM registers.
> + *
> + * RETURN VALUE:
> + * -EINVAL if the requested state is invalid.
> + * -EIO if device does not support PCI PM or its PM capabilities register has a
> + * wrong version, or device doesn't support the requested state.
> + * 0 if device already is in the requested state.
> + * 0 if device's power state has been successfully changed.
> + */
> +int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
> +{
> + int pm, error;
> +
> + /* bound the state we're entering */
> + if (state > PCI_D3hot)
> + state = PCI_D3hot;
> + else if (state < PCI_D0)
> + state = PCI_D0;
Should it return einval in those two cases? Docs above says it does...
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 04/11] ACPI: Introduce acpi_device_sleep_wake function
[not found] ` <200806231945.39951.rjw@sisk.pl>
@ 2008-07-07 7:18 ` Pavel Machek
0 siblings, 0 replies; 20+ messages in thread
From: Pavel Machek @ 2008-07-07 7:18 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Jesse Barnes
On Mon 2008-06-23 19:45:39, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
>
> ACPI: Introduce acpi_device_sleep_wake function
>
> The currect ACPI code attempts to execute _PSW at three different
> places and in one of them only it tries to execute _DSW before _PSW,
> which is inconsistent with the other two cases.
>
> Move the execution of _DSW and _PSW into a separate function called
> acpi_device_sleep_wake() and call it wherever appropriate instead of
> executing _DSW and/or _PSW directly.
>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
ACK.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 05/11] ACPI: Introduce new device wakeup flag 'prepared'
[not found] ` <200806231945.47937.rjw@sisk.pl>
@ 2008-07-07 7:20 ` Pavel Machek
0 siblings, 0 replies; 20+ messages in thread
From: Pavel Machek @ 2008-07-07 7:20 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Jesse Barnes
On Mon 2008-06-23 19:45:47, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
>
> ACPI: Introduce new device wakeup flag 'prepared'
>
> Introduce additional flag 'prepared' in
> struct acpi_device_wakeup_flags and use it to prevent devices from
> being enable/disabled do wake up the system multiple times in a row
> (this does not happen currently, but will be possible after some of
> the following patches).
>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
ACK.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2008-07-07 7:20 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <200806231934.08565.rjw@sisk.pl>
2008-06-23 17:44 ` [PATCH 10/11] PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 01/11] ACPI: Introduce acpi_bus_power_manageable function Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 02/11] PCI: Introduce platform_pci_power_manageable function Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 03/11] PCI: Rework pci_set_power_state function (rev. 3) Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 04/11] ACPI: Introduce acpi_device_sleep_wake function Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 05/11] ACPI: Introduce new device wakeup flag 'prepared' Rafael J. Wysocki
2008-06-23 17:45 ` [PATCH 06/11] PCI ACPI: Introduce acpi_pm_device_sleep_wake function Rafael J. Wysocki
2008-06-23 17:46 ` [PATCH 07/11] PCI ACPI: Introduce can_wakeup platform callback Rafael J. Wysocki
2008-06-23 17:46 ` [PATCH 08/11] PCI PM: Rework device PM initialization (rev. 3) Rafael J. Wysocki
2008-06-23 17:46 ` [PATCH 09/11] ACPI: Make ACPI update wake-up capability flag for devices that can wake up Rafael J. Wysocki
2008-06-23 17:49 ` [PATCH 11/11] PCI: Simplify PCI device PM code Rafael J. Wysocki
2008-06-25 22:05 ` [PATCH 0/11] PCI PM: Handling of PCI devices wake-up functionality Jesse Barnes
2008-06-25 22:24 ` Rafael J. Wysocki
[not found] ` <200806231945.00404.rjw@sisk.pl>
2008-07-07 7:02 ` [PATCH 10/11] PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep Pavel Machek
[not found] ` <200806231945.19574.rjw@sisk.pl>
2008-07-07 7:03 ` [PATCH 01/11] ACPI: Introduce acpi_bus_power_manageable function Pavel Machek
[not found] ` <200806231945.26068.rjw@sisk.pl>
2008-07-07 7:05 ` [PATCH 02/11] PCI: Introduce platform_pci_power_manageable function Pavel Machek
[not found] ` <200806231945.32682.rjw@sisk.pl>
2008-07-07 7:15 ` [PATCH 03/11] PCI: Rework pci_set_power_state function (rev. 3) Pavel Machek
[not found] ` <200806231945.39951.rjw@sisk.pl>
2008-07-07 7:18 ` [PATCH 04/11] ACPI: Introduce acpi_device_sleep_wake function Pavel Machek
[not found] ` <200806231945.47937.rjw@sisk.pl>
2008-07-07 7:20 ` [PATCH 05/11] ACPI: Introduce new device wakeup flag 'prepared' Pavel Machek
2008-06-23 17:34 [PATCH 0/11] PCI PM: Handling of PCI devices wake-up functionality Rafael J. Wysocki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox