aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/pci.c160
-rw-r--r--drivers/pci/quirks.c16
2 files changed, 176 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index fd47ac0c4730..1bb879959a20 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1375,6 +1375,166 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
1375#endif 1375#endif
1376 1376
1377/** 1377/**
1378 * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
1379 * @dev: PCI device to query
1380 *
1381 * Returns mmrbc: maximum designed memory read count in bytes
1382 * or appropriate error value.
1383 */
1384int pcix_get_max_mmrbc(struct pci_dev *dev)
1385{
1386 int ret, err, cap;
1387 u32 stat;
1388
1389 cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
1390 if (!cap)
1391 return -EINVAL;
1392
1393 err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat);
1394 if (err)
1395 return -EINVAL;
1396
1397 ret = (stat & PCI_X_STATUS_MAX_READ) >> 12;
1398
1399 return ret;
1400}
1401EXPORT_SYMBOL(pcix_get_max_mmrbc);
1402
1403/**
1404 * pcix_get_mmrbc - get PCI-X maximum memory read byte count
1405 * @dev: PCI device to query
1406 *
1407 * Returns mmrbc: maximum memory read count in bytes
1408 * or appropriate error value.
1409 */
1410int pcix_get_mmrbc(struct pci_dev *dev)
1411{
1412 int ret, cap;
1413 u32 cmd;
1414
1415 cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
1416 if (!cap)
1417 return -EINVAL;
1418
1419 ret = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd);
1420 if (!ret)
1421 ret = 512 << ((cmd & PCI_X_CMD_MAX_READ) >> 2);
1422
1423 return ret;
1424}
1425EXPORT_SYMBOL(pcix_get_mmrbc);
1426
1427/**
1428 * pcix_set_mmrbc - set PCI-X maximum memory read byte count
1429 * @dev: PCI device to query
1430 * @mmrbc: maximum memory read count in bytes
1431 * valid values are 512, 1024, 2048, 4096
1432 *
1433 * If possible sets maximum memory read byte count, some bridges have erratas
1434 * that prevent this.
1435 */
1436int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc)
1437{
1438 int cap, err = -EINVAL;
1439 u32 stat, cmd, v, o;
1440
1441 if (mmrbc < 512 || mmrbc > 4096 || (mmrbc & (mmrbc-1)))
1442 goto out;
1443
1444 v = ffs(mmrbc) - 10;
1445
1446 cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
1447 if (!cap)
1448 goto out;
1449
1450 err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat);
1451 if (err)
1452 goto out;
1453
1454 if (v > (stat & PCI_X_STATUS_MAX_READ) >> 21)
1455 return -E2BIG;
1456
1457 err = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd);
1458 if (err)
1459 goto out;
1460
1461 o = (cmd & PCI_X_CMD_MAX_READ) >> 2;
1462 if (o != v) {
1463 if (v > o && dev->bus &&
1464 (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MMRBC))
1465 return -EIO;
1466
1467 cmd &= ~PCI_X_CMD_MAX_READ;
1468 cmd |= v << 2;
1469 err = pci_write_config_dword(dev, cap + PCI_X_CMD, cmd);
1470 }
1471out:
1472 return err;
1473}
1474EXPORT_SYMBOL(pcix_set_mmrbc);
1475
1476/**
1477 * pcie_get_readrq - get PCI Express read request size
1478 * @dev: PCI device to query
1479 *
1480 * Returns maximum memory read request in bytes
1481 * or appropriate error value.
1482 */
1483int pcie_get_readrq(struct pci_dev *dev)
1484{
1485 int ret, cap;
1486 u16 ctl;
1487
1488 cap = pci_find_capability(dev, PCI_CAP_ID_EXP);
1489 if (!cap)
1490 return -EINVAL;
1491
1492 ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
1493 if (!ret)
1494 ret = 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12);
1495
1496 return ret;
1497}
1498EXPORT_SYMBOL(pcie_get_readrq);
1499
1500/**
1501 * pcie_set_readrq - set PCI Express maximum memory read request
1502 * @dev: PCI device to query
1503 * @count: maximum memory read count in bytes
1504 * valid values are 128, 256, 512, 1024, 2048, 4096
1505 *
1506 * If possible sets maximum read byte count
1507 */
1508int pcie_set_readrq(struct pci_dev *dev, int rq)
1509{
1510 int cap, err = -EINVAL;
1511 u16 ctl, v;
1512
1513 if (rq < 128 || rq > 4096 || (rq & (rq-1)))
1514 goto out;
1515
1516 v = (ffs(rq) - 8) << 12;
1517
1518 cap = pci_find_capability(dev, PCI_CAP_ID_EXP);
1519 if (!cap)
1520 goto out;
1521
1522 err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
1523 if (err)
1524 goto out;
1525
1526 if ((ctl & PCI_EXP_DEVCTL_READRQ) != v) {
1527 ctl &= ~PCI_EXP_DEVCTL_READRQ;
1528 ctl |= v;
1529 err = pci_write_config_dword(dev, cap + PCI_EXP_DEVCTL, ctl);
1530 }
1531
1532out:
1533 return err;
1534}
1535EXPORT_SYMBOL(pcie_set_readrq);
1536
1537/**
1378 * pci_select_bars - Make BAR mask from the type of resource 1538 * pci_select_bars - Make BAR mask from the type of resource
1379 * @dev: the PCI device for which BAR mask is made 1539 * @dev: the PCI device for which BAR mask is made
1380 * @flags: resource type mask to be selected 1540 * @flags: resource type mask to be selected
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 01d8f8a8843c..75bd6a8648f6 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -627,6 +627,22 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_
627DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic); 627DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic);
628#endif /* CONFIG_X86_IO_APIC */ 628#endif /* CONFIG_X86_IO_APIC */
629 629
630/*
631 * Some settings of MMRBC can lead to data corruption so block changes.
632 * See AMD 8131 HyperTransport PCI-X Tunnel Revision Guide
633 */
634static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
635{
636 unsigned char revid;
637
638 pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
639 if (dev->subordinate && revid <= 0x12) {
640 printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X MMRBC\n",
641 revid);
642 dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC;
643 }
644}
645DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_mmrbc);
630 646
631/* 647/*
632 * FIXME: it is questionable that quirk_via_acpi 648 * FIXME: it is questionable that quirk_via_acpi