Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d578573 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull some left-over PM patches from Rafael J. Wysocki.

* 'pm-acpi' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI / PM: Make acpi_pm_device_sleep_state() follow the specification
  ACPI / PM: Make __acpi_bus_get_power() cover D3cold correctly
  ACPI / PM: Fix error messages in drivers/acpi/bus.c
  rtc-cmos / PM: report wakeup event on ACPI RTC alarm
  ACPI / PM: Generate wakeup events on fixed power button
parents 68e3e926 dbe9a2ed
Loading
Loading
Loading
Loading
+57 −31
Original line number Diff line number Diff line
@@ -182,41 +182,66 @@ EXPORT_SYMBOL(acpi_bus_get_private_data);
                                 Power Management
   -------------------------------------------------------------------------- */

static const char *state_string(int state)
{
	switch (state) {
	case ACPI_STATE_D0:
		return "D0";
	case ACPI_STATE_D1:
		return "D1";
	case ACPI_STATE_D2:
		return "D2";
	case ACPI_STATE_D3_HOT:
		return "D3hot";
	case ACPI_STATE_D3_COLD:
		return "D3";
	default:
		return "(unknown)";
	}
}

static int __acpi_bus_get_power(struct acpi_device *device, int *state)
{
	int result = 0;
	acpi_status status = 0;
	unsigned long long psc = 0;
	int result = ACPI_STATE_UNKNOWN;

	if (!device || !state)
		return -EINVAL;

	*state = ACPI_STATE_UNKNOWN;
	if (!device->flags.power_manageable) {
		/* TBD: Non-recursive algorithm for walking up hierarchy. */
		*state = device->parent ?
			device->parent->power.state : ACPI_STATE_D0;
		goto out;
	}

	if (device->flags.power_manageable) {
	/*
	 * Get the device's power state either directly (via _PSC) or
	 * indirectly (via power resources).
	 */
		if (device->power.flags.power_resources) {
			result = acpi_power_get_inferred_state(device, state);
			if (result)
				return result;
		} else if (device->power.flags.explicit_get) {
			status = acpi_evaluate_integer(device->handle, "_PSC",
						       NULL, &psc);
	if (device->power.flags.explicit_get) {
		unsigned long long psc;
		acpi_status status = acpi_evaluate_integer(device->handle,
							   "_PSC", NULL, &psc);
		if (ACPI_FAILURE(status))
			return -ENODEV;
			*state = (int)psc;

		result = psc;
	}
	} else {
		/* TBD: Non-recursive algorithm for walking up hierarchy. */
		*state = device->parent ?
			device->parent->power.state : ACPI_STATE_D0;
	/* The test below covers ACPI_STATE_UNKNOWN too. */
	if (result <= ACPI_STATE_D2) {
	  ; /* Do nothing. */
	} else if (device->power.flags.power_resources) {
		int error = acpi_power_get_inferred_state(device, &result);
		if (error)
			return error;
	} else if (result == ACPI_STATE_D3_HOT) {
		result = ACPI_STATE_D3;
	}
	*state = result;

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n",
			  device->pnp.bus_id, *state));
 out:
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
			  device->pnp.bus_id, state_string(*state)));

	return 0;
}
@@ -234,13 +259,14 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state)
	/* Make sure this is a valid target state */

	if (state == device->power.state) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
				  state));
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
				  state_string(state)));
		return 0;
	}

	if (!device->power.states[state].flags.valid) {
		printk(KERN_WARNING PREFIX "Device does not support D%d\n", state);
		printk(KERN_WARNING PREFIX "Device does not support %s\n",
		       state_string(state));
		return -ENODEV;
	}
	if (device->parent && (state < device->parent->power.state)) {
@@ -294,13 +320,13 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state)
      end:
	if (result)
		printk(KERN_WARNING PREFIX
			      "Device [%s] failed to transition to D%d\n",
			      device->pnp.bus_id, state);
			      "Device [%s] failed to transition to %s\n",
			      device->pnp.bus_id, state_string(state));
	else {
		device->power.state = state;
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Device [%s] transitioned to D%d\n",
				  device->pnp.bus_id, state));
				  "Device [%s] transitioned to %s\n",
				  device->pnp.bus_id, state_string(state)));
	}

	return result;
