|
6 | 6 | #include <linux/delay.h>
|
7 | 7 | #include <linux/init.h>
|
8 | 8 | #include <linux/pci.h>
|
| 9 | +#include <linux/pci_hotplug.h> |
9 | 10 | #include <linux/slab.h>
|
10 | 11 | #include <linux/module.h>
|
11 | 12 | #include <linux/cpumask.h>
|
@@ -1236,6 +1237,155 @@ int pci_setup_device(struct pci_dev *dev)
|
1236 | 1237 | return 0;
|
1237 | 1238 | }
|
1238 | 1239 |
|
| 1240 | +static struct hpp_type0 pci_default_type0 = { |
| 1241 | + .revision = 1, |
| 1242 | + .cache_line_size = 8, |
| 1243 | + .latency_timer = 0x40, |
| 1244 | + .enable_serr = 0, |
| 1245 | + .enable_perr = 0, |
| 1246 | +}; |
| 1247 | + |
| 1248 | +static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp) |
| 1249 | +{ |
| 1250 | + u16 pci_cmd, pci_bctl; |
| 1251 | + |
| 1252 | + if (!hpp) { |
| 1253 | + /* |
| 1254 | + * Perhaps we *should* use default settings for PCIe, but |
| 1255 | + * pciehp didn't, so we won't either. |
| 1256 | + */ |
| 1257 | + if (pci_is_pcie(dev)) |
| 1258 | + return; |
| 1259 | + hpp = &pci_default_type0; |
| 1260 | + } |
| 1261 | + |
| 1262 | + if (hpp->revision > 1) { |
| 1263 | + dev_warn(&dev->dev, |
| 1264 | + "PCI settings rev %d not supported; using defaults\n", |
| 1265 | + hpp->revision); |
| 1266 | + hpp = &pci_default_type0; |
| 1267 | + } |
| 1268 | + |
| 1269 | + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp->cache_line_size); |
| 1270 | + pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp->latency_timer); |
| 1271 | + pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); |
| 1272 | + if (hpp->enable_serr) |
| 1273 | + pci_cmd |= PCI_COMMAND_SERR; |
| 1274 | + else |
| 1275 | + pci_cmd &= ~PCI_COMMAND_SERR; |
| 1276 | + if (hpp->enable_perr) |
| 1277 | + pci_cmd |= PCI_COMMAND_PARITY; |
| 1278 | + else |
| 1279 | + pci_cmd &= ~PCI_COMMAND_PARITY; |
| 1280 | + pci_write_config_word(dev, PCI_COMMAND, pci_cmd); |
| 1281 | + |
| 1282 | + /* Program bridge control value */ |
| 1283 | + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { |
| 1284 | + pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, |
| 1285 | + hpp->latency_timer); |
| 1286 | + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); |
| 1287 | + if (hpp->enable_serr) |
| 1288 | + pci_bctl |= PCI_BRIDGE_CTL_SERR; |
| 1289 | + else |
| 1290 | + pci_bctl &= ~PCI_BRIDGE_CTL_SERR; |
| 1291 | + if (hpp->enable_perr) |
| 1292 | + pci_bctl |= PCI_BRIDGE_CTL_PARITY; |
| 1293 | + else |
| 1294 | + pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; |
| 1295 | + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); |
| 1296 | + } |
| 1297 | +} |
| 1298 | + |
| 1299 | +static void program_hpp_type1(struct pci_dev *dev, struct hpp_type1 *hpp) |
| 1300 | +{ |
| 1301 | + if (hpp) |
| 1302 | + dev_warn(&dev->dev, "PCI-X settings not supported\n"); |
| 1303 | +} |
| 1304 | + |
| 1305 | +static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) |
| 1306 | +{ |
| 1307 | + int pos; |
| 1308 | + u32 reg32; |
| 1309 | + |
| 1310 | + if (!hpp) |
| 1311 | + return; |
| 1312 | + |
| 1313 | + if (hpp->revision > 1) { |
| 1314 | + dev_warn(&dev->dev, "PCIe settings rev %d not supported\n", |
| 1315 | + hpp->revision); |
| 1316 | + return; |
| 1317 | + } |
| 1318 | + |
| 1319 | + /* Initialize Device Control Register */ |
| 1320 | + pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, |
| 1321 | + ~hpp->pci_exp_devctl_and, hpp->pci_exp_devctl_or); |
| 1322 | + |
| 1323 | + /* Initialize Link Control Register */ |
| 1324 | + if (dev->subordinate) |
| 1325 | + pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, |
| 1326 | + ~hpp->pci_exp_lnkctl_and, hpp->pci_exp_lnkctl_or); |
| 1327 | + |
| 1328 | + /* Find Advanced Error Reporting Enhanced Capability */ |
| 1329 | + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); |
| 1330 | + if (!pos) |
| 1331 | + return; |
| 1332 | + |
| 1333 | + /* Initialize Uncorrectable Error Mask Register */ |
| 1334 | + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, ®32); |
| 1335 | + reg32 = (reg32 & hpp->unc_err_mask_and) | hpp->unc_err_mask_or; |
| 1336 | + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32); |
| 1337 | + |
| 1338 | + /* Initialize Uncorrectable Error Severity Register */ |
| 1339 | + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, ®32); |
| 1340 | + reg32 = (reg32 & hpp->unc_err_sever_and) | hpp->unc_err_sever_or; |
| 1341 | + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32); |
| 1342 | + |
| 1343 | + /* Initialize Correctable Error Mask Register */ |
| 1344 | + pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®32); |
| 1345 | + reg32 = (reg32 & hpp->cor_err_mask_and) | hpp->cor_err_mask_or; |
| 1346 | + pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32); |
| 1347 | + |
| 1348 | + /* Initialize Advanced Error Capabilities and Control Register */ |
| 1349 | + pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); |
| 1350 | + reg32 = (reg32 & hpp->adv_err_cap_and) | hpp->adv_err_cap_or; |
| 1351 | + pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); |
| 1352 | + |
| 1353 | + /* |
| 1354 | + * FIXME: The following two registers are not supported yet. |
| 1355 | + * |
| 1356 | + * o Secondary Uncorrectable Error Severity Register |
| 1357 | + * o Secondary Uncorrectable Error Mask Register |
| 1358 | + */ |
| 1359 | +} |
| 1360 | + |
| 1361 | +void pci_configure_slot(struct pci_dev *dev) |
| 1362 | +{ |
| 1363 | + struct pci_dev *cdev; |
| 1364 | + struct hotplug_params hpp; |
| 1365 | + int ret; |
| 1366 | + |
| 1367 | + if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || |
| 1368 | + (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && |
| 1369 | + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) |
| 1370 | + return; |
| 1371 | + |
| 1372 | + pcie_bus_configure_settings(dev->bus); |
| 1373 | + |
| 1374 | + memset(&hpp, 0, sizeof(hpp)); |
| 1375 | + ret = pci_get_hp_params(dev, &hpp); |
| 1376 | + |
| 1377 | + program_hpp_type2(dev, hpp.t2); |
| 1378 | + program_hpp_type1(dev, hpp.t1); |
| 1379 | + program_hpp_type0(dev, hpp.t0); |
| 1380 | + |
| 1381 | + if (dev->subordinate) { |
| 1382 | + list_for_each_entry(cdev, &dev->subordinate->devices, |
| 1383 | + bus_list) |
| 1384 | + pci_configure_slot(cdev); |
| 1385 | + } |
| 1386 | +} |
| 1387 | +EXPORT_SYMBOL_GPL(pci_configure_slot); |
| 1388 | + |
1239 | 1389 | static void pci_release_capabilities(struct pci_dev *dev)
|
1240 | 1390 | {
|
1241 | 1391 | pci_vpd_release(dev);
|
|
0 commit comments