aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/pci-acpi.c19
-rw-r--r--drivers/pci/pci.c40
-rw-r--r--drivers/pci/pci.h26
3 files changed, 65 insertions, 20 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 056ea80ee27a..e4df71ab79b3 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -215,7 +215,6 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
215} 215}
216EXPORT_SYMBOL(pci_osc_control_set); 216EXPORT_SYMBOL(pci_osc_control_set);
217 217
218#ifdef CONFIG_ACPI_SLEEP
219/* 218/*
220 * _SxD returns the D-state with the highest power 219 * _SxD returns the D-state with the highest power
221 * (lowest D-state number) supported in the S-state "x". 220 * (lowest D-state number) supported in the S-state "x".
@@ -259,7 +258,13 @@ static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
259 } 258 }
260 return PCI_POWER_ERROR; 259 return PCI_POWER_ERROR;
261} 260}
262#endif 261
262static bool acpi_pci_power_manageable(struct pci_dev *dev)
263{
264 acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
265
266 return handle ? acpi_bus_power_manageable(handle) : false;
267}
263 268
264static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) 269static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
265{ 270{
@@ -290,6 +295,11 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
290 return -EINVAL; 295 return -EINVAL;
291} 296}
292 297
298static struct pci_platform_pm_ops acpi_pci_platform_pm = {
299 .is_manageable = acpi_pci_power_manageable,
300 .set_state = acpi_pci_set_power_state,
301 .choose_state = acpi_pci_choose_state,
302};
293 303
294/* ACPI bus type */ 304/* ACPI bus type */
295static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) 305static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
@@ -341,10 +351,7 @@ static int __init acpi_pci_init(void)
341 ret = register_acpi_bus_type(&acpi_pci_bus); 351 ret = register_acpi_bus_type(&acpi_pci_bus);
342 if (ret) 352 if (ret)
343 return 0; 353 return 0;
344#ifdef CONFIG_ACPI_SLEEP 354 pci_set_platform_pm(&acpi_pci_platform_pm);
345 platform_pci_choose_state = acpi_pci_choose_state;
346#endif
347 platform_pci_set_power_state = acpi_pci_set_power_state;
348 return 0; 355 return 0;
349} 356}
350arch_initcall(acpi_pci_init); 357arch_initcall(acpi_pci_init);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8e8ecc1da93d..f8074525267c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -376,7 +376,32 @@ pci_restore_bars(struct pci_dev *dev)
376 pci_update_resource(dev, &dev->resource[i], i); 376 pci_update_resource(dev, &dev->resource[i], i);
377} 377}
378 378
379int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); 379static struct pci_platform_pm_ops *pci_platform_pm;
380
381int pci_set_platform_pm(struct pci_platform_pm_ops *ops)
382{
383 if (!ops->is_manageable || !ops->set_state || !ops->choose_state)
384 return -EINVAL;
385 pci_platform_pm = ops;
386 return 0;
387}
388
389static inline bool platform_pci_power_manageable(struct pci_dev *dev)
390{
391 return pci_platform_pm ? pci_platform_pm->is_manageable(dev) : false;
392}
393
394static inline int platform_pci_set_power_state(struct pci_dev *dev,
395 pci_power_t t)
396{
397 return pci_platform_pm ? pci_platform_pm->set_state(dev, t) : -ENOSYS;
398}
399
400static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
401{
402 return pci_platform_pm ?
403 pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR;
404}
380 405
381/** 406/**
382 * pci_set_power_state - Set the power state of a PCI device 407 * pci_set_power_state - Set the power state of a PCI device
@@ -479,8 +504,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
479 * Give firmware a chance to be called, such as ACPI _PRx, _PSx 504 * Give firmware a chance to be called, such as ACPI _PRx, _PSx
480 * Firmware method after native method ? 505 * Firmware method after native method ?
481 */ 506 */
482 if (platform_pci_set_power_state) 507 platform_pci_set_power_state(dev, state);
483 platform_pci_set_power_state(dev, state);
484 508
485 dev->current_state = state; 509 dev->current_state = state;
486 510
@@ -505,8 +529,6 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
505 return 0; 529 return 0;
506} 530}
507 531
508pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev);
509
510/** 532/**
511 * pci_choose_state - Choose the power state of a PCI device 533 * pci_choose_state - Choose the power state of a PCI device
512 * @dev: PCI device to be suspended 534 * @dev: PCI device to be suspended
@@ -524,11 +546,9 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
524 if (!pci_find_capability(dev, PCI_CAP_ID_PM)) 546 if (!pci_find_capability(dev, PCI_CAP_ID_PM))
525 return PCI_D0; 547 return PCI_D0;
526 548
527 if (platform_pci_choose_state) { 549 ret = platform_pci_choose_state(dev);
528 ret = platform_pci_choose_state(dev); 550 if (ret != PCI_POWER_ERROR)
529 if (ret != PCI_POWER_ERROR) 551 return ret;
530 return ret;
531 }
532 552
533 switch (state.event) { 553 switch (state.event) {
534 case PM_EVENT_ON: 554 case PM_EVENT_ON:
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index e0eff35825a6..0cd2e719933b 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -5,10 +5,28 @@ extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
5extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); 5extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
6extern void pci_cleanup_rom(struct pci_dev *dev); 6extern void pci_cleanup_rom(struct pci_dev *dev);
7 7
8/* Firmware callbacks */ 8/**
9extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev); 9 * Firmware PM callbacks
10extern int (*platform_pci_set_power_state)(struct pci_dev *dev, 10 *
11 pci_power_t state); 11 * @is_manageable - returns 'true' if given device is power manageable by the
12 * platform firmware
13 *
14 * @set_state - invokes the platform firmware to set the device's power state
15 *
16 * @choose_state - returns PCI power state of given device preferred by the
17 * platform; to be used during system-wide transitions from a
18 * sleeping state to the working state and vice versa
19 *
20 * If given platform is generally capable of power managing PCI devices, all of
21 * these callbacks are mandatory.
22 */
23struct pci_platform_pm_ops {
24 bool (*is_manageable)(struct pci_dev *dev);
25 int (*set_state)(struct pci_dev *dev, pci_power_t state);
26 pci_power_t (*choose_state)(struct pci_dev *dev);
27};
28
29extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
12 30
13extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); 31extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
14extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); 32extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);