Merge branch 'pci/resource'

- Build zero-sized resources when a BAR is larger than 4G but
  pci_bus_addr_t or resource_size_t can't represent 64-bit addresses (Ilpo
  Järvinen)

- Fix bridge window alignment with optional resources, where we previously
  lost the additional alignment requirement (Ilpo Järvinen)

- Stop over-estimating bridge window size since we now assign them without
  any gaps between them (Ilpo Järvinen)

- Increase resource MAX_IORES_LEVEL to avoid /proc/iomem flattening for
  nested bridges and endpoints (Ilpo Järvinen)

- Remove old_size limit from bridge window sizing (Ilpo Järvinen)

- Push realloc check into pbus_size_mem() to simplify callers (Ilpo
  Järvinen)

- Pass bridge window resource to pbus_size_mem() to avoid looking it up
  again (Ilpo Järvinen)

- Use res_to_dev_res() instead of open-coding the same search (Ilpo
  Järvinen)

- Add pci_resource_is_bridge_win() helper (Ilpo Järvinen)

- Add more logging of resource assignment (Ilpo Järvinen)

- Add pbus_mem_size_optional() to handle sizes of optional resources
  (SR-IOV VF BARs, expansion ROMs, bridge windows) (Ilpo Järvinen)

- Move CardBus code to setup-cardbus.c and only build it when
  CONFIG_CARDBUS is set (Ilpo Järvinen)

- Use scnprintf() instead of sprintf() (Ilpo Järvinen)

- Add pbus_validate_busn() for Bus Number validation (Ilpo Järvinen)

- Don't claim disabled bridge windows to avoid spurious claim failures
  (Ilpo Järvinen)

* pci/resource:
  PCI: Don't claim disabled bridge windows
  PCI: Move CardBus bridge scanning to setup-cardbus.c
  PCI: Add pbus_validate_busn() for Bus Number validation
  PCI: Add dword #defines for Bus Number + Secondary Latency Timer
  PCI: Use scnprintf() instead of sprintf()
  PCI: Handle CardBus-specific params in setup-cardbus.c
  PCI: Separate CardBus setup & build it only with CONFIG_CARDBUS
  PCI: Add 'pci' prefix to struct pci_dev_resource handling functions
  PCI: Use resource_assigned() in setup-bus.c algorithm
  resource: Mark res given to resource_assigned() as const
  PCI: Add pbus_mem_size_optional() to handle optional sizes
  PCI: Check invalid align earlier in pbus_size_mem()
  PCI: Log reset and restore of resources
  PCI: Add pci_resource_is_bridge_win()
  PCI: Fetch dev_res to local var in __assign_resources_sorted()
  PCI: Use res_to_dev_res() in reassign_resources_sorted()
  PCI: Pass bridge window resource to pbus_size_mem()
  PCI: Push realloc check into pbus_size_mem()
  PCI: Remove old_size limit from bridge window sizing
  resource: Increase MAX_IORES_LEVEL to 8
  PCI: Stop over-estimating bridge window size
  PCI: Rewrite bridge window head alignment function
  PCI: Fix bridge window alignment with optional resources
  PCI: Use resource_set_range() that correctly sets ->end
This commit is contained in:
Bjorn Helgaas 2026-02-06 17:09:25 -06:00
commit 73b4779864
13 changed files with 648 additions and 515 deletions

View File

@ -39,6 +39,7 @@ obj-$(CONFIG_PCI_TSM) += tsm.o
obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o
obj-$(CONFIG_PCI_NPEM) += npem.o
obj-$(CONFIG_PCIE_TPH) += tph.o
obj-$(CONFIG_CARDBUS) += setup-cardbus.o
# Endpoint library must be initialized before its users
obj-$(CONFIG_PCI_ENDPOINT) += endpoint/

View File

