diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2008-07-06 21:36:24 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2008-07-07 19:26:50 -0400 |
commit | 337001b6c42938f49a880b1b8306c3ed771a7e61 (patch) | |
tree | 0e704359c989beba626388cf2404f038e55f442e /drivers/pci | |
parent | 404cc2d8ce41ed4031958fba8e633767e8a2e028 (diff) |
PCI: Simplify PCI device PM code
If the offset of PCI device's PM capability in its configuration space,
the mask of states that the device supports PME# from and the D1 and D2
support bits are cached in the corresponding struct pci_dev, the PCI
device PM code can be simplified quite a bit.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci.c | 118 |
1 files changed, 52 insertions, 66 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1b0ec45e9934..e632a58ba5d0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -419,7 +419,6 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable) | |||
419 | * pci_raw_set_power_state - Use PCI PM registers to set the power state of | 419 | * pci_raw_set_power_state - Use PCI PM registers to set the power state of |
420 | * given PCI device | 420 | * given PCI device |
421 | * @dev: PCI device to handle. | 421 | * @dev: PCI device to handle. |
422 | * @pm: PCI PM capability offset of the device. | ||
423 | * @state: PCI power state (D0, D1, D2, D3hot) to put the device into. | 422 | * @state: PCI power state (D0, D1, D2, D3hot) to put the device into. |
424 | * | 423 | * |
425 | * RETURN VALUE: | 424 | * RETURN VALUE: |
@@ -430,12 +429,12 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable) | |||
430 | * 0 if device's power state has been successfully changed. | 429 | * 0 if device's power state has been successfully changed. |
431 | */ | 430 | */ |
432 | static int | 431 | static int |
433 | pci_raw_set_power_state(struct pci_dev *dev, int pm, pci_power_t state) | 432 | pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) |
434 | { | 433 | { |
435 | u16 pmcsr, pmc; | 434 | u16 pmcsr; |
436 | bool need_restore = false; | 435 | bool need_restore = false; |
437 | 436 | ||
438 | if (!pm) | 437 | if (!dev->pm_cap) |
439 | return -EIO; | 438 | return -EIO; |
440 | 439 | ||
441 | if (state < PCI_D0 || state > PCI_D3hot) | 440 | if (state < PCI_D0 || state > PCI_D3hot) |
@@ -455,20 +454,12 @@ pci_raw_set_power_state(struct pci_dev *dev, int pm, pci_power_t state) | |||
455 | return -EINVAL; | 454 | return -EINVAL; |
456 | } | 455 | } |
457 | 456 | ||
458 | pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc); | ||
459 | |||
460 | if ((pmc & PCI_PM_CAP_VER_MASK) > 3) { | ||
461 | dev_err(&dev->dev, "unsupported PM cap regs version (%u)\n", | ||
462 | pmc & PCI_PM_CAP_VER_MASK); | ||
463 | return -EIO; | ||
464 | } | ||
465 | |||
466 | /* check if this device supports the desired state */ | 457 | /* check if this device supports the desired state */ |
467 | if ((state == PCI_D1 && !(pmc & PCI_PM_CAP_D1)) | 458 | if ((state == PCI_D1 && !dev->d1_support) |
468 | || (state == PCI_D2 && !(pmc & PCI_PM_CAP_D2))) | 459 | || (state == PCI_D2 && !dev->d2_support)) |
469 | return -EIO; | 460 | return -EIO; |
470 | 461 | ||
471 | pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); | 462 | pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); |
472 | 463 | ||
473 | /* If we're (effectively) in D3, force entire word to 0. | 464 | /* If we're (effectively) in D3, force entire word to 0. |
474 | * This doesn't affect PME_Status, disables PME_En, and | 465 | * This doesn't affect PME_Status, disables PME_En, and |
@@ -492,7 +483,7 @@ pci_raw_set_power_state(struct pci_dev *dev, int pm, pci_power_t state) | |||
492 | } | 483 | } |
493 | 484 | ||
494 | /* enter specified state */ | 485 | /* enter specified state */ |
495 | pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr); | 486 | pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr); |
496 | 487 | ||
497 | /* Mandatory power management transition delays */ | 488 | /* Mandatory power management transition delays */ |
498 | /* see PCI PM 1.1 5.6.1 table 18 */ | 489 | /* see PCI PM 1.1 5.6.1 table 18 */ |
@@ -528,14 +519,13 @@ pci_raw_set_power_state(struct pci_dev *dev, int pm, pci_power_t state) | |||
528 | * pci_update_current_state - Read PCI power state of given device from its | 519 | * pci_update_current_state - Read PCI power state of given device from its |
529 | * PCI PM registers and cache it | 520 | * PCI PM registers and cache it |
530 | * @dev: PCI device to handle. | 521 | * @dev: PCI device to handle. |
531 | * @pm: PCI PM capability offset of the device. | ||
532 | */ | 522 | */ |
533 | static void pci_update_current_state(struct pci_dev *dev, int pm) | 523 | static void pci_update_current_state(struct pci_dev *dev) |
534 | { | 524 | { |
535 | if (pm) { | 525 | if (dev->pm_cap) { |
536 | u16 pmcsr; | 526 | u16 pmcsr; |
537 | 527 | ||
538 | pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); | 528 | pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); |
539 | dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK); | 529 | dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK); |
540 | } | 530 | } |
541 | } | 531 | } |
@@ -557,7 +547,7 @@ static void pci_update_current_state(struct pci_dev *dev, int pm) | |||
557 | */ | 547 | */ |
558 | int pci_set_power_state(struct pci_dev *dev, pci_power_t state) | 548 | int pci_set_power_state(struct pci_dev *dev, pci_power_t state) |
559 | { | 549 | { |
560 | int pm, error; | 550 | int error; |
561 | 551 | ||
562 | /* bound the state we're entering */ | 552 | /* bound the state we're entering */ |
563 | if (state > PCI_D3hot) | 553 | if (state > PCI_D3hot) |
@@ -572,9 +562,6 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
572 | */ | 562 | */ |
573 | return 0; | 563 | return 0; |
574 | 564 | ||
575 | /* Find PCI PM capability in the list */ | ||
576 | pm = pci_find_capability(dev, PCI_CAP_ID_PM); | ||
577 | |||
578 | if (state == PCI_D0 && platform_pci_power_manageable(dev)) { | 565 | if (state == PCI_D0 && platform_pci_power_manageable(dev)) { |
579 | /* | 566 | /* |
580 | * Allow the platform to change the state, for example via ACPI | 567 | * Allow the platform to change the state, for example via ACPI |
@@ -582,16 +569,16 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
582 | */ | 569 | */ |
583 | int ret = platform_pci_set_power_state(dev, PCI_D0); | 570 | int ret = platform_pci_set_power_state(dev, PCI_D0); |
584 | if (!ret) | 571 | if (!ret) |
585 | pci_update_current_state(dev, pm); | 572 | pci_update_current_state(dev); |
586 | } | 573 | } |
587 | 574 | ||
588 | error = pci_raw_set_power_state(dev, pm, state); | 575 | error = pci_raw_set_power_state(dev, state); |
589 | 576 | ||
590 | if (state > PCI_D0 && platform_pci_power_manageable(dev)) { | 577 | if (state > PCI_D0 && platform_pci_power_manageable(dev)) { |
591 | /* Allow the platform to finalize the transition */ | 578 | /* Allow the platform to finalize the transition */ |
592 | int ret = platform_pci_set_power_state(dev, state); | 579 | int ret = platform_pci_set_power_state(dev, state); |
593 | if (!ret) { | 580 | if (!ret) { |
594 | pci_update_current_state(dev, pm); | 581 | pci_update_current_state(dev); |
595 | error = 0; | 582 | error = 0; |
596 | } | 583 | } |
597 | } | 584 | } |
@@ -1050,48 +1037,38 @@ int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) | |||
1050 | /** | 1037 | /** |
1051 | * pci_pme_capable - check the capability of PCI device to generate PME# | 1038 | * pci_pme_capable - check the capability of PCI device to generate PME# |
1052 | * @dev: PCI device to handle. | 1039 | * @dev: PCI device to handle. |
1053 | * @pm: PCI PM capability offset of the device. | ||
1054 | * @state: PCI state from which device will issue PME#. | 1040 | * @state: PCI state from which device will issue PME#. |
1055 | */ | 1041 | */ |
1056 | static bool pci_pme_capable(struct pci_dev *dev, int pm, pci_power_t state) | 1042 | static bool pci_pme_capable(struct pci_dev *dev, pci_power_t state) |
1057 | { | 1043 | { |
1058 | u16 pmc; | 1044 | if (!dev->pm_cap) |
1059 | |||
1060 | if (!pm) | ||
1061 | return false; | 1045 | return false; |
1062 | 1046 | ||
1063 | /* Check device's ability to generate PME# from given state */ | 1047 | return !!(dev->pme_support & (1 << state)); |
1064 | pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc); | ||
1065 | |||
1066 | pmc &= PCI_PM_CAP_PME_MASK; | ||
1067 | pmc >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */ | ||
1068 | |||
1069 | return !!(pmc & (1 << state)); | ||
1070 | } | 1048 | } |
1071 | 1049 | ||
1072 | /** | 1050 | /** |
1073 | * pci_pme_active - enable or disable PCI device's PME# function | 1051 | * pci_pme_active - enable or disable PCI device's PME# function |
1074 | * @dev: PCI device to handle. | 1052 | * @dev: PCI device to handle. |
1075 | * @pm: PCI PM capability offset of the device. | ||
1076 | * @enable: 'true' to enable PME# generation; 'false' to disable it. | 1053 | * @enable: 'true' to enable PME# generation; 'false' to disable it. |
1077 | * | 1054 | * |
1078 | * The caller must verify that the device is capable of generating PME# before | 1055 | * The caller must verify that the device is capable of generating PME# before |
1079 | * calling this function with @enable equal to 'true'. | 1056 | * calling this function with @enable equal to 'true'. |
1080 | */ | 1057 | */ |
1081 | static void pci_pme_active(struct pci_dev *dev, int pm, bool enable) | 1058 | static void pci_pme_active(struct pci_dev *dev, bool enable) |
1082 | { | 1059 | { |
1083 | u16 pmcsr; | 1060 | u16 pmcsr; |
1084 | 1061 | ||
1085 | if (!pm) | 1062 | if (!dev->pm_cap) |
1086 | return; | 1063 | return; |
1087 | 1064 | ||
1088 | pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); | 1065 | pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); |
1089 | /* Clear PME_Status by writing 1 to it and enable PME# */ | 1066 | /* Clear PME_Status by writing 1 to it and enable PME# */ |
1090 | pmcsr |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE; | 1067 | pmcsr |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE; |
1091 | if (!enable) | 1068 | if (!enable) |
1092 | pmcsr &= ~PCI_PM_CTRL_PME_ENABLE; | 1069 | pmcsr &= ~PCI_PM_CTRL_PME_ENABLE; |
1093 | 1070 | ||
1094 | pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr); | 1071 | pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr); |
1095 | 1072 | ||
1096 | dev_printk(KERN_INFO, &dev->dev, "PME# %s\n", | 1073 | dev_printk(KERN_INFO, &dev->dev, "PME# %s\n", |
1097 | enable ? "enabled" : "disabled"); | 1074 | enable ? "enabled" : "disabled"); |
@@ -1118,7 +1095,6 @@ static void pci_pme_active(struct pci_dev *dev, int pm, bool enable) | |||
1118 | */ | 1095 | */ |
1119 | int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) | 1096 | int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) |
1120 | { | 1097 | { |
1121 | int pm; | ||
1122 | int error = 0; | 1098 | int error = 0; |
1123 | bool pme_done = false; | 1099 | bool pme_done = false; |
1124 | 1100 | ||
@@ -1134,9 +1110,8 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) | |||
1134 | if (!enable && platform_pci_can_wakeup(dev)) | 1110 | if (!enable && platform_pci_can_wakeup(dev)) |
1135 | error = platform_pci_sleep_wake(dev, false); | 1111 | error = platform_pci_sleep_wake(dev, false); |
1136 | 1112 | ||
1137 | pm = pci_find_capability(dev, PCI_CAP_ID_PM); | 1113 | if (!enable || pci_pme_capable(dev, state)) { |
1138 | if (!enable || pci_pme_capable(dev, pm, state)) { | 1114 | pci_pme_active(dev, enable); |
1139 | pci_pme_active(dev, pm, enable); | ||
1140 | pme_done = true; | 1115 | pme_done = true; |
1141 | } | 1116 | } |
1142 | 1117 | ||
@@ -1158,7 +1133,6 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) | |||
1158 | int pci_prepare_to_sleep(struct pci_dev *dev) | 1133 | int pci_prepare_to_sleep(struct pci_dev *dev) |
1159 | { | 1134 | { |
1160 | pci_power_t target_state = PCI_D3hot; | 1135 | pci_power_t target_state = PCI_D3hot; |
1161 | int pm = pci_find_capability(dev, PCI_CAP_ID_PM); | ||
1162 | int error; | 1136 | int error; |
1163 | 1137 | ||
1164 | if (platform_pci_power_manageable(dev)) { | 1138 | if (platform_pci_power_manageable(dev)) { |
@@ -1186,23 +1160,14 @@ int pci_prepare_to_sleep(struct pci_dev *dev) | |||
1186 | * wake-up events, make it the target state and enable device | 1160 | * wake-up events, make it the target state and enable device |
1187 | * to generate PME#. | 1161 | * to generate PME#. |
1188 | */ | 1162 | */ |
1189 | u16 pmc; | 1163 | if (!dev->pm_cap) |
1190 | |||
1191 | if (!pm) | ||
1192 | return -EIO; | 1164 | return -EIO; |
1193 | 1165 | ||
1194 | pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc); | 1166 | if (dev->pme_support) { |
1195 | if (pmc & PCI_PM_CAP_PME_MASK) { | 1167 | while (target_state |
1196 | if (!(pmc & PCI_PM_CAP_PME_D3)) { | 1168 | && !(dev->pme_support & (1 << target_state))) |
1197 | /* Device cannot generate PME# from D3_hot */ | 1169 | target_state--; |
1198 | if (pmc & PCI_PM_CAP_PME_D2) | 1170 | pci_pme_active(dev, true); |
1199 | target_state = PCI_D2; | ||
1200 | else if (pmc & PCI_PM_CAP_PME_D1) | ||
1201 | target_state = PCI_D1; | ||
1202 | else | ||
1203 | target_state = PCI_D0; | ||
1204 | } | ||
1205 | pci_pme_active(dev, pm, true); | ||
1206 | } | 1171 | } |
1207 | } | 1172 | } |
1208 | 1173 | ||
@@ -1236,6 +1201,8 @@ void pci_pm_init(struct pci_dev *dev) | |||
1236 | int pm; | 1201 | int pm; |
1237 | u16 pmc; | 1202 | u16 pmc; |
1238 | 1203 | ||
1204 | dev->pm_cap = 0; | ||
1205 | |||
1239 | /* find PCI PM capability in list */ | 1206 | /* find PCI PM capability in list */ |
1240 | pm = pci_find_capability(dev, PCI_CAP_ID_PM); | 1207 | pm = pci_find_capability(dev, PCI_CAP_ID_PM); |
1241 | if (!pm) | 1208 | if (!pm) |
@@ -1249,7 +1216,23 @@ void pci_pm_init(struct pci_dev *dev) | |||
1249 | return; | 1216 | return; |
1250 | } | 1217 | } |
1251 | 1218 | ||
1252 | if (pmc & PCI_PM_CAP_PME_MASK) { | 1219 | dev->pm_cap = pm; |
1220 | |||
1221 | dev->d1_support = false; | ||
1222 | dev->d2_support = false; | ||
1223 | if (!pci_no_d1d2(dev)) { | ||
1224 | if (pmc & PCI_PM_CAP_D1) { | ||
1225 | dev_printk(KERN_DEBUG, &dev->dev, "supports D1\n"); | ||
1226 | dev->d1_support = true; | ||
1227 | } | ||
1228 | if (pmc & PCI_PM_CAP_D2) { | ||
1229 | dev_printk(KERN_DEBUG, &dev->dev, "supports D2\n"); | ||
1230 | dev->d2_support = true; | ||
1231 | } | ||
1232 | } | ||
1233 | |||
1234 | pmc &= PCI_PM_CAP_PME_MASK; | ||
1235 | if (pmc) { | ||
1253 | dev_printk(KERN_INFO, &dev->dev, | 1236 | dev_printk(KERN_INFO, &dev->dev, |
1254 | "PME# supported from%s%s%s%s%s\n", | 1237 | "PME# supported from%s%s%s%s%s\n", |
1255 | (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "", | 1238 | (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "", |
@@ -1257,6 +1240,7 @@ void pci_pm_init(struct pci_dev *dev) | |||
1257 | (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "", | 1240 | (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "", |
1258 | (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "", | 1241 | (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "", |
1259 | (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : ""); | 1242 | (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : ""); |
1243 | dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT; | ||
1260 | /* | 1244 | /* |
1261 | * Make device's PM flags reflect the wake-up capability, but | 1245 | * Make device's PM flags reflect the wake-up capability, but |
1262 | * let the user space enable it to wake up the system as needed. | 1246 | * let the user space enable it to wake up the system as needed. |
@@ -1264,7 +1248,9 @@ void pci_pm_init(struct pci_dev *dev) | |||
1264 | device_set_wakeup_capable(&dev->dev, true); | 1248 | device_set_wakeup_capable(&dev->dev, true); |
1265 | device_set_wakeup_enable(&dev->dev, false); | 1249 | device_set_wakeup_enable(&dev->dev, false); |
1266 | /* Disable the PME# generation functionality */ | 1250 | /* Disable the PME# generation functionality */ |
1267 | pci_pme_active(dev, pm, false); | 1251 | pci_pme_active(dev, false); |
1252 | } else { | ||
1253 | dev->pme_support = 0; | ||
1268 | } | 1254 | } |
1269 | } | 1255 | } |
1270 | 1256 | ||