mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-02 04:41:10 -04:00
PCI: Move CardBus bridge scanning to setup-cardbus.c
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 <ilpo.jarvinen@linux.intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Link: https://patch.msgid.link/20251219174036.16738-24-ilpo.jarvinen@linux.intel.com
This commit is contained in:
committed by
Bjorn Helgaas
parent
3cbb40c3d4
commit
5d413c7351
@@ -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 */
|
||||
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
#include <linux/bitfield.h>
|
||||
#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);
|
||||
|
||||
@@ -3,14 +3,19 @@
|
||||
* Cardbus bridge setup routines.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/sprintf.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user