[PATCH v7 18/26] PCI: Treat VGA BARs as immovable

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxx>
---
 drivers/pci/probe.c | 34 +++++++++++++++++++++++++++++-----
 1 file changed, 29 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index f8f643dac6d1..b810d28ebf96 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -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;
 
-- 
2.24.1




[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux