@@ -164,6 +164,20 @@ static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar)
#define PCI_COMMAND_DECODE_ENABLE (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)
+static void expand_immovable_range(struct pci_bus *bus, struct resource *res, int idx)
+{
+ struct resource *immovable_range = &bus->immovable_range[idx];
+
+ if (!immovable_range->start || immovable_range->start > res->start)
+ immovable_range->start = res->start;
+
+ if (immovable_range->end < res->end)
+ immovable_range->end = res->end;
+
+ if (bus->parent)
+ expand_immovable_range(bus->parent, immovable_range, idx);
+}
+
/**
* pci_read_base - Read a PCI BAR
* @dev: the PCI device
@@ -307,11 +321,16 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
}
if (pci_can_move_bars && res->start && !(res->flags & IORESOURCE_IO)) {
- pci_warn(dev, "ignore the current offset of BAR %llx-%llx\n",
- l64, l64 + sz64 - 1);
- res->start = 0;
- res->end = sz64 - 1;
- res->flags |= IORESOURCE_SIZEALIGN;
+ if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
+ expand_immovable_range(dev->bus, res,
+ pci_get_bridge_resource_idx(res));
+ } else {
+ pci_warn(dev, "ignore the current offset of BAR %llx-%llx\n",
+ l64, l64 + sz64 - 1);
+ res->start = 0;
+ res->end = sz64 - 1;
+ res->flags |= IORESOURCE_SIZEALIGN;
+ }
}
goto out;
@@ -3164,6 +3183,11 @@ bool pci_dev_bar_movable(struct pci_dev *dev, struct resource *res)
if (region.start == 0xa0000)
return false;
+ if (res->start &&
+ !(res->flags & IORESOURCE_IO) &&
+ (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+ return false;
+
if (!dev->driver && !res->child)
return true;
Some framebuffer drivers (efifb) don't act as a PCI driver (like nouveau), but take information about BARs indirectly - from BIOS for example. This makes them vulnerable to BAR movement during boot, when setting reported by BIOS/bootloader differs from new addresses assigned by the kernel. Until every such driver is aware of movable BARs, mark every VGA BAR as immovable. Perhaps this is also useful for splash screens, so they don't flicker. This makes some BARs and bridge windows immovable during boot, so update the parent's struct pci_bus->immovable_range when encountered. Signed-off-by: Sergei Miroshnichenko <s.miroshnichenko@yadro.com> --- drivers/pci/probe.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-)