Skip to content

Commit

Permalink
Merge branches 'acpi-scan' and 'acpi-pm'
Browse files Browse the repository at this point in the history
* acpi-scan:
  ACPI / scan: Enable GPEs before scanning the namespace
  ACPICA: Make it possible to enable runtime GPEs earlier
  ACPICA: Dispatch active GPEs at init time

* acpi-pm:
  ACPI / PM: Add debug statements to acpi_pm_notify_handler()
  ACPI: Add debug statements to acpi_global_event_handler()
  ACPI / sleep: Make acpi_sleep_syscore_init() static
  ACPI / PCI / PM: Rework acpi_pci_propagate_wakeup()
  ACPI / PM: Split acpi_device_wakeup()
  PCI / PM: Skip bridges in pci_enable_wake()
  • Loading branch information
Rafael J. Wysocki committed Sep 3, 2017
3 parents b2a84ee + eb7f43c + 020a637 commit 4467ade
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 75 deletions.
30 changes: 21 additions & 9 deletions drivers/acpi/acpica/evgpeblk.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,9 +440,11 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
void *ignored)
{
acpi_status status;
acpi_event_status event_status;
struct acpi_gpe_event_info *gpe_event_info;
u32 gpe_enabled_count;
u32 gpe_index;
u32 gpe_number;
u32 i;
u32 j;

Expand Down Expand Up @@ -470,30 +472,40 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,

gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
gpe_event_info = &gpe_block->event_info[gpe_index];
gpe_number = gpe_block->block_base_number + gpe_index;

/*
* Ignore GPEs that have no corresponding _Lxx/_Exx method
* and GPEs that are used to wake the system
* and GPEs that are used for wakeup
*/
if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_NONE)
|| (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_HANDLER)
|| (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_RAW_HANDLER)
if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
ACPI_GPE_DISPATCH_METHOD)
|| (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
continue;
}

event_status = 0;
(void)acpi_hw_get_gpe_status(gpe_event_info,
&event_status);

status = acpi_ev_add_gpe_reference(gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Could not enable GPE 0x%02X",
gpe_index +
gpe_block->block_base_number));
gpe_number));
continue;
}

gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED;

if (event_status & ACPI_EVENT_FLAG_STATUS_SET) {
ACPI_INFO(("GPE 0x%02X active on init",
gpe_number));
(void)acpi_ev_gpe_dispatch(gpe_block->node,
gpe_event_info,
gpe_number);
}

gpe_enabled_count++;
}
}
Expand Down
8 changes: 8 additions & 0 deletions drivers/acpi/acpica/evxfgpe.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,14 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
*/
gpe_event_info->flags =
(ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED);
} else if (gpe_event_info->flags & ACPI_GPE_AUTO_ENABLED) {
/*
* A reference to this GPE has been added during the GPE block
* initialization, so drop it now to prevent the GPE from being
* permanently enabled and clear its ACPI_GPE_AUTO_ENABLED flag.
*/
(void)acpi_ev_remove_gpe_reference(gpe_event_info);
gpe_event_info->flags &= ~ACPI_GPE_AUTO_ENABLED;
}

