]> www.infradead.org Git - users/hch/misc.git/commitdiff
PCI: Disable non-claimed bridge window
authorIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Fri, 29 Aug 2025 13:10:56 +0000 (16:10 +0300)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 16 Sep 2025 16:19:06 +0000 (11:19 -0500)
If clipping or claiming the bridge window fails, the bridge window is left
in a state that does not match the kernel's view on what the bridge window
is.

Disable the bridge window by writing the magic disable value into the Base
and Limit Registers if clipping or claiming failed. To detect if claiming
the resource was successful, add res->parent checks into the bridge setup
functions.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20250829131113.36754-8-ilpo.jarvinen@linux.intel.com
drivers/pci/setup-bus.c

index b477f68b236ce75979e6bbe4c023e9ee633213c1..6bdc1af887dad58b109a7dd2eaa9e17244419da5 100644 (file)
@@ -660,7 +660,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
 
        res = bus->resource[0];
        pcibios_resource_to_bus(bridge->bus, &region, res);
-       if (res->flags & IORESOURCE_IO) {
+       if (res->parent && res->flags & IORESOURCE_IO) {
                /*
                 * The IO resource is allocated a range twice as large as it
                 * would normally need.  This allows us to set both IO regs.
@@ -674,7 +674,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
 
        res = bus->resource[1];
        pcibios_resource_to_bus(bridge->bus, &region, res);
-       if (res->flags & IORESOURCE_IO) {
+       if (res->parent && res->flags & IORESOURCE_IO) {
                pci_info(bridge, "  bridge window %pR\n", res);
                pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
                                        region.start);
@@ -684,7 +684,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
 
        res = bus->resource[2];
        pcibios_resource_to_bus(bridge->bus, &region, res);
-       if (res->flags & IORESOURCE_MEM) {
+       if (res->parent && res->flags & IORESOURCE_MEM) {
                pci_info(bridge, "  bridge window %pR\n", res);
                pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
                                        region.start);
@@ -694,7 +694,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
 
        res = bus->resource[3];
        pcibios_resource_to_bus(bridge->bus, &region, res);
-       if (res->flags & IORESOURCE_MEM) {
+       if (res->parent && res->flags & IORESOURCE_MEM) {
                pci_info(bridge, "  bridge window %pR\n", res);
                pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
                                        region.start);
@@ -735,7 +735,7 @@ static void pci_setup_bridge_io(struct pci_dev *bridge)
        res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
        res_name = pci_resource_name(bridge, PCI_BRIDGE_IO_WINDOW);
        pcibios_resource_to_bus(bridge->bus, &region, res);
-       if (res->flags & IORESOURCE_IO) {
+       if (res->parent && res->flags & IORESOURCE_IO) {
                pci_read_config_word(bridge, PCI_IO_BASE, &l);
                io_base_lo = (region.start >> 8) & io_mask;
                io_limit_lo = (region.end >> 8) & io_mask;
@@ -767,7 +767,7 @@ static void pci_setup_bridge_mmio(struct pci_dev *bridge)
        res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
        res_name = pci_resource_name(bridge, PCI_BRIDGE_MEM_WINDOW);
        pcibios_resource_to_bus(bridge->bus, &region, res);
-       if (res->flags & IORESOURCE_MEM) {
+       if (res->parent && res->flags & IORESOURCE_MEM) {
                l = (region.start >> 16) & 0xfff0;
                l |= region.end & 0xfff00000;
                pci_info(bridge, "  %s %pR\n", res_name, res);
@@ -796,7 +796,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
        res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
        res_name = pci_resource_name(bridge, PCI_BRIDGE_PREF_MEM_WINDOW);
        pcibios_resource_to_bus(bridge->bus, &region, res);
-       if (res->flags & IORESOURCE_PREFETCH) {
+       if (res->parent && res->flags & IORESOURCE_PREFETCH) {
                l = (region.start >> 16) & 0xfff0;
                l |= region.end & 0xfff00000;
                if (res->flags & IORESOURCE_MEM_64) {
@@ -848,6 +848,8 @@ static void pci_setup_bridge(struct pci_bus *bus)
 
 int pci_claim_bridge_resource(struct pci_dev *bridge, int i)
 {
+       int ret = -EINVAL;
+
        if (i < PCI_BRIDGE_RESOURCES || i > PCI_BRIDGE_RESOURCE_END)
                return 0;
 
@@ -861,11 +863,8 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i)
                return -EINVAL;
 
        /* Try to clip the resource and claim the smaller window */
-       if (!pci_bus_clip_resource(bridge, i))
-               return -EINVAL; /* Clipping didn't change anything */
-
-       if (!pci_claim_resource(bridge, i))
-               return -EINVAL;
+       if (pci_bus_clip_resource(bridge, i))
+               ret = pci_claim_resource(bridge, i);
 
        switch (i) {
        case PCI_BRIDGE_IO_WINDOW:
@@ -881,7 +880,7 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i)
                return -EINVAL;
        }
 
-       return 0;
+       return ret;
 }
 
 /*