aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2008-07-06 21:36:24 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-07-07 19:26:50 -0400
commit337001b6c42938f49a880b1b8306c3ed771a7e61 (patch)
tree0e704359c989beba626388cf2404f038e55f442e /drivers
parent404cc2d8ce41ed4031958fba8e633767e8a2e028 (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')
-rw-r--r--drivers/pci/pci.c118
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 */
432static int 431static int
433pci_raw_set_power_state(struct pci_dev *dev, int pm, pci_power_t state) 432pci_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 */
533static void pci_update_current_state(struct pci_dev *dev, int pm) 523static 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 */
558int pci_set_power_state(struct pci_dev *dev, pci_power_t state) 548int 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 */
1056static bool pci_pme_capable(struct pci_dev *dev, int pm, pci_power_t state) 1042static 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 */
1081static void pci_pme_active(struct pci_dev *dev, int pm, bool enable) 1058static 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 */
1119int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) 1096int 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)
1158int pci_prepare_to_sleep(struct pci_dev *dev) 1133int 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