From 5895af79158a55562753f7f05762f3bd766d32b9 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Mon, 26 Aug 2013 16:33:06 +0800 Subject: 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 Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas Cc: Jon Mason diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 94c5a77c..cd5c4ac 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -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. -- cgit v0.10.2