Skip to content

Commit 99d8845

Browse files
committed
ACPI / PM: Split acpi_device_wakeup()
To prepare for a subsequent change and make the code somewhat easier to follow, do the following in the ACPI device wakeup handling code: * Replace wakeup.flags.enabled under struct acpi_device with wakeup.enable_count as that will be necessary going forward. For now, wakeup.enable_count is not allowed to grow beyond 1, so the current behavior is retained. * Split acpi_device_wakeup() into acpi_device_wakeup_enable() and acpi_device_wakeup_disable() and modify the callers of it accordingly. * Introduce a new acpi_wakeup_lock mutex to protect the wakeup enabling/disabling code from races in case it is executed more than once in parallel for the same device (which may happen for bridges theoretically). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
1 parent baecc47 commit 99d8845

File tree

2 files changed

+80
-43
lines changed

2 files changed

+80
-43
lines changed

drivers/acpi/device_pm.c

Lines changed: 79 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -682,47 +682,74 @@ static void acpi_pm_notify_work_func(struct acpi_device_wakeup_context *context)
682682
}
683683
}
684684

685+
static DEFINE_MUTEX(acpi_wakeup_lock);
686+
685687
/**
686-
* acpi_device_wakeup - Enable/disable wakeup functionality for device.
687-
* @adev: ACPI device to enable/disable wakeup functionality for.
688+
* acpi_device_wakeup_enable - Enable wakeup functionality for device.
689+
* @adev: ACPI device to enable wakeup functionality for.
688690
* @target_state: State the system is transitioning into.
689-
* @enable: Whether to enable or disable the wakeup functionality.
690691
*
691-
* Enable/disable the GPE associated with @adev so that it can generate
692-
* wakeup signals for the device in response to external (remote) events and
693-
* enable/disable device wakeup power.
692+
* Enable the GPE associated with @adev so that it can generate wakeup signals
693+
* for the device in response to external (remote) events and enable wakeup
694+
* power for it.
694695
*
695696
* Callers must ensure that @adev is a valid ACPI device node before executing
696697
* this function.
697698
*/
698-
static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
699-
bool enable)
699+
static int acpi_device_wakeup_enable(struct acpi_device *adev, u32 target_state)
700700
{
701701
struct acpi_device_wakeup *wakeup = &adev->wakeup;
702+
acpi_status status;
703+
int error = 0;
702704

703-
if (enable) {
704-
acpi_status res;
705-
int error;
705+
mutex_lock(&acpi_wakeup_lock);
706706

707-
if (adev->wakeup.flags.enabled)
708-
return 0;
707+
if (wakeup->enable_count > 0)
708+
goto out;
709709

710-
error = acpi_enable_wakeup_device_power(adev, target_state);
711-
if (error)
712-
return error;
710+
error = acpi_enable_wakeup_device_power(adev, target_state);
711+
if (error)
712+
goto out;
713713

714-
res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
715-
if (ACPI_FAILURE(res)) {
716-
acpi_disable_wakeup_device_power(adev);
717-
return -EIO;
718-
}
719-
adev->wakeup.flags.enabled = 1;
720-
} else if (adev->wakeup.flags.enabled) {
721-
acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
714+
status = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
715+
if (ACPI_FAILURE(status)) {
722716
acpi_disable_wakeup_device_power(adev);
723-
adev->wakeup.flags.enabled = 0;
717+
error = -EIO;
718+
goto out;
724719
}
725-
return 0;
720+
721+
wakeup->enable_count++;
722+
723+
out:
724+
mutex_unlock(&acpi_wakeup_lock);
725+
return error;
726+
}
727+
728+
/**
729+
* acpi_device_wakeup_disable - Disable wakeup functionality for device.
730+
* @adev: ACPI device to disable wakeup functionality for.
731+
*
732+
* Disable the GPE associated with @adev and disable wakeup power for it.
733+
*
734+
* Callers must ensure that @adev is a valid ACPI device node before executing
735+
* this function.
736+
*/
737+
static void acpi_device_wakeup_disable(struct acpi_device *adev)
738+
{
739+
struct acpi_device_wakeup *wakeup = &adev->wakeup;
740+
741+
mutex_lock(&acpi_wakeup_lock);
742+
743+
if (!wakeup->enable_count)
744+
goto out;
745+
746+
acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
747+
acpi_disable_wakeup_device_power(adev);
748+
749+
wakeup->enable_count--;
750+
751+
out:
752+
mutex_unlock(&acpi_wakeup_lock);
726753
}
727754

728755
/**
@@ -744,9 +771,15 @@ int acpi_pm_set_device_wakeup(struct device *dev, bool enable)
744771
if (!acpi_device_can_wakeup(adev))
745772
return -EINVAL;
746773

747-
error = acpi_device_wakeup(adev, acpi_target_system_state(), enable);
774+
if (!enable) {
775+
acpi_device_wakeup_disable(adev);
776+
dev_dbg(dev, "Wakeup disabled by ACPI\n");
777+
return 0;
778+
}
779+
780+
error = acpi_device_wakeup_enable(adev, acpi_target_system_state());
748781
if (!error)
749-
dev_dbg(dev, "Wakeup %s by ACPI\n", enable ? "enabled" : "disabled");
782+
dev_dbg(dev, "Wakeup enabled by ACPI\n");
750783

751784
return error;
752785
}
@@ -800,13 +833,15 @@ int acpi_dev_runtime_suspend(struct device *dev)
800833

801834
remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) >
802835
PM_QOS_FLAGS_NONE;
803-
error = acpi_device_wakeup(adev, ACPI_STATE_S0, remote_wakeup);
804-
if (remote_wakeup && error)
805-
return -EAGAIN;
836+
if (remote_wakeup) {
837+
error = acpi_device_wakeup_enable(adev, ACPI_STATE_S0);
838+
if (error)
839+
return -EAGAIN;
840+
}
806841

807842
error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
808-
if (error)
809-
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
843+
if (error && remote_wakeup)
844+
acpi_device_wakeup_disable(adev);
810845

811846
return error;
812847
}
@@ -829,7 +864,7 @@ int acpi_dev_runtime_resume(struct device *dev)
829864
return 0;
830865

831866
error = acpi_dev_pm_full_power(adev);
832-
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
867+
acpi_device_wakeup_disable(adev);
833868
return error;
834869
}
835870
EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
@@ -884,13 +919,15 @@ int acpi_dev_suspend_late(struct device *dev)
884919

885920
target_state = acpi_target_system_state();
886921
wakeup = device_may_wakeup(dev) && acpi_device_can_wakeup(adev);
887-
error = acpi_device_wakeup(adev, target_state, wakeup);
888-
if (wakeup && error)
889-
return error;
922+
if (wakeup) {
923+
error = acpi_device_wakeup_enable(adev, target_state);
924+
if (error)
925+
return error;
926+
}
890927

891928
error = acpi_dev_pm_low_power(dev, adev, target_state);
892-
if (error)
893-
acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
929+
if (error && wakeup)
930+
acpi_device_wakeup_disable(adev);
894931

895932
return error;
896933
}
@@ -913,7 +950,7 @@ int acpi_dev_resume_early(struct device *dev)
913950
return 0;
914951

915952
error = acpi_dev_pm_full_power(adev);
916-
acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
953+
acpi_device_wakeup_disable(adev);
917954
return error;
918955
}
919956
EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
@@ -1056,7 +1093,7 @@ static void acpi_dev_pm_detach(struct device *dev, bool power_off)
10561093
*/
10571094
dev_pm_qos_hide_latency_limit(dev);
10581095
dev_pm_qos_hide_flags(dev);
1059-
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
1096+
acpi_device_wakeup_disable(adev);
10601097
acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
10611098
}
10621099
}
@@ -1100,7 +1137,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
11001137
dev_pm_domain_set(dev, &acpi_general_pm_domain);
11011138
if (power_on) {
11021139
acpi_dev_pm_full_power(adev);
1103-
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
1140+
acpi_device_wakeup_disable(adev);
11041141
}
11051142

11061143
dev->pm_domain->detach = acpi_dev_pm_detach;

include/acpi/acpi_bus.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,6 @@ struct acpi_device_perf {
316316
struct acpi_device_wakeup_flags {
317317
u8 valid:1; /* Can successfully enable wakeup? */
318318
u8 notifier_present:1; /* Wake-up notify handler has been installed */
319-
u8 enabled:1; /* Enabled for wakeup */
320319
};
321320

322321
struct acpi_device_wakeup_context {
@@ -333,6 +332,7 @@ struct acpi_device_wakeup {
333332
struct acpi_device_wakeup_context context;
334333
struct wakeup_source *ws;
335334
int prepare_count;
335+
int enable_count;
336336
};
337337

338338
struct acpi_device_physical_node {

0 commit comments

Comments
 (0)