commit 1eb0e6b5cef8564d34873827cde57076f9d8a652 Author: Bjorn Helgaas Date: Thu Jun 5 17:14:03 2014 -0600 PCI: Detect invalid read-only BARs Bill reported that on a Panasonic Toughbook CF-S10 with BIOS V2.00L12 06/16/2011, one device has a read-only BAR: pci 0000:00:04.0: reg 10: [mem 0xfed98000-0xfed9ffff 64bit] pci 0000:00:04.0: no compatible bridge window for [mem 0xfed98000-0xfed9ffff 64bit] pci 0000:00:04.0: BAR 0: assigned [mem 0xdfa00000-0xdfa07fff 64bit] pci 0000:00:04.0: BAR 0: error updating (0xdfa00004 != 0xfed98004) Such a BAR is illegal, of course; we can't determine its size. In this case, we assume it is 32K based on the lowest-order bit set in the BAR address, but it could be smaller (16K, 8K, 4K, etc.) The BAR address is not in a host bridge aperture, so Linux tried to move it into an aperture, but that failed because it is read-only. This is all probably caused by a BIOS defect: there is an ACPI PNP0c02 device at the same address: pnp 00:0e: [mem 0xfed98000-0xfed9ffff] system 00:0e: Plug and Play ACPI device, IDs PNP0C02 (active) I think the BIOS intent was to hide the PCI device and expose it only as the PNP0C02 device. Mark the BAR as IORESOURCE_PCI_FIXED so we don't try to move it. Link: https://bugzilla.kernel.org/show_bug.cgi?id=43331 Reported-by: Bill Unruh Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index e674d0d5b9bd..29b00e77a2e0 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -175,6 +175,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, u16 orig_cmd; struct pci_bus_region region, inverted_region; bool bar_too_big = false, bar_too_high = false, bar_invalid = false; + bool bar_readonly = false; mask = type ? PCI_ROM_ADDRESS_MASK : ~0; @@ -213,6 +214,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, if (type == pci_bar_unknown) { res->flags = decode_bar(dev, l); res->flags |= IORESOURCE_SIZEALIGN; + if (l == sz) + res->flags |= IORESOURCE_PCI_FIXED; if (res->flags & IORESOURCE_IO) { l &= PCI_BASE_ADDRESS_IO_MASK; mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT; @@ -305,6 +308,9 @@ out: (orig_cmd & PCI_COMMAND_DECODE_ENABLE)) pci_write_config_word(dev, PCI_COMMAND, orig_cmd); + if (bar_readonly) + dev_info(&dev->dev, FW_BUG "reg 0x%x: read-only; can't determine actual size and can't move it\n", + pos); if (bar_too_big) dev_err(&dev->dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n", pos, (unsigned long long) sz64);