Loading drivers/acpi/sleep/main.c +127 −33 Original line number Diff line number Diff line Loading @@ -34,35 +34,55 @@ static u32 acpi_suspend_states[] = { static int init_8259A_after_S1; extern int acpi_sleep_prepare(u32 acpi_state); extern void acpi_power_off(void); static u32 acpi_target_sleep_state = ACPI_STATE_S0; /** * acpi_pm_set_target - Set the target system sleep state to the state * associated with given @pm_state, if supported. */ static int acpi_pm_set_target(suspend_state_t pm_state) { u32 acpi_state = acpi_suspend_states[pm_state]; int error = 0; if (sleep_states[acpi_state]) { acpi_target_sleep_state = acpi_state; } else { printk(KERN_ERR "ACPI does not support this state: %d\n", pm_state); error = -ENOSYS; } return error; } /** * acpi_pm_prepare - Do preliminary suspend work. * @pm_state: suspend state we're entering. * @pm_state: ignored * * Make sure we support the state. If we do, and we need it, set the * firmware waking vector and do arch-specific nastiness to get the * wakeup code to the waking vector. * If necessary, set the firmware waking vector and do arch-specific * nastiness to get the wakeup code to the waking vector. */ extern int acpi_sleep_prepare(u32 acpi_state); extern void acpi_power_off(void); static int acpi_pm_prepare(suspend_state_t pm_state) { u32 acpi_state = acpi_suspend_states[pm_state]; int error = acpi_sleep_prepare(acpi_target_sleep_state); if (!sleep_states[acpi_state]) { printk("acpi_pm_prepare does not support %d \n", pm_state); return -EPERM; } return acpi_sleep_prepare(acpi_state); if (error) acpi_target_sleep_state = ACPI_STATE_S0; return error; } /** * acpi_pm_enter - Actually enter a sleep state. * @pm_state: State we're entering. * @pm_state: ignored * * Flush caches and go to sleep. For STR or STD, we have to call * arch-specific assembly, which in turn call acpi_enter_sleep_state(). * Flush caches and go to sleep. For STR we have to call arch-specific * assembly, which in turn call acpi_enter_sleep_state(). * It's unfortunate, but it works. Please fix if you're feeling frisky. */ Loading @@ -70,31 +90,31 @@ static int acpi_pm_enter(suspend_state_t pm_state) { acpi_status status = AE_OK; unsigned long flags = 0; u32 acpi_state = acpi_suspend_states[pm_state]; u32 acpi_state = acpi_target_sleep_state; ACPI_FLUSH_CPU_CACHE(); /* Do arch specific saving of state. */ if (pm_state > PM_SUSPEND_STANDBY) { if (acpi_state == ACPI_STATE_S3) { int error = acpi_save_state_mem(); if (error) if (error) { acpi_target_sleep_state = ACPI_STATE_S0; return error; } } local_irq_save(flags); acpi_enable_wakeup_device(acpi_state); switch (pm_state) { case PM_SUSPEND_STANDBY: switch (acpi_state) { case ACPI_STATE_S1: barrier(); status = acpi_enter_sleep_state(acpi_state); break; case PM_SUSPEND_MEM: case ACPI_STATE_S3: do_suspend_lowlevel(); break; default: return -EINVAL; } /* ACPI 3.0 specs (P62) says that it's the responsabilty Loading @@ -107,12 +127,8 @@ static int acpi_pm_enter(suspend_state_t pm_state) local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); /* restore processor state * We should only be here if we're coming back from STR or STD. * And, in the case of the latter, the memory image should have already * been loaded from disk. */ if (pm_state > PM_SUSPEND_STANDBY) /* restore processor state */ if (acpi_state == ACPI_STATE_S3) acpi_restore_state_mem(); return ACPI_SUCCESS(status) ? 0 : -EFAULT; Loading @@ -120,7 +136,7 @@ static int acpi_pm_enter(suspend_state_t pm_state) /** * acpi_pm_finish - Finish up suspend sequence. * @pm_state: State we're coming out of. * @pm_state: ignored * * This is called after we wake back up (or if entering the sleep state * failed). Loading @@ -128,7 +144,7 @@ static int acpi_pm_enter(suspend_state_t pm_state) static int acpi_pm_finish(suspend_state_t pm_state) { u32 acpi_state = acpi_suspend_states[pm_state]; u32 acpi_state = acpi_target_sleep_state; acpi_leave_sleep_state(acpi_state); acpi_disable_wakeup_device(acpi_state); Loading @@ -136,6 +152,8 @@ static int acpi_pm_finish(suspend_state_t pm_state) /* reset firmware waking vector */ acpi_set_firmware_waking_vector((acpi_physical_address) 0); acpi_target_sleep_state = ACPI_STATE_S0; #ifdef CONFIG_X86 if (init_8259A_after_S1) { printk("Broken toshiba laptop -> kicking interrupts\n"); Loading Loading @@ -178,6 +196,7 @@ static int acpi_pm_state_valid(suspend_state_t pm_state) static struct pm_ops acpi_pm_ops = { .valid = acpi_pm_state_valid, .set_target = acpi_pm_set_target, .prepare = acpi_pm_prepare, .enter = acpi_pm_enter, .finish = acpi_pm_finish, Loading Loading @@ -237,6 +256,81 @@ static struct hibernation_ops acpi_hibernation_ops = { }; #endif /* CONFIG_SOFTWARE_SUSPEND */ /** * acpi_pm_device_sleep_state - return preferred power state of ACPI device * in the system sleep state given by %acpi_target_sleep_state * @dev: device to examine * @wake: if set, the device should be able to wake up the system * @d_min_p: used to store the upper limit of allowed states range * Return value: preferred power state of the device on success, -ENODEV on * failure (ie. if there's no 'struct acpi_device' for @dev) * * Find the lowest power (highest number) ACPI device power state that * device @dev can be in while the system is in the sleep state represented * by %acpi_target_sleep_state. If @wake is nonzero, the device should be * able to wake up the system from this sleep state. If @d_min_p is set, * the highest power (lowest number) device power state of @dev allowed * in this system sleep state is stored at the location pointed to by it. * * The caller must ensure that @dev is valid before using this function. * The caller is also responsible for figuring out if the device is * supposed to be able to wake up the system and passing this information * via @wake. */ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p) { acpi_handle handle = DEVICE_ACPI_HANDLE(dev); struct acpi_device *adev; char acpi_method[] = "_SxD"; unsigned long d_min, d_max; if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { printk(KERN_ERR "ACPI handle has no context!\n"); return -ENODEV; } acpi_method[2] = '0' + acpi_target_sleep_state; /* * If the sleep state is S0, we will return D3, but if the device has * _S0W, we will use the value from _S0W */ d_min = ACPI_STATE_D0; d_max = ACPI_STATE_D3; /* * If present, _SxD methods return the minimum D-state (highest power * state) we can use for the corresponding S-states. Otherwise, the * minimum D-state is D0 (ACPI 3.x). * * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer * provided -- that's our fault recovery, we ignore retval. */ if (acpi_target_sleep_state > ACPI_STATE_S0) acpi_evaluate_integer(handle, acpi_method, NULL, &d_min); /* * If _PRW says we can wake up the system from the target sleep state, * the D-state returned by _SxD is sufficient for that (we assume a * wakeup-aware driver if wake is set). Still, if _SxW exists * (ACPI 3.x), it should return the maximum (lowest power) D-state that * can wake the system. _S0W may be valid, too. */ if (acpi_target_sleep_state == ACPI_STATE_S0 || (wake && adev->wakeup.state.enabled && adev->wakeup.sleep_state <= acpi_target_sleep_state)) { acpi_method[3] = 'W'; acpi_evaluate_integer(handle, acpi_method, NULL, &d_max); /* Sanity check */ if (d_max < d_min) d_min = d_max; } if (d_min_p) *d_min_p = d_min; return d_max; } /* * Toshiba fails to preserve interrupts over S1, reinitialization * of 8259 is needed after S1 resume. Loading drivers/pci/pci-acpi.c +24 −4 Original line number Diff line number Diff line Loading @@ -245,16 +245,33 @@ EXPORT_SYMBOL(pci_osc_control_set); * currently we simply return _SxD, if present. */ static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) { /* TBD */ return -ENODEV; int acpi_state; acpi_state = acpi_pm_device_sleep_state(&pdev->dev, device_may_wakeup(&pdev->dev), NULL); if (acpi_state < 0) return PCI_POWER_ERROR; switch (acpi_state) { case ACPI_STATE_D0: return PCI_D0; case ACPI_STATE_D1: return PCI_D1; case ACPI_STATE_D2: return PCI_D2; case ACPI_STATE_D3: return PCI_D3hot; } return PCI_POWER_ERROR; } static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) { acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); acpi_handle tmp; static int state_conv[] = { [0] = 0, [1] = 1, Loading @@ -266,6 +283,9 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) if (!handle) return -ENODEV; /* If the ACPI device has _EJ0, ignore the device */ if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) return 0; return acpi_bus_set_power(handle, acpi_state); } Loading drivers/pci/pci.c +4 −4 Original line number Diff line number Diff line Loading @@ -499,7 +499,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) return 0; } int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); /** * pci_choose_state - Choose the power state of a PCI device Loading @@ -513,15 +513,15 @@ int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { int ret; pci_power_t ret; if (!pci_find_capability(dev, PCI_CAP_ID_PM)) return PCI_D0; if (platform_pci_choose_state) { ret = platform_pci_choose_state(dev, state); if (ret >= 0) state.event = ret; if (ret != PCI_POWER_ERROR) return ret; } switch (state.event) { Loading drivers/pci/pci.h +1 −1 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t, resource_size_t), void *alignf_data); /* Firmware callbacks */ extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state); extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); Loading drivers/pnp/driver.c +5 −0 Original line number Diff line number Diff line Loading @@ -167,6 +167,8 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state) return error; } if (pnp_dev->protocol && pnp_dev->protocol->suspend) pnp_dev->protocol->suspend(pnp_dev, state); return 0; } Loading @@ -179,6 +181,9 @@ static int pnp_bus_resume(struct device *dev) if (!pnp_drv) return 0; if (pnp_dev->protocol && pnp_dev->protocol->resume) pnp_dev->protocol->resume(pnp_dev); if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) { error = pnp_start_dev(pnp_dev); if (error) Loading Loading
drivers/acpi/sleep/main.c +127 −33 Original line number Diff line number Diff line Loading @@ -34,35 +34,55 @@ static u32 acpi_suspend_states[] = { static int init_8259A_after_S1; extern int acpi_sleep_prepare(u32 acpi_state); extern void acpi_power_off(void); static u32 acpi_target_sleep_state = ACPI_STATE_S0; /** * acpi_pm_set_target - Set the target system sleep state to the state * associated with given @pm_state, if supported. */ static int acpi_pm_set_target(suspend_state_t pm_state) { u32 acpi_state = acpi_suspend_states[pm_state]; int error = 0; if (sleep_states[acpi_state]) { acpi_target_sleep_state = acpi_state; } else { printk(KERN_ERR "ACPI does not support this state: %d\n", pm_state); error = -ENOSYS; } return error; } /** * acpi_pm_prepare - Do preliminary suspend work. * @pm_state: suspend state we're entering. * @pm_state: ignored * * Make sure we support the state. If we do, and we need it, set the * firmware waking vector and do arch-specific nastiness to get the * wakeup code to the waking vector. * If necessary, set the firmware waking vector and do arch-specific * nastiness to get the wakeup code to the waking vector. */ extern int acpi_sleep_prepare(u32 acpi_state); extern void acpi_power_off(void); static int acpi_pm_prepare(suspend_state_t pm_state) { u32 acpi_state = acpi_suspend_states[pm_state]; int error = acpi_sleep_prepare(acpi_target_sleep_state); if (!sleep_states[acpi_state]) { printk("acpi_pm_prepare does not support %d \n", pm_state); return -EPERM; } return acpi_sleep_prepare(acpi_state); if (error) acpi_target_sleep_state = ACPI_STATE_S0; return error; } /** * acpi_pm_enter - Actually enter a sleep state. * @pm_state: State we're entering. * @pm_state: ignored * * Flush caches and go to sleep. For STR or STD, we have to call * arch-specific assembly, which in turn call acpi_enter_sleep_state(). * Flush caches and go to sleep. For STR we have to call arch-specific * assembly, which in turn call acpi_enter_sleep_state(). * It's unfortunate, but it works. Please fix if you're feeling frisky. */ Loading @@ -70,31 +90,31 @@ static int acpi_pm_enter(suspend_state_t pm_state) { acpi_status status = AE_OK; unsigned long flags = 0; u32 acpi_state = acpi_suspend_states[pm_state]; u32 acpi_state = acpi_target_sleep_state; ACPI_FLUSH_CPU_CACHE(); /* Do arch specific saving of state. */ if (pm_state > PM_SUSPEND_STANDBY) { if (acpi_state == ACPI_STATE_S3) { int error = acpi_save_state_mem(); if (error) if (error) { acpi_target_sleep_state = ACPI_STATE_S0; return error; } } local_irq_save(flags); acpi_enable_wakeup_device(acpi_state); switch (pm_state) { case PM_SUSPEND_STANDBY: switch (acpi_state) { case ACPI_STATE_S1: barrier(); status = acpi_enter_sleep_state(acpi_state); break; case PM_SUSPEND_MEM: case ACPI_STATE_S3: do_suspend_lowlevel(); break; default: return -EINVAL; } /* ACPI 3.0 specs (P62) says that it's the responsabilty Loading @@ -107,12 +127,8 @@ static int acpi_pm_enter(suspend_state_t pm_state) local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); /* restore processor state * We should only be here if we're coming back from STR or STD. * And, in the case of the latter, the memory image should have already * been loaded from disk. */ if (pm_state > PM_SUSPEND_STANDBY) /* restore processor state */ if (acpi_state == ACPI_STATE_S3) acpi_restore_state_mem(); return ACPI_SUCCESS(status) ? 0 : -EFAULT; Loading @@ -120,7 +136,7 @@ static int acpi_pm_enter(suspend_state_t pm_state) /** * acpi_pm_finish - Finish up suspend sequence. * @pm_state: State we're coming out of. * @pm_state: ignored * * This is called after we wake back up (or if entering the sleep state * failed). Loading @@ -128,7 +144,7 @@ static int acpi_pm_enter(suspend_state_t pm_state) static int acpi_pm_finish(suspend_state_t pm_state) { u32 acpi_state = acpi_suspend_states[pm_state]; u32 acpi_state = acpi_target_sleep_state; acpi_leave_sleep_state(acpi_state); acpi_disable_wakeup_device(acpi_state); Loading @@ -136,6 +152,8 @@ static int acpi_pm_finish(suspend_state_t pm_state) /* reset firmware waking vector */ acpi_set_firmware_waking_vector((acpi_physical_address) 0); acpi_target_sleep_state = ACPI_STATE_S0; #ifdef CONFIG_X86 if (init_8259A_after_S1) { printk("Broken toshiba laptop -> kicking interrupts\n"); Loading Loading @@ -178,6 +196,7 @@ static int acpi_pm_state_valid(suspend_state_t pm_state) static struct pm_ops acpi_pm_ops = { .valid = acpi_pm_state_valid, .set_target = acpi_pm_set_target, .prepare = acpi_pm_prepare, .enter = acpi_pm_enter, .finish = acpi_pm_finish, Loading Loading @@ -237,6 +256,81 @@ static struct hibernation_ops acpi_hibernation_ops = { }; #endif /* CONFIG_SOFTWARE_SUSPEND */ /** * acpi_pm_device_sleep_state - return preferred power state of ACPI device * in the system sleep state given by %acpi_target_sleep_state * @dev: device to examine * @wake: if set, the device should be able to wake up the system * @d_min_p: used to store the upper limit of allowed states range * Return value: preferred power state of the device on success, -ENODEV on * failure (ie. if there's no 'struct acpi_device' for @dev) * * Find the lowest power (highest number) ACPI device power state that * device @dev can be in while the system is in the sleep state represented * by %acpi_target_sleep_state. If @wake is nonzero, the device should be * able to wake up the system from this sleep state. If @d_min_p is set, * the highest power (lowest number) device power state of @dev allowed * in this system sleep state is stored at the location pointed to by it. * * The caller must ensure that @dev is valid before using this function. * The caller is also responsible for figuring out if the device is * supposed to be able to wake up the system and passing this information * via @wake. */ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p) { acpi_handle handle = DEVICE_ACPI_HANDLE(dev); struct acpi_device *adev; char acpi_method[] = "_SxD"; unsigned long d_min, d_max; if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { printk(KERN_ERR "ACPI handle has no context!\n"); return -ENODEV; } acpi_method[2] = '0' + acpi_target_sleep_state; /* * If the sleep state is S0, we will return D3, but if the device has * _S0W, we will use the value from _S0W */ d_min = ACPI_STATE_D0; d_max = ACPI_STATE_D3; /* * If present, _SxD methods return the minimum D-state (highest power * state) we can use for the corresponding S-states. Otherwise, the * minimum D-state is D0 (ACPI 3.x). * * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer * provided -- that's our fault recovery, we ignore retval. */ if (acpi_target_sleep_state > ACPI_STATE_S0) acpi_evaluate_integer(handle, acpi_method, NULL, &d_min); /* * If _PRW says we can wake up the system from the target sleep state, * the D-state returned by _SxD is sufficient for that (we assume a * wakeup-aware driver if wake is set). Still, if _SxW exists * (ACPI 3.x), it should return the maximum (lowest power) D-state that * can wake the system. _S0W may be valid, too. */ if (acpi_target_sleep_state == ACPI_STATE_S0 || (wake && adev->wakeup.state.enabled && adev->wakeup.sleep_state <= acpi_target_sleep_state)) { acpi_method[3] = 'W'; acpi_evaluate_integer(handle, acpi_method, NULL, &d_max); /* Sanity check */ if (d_max < d_min) d_min = d_max; } if (d_min_p) *d_min_p = d_min; return d_max; } /* * Toshiba fails to preserve interrupts over S1, reinitialization * of 8259 is needed after S1 resume. Loading
drivers/pci/pci-acpi.c +24 −4 Original line number Diff line number Diff line Loading @@ -245,16 +245,33 @@ EXPORT_SYMBOL(pci_osc_control_set); * currently we simply return _SxD, if present. */ static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) { /* TBD */ return -ENODEV; int acpi_state; acpi_state = acpi_pm_device_sleep_state(&pdev->dev, device_may_wakeup(&pdev->dev), NULL); if (acpi_state < 0) return PCI_POWER_ERROR; switch (acpi_state) { case ACPI_STATE_D0: return PCI_D0; case ACPI_STATE_D1: return PCI_D1; case ACPI_STATE_D2: return PCI_D2; case ACPI_STATE_D3: return PCI_D3hot; } return PCI_POWER_ERROR; } static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) { acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); acpi_handle tmp; static int state_conv[] = { [0] = 0, [1] = 1, Loading @@ -266,6 +283,9 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) if (!handle) return -ENODEV; /* If the ACPI device has _EJ0, ignore the device */ if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) return 0; return acpi_bus_set_power(handle, acpi_state); } Loading
drivers/pci/pci.c +4 −4 Original line number Diff line number Diff line Loading @@ -499,7 +499,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) return 0; } int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); /** * pci_choose_state - Choose the power state of a PCI device Loading @@ -513,15 +513,15 @@ int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { int ret; pci_power_t ret; if (!pci_find_capability(dev, PCI_CAP_ID_PM)) return PCI_D0; if (platform_pci_choose_state) { ret = platform_pci_choose_state(dev, state); if (ret >= 0) state.event = ret; if (ret != PCI_POWER_ERROR) return ret; } switch (state.event) { Loading
drivers/pci/pci.h +1 −1 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t, resource_size_t), void *alignf_data); /* Firmware callbacks */ extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state); extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); Loading
drivers/pnp/driver.c +5 −0 Original line number Diff line number Diff line Loading @@ -167,6 +167,8 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state) return error; } if (pnp_dev->protocol && pnp_dev->protocol->suspend) pnp_dev->protocol->suspend(pnp_dev, state); return 0; } Loading @@ -179,6 +181,9 @@ static int pnp_bus_resume(struct device *dev) if (!pnp_drv) return 0; if (pnp_dev->protocol && pnp_dev->protocol->resume) pnp_dev->protocol->resume(pnp_dev); if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) { error = pnp_start_dev(pnp_dev); if (error) Loading