From 5d413c735175fd3a862cd747b330d0097f74abce Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 19 Dec 2025 19:40:36 +0200 Subject: [PATCH] PCI: Move CardBus bridge scanning to setup-cardbus.c MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The PCI core's pci_scan_bridge_extend() contains convoluted logic specific to setting up bus numbers for legacy CardBus bridges. Extract the CardBus specific part out into setup-cardbus.c to make the core code cleaner and allow omitting CardBus bridge support from modern systems. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20251219174036.16738-24-ilpo.jarvinen@linux.intel.com --- drivers/pci/pci.h | 16 +++++ drivers/pci/probe.c | 73 +++++----------------- drivers/pci/setup-cardbus.c | 118 ++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 58 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b20ff7ef20ff..c586bf8a9da9 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -242,6 +242,7 @@ void pci_config_pm_runtime_put(struct pci_dev *dev); void pci_pm_power_up_and_verify_state(struct pci_dev *pci_dev); void pci_pm_init(struct pci_dev *dev); void pci_ea_init(struct pci_dev *dev); +bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub); void pci_msi_init(struct pci_dev *dev); void pci_msix_init(struct pci_dev *dev); bool pci_bridge_d3_possible(struct pci_dev *dev); @@ -377,10 +378,17 @@ extern unsigned long pci_hotplug_mmio_size; extern unsigned long pci_hotplug_mmio_pref_size; extern unsigned long pci_hotplug_bus_size; +static inline bool pci_is_cardbus_bridge(struct pci_dev *dev) +{ + return dev->hdr_type == PCI_HEADER_TYPE_CARDBUS; +} #ifdef CONFIG_CARDBUS unsigned long pci_cardbus_resource_alignment(struct resource *res); int pci_bus_size_cardbus_bridge(struct pci_bus *bus, struct list_head *realloc_head); +int pci_cardbus_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, + u32 buses, int max, + unsigned int available_buses, int pass); int pci_setup_cardbus(char *str); #else @@ -393,6 +401,14 @@ static inline int pci_bus_size_cardbus_bridge(struct pci_bus *bus, { return -EOPNOTSUPP; } +static inline int pci_cardbus_scan_bridge_extend(struct pci_bus *bus, + struct pci_dev *dev, + u32 buses, int max, + unsigned int available_buses, + int pass) +{ + return max; +} static inline int pci_setup_cardbus(char *str) { return -ENOENT; } #endif /* CONFIG_CARDBUS */ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 388bcf3a41f1..8f5436456c7a 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -25,9 +25,6 @@ #include #include "pci.h" -#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ -#define CARDBUS_RESERVE_BUSNR 3 - static struct resource busn_resource = { .name = "PCI busn", .start = 0, @@ -1343,7 +1340,7 @@ void pbus_validate_busn(struct pci_bus *bus) * and subordinate bus numbers, return true with the bus numbers in @sec * and @sub. Otherwise return false. */ -static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub) +bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub) { int ea, offset; u32 dw; @@ -1397,8 +1394,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, int pass) { struct pci_bus *child; - int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); - u32 buses, i, j = 0; + u32 buses; u16 bctl; u8 primary, secondary, subordinate; int broken = 0; @@ -1442,8 +1438,15 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT); - if ((secondary || subordinate) && !pcibios_assign_all_busses() && - !is_cardbus && !broken) { + if (pci_is_cardbus_bridge(dev)) { + max = pci_cardbus_scan_bridge_extend(bus, dev, buses, max, + available_buses, + pass); + goto out; + } + + if ((secondary || subordinate) && + !pcibios_assign_all_busses() && !broken) { unsigned int cmax, buses; /* @@ -1485,7 +1488,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, * do in the second pass. */ if (!pass) { - if (pcibios_assign_all_busses() || broken || is_cardbus) + if (pcibios_assign_all_busses() || broken) /* * Temporarily disable forwarding of the @@ -1532,55 +1535,11 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, FIELD_PREP(PCI_SECONDARY_BUS_MASK, child->busn_res.start) | FIELD_PREP(PCI_SUBORDINATE_BUS_MASK, child->busn_res.end); - /* - * yenta.c forces a secondary latency timer of 176. - * Copy that behaviour here. - */ - if (is_cardbus) { - buses &= ~PCI_SEC_LATENCY_TIMER_MASK; - buses |= FIELD_PREP(PCI_SEC_LATENCY_TIMER_MASK, - CARDBUS_LATENCY_TIMER); - } - /* We need to blast all three values with a single write */ pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); - if (!is_cardbus) { - child->bridge_ctl = bctl; - max = pci_scan_child_bus_extend(child, available_buses); - } else { - - /* - * For CardBus bridges, we leave 4 bus numbers as - * cards with a PCI-to-PCI bridge can be inserted - * later. - */ - for (i = 0; i < CARDBUS_RESERVE_BUSNR; i++) { - struct pci_bus *parent = bus; - if (pci_find_bus(pci_domain_nr(bus), - max+i+1)) - break; - while (parent->parent) { - if ((!pcibios_assign_all_busses()) && - (parent->busn_res.end > max) && - (parent->busn_res.end <= max+i)) { - j = 1; - } - parent = parent->parent; - } - if (j) { - - /* - * Often, there are two CardBus - * bridges -- try to leave one - * valid bus number for each one. - */ - i /= 2; - break; - } - } - max += i; - } + child->bridge_ctl = bctl; + max = pci_scan_child_bus_extend(child, available_buses); /* * Set subordinate bus number to its real value. @@ -1592,9 +1551,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, pci_bus_update_busn_res_end(child, max); pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); } - - scnprintf(child->name, sizeof(child->name), - (is_cardbus ? "PCI CardBus %04x:%02x" : "PCI Bus %04x:%02x"), + scnprintf(child->name, sizeof(child->name), "PCI Bus %04x:%02x", pci_domain_nr(bus), child->number); pbus_validate_busn(child); diff --git a/drivers/pci/setup-cardbus.c b/drivers/pci/setup-cardbus.c index 93a2b43c637b..1ebd13a1f730 100644 --- a/drivers/pci/setup-cardbus.c +++ b/drivers/pci/setup-cardbus.c @@ -3,14 +3,19 @@ * Cardbus bridge setup routines. */ +#include #include #include #include #include +#include #include #include "pci.h" +#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ +#define CARDBUS_RESERVE_BUSNR 3 + #define DEFAULT_CARDBUS_IO_SIZE SZ_256 #define DEFAULT_CARDBUS_MEM_SIZE SZ_64M /* pci=cbmemsize=nnM,cbiosize=nn can override this */ @@ -186,3 +191,116 @@ int pci_setup_cardbus(char *str) return -ENOENT; } + +int pci_cardbus_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, + u32 buses, int max, + unsigned int available_buses, int pass) +{ + struct pci_bus *child; + bool fixed_buses; + u8 fixed_sec, fixed_sub; + int next_busnr; + u32 i, j = 0; + + /* + * We need to assign a number to this bus which we always do in the + * second pass. + */ + if (!pass) { + /* + * Temporarily disable forwarding of the configuration + * cycles on all bridges in this bus segment to avoid + * possible conflicts in the second pass between two bridges + * programmed with overlapping bus ranges. + */ + pci_write_config_dword(dev, PCI_PRIMARY_BUS, + buses & PCI_SEC_LATENCY_TIMER_MASK); + return max; + } + + /* Clear errors */ + pci_write_config_word(dev, PCI_STATUS, 0xffff); + + /* Read bus numbers from EA Capability (if present) */ + fixed_buses = pci_ea_fixed_busnrs(dev, &fixed_sec, &fixed_sub); + if (fixed_buses) + next_busnr = fixed_sec; + else + next_busnr = max + 1; + + /* + * Prevent assigning a bus number that already exists. This can + * happen when a bridge is hot-plugged, so in this case we only + * re-scan this bus. + */ + child = pci_find_bus(pci_domain_nr(bus), next_busnr); + if (!child) { + child = pci_add_new_bus(bus, dev, next_busnr); + if (!child) + return max; + pci_bus_insert_busn_res(child, next_busnr, bus->busn_res.end); + } + max++; + if (available_buses) + available_buses--; + + buses = (buses & PCI_SEC_LATENCY_TIMER_MASK) | + FIELD_PREP(PCI_PRIMARY_BUS_MASK, child->primary) | + FIELD_PREP(PCI_SECONDARY_BUS_MASK, child->busn_res.start) | + FIELD_PREP(PCI_SUBORDINATE_BUS_MASK, child->busn_res.end); + + /* + * yenta.c forces a secondary latency timer of 176. + * Copy that behaviour here. + */ + buses &= ~PCI_SEC_LATENCY_TIMER_MASK; + buses |= FIELD_PREP(PCI_SEC_LATENCY_TIMER_MASK, CARDBUS_LATENCY_TIMER); + + /* We need to blast all three values with a single write */ + pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); + + /* + * For CardBus bridges, we leave 4 bus numbers as cards with a + * PCI-to-PCI bridge can be inserted later. + */ + for (i = 0; i < CARDBUS_RESERVE_BUSNR; i++) { + struct pci_bus *parent = bus; + + if (pci_find_bus(pci_domain_nr(bus), max + i + 1)) + break; + + while (parent->parent) { + if (!pcibios_assign_all_busses() && + (parent->busn_res.end > max) && + (parent->busn_res.end <= max + i)) { + j = 1; + } + parent = parent->parent; + } + if (j) { + /* + * Often, there are two CardBus bridges -- try to + * leave one valid bus number for each one. + */ + i /= 2; + break; + } + } + max += i; + + /* + * Set subordinate bus number to its real value. If fixed + * subordinate bus number exists from EA capability then use it. + */ + if (fixed_buses) + max = fixed_sub; + pci_bus_update_busn_res_end(child, max); + pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); + + scnprintf(child->name, sizeof(child->name), "PCI CardBus %04x:%02x", + pci_domain_nr(bus), child->number); + + pbus_validate_busn(child); + + return max; +} -- 2.47.3