/*
Expand Down
175 changes: 123 additions & 52 deletions drivers/acpi/device_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,8 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
if (val != ACPI_NOTIFY_DEVICE_WAKE)
return;

acpi_handle_debug(handle, "Wake notify\n");

adev = acpi_bus_get_acpi_device(handle);
if (!adev)
return;
Expand All @@ -409,8 +411,12 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)

if (adev->wakeup.flags.notifier_present) {
pm_wakeup_ws_event(adev->wakeup.ws, 0, acpi_s2idle_wakeup());
if (adev->wakeup.context.func)
if (adev->wakeup.context.func) {
acpi_handle_debug(handle, "Running %pF for %s\n",
adev->wakeup.context.func,
dev_name(adev->wakeup.context.dev));
adev->wakeup.context.func(&adev->wakeup.context);
}
}

mutex_unlock(&acpi_pm_notifier_lock);
Expand Down Expand Up @@ -682,55 +688,88 @@ static void acpi_pm_notify_work_func(struct acpi_device_wakeup_context *context)
}
}

static DEFINE_MUTEX(acpi_wakeup_lock);

static int __acpi_device_wakeup_enable(struct acpi_device *adev,
u32 target_state, int max_count)
{
struct acpi_device_wakeup *wakeup = &adev->wakeup;
acpi_status status;
int error = 0;

mutex_lock(&acpi_wakeup_lock);

if (wakeup->enable_count >= max_count)
goto out;

if (wakeup->enable_count > 0)
goto inc;

error = acpi_enable_wakeup_device_power(adev, target_state);
if (error)
goto out;

status = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
if (ACPI_FAILURE(status)) {
acpi_disable_wakeup_device_power(adev);
error = -EIO;
goto out;
}

inc:
wakeup->enable_count++;

out:
mutex_unlock(&acpi_wakeup_lock);
return error;
}

/**
* acpi_device_wakeup - Enable/disable wakeup functionality for device.
* @adev: ACPI device to enable/disable wakeup functionality for.
* acpi_device_wakeup_enable - Enable wakeup functionality for device.
* @adev: ACPI device to enable wakeup functionality for.
* @target_state: State the system is transitioning into.
* @enable: Whether to enable or disable the wakeup functionality.
*
* Enable/disable the GPE associated with @adev so that it can generate
* wakeup signals for the device in response to external (remote) events and
* enable/disable device wakeup power.
* Enable the GPE associated with @adev so that it can generate wakeup signals
* for the device in response to external (remote) events and enable wakeup
* power for it.
*
* Callers must ensure that @adev is a valid ACPI device node before executing
* this function.
*/
static int acpi_device_wakeup_enable(struct acpi_device *adev, u32 target_state)
{
return __acpi_device_wakeup_enable(adev, target_state, 1);
}

/**
* acpi_device_wakeup_disable - Disable wakeup functionality for device.
* @adev: ACPI device to disable wakeup functionality for.
*
* Disable the GPE associated with @adev and disable wakeup power for it.
*
* Callers must ensure that @adev is a valid ACPI device node before executing
* this function.
*/
static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
bool enable)
static void acpi_device_wakeup_disable(struct acpi_device *adev)
{
struct acpi_device_wakeup *wakeup = &adev->wakeup;

if (enable) {
acpi_status res;
int error;
mutex_lock(&acpi_wakeup_lock);

if (adev->wakeup.flags.enabled)
return 0;
if (!wakeup->enable_count)
goto out;

error = acpi_enable_wakeup_device_power(adev, target_state);
if (error)
return error;
acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
acpi_disable_wakeup_device_power(adev);

res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
if (ACPI_FAILURE(res)) {
acpi_disable_wakeup_device_power(adev);
return -EIO;
}
adev->wakeup.flags.enabled = 1;
} else if (adev->wakeup.flags.enabled) {
acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
acpi_disable_wakeup_device_power(adev);
adev->wakeup.flags.enabled = 0;
}
return 0;
wakeup->enable_count--;

out:
mutex_unlock(&acpi_wakeup_lock);
}

/**
* acpi_pm_set_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_set_device_wakeup(struct device *dev, bool enable)
static int __acpi_pm_set_device_wakeup(struct device *dev, bool enable,
int max_count)
{
struct acpi_device *adev;
int error;
Expand All @@ -744,13 +783,41 @@ int acpi_pm_set_device_wakeup(struct device *dev, bool enable)
if (!acpi_device_can_wakeup(adev))
return -EINVAL;

error = acpi_device_wakeup(adev, acpi_target_system_state(), enable);
if (!enable) {
acpi_device_wakeup_disable(adev);
dev_dbg(dev, "Wakeup disabled by ACPI\n");
return 0;
}

error = __acpi_device_wakeup_enable(adev, acpi_target_system_state(),
max_count);
if (!error)
dev_dbg(dev, "Wakeup %s by ACPI\n", enable ? "enabled" : "disabled");
dev_dbg(dev, "Wakeup enabled by ACPI\n");

return error;
}
EXPORT_SYMBOL(acpi_pm_set_device_wakeup);

/**
* acpi_pm_set_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_set_device_wakeup(struct device *dev, bool enable)
{
return __acpi_pm_set_device_wakeup(dev, enable, 1);
}
EXPORT_SYMBOL_GPL(acpi_pm_set_device_wakeup);

/**
* acpi_pm_set_bridge_wakeup - Enable/disable remote wakeup for given bridge.
* @dev: Bridge device to enable/disable to generate wakeup events.
* @enable: Whether to enable or disable the wakeup functionality.
*/
int acpi_pm_set_bridge_wakeup(struct device *dev, bool enable)
{
return __acpi_pm_set_device_wakeup(dev, enable, INT_MAX);
}
EXPORT_SYMBOL_GPL(acpi_pm_set_bridge_wakeup);

