PCI: Warn if unsafe MPS settings detected
authorYijing Wang <wangyijing@huawei.com>
Mon, 26 Aug 2013 08:33:06 +0000 (16:33 +0800)
committerBjorn Helgaas <bhelgaas@google.com>
Mon, 26 Aug 2013 20:49:28 +0000 (14:49 -0600)
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>
drivers/pci/probe.c

index 94c5a77ce85391a9e5487da32624287075570218..cd5c4acb53679dafbefe0bf31ef31f7036f4a27e 100644 (file)
@@ -1582,6 +1582,22 @@ static void pcie_write_mrrs(struct pci_dev *dev)
                        "with pci=pcie_bus_safe.\n");
 }
 
+static void pcie_bus_detect_mps(struct pci_dev *dev)
+{
+       struct pci_dev *bridge = dev->bus->self;
+       int mps, p_mps;
+
+       if (!bridge)
+               return;
+
+       mps = pcie_get_mps(dev);
+       p_mps = pcie_get_mps(bridge);
+
+       if (mps != p_mps)
+               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",
+                        mps, pci_name(bridge), p_mps);
+}
+
 static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
 {
        int mps, orig_mps;
@@ -1589,6 +1605,11 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
        if (!pci_is_pcie(dev))
                return 0;
 
+       if (pcie_bus_config == PCIE_BUS_TUNE_OFF) {
+               pcie_bus_detect_mps(dev);
+               return 0;
+       }
+
        mps = 128 << *(u8 *)data;
        orig_mps = pcie_get_mps(dev);
 
@@ -1616,9 +1637,6 @@ void pcie_bus_configure_settings(struct pci_bus *bus)
        if (!pci_is_pcie(bus->self))
                return;
 
-       if (pcie_bus_config == PCIE_BUS_TUNE_OFF)
-               return;
-
        /* FIXME - Peer to peer DMA is possible, though the endpoint would need
         * to be aware of the MPS of the destination.  To work around this,
         * simply force the MPS of the entire system to the smallest possible.
This page took 0.027007 seconds and 5 git commands to generate.