diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2021-12-21 19:45:07 +0300 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2022-01-11 18:33:10 +0300 |
commit | 500b55b05d0a21c4adddf4c3b29ee6f32b502046 (patch) | |
tree | fb08ffe79a38b7948798745fb5336849368a3432 | |
parent | fa55b7dcdc43c1aa1ba12bca9d2dd4318c2a0dbf (diff) | |
download | linux-500b55b05d0a21c4adddf4c3b29ee6f32b502046.tar.xz |
PCI: Work around Intel I210 ROM BAR overlap defect
Per PCIe r5, sec 7.5.1.2.4, a device must not claim accesses to its
Expansion ROM unless both the Memory Space Enable and the Expansion ROM
Enable bit are set. But apparently some Intel I210 NICs don't work
correctly if the ROM BAR overlaps another BAR, even if the Expansion ROM is
disabled.
Michael reported that on a Kontron SMARC-sAL28 ARM64 system with U-Boot
v2021.01-rc3, the ROM BAR overlaps BAR 3, and networking doesn't work at
all:
BAR 0: 0x40000000 (32-bit, non-prefetchable) [size=1M]
BAR 3: 0x40200000 (32-bit, non-prefetchable) [size=16K]
ROM: 0x40200000 (disabled) [size=1M]
NETDEV WATCHDOG: enP2p1s0 (igb): transmit queue 0 timed out
Hardware name: Kontron SMARC-sAL28 (Single PHY) on SMARC Eval 2.0 carrier (DT)
igb 0002:01:00.0 enP2p1s0: Reset adapter
Previously, pci_std_update_resource() wrote the assigned ROM address to the
BAR only when the ROM was enabled. This meant that the I210 ROM BAR could
be left with an address assigned by firmware, which might overlap with
other BARs.
Quirk these I210 devices so pci_std_update_resource() always writes the
assigned address to the ROM BAR, whether or not the ROM is enabled.
Link: https://lore.kernel.org/r/20211223163754.GA1267351@bhelgaas
Link: https://lore.kernel.org/r/20201230185317.30915-1-michael@walle.cc
Link: https://bugzilla.kernel.org/show_bug.cgi?id=211105
Reported-by: Michael Walle <michael@walle.cc>
Tested-by: Michael Walle <michael@walle.cc>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r-- | drivers/pci/quirks.c | 10 | ||||
-rw-r--r-- | drivers/pci/setup-res.c | 8 | ||||
-rw-r--r-- | include/linux/pci.h | 1 |
3 files changed, 17 insertions, 2 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 003950c738d2..46ff04091fa3 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -5857,3 +5857,13 @@ static void nvidia_ion_ahci_fixup(struct pci_dev *pdev) pdev->dev_flags |= PCI_DEV_FLAGS_HAS_MSI_MASKING; } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0ab8, nvidia_ion_ahci_fixup); + +static void rom_bar_overlap_defect(struct pci_dev *dev) +{ + pci_info(dev, "working around ROM BAR overlap defect\n"); + dev->rom_bar_overlap = 1; +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1533, rom_bar_overlap_defect); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1536, rom_bar_overlap_defect); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1537, rom_bar_overlap_defect); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1538, rom_bar_overlap_defect); diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 7f1acb3918d0..439ac5f5907a 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -75,12 +75,16 @@ static void pci_std_update_resource(struct pci_dev *dev, int resno) * as zero when disabled, so don't update ROM BARs unless * they're enabled. See * https://lore.kernel.org/r/43147B3D.1030309@vc.cvut.cz/ + * But we must update ROM BAR for buggy devices where even a + * disabled ROM can conflict with other BARs. */ - if (!(res->flags & IORESOURCE_ROM_ENABLE)) + if (!(res->flags & IORESOURCE_ROM_ENABLE) && + !dev->rom_bar_overlap) return; reg = dev->rom_base_reg; - new |= PCI_ROM_ADDRESS_ENABLE; + if (res->flags & IORESOURCE_ROM_ENABLE) + new |= PCI_ROM_ADDRESS_ENABLE; } else return; diff --git a/include/linux/pci.h b/include/linux/pci.h index 18a75c8e615c..51c4a063f489 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -455,6 +455,7 @@ struct pci_dev { unsigned int link_active_reporting:1;/* Device capable of reporting link active */ unsigned int no_vf_scan:1; /* Don't scan for VFs after IOV enablement */ unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ pci_dev_flags_t dev_flags; atomic_t enable_cnt; /* pci_enable_device has been called */ |