@ -181,7 +181,7 @@ static ssize_t resource_show(struct device *dev, struct device_attribute *attr,
struct resource zerores = {};
/* For backwards compatibility */
if (i >= PCI_BRIDGE_RESOURCES && i <= PCI_BRIDGE_RESOURCE_END &&
if (pci_resource_is_bridge_win(i) &&
res->flags & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
res = &zerores;

View File

@ -99,12 +99,6 @@ bool pci_reset_supported(struct pci_dev *dev)
int pci_domains_supported = 1;
#endif
#define DEFAULT_CARDBUS_IO_SIZE (256)
#define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024)
/* pci=cbmemsize=nnM,cbiosize=nn can override this */
unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE;
unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
#define DEFAULT_HOTPLUG_IO_SIZE (256)
#define DEFAULT_HOTPLUG_MMIO_SIZE (2*1024*1024)
#define DEFAULT_HOTPLUG_MMIO_PREF_SIZE (2*1024*1024)
@ -6639,7 +6633,9 @@ static int __init pci_setup(char *str)
if (k)
*k++ = 0;
if (*str && (str = pcibios_setup(str)) && *str) {
if (!strcmp(str, "nomsi")) {
if (!pci_setup_cardbus(str)) {
/* Function handled the parameters */
} else if (!strcmp(str, "nomsi")) {
pci_no_msi();
} else if (!strncmp(str, "noats", 5)) {
pr_info("PCIe: ATS is disabled\n");
@ -6658,10 +6654,6 @@ static int __init pci_setup(char *str)
pcie_ari_disabled = true;
} else if (!strncmp(str, "notph", 5)) {
pci_no_tph();
} else if (!strncmp(str, "cbiosize=", 9)) {
pci_cardbus_io_size = memparse(str + 9, &str);
} else if (!strncmp(str, "cbmemsize=", 10)) {
pci_cardbus_mem_size = memparse(str + 10, &str);
} else if (!strncmp(str, "resource_alignment=", 19)) {
resource_alignment_param = str + 19;
} else if (!strncmp(str, "ecrc=", 5)) {

View File

@ -245,6 +245,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);
@ -379,8 +380,40 @@ extern unsigned long pci_hotplug_io_size;
extern unsigned long pci_hotplug_mmio_size;
extern unsigned long pci_hotplug_mmio_pref_size;
extern unsigned long pci_hotplug_bus_size;
extern unsigned long pci_cardbus_io_size;
extern unsigned long pci_cardbus_mem_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
static inline unsigned long pci_cardbus_resource_alignment(struct resource *res)
{
return 0;
}
static inline int pci_bus_size_cardbus_bridge(struct pci_bus *bus,
struct list_head *realloc_head)
{
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 */
/**
* pci_match_one_device - Tell if a PCI device structure has a matching
@ -443,6 +476,10 @@ void __pci_size_stdbars(struct pci_dev *dev, int count,
int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
struct resource *res, unsigned int reg, u32 *sizes);
void pci_configure_ari(struct pci_dev *dev);
int pci_dev_res_add_to_list(struct list_head *head, struct pci_dev *dev,
struct resource *res, resource_size_t add_size,
resource_size_t min_align);
void __pci_bus_size_bridges(struct pci_bus *bus,
struct list_head *realloc_head);
void __pci_bus_assign_resources(const struct pci_bus *bus,
@ -455,6 +492,11 @@ void pci_walk_bus_locked(struct pci_bus *top,
const char *pci_resource_name(struct pci_dev *dev, unsigned int i);
bool pci_resource_is_optional(const struct pci_dev *dev, int resno);
static inline bool pci_resource_is_bridge_win(int resno)
{
return resno >= PCI_BRIDGE_RESOURCES &&
resno <= PCI_BRIDGE_RESOURCE_END;
}
/**
* pci_resource_num - Reverse lookup resource number from device resources
@ -478,6 +520,7 @@ static inline int pci_resource_num(const struct pci_dev *dev,
return resno;
}
void pbus_validate_busn(struct pci_bus *bus);
struct resource *pbus_select_window(struct pci_bus *bus,
const struct resource *res);
void pci_reassigndev_resource_alignment(struct pci_dev *dev);
@ -927,8 +970,6 @@ static inline void pci_suspend_ptm(struct pci_dev *dev) { }
static inline void pci_resume_ptm(struct pci_dev *dev) { }
#endif
unsigned long pci_cardbus_resource_alignment(struct resource *);
static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
struct resource *res)
{

View File

@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/pci_hotplug.h>
#include <linux/slab.h>
#include <linux/sprintf.h>
#include <linux/module.h>
#include <linux/cpumask.h>
#include <linux/aer.h>
@ -24,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,
@ -287,8 +285,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
if ((sizeof(pci_bus_addr_t) < 8 || sizeof(resource_size_t) < 8)
&& sz64 > 0x100000000ULL) {
res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
res->start = 0;
res->end = 0;
resource_set_range(res, 0, 0);
pci_err(dev, "%s: can't handle BAR larger than 4GB (size %#010llx)\n",
res_name, (unsigned long long)sz64);
goto out;
@ -297,8 +294,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
if ((sizeof(pci_bus_addr_t) < 8) && l) {
/* Above 32-bit boundary; try to reallocate */
res->flags |= IORESOURCE_UNSET;
res->start = 0;
res->end = sz64 - 1;
resource_set_range(res, 0, sz64);
pci_info(dev, "%s: can't handle BAR above 4GB (bus address %#010llx)\n",
res_name, (unsigned long long)l64);
goto out;
@ -525,8 +521,8 @@ static void pci_read_bridge_windows(struct pci_dev *bridge)
pci_read_config_dword(bridge, PCI_PRIMARY_BUS, &buses);
res.flags = IORESOURCE_BUS;
res.start = (buses >> 8) & 0xff;
res.end = (buses >> 16) & 0xff;
res.start = FIELD_GET(PCI_SECONDARY_BUS_MASK, buses);
res.end = FIELD_GET(PCI_SUBORDINATE_BUS_MASK, buses);
pci_info(bridge, "PCI bridge to %pR%s\n", &res,
bridge->transparent ? " (subtractive decode)" : "");
@ -1313,6 +1309,26 @@ static void pci_enable_rrs_sv(struct pci_dev *pdev)
static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
unsigned int available_buses);
void pbus_validate_busn(struct pci_bus *bus)
{
struct pci_bus *upstream = bus->parent;
struct pci_dev *bridge = bus->self;
/* Check that all devices are accessible */
while (upstream->parent) {
if ((bus->busn_res.end > upstream->busn_res.end) ||
(bus->number > upstream->busn_res.end) ||
(bus->number < upstream->number) ||
(bus->busn_res.end < upstream->number)) {
pci_info(bridge, "devices behind bridge are unusable because %pR cannot be assigned for them\n",
&bus->busn_res);
break;
}
upstream = upstream->parent;
}
}
/**
* pci_ea_fixed_busnrs() - Read fixed Secondary and Subordinate bus
* numbers from EA capability.
@ -1324,7 +1340,7 @@ static unsigned int pci_scan_child_bus_extend(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;
@ -1378,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;
@ -1394,9 +1409,9 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
pm_runtime_get_sync(&dev->dev);
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
primary = buses & 0xFF;
secondary = (buses >> 8) & 0xFF;
subordinate = (buses >> 16) & 0xFF;
primary = FIELD_GET(PCI_PRIMARY_BUS_MASK, buses);
secondary = FIELD_GET(PCI_SECONDARY_BUS_MASK, buses);
subordinate = FIELD_GET(PCI_SUBORDINATE_BUS_MASK, buses);
pci_dbg(dev, "scanning [bus %02x-%02x] behind bridge, pass %d\n",
secondary, subordinate, pass);
@ -1423,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;
/*
@ -1466,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
@ -1477,7 +1499,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
* ranges.
*/
pci_write_config_dword(dev, PCI_PRIMARY_BUS,
buses & ~0xffffff);
buses & PCI_SEC_LATENCY_TIMER_MASK);
goto out;
}
@ -1508,59 +1530,16 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
if (available_buses)
available_buses--;
buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0)
| ((unsigned int)(child->busn_res.start) << 8)
| ((unsigned int)(child->busn_res.end) << 16);
/*
* yenta.c forces a secondary latency timer of 176.
* Copy that behaviour here.
*/
if (is_cardbus) {
buses &= ~0xff000000;
buses |= CARDBUS_LATENCY_TIMER << 24;
}
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);
/* 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.
@ -1572,23 +1551,10 @@ 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), "PCI Bus %04x:%02x",
pci_domain_nr(bus), child->number);
sprintf(child->name,
(is_cardbus ? "PCI CardBus %04x:%02x" : "PCI Bus %04x:%02x"),
pci_domain_nr(bus), child->number);
/* Check that all devices are accessible */
while (bus->parent) {
if ((child->busn_res.end > bus->busn_res.end) ||
(child->number > bus->busn_res.end) ||
(child->number < bus->number) ||
(child->busn_res.end < bus->number)) {
dev_info(&dev->dev, "devices behind bridge are unusable because %pR cannot be assigned for them\n",
&child->busn_res);
break;
}
bus = bus->parent;
}
pbus_validate_busn(child);
out:
/* Clear errors in the Secondary Status Register */

File diff suppressed because it is too large Load Diff

306
drivers/pci/setup-cardbus.c Normal file
View File

@ -0,0 +1,306 @@
// SPDX-License-Identifier: GPL-2.0
/*
* 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 */
static unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE;
static unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
unsigned long pci_cardbus_resource_alignment(struct resource *res)
{
if (res->flags & IORESOURCE_IO)
return pci_cardbus_io_size;
if (res->flags & IORESOURCE_MEM)
return pci_cardbus_mem_size;
return 0;
}
int pci_bus_size_cardbus_bridge(struct pci_bus *bus,
struct list_head *realloc_head)
{
struct pci_dev *bridge = bus->self;
struct resource *b_res;
resource_size_t b_res_3_size = pci_cardbus_mem_size * 2;
u16 ctrl;
b_res = &bridge->resource[PCI_CB_BRIDGE_IO_0_WINDOW];
if (resource_assigned(b_res))
goto handle_b_res_1;
/*
* Reserve some resources for CardBus. We reserve a fixed amount
* of bus space for CardBus bridges.
*/
resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size);
b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
if (realloc_head) {
b_res->end -= pci_cardbus_io_size;
pci_dev_res_add_to_list(realloc_head, bridge, b_res,
pci_cardbus_io_size,
pci_cardbus_io_size);
}
handle_b_res_1:
b_res = &bridge->resource[PCI_CB_BRIDGE_IO_1_WINDOW];
if (resource_assigned(b_res))
goto handle_b_res_2;
resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size);
b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
if (realloc_head) {
b_res->end -= pci_cardbus_io_size;
pci_dev_res_add_to_list(realloc_head, bridge, b_res,
pci_cardbus_io_size,
pci_cardbus_io_size);
}
handle_b_res_2:
/* MEM1 must not be pref MMIO */
pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) {
ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
}
/* Check whether prefetchable memory is supported by this bridge. */
pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) {
ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
}
b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_0_WINDOW];
if (resource_assigned(b_res))
goto handle_b_res_3;
/*
* If we have prefetchable memory support, allocate two regions.
* Otherwise, allocate one region of twice the size.
*/
if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
resource_set_range(b_res, pci_cardbus_mem_size,
pci_cardbus_mem_size);
b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
IORESOURCE_STARTALIGN;
if (realloc_head) {
b_res->end -= pci_cardbus_mem_size;
pci_dev_res_add_to_list(realloc_head, bridge, b_res,
pci_cardbus_mem_size,
pci_cardbus_mem_size);
}
/* Reduce that to half */
b_res_3_size = pci_cardbus_mem_size;
}
handle_b_res_3:
b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_1_WINDOW];
if (resource_assigned(b_res))
goto handle_done;
resource_set_range(b_res, pci_cardbus_mem_size, b_res_3_size);
b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
if (realloc_head) {
b_res->end -= b_res_3_size;
pci_dev_res_add_to_list(realloc_head, bridge, b_res,
b_res_3_size, pci_cardbus_mem_size);
}
handle_done:
return 0;
}
void pci_setup_cardbus_bridge(struct pci_bus *bus)
{
struct pci_dev *bridge = bus->self;
struct resource *res;
struct pci_bus_region region;
pci_info(bridge, "CardBus bridge to %pR\n",
&bus->busn_res);
res = bus->resource[0];
pcibios_resource_to_bus(bridge->bus, &region, res);
if (resource_assigned(res) && 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.
*/
pci_info(bridge, " bridge window %pR\n", res);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
region.end);
}
res = bus->resource[1];
pcibios_resource_to_bus(bridge->bus, &region, res);
if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
pci_info(bridge, " bridge window %pR\n", res);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
region.end);
}
res = bus->resource[2];
pcibios_resource_to_bus(bridge->bus, &region, res);
if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
pci_info(bridge, " bridge window %pR\n", res);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
region.end);
}
res = bus->resource[3];
pcibios_resource_to_bus(bridge->bus, &region, res);
if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
pci_info(bridge, " bridge window %pR\n", res);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
region.end);
}
}
EXPORT_SYMBOL(pci_setup_cardbus_bridge);
int pci_setup_cardbus(char *str)
{
if (!strncmp(str, "cbiosize=", 9)) {
pci_cardbus_io_size = memparse(str + 9, &str);
return 0;
} else if (!strncmp(str, "cbmemsize=", 10)) {
pci_cardbus_mem_size = memparse(str + 10, &str);
return 0;
}
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;
}

