Skip to content

Commit

Permalink
ACPI / PCI: Rework the setup and cleanup of device wakeup
Browse files Browse the repository at this point in the history
Currently, the ACPI wakeup capability of PCI devices is set up
in two different places, partially in acpi_pci_bind() where
runtime wakeup is initialized and partially in
platform_pci_wakeup_init(), where system wakeup is initialized.
The cleanup is only done in acpi_pci_unbind() and it only covers
runtime wakeup.

Use the new .setup() and .cleanup() callbacks in struct acpi_bus_type
to consolidate that code and do the setup and the cleanup each in one
place.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Yinghai Lu <yinghai@kernel.org>
Acked-by: Toshi Kani <toshi.kani@hp.com>
  • Loading branch information
Rafael J. Wysocki committed Jan 3, 2013
1 parent 11909ca commit d2e5f0c
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 38 deletions.
2 changes: 1 addition & 1 deletion drivers/acpi/device_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
* acpi_dev_pm_get_node - Get ACPI device node for the given physical device.
* @dev: Device to get the ACPI node for.
*/
static struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
{
acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
struct acpi_device *adev;
Expand Down
5 changes: 0 additions & 5 deletions drivers/acpi/pci_bind.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ static int acpi_pci_unbind(struct acpi_device *device)
if (!dev)
goto out;

device_set_run_wake(&dev->dev, false);
pci_acpi_remove_pm_notifier(device);
acpi_power_resource_unregister_device(&dev->dev, device->handle);

if (!dev->subordinate)
Expand All @@ -71,10 +69,7 @@ static int acpi_pci_bind(struct acpi_device *device)
if (!dev)
return 0;

pci_acpi_add_pm_notifier(device, dev);
acpi_power_resource_register_device(&dev->dev, device->handle);
if (device->wakeup.flags.run_wake)
device_set_run_wake(&dev->dev, true);

/*
* Install the 'bind' function to facilitate callbacks for
Expand Down
30 changes: 29 additions & 1 deletion drivers/pci/pci-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,6 @@ 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,
.can_wakeup = acpi_pci_can_wakeup,
.sleep_wake = acpi_pci_sleep_wake,
.run_wake = acpi_pci_run_wake,
};
Expand Down Expand Up @@ -321,10 +320,39 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle)
return 0;
}

static void acpi_pci_wakeup_setup(struct device *dev)
{
struct acpi_device *adev = acpi_dev_pm_get_node(dev);
struct pci_dev *pci_dev = to_pci_dev(dev);

if (!adev || !adev->wakeup.flags.valid)
return;

device_set_wakeup_capable(dev, true);
acpi_pci_sleep_wake(pci_dev, false);

pci_acpi_add_pm_notifier(adev, pci_dev);
if (adev->wakeup.flags.run_wake)
device_set_run_wake(dev, true);
}

static void acpi_pci_wakeup_cleanup(struct device *dev)
{
struct acpi_device *adev = acpi_dev_pm_get_node(dev);

if (adev && adev->wakeup.flags.valid) {
device_set_wakeup_capable(dev, false);
device_set_run_wake(dev, false);
pci_acpi_remove_pm_notifier(adev);
}
}

static struct acpi_bus_type acpi_pci_bus = {
.bus = &pci_bus_type,
.find_device = acpi_pci_find_device,
.find_bridge = acpi_pci_find_root_bridge,
.setup = acpi_pci_wakeup_setup,
.cleanup = acpi_pci_wakeup_cleanup,
};

static int __init acpi_pci_init(void)
Expand Down
26 changes: 1 addition & 25 deletions drivers/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ 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
|| !ops->sleep_wake || !ops->can_wakeup)
|| !ops->sleep_wake)
return -EINVAL;
pci_platform_pm = ops;
return 0;
Expand All @@ -473,11 +473,6 @@ static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
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 ?
Expand Down Expand Up @@ -1985,25 +1980,6 @@ void pci_pm_init(struct pci_dev *dev)
}
}

/**
* platform_pci_wakeup_init - init platform wakeup if present
* @dev: PCI device
*
* Some devices don't have PCI PM caps but can still generate wakeup
* events through platform methods (like ACPI events). If @dev supports
* platform wakeup events, set the device flag to indicate as much. This
* may be redundant if the device also supports PCI PM caps, but double
* initialization should be safe in that case.
*/
void platform_pci_wakeup_init(struct pci_dev *dev)
{
if (!platform_pci_can_wakeup(dev))
return;

device_set_wakeup_capable(&dev->dev, true);
platform_pci_sleep_wake(dev, false);
}

static void pci_add_saved_cap(struct pci_dev *pci_dev,
struct pci_cap_saved_state *new_cap)
{
Expand Down
5 changes: 0 additions & 5 deletions drivers/pci/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ int pci_probe_reset_function(struct pci_dev *dev);
* 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
*
* @run_wake: enables/disables the platform to generate run-time wake-up events
Expand All @@ -59,7 +56,6 @@ 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);
int (*run_wake)(struct pci_dev *dev, bool enable);
};
Expand All @@ -74,7 +70,6 @@ extern void pci_wakeup_bus(struct pci_bus *bus);
extern void pci_config_pm_runtime_get(struct pci_dev *dev);
extern void pci_config_pm_runtime_put(struct pci_dev *dev);
extern void pci_pm_init(struct pci_dev *dev);
extern void platform_pci_wakeup_init(struct pci_dev *dev);
extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
void pci_free_cap_save_buffers(struct pci_dev *dev);

Expand Down
1 change: 0 additions & 1 deletion drivers/pci/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -1280,7 +1280,6 @@ static void pci_init_capabilities(struct pci_dev *dev)

/* Power Management */
pci_pm_init(dev);
platform_pci_wakeup_init(dev);

/* Vital Product Data */
pci_vpd_pci22_init(dev);
Expand Down
5 changes: 5 additions & 0 deletions include/linux/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -526,9 +526,14 @@ static inline int acpi_subsys_resume_early(struct device *dev) { return 0; }
#endif

#if defined(CONFIG_ACPI) && defined(CONFIG_PM)
struct acpi_device *acpi_dev_pm_get_node(struct device *dev);
int acpi_dev_pm_attach(struct device *dev, bool power_on);
void acpi_dev_pm_detach(struct device *dev, bool power_off);
#else
static inline struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
{
return NULL;
}
static inline int acpi_dev_pm_attach(struct device *dev, bool power_on)
{
return -ENODEV;
Expand Down

0 comments on commit d2e5f0c

Please sign in to comment.