/**
* acpi_dev_pm_low_power - Put ACPI device into a low-power state.
Expand Down Expand Up @@ -800,13 +867,15 @@ int acpi_dev_runtime_suspend(struct device *dev)

remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) >
PM_QOS_FLAGS_NONE;
error = acpi_device_wakeup(adev, ACPI_STATE_S0, remote_wakeup);
if (remote_wakeup && error)
return -EAGAIN;
if (remote_wakeup) {
error = acpi_device_wakeup_enable(adev, ACPI_STATE_S0);
if (error)
return -EAGAIN;
}

error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
if (error)
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
if (error && remote_wakeup)
acpi_device_wakeup_disable(adev);

return error;
}
Expand All @@ -829,7 +898,7 @@ int acpi_dev_runtime_resume(struct device *dev)
return 0;

error = acpi_dev_pm_full_power(adev);
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
acpi_device_wakeup_disable(adev);
return error;
}
EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
Expand Down Expand Up @@ -884,13 +953,15 @@ int acpi_dev_suspend_late(struct device *dev)

target_state = acpi_target_system_state();
wakeup = device_may_wakeup(dev) && acpi_device_can_wakeup(adev);
error = acpi_device_wakeup(adev, target_state, wakeup);
if (wakeup && error)
return error;
if (wakeup) {
error = acpi_device_wakeup_enable(adev, target_state);
if (error)
return error;
}

error = acpi_dev_pm_low_power(dev, adev, target_state);
if (error)
acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
if (error && wakeup)
acpi_device_wakeup_disable(adev);

return error;
}
Expand All @@ -913,7 +984,7 @@ int acpi_dev_resume_early(struct device *dev)
return 0;

error = acpi_dev_pm_full_power(adev);
acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
acpi_device_wakeup_disable(adev);
return error;
}
EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
Expand Down Expand Up @@ -1056,7 +1127,7 @@ static void acpi_dev_pm_detach(struct device *dev, bool power_off)
*/
dev_pm_qos_hide_latency_limit(dev);
dev_pm_qos_hide_flags(dev);
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
acpi_device_wakeup_disable(adev);
acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
}
}
Expand Down Expand Up @@ -1100,7 +1171,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
dev_pm_domain_set(dev, &acpi_general_pm_domain);
if (power_on) {
acpi_dev_pm_full_power(adev);
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
acpi_device_wakeup_disable(adev);
}

dev->pm_domain->detach = acpi_dev_pm_detach;
Expand Down
6 changes: 3 additions & 3 deletions drivers/acpi/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -2058,6 +2058,9 @@ int __init acpi_scan_init(void)
acpi_get_spcr_uart_addr();
}

acpi_gpe_apply_masked_gpes();
acpi_update_all_gpes();

mutex_lock(&acpi_scan_lock);
/*
* Enumerate devices in the ACPI namespace.
Expand All @@ -2082,9 +2085,6 @@ int __init acpi_scan_init(void)
}
}

acpi_gpe_apply_masked_gpes();
acpi_update_all_gpes();

acpi_scan_initialized = true;

out:
Expand Down
2 changes: 1 addition & 1 deletion drivers/acpi/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ static struct syscore_ops acpi_sleep_syscore_ops = {
.resume = acpi_restore_bm_rld,
};

void acpi_sleep_syscore_init(void)
static void acpi_sleep_syscore_init(void)
{
register_syscore_ops(&acpi_sleep_syscore_ops);
}
Expand Down
Loading

0 comments on commit 4467ade

Please sign in to comment.