diff options
author | Yijing Wang <wangyijing@huawei.com> | 2013-08-26 04:33:06 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2013-08-26 16:49:28 -0400 |
commit | 5895af79158a55562753f7f05762f3bd766d32b9 (patch) | |
tree | 39eecfd0c9fa8c4963ec081ea171977e05b5b0b9 /drivers/pci/probe.c | |
parent | 3315472c474af8e1c2beb40d980dfc92f03e4d8e (diff) |
PCI: Warn if unsafe MPS settings detected
If a BIOS configures MPS incorrectly, devices may not work normally.
For example, if a bridge has MPS set larger than an endpoint below it,
the endpoint may discard packets.
To help diagnose this issue, print a warning if we find an endpoint
MPS setting different than that of the upstream bridge.
[bhelgaas: changelog, "bridge" temporary, warning text]
Reference: https://bugzilla.kernel.org/show_bug.cgi?id=60799
Reported-by: Joe Jin <joe.jin@oracle.com>
Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Cc: Jon Mason <jdmason@kudzu.us>
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r-- | drivers/pci/probe.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 94c5a77ce853..cd5c4acb5367 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -1582,6 +1582,22 @@ static void pcie_write_mrrs(struct pci_dev *dev) | |||
1582 | "with pci=pcie_bus_safe.\n"); | 1582 | "with pci=pcie_bus_safe.\n"); |
1583 | } | 1583 | } |
1584 | 1584 | ||
1585 | static void pcie_bus_detect_mps(struct pci_dev *dev) | ||
1586 | { | ||
1587 | struct pci_dev *bridge = dev->bus->self; | ||
1588 | int mps, p_mps; | ||
1589 | |||
1590 | if (!bridge) | ||
1591 | return; | ||
1592 | |||
1593 | mps = pcie_get_mps(dev); | ||
1594 | p_mps = pcie_get_mps(bridge); | ||
1595 | |||
1596 | if (mps != p_mps) | ||
1597 | dev_warn(&dev->dev, "Max Payload Size %d, but upstream %s set to %d; if necessary, use \"pci=pcie_bus_safe\" and report a bug\n", | ||
1598 | mps, pci_name(bridge), p_mps); | ||
1599 | } | ||
1600 | |||
1585 | static int pcie_bus_configure_set(struct pci_dev *dev, void *data) | 1601 | static int pcie_bus_configure_set(struct pci_dev *dev, void *data) |
1586 | { | 1602 | { |
1587 | int mps, orig_mps; | 1603 | int mps, orig_mps; |
@@ -1589,6 +1605,11 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data) | |||
1589 | if (!pci_is_pcie(dev)) | 1605 | if (!pci_is_pcie(dev)) |
1590 | return 0; | 1606 | return 0; |
1591 | 1607 | ||
1608 | if (pcie_bus_config == PCIE_BUS_TUNE_OFF) { | ||
1609 | pcie_bus_detect_mps(dev); | ||
1610 | return 0; | ||
1611 | } | ||
1612 | |||
1592 | mps = 128 << *(u8 *)data; | 1613 | mps = 128 << *(u8 *)data; |
1593 | orig_mps = pcie_get_mps(dev); | 1614 | orig_mps = pcie_get_mps(dev); |
1594 | 1615 | ||
@@ -1616,9 +1637,6 @@ void pcie_bus_configure_settings(struct pci_bus *bus) | |||
1616 | if (!pci_is_pcie(bus->self)) | 1637 | if (!pci_is_pcie(bus->self)) |
1617 | return; | 1638 | return; |
1618 | 1639 | ||
1619 | if (pcie_bus_config == PCIE_BUS_TUNE_OFF) | ||
1620 | return; | ||
1621 | |||
1622 | /* FIXME - Peer to peer DMA is possible, though the endpoint would need | 1640 | /* FIXME - Peer to peer DMA is possible, though the endpoint would need |
1623 | * to be aware of the MPS of the destination. To work around this, | 1641 | * to be aware of the MPS of the destination. To work around this, |
1624 | * simply force the MPS of the entire system to the smallest possible. | 1642 | * simply force the MPS of the entire system to the smallest possible. |