mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-04 16:15:11 +00:00
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>
This commit is contained in:
parent
3315472c47
commit
5895af7915
1 changed files with 21 additions and 3 deletions
|
@ -1582,6 +1582,22 @@ static void pcie_write_mrrs(struct pci_dev *dev)
|
||||||
"with pci=pcie_bus_safe.\n");
|
"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)
|
static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
|
||||||
{
|
{
|
||||||
int mps, orig_mps;
|
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))
|
if (!pci_is_pcie(dev))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (pcie_bus_config == PCIE_BUS_TUNE_OFF) {
|
||||||
|
pcie_bus_detect_mps(dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
mps = 128 << *(u8 *)data;
|
mps = 128 << *(u8 *)data;
|
||||||
orig_mps = pcie_get_mps(dev);
|
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))
|
if (!pci_is_pcie(bus->self))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (pcie_bus_config == PCIE_BUS_TUNE_OFF)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* FIXME - Peer to peer DMA is possible, though the endpoint would need
|
/* 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,
|
* 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.
|
* simply force the MPS of the entire system to the smallest possible.
|
||||||
|
|
Loading…
Reference in a new issue