Commit b913100d7304ea9596d8d85ab5f3ae04bd2b0ddb
Committed by
Len Brown
1 parent
0f64474b8f
Exists in
master
and in
39 other branches
[ACPI] pci_set_power_state() now calls
platform_pci_set_power_state() and ACPI can answer http://bugzilla.kernel.org/show_bug.cgi?id=4277 Signed-off-by: David Shaohua Li <shaohua.li@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Showing 4 changed files with 36 additions and 3 deletions Side-by-side Diff
drivers/acpi/bus.c
... | ... | @@ -212,6 +212,12 @@ |
212 | 212 | ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device is not power manageable\n")); |
213 | 213 | return_VALUE(-ENODEV); |
214 | 214 | } |
215 | + /* | |
216 | + * Get device's current power state if it's unknown | |
217 | + * This means device power state isn't initialized or previous setting failed | |
218 | + */ | |
219 | + if (device->power.state == ACPI_STATE_UNKNOWN) | |
220 | + acpi_bus_get_power(device->handle, &device->power.state); | |
215 | 221 | if (state == device->power.state) { |
216 | 222 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); |
217 | 223 | return_VALUE(0); |
... | ... | @@ -231,7 +237,7 @@ |
231 | 237 | * On transitions to a high-powered state we first apply power (via |
232 | 238 | * power resources) then evalute _PSx. Conversly for transitions to |
233 | 239 | * a lower-powered state. |
234 | - */ | |
240 | + */ | |
235 | 241 | if (state < device->power.state) { |
236 | 242 | if (device->power.flags.power_resources) { |
237 | 243 | result = acpi_power_transition(device, state); |
drivers/pci/pci-acpi.c
... | ... | @@ -253,6 +253,24 @@ |
253 | 253 | return -ENODEV; |
254 | 254 | } |
255 | 255 | |
256 | +static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |
257 | +{ | |
258 | + acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); | |
259 | + static int state_conv[] = { | |
260 | + [0] = 0, | |
261 | + [1] = 1, | |
262 | + [2] = 2, | |
263 | + [3] = 3, | |
264 | + [4] = 3 | |
265 | + }; | |
266 | + int acpi_state = state_conv[(int __force) state]; | |
267 | + | |
268 | + if (!handle) | |
269 | + return -ENODEV; | |
270 | + return acpi_bus_set_power(handle, acpi_state); | |
271 | +} | |
272 | + | |
273 | + | |
256 | 274 | /* ACPI bus type */ |
257 | 275 | static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) |
258 | 276 | { |
... | ... | @@ -300,6 +318,7 @@ |
300 | 318 | if (ret) |
301 | 319 | return 0; |
302 | 320 | platform_pci_choose_state = acpi_pci_choose_state; |
321 | + platform_pci_set_power_state = acpi_pci_set_power_state; | |
303 | 322 | return 0; |
304 | 323 | } |
305 | 324 | arch_initcall(pci_acpi_init); |
drivers/pci/pci.c
... | ... | @@ -235,7 +235,7 @@ |
235 | 235 | * -EIO if device does not support PCI PM. |
236 | 236 | * 0 if we can successfully change the power state. |
237 | 237 | */ |
238 | - | |
238 | +int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t) = NULL; | |
239 | 239 | int |
240 | 240 | pci_set_power_state(struct pci_dev *dev, pci_power_t state) |
241 | 241 | { |
242 | 242 | |
... | ... | @@ -299,8 +299,15 @@ |
299 | 299 | msleep(10); |
300 | 300 | else if (state == PCI_D2 || dev->current_state == PCI_D2) |
301 | 301 | udelay(200); |
302 | - dev->current_state = state; | |
303 | 302 | |
303 | + /* | |
304 | + * Give firmware a chance to be called, such as ACPI _PRx, _PSx | |
305 | + * Firmware method after natice method ? | |
306 | + */ | |
307 | + if (platform_pci_set_power_state) | |
308 | + platform_pci_set_power_state(dev, state); | |
309 | + | |
310 | + dev->current_state = state; | |
304 | 311 | return 0; |
305 | 312 | } |
306 | 313 |
drivers/pci/pci.h
... | ... | @@ -13,6 +13,7 @@ |
13 | 13 | void *alignf_data); |
14 | 14 | /* Firmware callbacks */ |
15 | 15 | extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); |
16 | +extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state); | |
16 | 17 | |
17 | 18 | /* PCI /proc functions */ |
18 | 19 | #ifdef CONFIG_PROC_FS |