aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c91
1 files changed, 74 insertions, 17 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index dbe9f39f4436..4db261e13e69 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -213,10 +213,13 @@ int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
213int pci_find_ext_capability(struct pci_dev *dev, int cap) 213int pci_find_ext_capability(struct pci_dev *dev, int cap)
214{ 214{
215 u32 header; 215 u32 header;
216 int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */ 216 int ttl;
217 int pos = 0x100; 217 int pos = PCI_CFG_SPACE_SIZE;
218 218
219 if (dev->cfg_size <= 256) 219 /* minimum 8 bytes per capability */
220 ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
221
222 if (dev->cfg_size <= PCI_CFG_SPACE_SIZE)
220 return 0; 223 return 0;
221 224
222 if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL) 225 if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
@@ -234,7 +237,7 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap)
234 return pos; 237 return pos;
235 238
236 pos = PCI_EXT_CAP_NEXT(header); 239 pos = PCI_EXT_CAP_NEXT(header);
237 if (pos < 0x100) 240 if (pos < PCI_CFG_SPACE_SIZE)
238 break; 241 break;
239 242
240 if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL) 243 if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
@@ -1127,6 +1130,27 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
1127} 1130}
1128 1131
1129/** 1132/**
1133 * pci_wake_from_d3 - enable/disable device to wake up from D3_hot or D3_cold
1134 * @dev: PCI device to prepare
1135 * @enable: True to enable wake-up event generation; false to disable
1136 *
1137 * Many drivers want the device to wake up the system from D3_hot or D3_cold
1138 * and this function allows them to set that up cleanly - pci_enable_wake()
1139 * should not be called twice in a row to enable wake-up due to PCI PM vs ACPI
1140 * ordering constraints.
1141 *
1142 * This function only returns error code if the device is not capable of
1143 * generating PME# from both D3_hot and D3_cold, and the platform is unable to
1144 * enable wake-up power for it.
1145 */
1146int pci_wake_from_d3(struct pci_dev *dev, bool enable)
1147{
1148 return pci_pme_capable(dev, PCI_D3cold) ?
1149 pci_enable_wake(dev, PCI_D3cold, enable) :
1150 pci_enable_wake(dev, PCI_D3hot, enable);
1151}
1152
1153/**
1130 * pci_target_state - find an appropriate low power state for a given PCI dev 1154 * pci_target_state - find an appropriate low power state for a given PCI dev
1131 * @dev: PCI device 1155 * @dev: PCI device
1132 * 1156 *
@@ -1242,25 +1266,25 @@ void pci_pm_init(struct pci_dev *dev)
1242 dev->d1_support = false; 1266 dev->d1_support = false;
1243 dev->d2_support = false; 1267 dev->d2_support = false;
1244 if (!pci_no_d1d2(dev)) { 1268 if (!pci_no_d1d2(dev)) {
1245 if (pmc & PCI_PM_CAP_D1) { 1269 if (pmc & PCI_PM_CAP_D1)
1246 dev_printk(KERN_DEBUG, &dev->dev, "supports D1\n");
1247 dev->d1_support = true; 1270 dev->d1_support = true;
1248 } 1271 if (pmc & PCI_PM_CAP_D2)
1249 if (pmc & PCI_PM_CAP_D2) {
1250 dev_printk(KERN_DEBUG, &dev->dev, "supports D2\n");
1251 dev->d2_support = true; 1272 dev->d2_support = true;
1252 } 1273
1274 if (dev->d1_support || dev->d2_support)
1275 dev_printk(KERN_DEBUG, &dev->dev, "supports%s%s\n",
1276 dev->d1_support ? " D1" : "",
1277 dev->d2_support ? " D2" : "");
1253 } 1278 }
1254 1279
1255 pmc &= PCI_PM_CAP_PME_MASK; 1280 pmc &= PCI_PM_CAP_PME_MASK;
1256 if (pmc) { 1281 if (pmc) {
1257 dev_printk(KERN_INFO, &dev->dev, 1282 dev_info(&dev->dev, "PME# supported from%s%s%s%s%s\n",
1258 "PME# supported from%s%s%s%s%s\n", 1283 (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
1259 (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "", 1284 (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
1260 (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "", 1285 (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
1261 (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "", 1286 (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "",
1262 (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "", 1287 (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
1263 (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
1264 dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT; 1288 dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT;
1265 /* 1289 /*
1266 * Make device's PM flags reflect the wake-up capability, but 1290 * Make device's PM flags reflect the wake-up capability, but
@@ -1275,6 +1299,38 @@ void pci_pm_init(struct pci_dev *dev)
1275 } 1299 }
1276} 1300}
1277 1301
1302/**
1303 * pci_enable_ari - enable ARI forwarding if hardware support it
1304 * @dev: the PCI device
1305 */
1306void pci_enable_ari(struct pci_dev *dev)
1307{
1308 int pos;
1309 u32 cap;
1310 u16 ctrl;
1311
1312 if (!dev->is_pcie)
1313 return;
1314
1315 if (dev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
1316 dev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
1317 return;
1318
1319 pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
1320 if (!pos)
1321 return;
1322
1323 pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP2, &cap);
1324 if (!(cap & PCI_EXP_DEVCAP2_ARI))
1325 return;
1326
1327 pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
1328 ctrl |= PCI_EXP_DEVCTL2_ARI;
1329 pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
1330
1331 dev->ari_enabled = 1;
1332}
1333
1278int 1334int
1279pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) 1335pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
1280{ 1336{
@@ -1942,6 +1998,7 @@ EXPORT_SYMBOL(pci_restore_state);
1942EXPORT_SYMBOL(pci_pme_capable); 1998EXPORT_SYMBOL(pci_pme_capable);
1943EXPORT_SYMBOL(pci_pme_active); 1999EXPORT_SYMBOL(pci_pme_active);
1944EXPORT_SYMBOL(pci_enable_wake); 2000EXPORT_SYMBOL(pci_enable_wake);
2001EXPORT_SYMBOL(pci_wake_from_d3);
1945EXPORT_SYMBOL(pci_target_state); 2002EXPORT_SYMBOL(pci_target_state);
1946EXPORT_SYMBOL(pci_prepare_to_sleep); 2003EXPORT_SYMBOL(pci_prepare_to_sleep);
1947EXPORT_SYMBOL(pci_back_from_sleep); 2004EXPORT_SYMBOL(pci_back_from_sleep);