===================================================================
@@ -385,6 +385,7 @@ EXPORT_SYMBOL(acpi_bus_power_manageable)
#ifdef CONFIG_PM
static DEFINE_MUTEX(acpi_pm_notifier_lock);
+static DEFINE_MUTEX(acpi_wakeup_lock);
void acpi_pm_wakeup_event(struct device *dev)
{
@@ -724,14 +725,14 @@ static int acpi_device_wakeup(struct acp
}
/**
- * acpi_pm_device_wakeup - Enable/disable remote wakeup for given device.
+ * __acpi_pm_device_wakeup - Enable/disable remote wakeup for given device.
* @dev: Device to enable/disable to generate wakeup events.
* @enable: Whether to enable or disable the wakeup functionality.
*/
-int acpi_pm_device_wakeup(struct device *dev, bool enable)
+int __acpi_pm_device_wakeup(struct device *dev, bool enable, bool refcount)
{
struct acpi_device *adev;
- int error;
+ int error = 0;
adev = ACPI_COMPANION(dev);
if (!adev) {
@@ -742,13 +743,39 @@ int acpi_pm_device_wakeup(struct device
if (!acpi_device_can_wakeup(adev))
return -EINVAL;
+ if (refcount) {
+ mutex_lock(&acpi_wakeup_lock);
+
+ if (enable) {
+ if (++adev->wakeup.enable_count > 1)
+ goto out;
+ } else {
+ if (WARN_ON_ONCE(adev->wakeup.enable_count == 0))
+ goto out;
+
+ if (--adev->wakeup.enable_count > 0)
+ goto out;
+ }
+ }
error = acpi_device_wakeup(adev, acpi_target_system_state(), enable);
- if (!error)
+ if (error) {
+ if (refcount) {
+ if (enable)
+ adev->wakeup.enable_count--;
+ else
+ adev->wakeup.enable_count++;
+ }
+ } else {
dev_dbg(dev, "Wakeup %s by ACPI\n", enable ? "enabled" : "disabled");
+ }
+
+out:
+ if (refcount)
+ mutex_unlock(&acpi_wakeup_lock);
return error;
}
-EXPORT_SYMBOL(acpi_pm_device_wakeup);
+EXPORT_SYMBOL(__acpi_pm_device_wakeup);
/**
* acpi_dev_pm_low_power - Put ACPI device into a low-power state.
===================================================================
@@ -331,6 +331,7 @@ struct acpi_device_wakeup {
struct acpi_device_wakeup_context context;
struct wakeup_source *ws;
int prepare_count;
+ unsigned int enable_count;
};
struct acpi_device_physical_node {
@@ -603,7 +604,7 @@ acpi_status acpi_add_pm_notifier(struct
acpi_status acpi_remove_pm_notifier(struct acpi_device *adev);
bool acpi_pm_device_can_wakeup(struct device *dev);
int acpi_pm_device_sleep_state(struct device *, int *, int);
-int acpi_pm_device_wakeup(struct device *dev, bool enable);
+int __acpi_pm_device_wakeup(struct device *dev, bool enable, bool refcount);
#else
static inline void acpi_pm_wakeup_event(struct device *dev)
{
@@ -630,12 +631,18 @@ static inline int acpi_pm_device_sleep_s
return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3_COLD) ?
m : ACPI_STATE_D0;
}
-static inline int acpi_pm_device_wakeup(struct device *dev, bool enable)
+static inline int __acpi_pm_device_wakeup(struct device *dev, bool enable,
+ bool refcount)
{
return -ENODEV;
}
#endif
+static inline int acpi_pm_device_wakeup(struct device *dev, bool enable)
+{
+ return __acpi_pm_device_wakeup(dev, enable, false);
+}
+
#ifdef CONFIG_ACPI_SLEEP
u32 acpi_target_system_state(void);
#else
===================================================================
@@ -574,7 +574,7 @@ static int acpi_pci_propagate_wakeup(str
{
while (bus->parent) {
if (acpi_pm_device_can_wakeup(&bus->self->dev))
- return acpi_pm_device_wakeup(&bus->self->dev, enable);
+ return __acpi_pm_device_wakeup(&bus->self->dev, enable, true);
bus = bus->parent;
}
@@ -582,7 +582,7 @@ static int acpi_pci_propagate_wakeup(str
/* We have reached the root bus. */
if (bus->bridge) {
if (acpi_pm_device_can_wakeup(bus->bridge))
- return acpi_pm_device_wakeup(bus->bridge, enable);
+ return __acpi_pm_device_wakeup(bus->bridge, enable, true);
}
return 0;
}