View File

@ -359,7 +359,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
res->flags &= ~IORESOURCE_UNSET;
res->flags &= ~IORESOURCE_STARTALIGN;
if (resno >= PCI_BRIDGE_RESOURCES && resno <= PCI_BRIDGE_RESOURCE_END)
if (pci_resource_is_bridge_win(resno))
res->flags &= ~IORESOURCE_DISABLED;
pci_info(dev, "%s %pR: assigned\n", res_name, res);

View File

@ -779,7 +779,7 @@ static void yenta_allocate_resources(struct yenta_socket *socket)
IORESOURCE_MEM,
PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1);
if (program)
pci_setup_cardbus(socket->dev->subordinate);
pci_setup_cardbus_bridge(socket->dev->subordinate);
}

View File

@ -338,7 +338,7 @@ static inline bool resource_union(const struct resource *r1, const struct resour
* Check if this resource is added to a resource tree or detached. Caller is
* responsible for not racing assignment.
*/
static inline bool resource_assigned(struct resource *res)
static inline bool resource_assigned(const struct resource *res)
{
return res->parent;
}

View File

@ -1248,7 +1248,11 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev);
void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev);
void pci_stop_root_bus(struct pci_bus *bus);
void pci_remove_root_bus(struct pci_bus *bus);
void pci_setup_cardbus(struct pci_bus *bus);
#ifdef CONFIG_CARDBUS
void pci_setup_cardbus_bridge(struct pci_bus *bus);
#else
static inline void pci_setup_cardbus_bridge(struct pci_bus *bus) { }
#endif
void pcibios_setup_bridge(struct pci_bus *bus, unsigned long type);
void pci_sort_breadthfirst(void);
#define dev_is_pci(d) ((d)->bus == &pci_bus_type)

View File

@ -132,6 +132,11 @@
#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */
#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */
#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */
/* Masks for dword-sized processing of Bus Number and Sec Latency Timer fields */
#define PCI_PRIMARY_BUS_MASK 0x000000ff
#define PCI_SECONDARY_BUS_MASK 0x0000ff00
#define PCI_SUBORDINATE_BUS_MASK 0x00ff0000
#define PCI_SEC_LATENCY_TIMER_MASK 0xff000000
#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
#define PCI_IO_LIMIT 0x1d
#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */

View File

@ -82,7 +82,7 @@ static struct resource *next_resource(struct resource *p, bool skip_children,
#ifdef CONFIG_PROC_FS
enum { MAX_IORES_LEVEL = 5 };
enum { MAX_IORES_LEVEL = 8 };
static void *r_start(struct seq_file *m, loff_t *pos)
__acquires(resource_lock)