Merge branch 'pm-acpi' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
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
This commit is contained in:
		
						commit
						4d578573b8
					
				| @ -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) { | ||||
| 		/*
 | ||||
| 		 * 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 (ACPI_FAILURE(status)) | ||||
| 				return -ENODEV; | ||||
| 			*state = (int)psc; | ||||
| 		} | ||||
| 	} else { | ||||
| 	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; | ||||
| 	} | ||||
| 
 | ||||
| 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n", | ||||
| 			  device->pnp.bus_id, *state)); | ||||
| 	/*
 | ||||
| 	 * Get the device's power state either directly (via _PSC) or | ||||
| 	 * indirectly (via power resources). | ||||
| 	 */ | ||||
| 	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; | ||||
| 
 | ||||
| 		result = psc; | ||||
| 	} | ||||
| 	/* 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; | ||||
| 
 | ||||
|  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; | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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)) | ||||
| 		acpi_clear_event(ACPI_EVENT_POWER_BUTTON); | ||||
| 	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'; | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user