+1 −1
Original line number Diff line number Diff line
@@ -631,7 +631,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
	 * We know a device's inferred power state when all the resources
	 * required for a given D-state are 'on'.
	 */
	for (i = ACPI_STATE_D0; i < ACPI_STATE_D3_HOT; i++) {
	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
		list = &device->power.states[i].resources;
		if (list->count < 1)
			continue;
+1 −0
Original line number Diff line number Diff line
@@ -1567,6 +1567,7 @@ static int acpi_bus_scan_fixed(void)
						ACPI_BUS_TYPE_POWER_BUTTON,
						ACPI_STA_DEFAULT,
						&ops);
		device_init_wakeup(&device->dev, true);
	}

	if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
+45 −4
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend.");
MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".);

static u8 sleep_states[ACPI_S_STATE_COUNT];
static bool pwr_btn_event_pending;

static void acpi_sleep_tts_switch(u32 acpi_state)
{
@@ -184,6 +185,14 @@ static int acpi_pm_prepare(void)
	return error;
}

static int find_powerf_dev(struct device *dev, void *data)
{
	struct acpi_device *device = to_acpi_device(dev);
	const char *hid = acpi_device_hid(device);

	return !strcmp(hid, ACPI_BUTTON_HID_POWERF);
}

/**
 *	acpi_pm_finish - Instruct the platform to leave a sleep state.
 *
@@ -192,6 +201,7 @@ static int acpi_pm_prepare(void)
 */
static void acpi_pm_finish(void)
{
	struct device *pwr_btn_dev;
	u32 acpi_state = acpi_target_sleep_state;

	acpi_ec_unblock_transactions();
@@ -209,6 +219,23 @@ static void acpi_pm_finish(void)
	acpi_set_firmware_waking_vector((acpi_physical_address) 0);

	acpi_target_sleep_state = ACPI_STATE_S0;

	/* If we were woken with the fixed power button, provide a small
	 * hint to userspace in the form of a wakeup event on the fixed power
	 * button device (if it can be found).
	 *
	 * We delay the event generation til now, as the PM layer requires
	 * timekeeping to be running before we generate events. */
	if (!pwr_btn_event_pending)
		return;

	pwr_btn_event_pending = false;
	pwr_btn_dev = bus_find_device(&acpi_bus_type, NULL, NULL,
				      find_powerf_dev);
	if (pwr_btn_dev) {
		pm_wakeup_event(pwr_btn_dev, 0);
		put_device(pwr_btn_dev);
	}
}

/**
@@ -298,9 +325,23 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
	/* ACPI 3.0 specs (P62) says that it's the responsibility
	 * of the OSPM to clear the status bit [ implying that the
	 * POWER_BUTTON event should not reach userspace ]
	 *
	 * However, we do generate a small hint for userspace in the form of
	 * a wakeup event. We flag this condition for now and generate the
	 * event later, as we're currently too early in resume to be able to
	 * generate wakeup events.
	 */
	if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
	if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) {
		acpi_event_status pwr_btn_status;

		acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status);

		if (pwr_btn_status & ACPI_EVENT_FLAG_SET) {
			acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
			/* Flag for later */
			pwr_btn_event_pending = true;
		}
	}

	/*
	 * Disable and clear GPE status before interrupt is enabled. Some GPEs
@@ -730,8 +771,8 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
	 * can wake the system.  _S0W may be valid, too.
	 */
	if (acpi_target_sleep_state == ACPI_STATE_S0 ||
	    (device_may_wakeup(dev) &&
	     adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
	    (device_may_wakeup(dev) && adev->wakeup.flags.valid &&
	     adev->wakeup.sleep_state >= acpi_target_sleep_state)) {
		acpi_status status;

		acpi_method[3] = 'W';
+6 −3
Original line number Diff line number Diff line
@@ -910,14 +910,17 @@ static inline int cmos_poweroff(struct device *dev)

static u32 rtc_handler(void *context)
{
	struct device *dev = context;

	pm_wakeup_event(dev, 0);
	acpi_clear_event(ACPI_EVENT_RTC);
	acpi_disable_event(ACPI_EVENT_RTC, 0);
	return ACPI_INTERRUPT_HANDLED;
}

static inline void rtc_wake_setup(void)
static inline void rtc_wake_setup(struct device *dev)
{
	acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
	acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, dev);
	/*
	 * After the RTC handler is installed, the Fixed_RTC event should
	 * be disabled. Only when the RTC alarm is set will it be enabled.
@@ -950,7 +953,7 @@ cmos_wake_setup(struct device *dev)
	if (acpi_disabled)
		return;

	rtc_wake_setup();
	rtc_wake_setup(dev);
	acpi_rtc_info.wake_on = rtc_wake_on;
	acpi_rtc_info.wake_off = rtc_wake_off;