diff options
author | Peter Oruba <peter.oruba@amd.com> | 2007-05-15 07:59:13 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-11 19:02:07 -0400 |
commit | d556ad4bbe75faf17b239e151a9f003322b2e851 (patch) | |
tree | 794e4f21a9c6e76328feccf313e4d268d3ec5146 | |
parent | e4585da22ad04a055cbb5c863a37aa8cc02eac89 (diff) |
PCI: add PCI-X/PCI-Express read control interfaces
This patch introduces an interface to read and write PCI-X / PCI-Express
maximum read byte count values from PCI config space. There is a second
function that returns the maximum _designed_ read byte count, which marks the
maximum value for a device, since some drivers try to set MMRBC to the
highest allowed value and rely on such a function.
Based on patch set by Stephen Hemminger <shemminger@linux-foundation.org>
Cc: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Peter Oruba <peter.oruba@amd.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/pci/pci.c | 160 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 16 | ||||
-rw-r--r-- | include/linux/pci.h | 7 |
3 files changed, 182 insertions, 1 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 | */ | ||
1384 | int 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 | } | ||
1401 | EXPORT_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 | */ | ||
1410 | int 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 | } | ||
1425 | EXPORT_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 | */ | ||
1436 | int 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 | } | ||
1471 | out: | ||
1472 | return err; | ||
1473 | } | ||
1474 | EXPORT_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 | */ | ||
1483 | int 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 | } | ||
1498 | EXPORT_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 | */ | ||
1508 | int 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 | |||
1532 | out: | ||
1533 | return err; | ||
1534 | } | ||
1535 | EXPORT_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_ | |||
627 | DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic); | 627 | DECLARE_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 | */ | ||
634 | static 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 | } | ||
645 | DECLARE_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 |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 086a0e5a6318..ac403d74a222 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -111,7 +111,8 @@ enum pcie_reset_state { | |||
111 | 111 | ||
112 | typedef unsigned short __bitwise pci_bus_flags_t; | 112 | typedef unsigned short __bitwise pci_bus_flags_t; |
113 | enum pci_bus_flags { | 113 | enum pci_bus_flags { |
114 | PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, | 114 | PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, |
115 | PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2, | ||
115 | }; | 116 | }; |
116 | 117 | ||
117 | struct pci_cap_saved_state { | 118 | struct pci_cap_saved_state { |
@@ -549,6 +550,10 @@ void pci_intx(struct pci_dev *dev, int enable); | |||
549 | void pci_msi_off(struct pci_dev *dev); | 550 | void pci_msi_off(struct pci_dev *dev); |
550 | int pci_set_dma_mask(struct pci_dev *dev, u64 mask); | 551 | int pci_set_dma_mask(struct pci_dev *dev, u64 mask); |
551 | int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); | 552 | int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); |
553 | int pcix_get_max_mmrbc(struct pci_dev *dev); | ||
554 | int pcix_get_mmrbc(struct pci_dev *dev); | ||
555 | int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc); | ||
556 | int pcie_set_readrq(struct pci_dev *dev, int rq); | ||
552 | void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); | 557 | void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); |
553 | int __must_check pci_assign_resource(struct pci_dev *dev, int i); | 558 | int __must_check pci_assign_resource(struct pci_dev *dev, int i); |
554 | int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i); | 559 | int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i); |