diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-20 17:05:52 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-20 17:05:52 -0800 |
| commit | 3f6eb5a6d27b56ea44c2de9f9028d803aeccbfe8 (patch) | |
| tree | f20895da656cafd5064eefd500484c2b3053e374 | |
| parent | 433b23a3dad2b9423fc0d415c6d43add73ac7788 (diff) | |
| parent | 8c746e22096579897d1f8f74dbb6b17a6862fb6d (diff) | |
Merge tag 'pci-v7.0-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci
Pull pci fixes from Bjorn Helgaas:
- Fix bridge window selection bug that prevented resource assignment
(Kai-Heng Feng)
- Fix bridge window sizing, which failed to assign resources for
windows containing only optional resources (ROMs, SR-IOV BARs, etc)
(Ilpo Järvinen)
- Select CONFIGFS_FS when PCI_EPF_TEST is enabled to avoid a link error
(Arnd Bergmann)
- Fix recently merged Endpoint inbound submapping feature (Koichiro
Den)
* tag 'pci-v7.0-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci:
PCI: dwc: ep: Always clear IB maps on BAR update
PCI: dwc: ep: Return after clearing BAR-match inbound mapping
PCI: endpoint: pci-epf-test: Select configfs
PCI: Account fully optional bridge windows correctly
PCI: Validate window resource type in pbus_select_window_for_type()
| -rw-r--r-- | drivers/pci/controller/dwc/pcie-designware-ep.c | 15 | ||||
| -rw-r--r-- | drivers/pci/endpoint/functions/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/pci/setup-bus.c | 42 |
3 files changed, 39 insertions, 19 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 7e7844ff0f7e..295076cf70de 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -165,6 +165,7 @@ static void dw_pcie_ep_clear_ib_maps(struct dw_pcie_ep *ep, u8 func_no, enum pci dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, atu_index); clear_bit(atu_index, ep->ib_window_map); ep_func->bar_to_atu[bar] = 0; + return; } /* Tear down all Address Match Mode mappings, if any. */ @@ -518,6 +519,12 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, /* * We can only dynamically change a BAR if the new BAR size and * BAR flags do not differ from the existing configuration. + * + * Note: this safety check only works when the caller uses + * a new struct pci_epf_bar in the second set_bar() call. + * If the same instance is updated in place and passed in, + * we cannot reliably detect invalid barno/size/flags + * changes here. */ if (ep_func->epf_bar[bar]->barno != bar || ep_func->epf_bar[bar]->size != size || @@ -526,10 +533,12 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, /* * When dynamically changing a BAR, tear down any existing - * mappings before re-programming. + * mappings before re-programming. This is redundant when + * both the old and new mappings are BAR Match Mode, but + * required to handle in-place updates and match-mode + * changes reliably. */ - if (ep_func->epf_bar[bar]->num_submap || epf_bar->num_submap) - dw_pcie_ep_clear_ib_maps(ep, func_no, bar); + dw_pcie_ep_clear_ib_maps(ep, func_no, bar); /* * When dynamically changing a BAR, skip writing the BAR reg, as diff --git a/drivers/pci/endpoint/functions/Kconfig b/drivers/pci/endpoint/functions/Kconfig index 0c9cea0698d7..bb5a23994288 100644 --- a/drivers/pci/endpoint/functions/Kconfig +++ b/drivers/pci/endpoint/functions/Kconfig @@ -6,6 +6,7 @@ config PCI_EPF_TEST tristate "PCI Endpoint Test driver" depends on PCI_ENDPOINT + select CONFIGFS_FS select CRC32 help Enable this configuration option to enable the test driver diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 32aa72456a44..bd66ac47b3b9 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -224,14 +224,21 @@ static struct resource *pbus_select_window_for_type(struct pci_bus *bus, switch (iores_type) { case IORESOURCE_IO: - return pci_bus_resource_n(bus, PCI_BUS_BRIDGE_IO_WINDOW); + win = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_IO_WINDOW); + if (win && (win->flags & IORESOURCE_IO)) + return win; + return NULL; case IORESOURCE_MEM: mmio = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_MEM_WINDOW); mmio_pref = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_PREF_MEM_WINDOW); - if (!(type & IORESOURCE_PREFETCH) || - !(mmio_pref->flags & IORESOURCE_MEM)) + if (mmio && !(mmio->flags & IORESOURCE_MEM)) + mmio = NULL; + if (mmio_pref && !(mmio_pref->flags & IORESOURCE_MEM)) + mmio_pref = NULL; + + if (!(type & IORESOURCE_PREFETCH) || !mmio_pref) return mmio; if ((type & IORESOURCE_MEM_64) || @@ -1217,31 +1224,34 @@ static bool pbus_size_mem_optional(struct pci_dev *dev, int resno, struct resource *res = pci_resource_n(dev, resno); bool optional = pci_resource_is_optional(dev, resno); resource_size_t r_size = resource_size(res); - struct pci_dev_resource *dev_res; + struct pci_dev_resource *dev_res = NULL; if (!realloc_head) return false; - if (!optional) { - /* - * Only bridges have optional sizes in realloc_head at this - * point. As res_to_dev_res() walks the entire realloc_head - * list, skip calling it when known unnecessary. - */ - if (!pci_resource_is_bridge_win(resno)) - return false; - + /* + * Only bridges have optional sizes in realloc_head at this + * point. As res_to_dev_res() walks the entire realloc_head + * list, skip calling it when known unnecessary. + */ + if (pci_resource_is_bridge_win(resno)) { dev_res = res_to_dev_res(realloc_head, res); if (dev_res) { *children_add_size += dev_res->add_size; *add_align = max(*add_align, dev_res->min_align); } + } + if (!optional) return false; - } - /* Put SRIOV requested res to the optional list */ - pci_dev_res_add_to_list(realloc_head, dev, res, 0, align); + /* + * Put requested res to the optional list if not there yet (SR-IOV, + * disabled ROM). Bridge windows with an optional part are already + * on the list. + */ + if (!dev_res) + pci_dev_res_add_to_list(realloc_head, dev, res, 0, align); *children_add_size += r_size; *add_align = max(align, *add_align); |
