// SPDX-License-Identifier: GPL-2.0 /* * Support routines for initializing a PCI subsystem * * Extruded from code written by * Dave Rusling (david.rusling@reo.mts.dec.com) * David Mosberger (davidm@cs.arizona.edu) * David Miller (davem@redhat.com) * * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru> * PCI-PCI bridges cleanup, sorted resource allocation. * Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru> * Converted to allocation in 3 passes, which gives * tighter packing. Prefetchable range support.
*/
/** * add_to_list() - Add a new resource tracker to the list * @head: Head of the list * @dev: Device to which the resource belongs * @res: Resource to be tracked * @add_size: Additional size to be optionally added to the resource * @min_align: Minimum memory window alignment
*/ staticint add_to_list(struct list_head *head, struct pci_dev *dev, struct resource *res, resource_size_t add_size,
resource_size_t min_align)
{ struct pci_dev_resource *tmp;
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); if (!tmp) return -ENOMEM;
/** * reassign_resources_sorted() - Satisfy any additional resource requests * * @realloc_head: Head of the list tracking requests requiring * additional resources * @head: Head of the list tracking requests with allocated * resources * * Walk through each element of the realloc_head and try to procure additional * resources for the element, provided the element is in the head list.
*/ staticvoid reassign_resources_sorted(struct list_head *realloc_head, struct list_head *head)
{ struct pci_dev_resource *add_res, *tmp; struct pci_dev_resource *dev_res; struct pci_dev *dev; struct resource *res; constchar *res_name;
resource_size_t add_size, align; int idx;
res = add_res->res;
dev = add_res->dev;
idx = pci_resource_num(dev, res);
/* * Skip resource that failed the earlier assignment and is * not optional as it would just fail again.
*/ if (!res->parent && resource_size(res) &&
!pci_resource_is_optional(dev, idx)) goto out;
/* Skip this resource if not found in head list */
list_for_each_entry(dev_res, head, list) { if (dev_res->res == res) {
found_match = true; break;
}
} if (!found_match) /* Just skip */ continue;
/** * assign_requested_resources_sorted() - Satisfy resource requests * * @head: Head of the list tracking requests for resources * @fail_head: Head of the list tracking requests that could not be * allocated * @optional: Assign also optional resources * * Satisfy resource requests of each element in the list. Add requests that * could not be satisfied to the failed_list.
*/ staticvoid assign_requested_resources_sorted(struct list_head *head, struct list_head *fail_head, bool optional)
{ struct pci_dev_resource *dev_res; struct resource *res; struct pci_dev *dev; bool optional_res; int idx;
list_for_each_entry(dev_res, head, list) {
res = dev_res->res;
dev = dev_res->dev;
idx = pci_resource_num(dev, res);
optional_res = pci_resource_is_optional(dev, idx);
if (!resource_size(res)) continue;
if (!optional && optional_res) continue;
if (pci_assign_resource(dev, idx)) { if (fail_head) {
add_to_list(fail_head, dev, res,
0 /* don't care */,
0 /* don't care */);
}
}
}
}
/* * One pref failed resource will set IORESOURCE_MEM, as we can * allocate pref in non-pref range. Will release all assigned * non-pref sibling resources according to that bit.
*/ return mask & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH);
}
/* Check pref at first */ if (res->flags & IORESOURCE_PREFETCH) { if (mask & IORESOURCE_PREFETCH) returntrue; /* Count pref if its parent is non-pref */ elseif ((mask & IORESOURCE_MEM) &&
!(res->parent->flags & IORESOURCE_PREFETCH)) returntrue; else returnfalse;
}
if (res->flags & IORESOURCE_MEM) return !!(mask & IORESOURCE_MEM);
returnfalse; /* Should not get here */
}
/* Return: @true if assignment of a required resource failed. */ staticbool pci_required_resource_failed(struct list_head *fail_head, unsignedlong type)
{ struct pci_dev_resource *fail_res;
type &= PCI_RES_TYPE_MASK;
list_for_each_entry(fail_res, fail_head, list) { int idx = pci_resource_num(fail_res->dev, fail_res->res);
if (type && (fail_res->flags & PCI_RES_TYPE_MASK) != type) continue;
if (!pci_resource_is_optional(fail_res->dev, idx)) returntrue;
} returnfalse;
}
staticvoid __assign_resources_sorted(struct list_head *head, struct list_head *realloc_head, struct list_head *fail_head)
{ /* * Should not assign requested resources at first. They could be * adjacent, so later reassign can not reallocate them one by one in * parent resource window. * * Try to assign required and any optional resources at beginning * (add_size included). If all required resources were successfully * assigned, get out early. If could not do that, we still try to * assign required at first, then try to reassign some optional * resources. * * Separate three resource type checking if we need to release * assigned resource after requested + add_size try. * * 1. If IO port assignment fails, will release assigned IO * port. * 2. If pref MMIO assignment fails, release assigned pref * MMIO. If assigned pref MMIO's parent is non-pref MMIO * and non-pref MMIO assignment fails, will release that * assigned pref MMIO. * 3. If non-pref MMIO assignment fails or pref MMIO * assignment fails, will release assigned non-pref MMIO.
*/
LIST_HEAD(save_head);
LIST_HEAD(local_fail_head);
LIST_HEAD(dummy_head); struct pci_dev_resource *save_res; struct pci_dev_resource *dev_res, *tmp_res, *dev_res2; struct resource *res; struct pci_dev *dev; constchar *res_name; int idx; unsignedlong fail_type;
resource_size_t add_align, align;
if (!realloc_head)
realloc_head = &dummy_head;
/* Check if optional add_size is there */ if (list_empty(realloc_head)) goto assign;
/* Save original start, end, flags etc at first */
list_for_each_entry(dev_res, head, list) { if (add_to_list(&save_head, dev_res->dev, dev_res->res, 0, 0)) {
free_list(&save_head); goto assign;
}
}
/* Update res in head list with add_size in realloc_head list */
list_for_each_entry_safe(dev_res, tmp_res, head, list) {
res = dev_res->res;
res->end += get_res_add_size(realloc_head, res);
/* * There are two kinds of additional resources in the list: * 1. bridge resource -- IORESOURCE_STARTALIGN * 2. SR-IOV resource -- IORESOURCE_SIZEALIGN * Here just fix the additional alignment for bridge
*/ if (!(res->flags & IORESOURCE_STARTALIGN)) continue;
add_align = get_res_add_align(realloc_head, res);
/* * The "head" list is sorted by alignment so resources with * bigger alignment will be assigned first. After we * change the alignment of a dev_res in "head" list, we * need to reorder the list by alignment to make it * consistent.
*/ if (add_align > res->start) {
resource_set_range(res, add_align, resource_size(res));
/* All non-optional resources assigned? */ if (list_empty(&local_fail_head)) { /* Remove head list from realloc_head list */
list_for_each_entry(dev_res, head, list)
remove_from_list(realloc_head, dev_res->res);
free_list(&save_head); goto out;
}
/* Without realloc_head and only optional fails, nothing more to do. */ if (!pci_required_resource_failed(&local_fail_head, 0) &&
list_empty(realloc_head)) {
list_for_each_entry(save_res, &save_head, list) { struct resource *res = save_res->res;
/* Check failed type */
fail_type = pci_fail_res_type_mask(&local_fail_head); /* Remove not need to be released assigned res from head list etc */
list_for_each_entry_safe(dev_res, tmp_res, head, list) {
res = dev_res->res;
if (res->parent && !pci_need_to_release(fail_type, res)) { /* Remove it from realloc_head list */
remove_from_list(realloc_head, res);
remove_from_list(&save_head, res);
list_del(&dev_res->list);
kfree(dev_res);
}
}
free_list(&local_fail_head); /* Release assigned resource */
list_for_each_entry(dev_res, head, list) {
res = dev_res->res;
dev = dev_res->dev;
release_resource(res);
restore_dev_resource(dev_res);
} /* Restore start/end/flags from saved list */
list_for_each_entry(save_res, &save_head, list)
restore_dev_resource(save_res);
free_list(&save_head);
/* Satisfy the must-have resource requests */
assign_requested_resources_sorted(head, NULL, false);
/* Try to satisfy any additional optional resource requests */ if (!list_empty(realloc_head))
reassign_resources_sorted(realloc_head, head);
out: /* Reset any failed resource, cannot use fail_head as it can be NULL. */
list_for_each_entry(dev_res, head, list) {
res = dev_res->res;
dev = dev_res->dev;
if (res->parent) continue;
if (fail_head) {
add_to_list(fail_head, dev, res,
0 /* don't care */,
0 /* don't care */);
}
pci_info(bridge, "CardBus bridge to %pR\n",
&bus->busn_res);
res = bus->resource[0];
pcibios_resource_to_bus(bridge->bus, ®ion, res); if (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);
}
/* * Initialize bridges with base/limit values we have collected. PCI-to-PCI * Bridge Architecture Specification rev. 1.1 (1998) requires that if there * are no I/O ports or memory behind the bridge, the corresponding range * must be turned off by writing base value greater than limit to the * bridge's base/limit registers. * * Note: care must be taken when updating I/O base/limit registers of * bridges which support 32-bit I/O. This update requires two config space * writes, so it's quite possible that an I/O window of the bridge will * have some undesirable address (e.g. 0) after the first write. Ditto * 64-bit prefetchable MMIO.
*/ staticvoid pci_setup_bridge_io(struct pci_dev *bridge)
{ struct resource *res; constchar *res_name; struct pci_bus_region region; unsignedlong io_mask;
u8 io_base_lo, io_limit_lo;
u16 l;
u32 io_upper16;
io_mask = PCI_IO_RANGE_MASK; if (bridge->io_window_1k)
io_mask = PCI_IO_1K_RANGE_MASK;
/* Set up the top and bottom of the PCI I/O segment for this bus */
res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
res_name = pci_resource_name(bridge, PCI_BRIDGE_IO_WINDOW);
pcibios_resource_to_bus(bridge->bus, ®ion, res); if (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;
l = ((u16) io_limit_lo << 8) | io_base_lo; /* Set up upper 16 bits of I/O base/limit */
io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
pci_info(bridge, " %s %pR\n", res_name, res);
} else { /* Clear upper 16 bits of I/O base/limit */
io_upper16 = 0;
l = 0x00f0;
} /* Temporarily disable the I/O range before updating PCI_IO_BASE */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff); /* Update lower 16 bits of I/O base/limit */
pci_write_config_word(bridge, PCI_IO_BASE, l); /* Update upper 16 bits of I/O base/limit */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
}
/* Set up the top and bottom of the PCI Memory segment for this bus */
res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
res_name = pci_resource_name(bridge, PCI_BRIDGE_MEM_WINDOW);
pcibios_resource_to_bus(bridge->bus, ®ion, res); if (res->flags & IORESOURCE_MEM) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
pci_info(bridge, " %s %pR\n", res_name, res);
} else {
l = 0x0000fff0;
}
pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
}
/* * Clear out the upper 32 bits of PREF limit. If * PCI_PREF_BASE_UPPER32 was non-zero, this temporarily disables * PREF range, which is ok.
*/
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
/* Set up PREF base/limit */
bu = lu = 0;
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, ®ion, res); if (res->flags & IORESOURCE_PREFETCH) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000; if (res->flags & IORESOURCE_MEM_64) {
bu = upper_32_bits(region.start);
lu = upper_32_bits(region.end);
}
pci_info(bridge, " %s %pR\n", res_name, res);
} else {
l = 0x0000fff0;
}
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
/* Set the upper 32 bits of PREF base & limit */
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
}
/* * Helper function for sizing routines. Assigned resources have non-NULL * parent resource. * * Return first unassigned resource of the correct type. If there is none, * return first assigned resource of the correct type. If none of the * above, return NULL. * * Returning an assigned resource of the correct type allows the caller to * distinguish between already assigned and no resource of the correct type.
*/ staticstruct resource *find_bus_resource_of_type(struct pci_bus *bus, unsignedlong type_mask, unsignedlong type)
{ struct resource *r, *r_assigned = NULL;
pci_bus_for_each_resource(bus, r) { if (r == &ioport_resource || r == &iomem_resource) continue; if (r && (r->flags & type_mask) == type && !r->parent) return r; if (r && (r->flags & type_mask) == type && !r_assigned)
r_assigned = r;
} return r_assigned;
}
static resource_size_t calculate_iosize(resource_size_t size,
resource_size_t min_size,
resource_size_t size1,
resource_size_t add_size,
resource_size_t children_add_size,
resource_size_t old_size,
resource_size_t align)
{ if (size < min_size)
size = min_size; if (old_size == 1)
old_size = 0; /* * To be fixed in 2.5: we should have sort of HAVE_ISA flag in the * struct pci_bus.
*/ #ifdefined(CONFIG_ISA) || defined(CONFIG_EISA)
size = (size & 0xff) + ((size & ~0xffUL) << 2); #endif
size = size + size1;
if (type & IORESOURCE_MEM)
align = PCI_P2P_DEFAULT_MEM_ALIGN; elseif (type & IORESOURCE_IO) { /* * Per spec, I/O windows are 4K-aligned, but some bridges have * an extension to support 1K alignment.
*/ if (bus->self && bus->self->io_window_1k)
align = PCI_P2P_DEFAULT_IO_ALIGN_1K; else
align = PCI_P2P_DEFAULT_IO_ALIGN;
}
/** * pbus_size_io() - Size the I/O window of a given bus * * @bus: The bus * @min_size: The minimum I/O window that must be allocated * @add_size: Additional optional I/O window * @realloc_head: Track the additional I/O window on this list * * Sizing the I/O windows of the PCI-PCI bridge is trivial, since these * windows have 1K or 4K granularity and the I/O ranges of non-bridge PCI * devices are limited to 256 bytes. We must be careful with the ISA * aliasing though.
*/ staticvoid pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
resource_size_t add_size, struct list_head *realloc_head)
{ struct pci_dev *dev; struct resource *b_res = find_bus_resource_of_type(bus, IORESOURCE_IO,
IORESOURCE_IO);
resource_size_t size = 0, size0 = 0, size1 = 0;
resource_size_t children_add_size = 0;
resource_size_t min_align, align;
if (!b_res) return;
/* If resource is already assigned, nothing more to do */ if (b_res->parent) return;
/** * pbus_upstream_space_available - Check no upstream resource limits allocation * @bus: The bus * @mask: Mask the resource flag, then compare it with type * @type: The type of resource from bridge * @size: The size required from the bridge window * @align: Required alignment for the resource * * Checks that @size can fit inside the upstream bridge resources that are * already assigned. * * Return: %true if enough space is available on all assigned upstream * resources.
*/ staticbool pbus_upstream_space_available(struct pci_bus *bus, unsignedlong mask, unsignedlong type, resource_size_t size,
resource_size_t align)
{ struct resource_constraint constraint = {
.max = RESOURCE_SIZE_MAX,
.align = align,
}; struct pci_bus *downstream = bus; struct resource *r;
while ((bus = bus->parent)) { if (pci_is_root_bus(bus)) break;
if (resource_size(r) >= size) { struct resource gap = {};
if (find_resource_space(r, &gap, size, &constraint) == 0) {
gap.flags = type;
pci_dbg(bus->self, "Assigned bridge window %pR to %pR free space at %pR\n",
r, &bus->busn_res, &gap); returntrue;
}
}
if (bus->self) {
pci_info(bus->self, "Assigned bridge window %pR to %pR cannot fit 0x%llx required for %s bridging to %pR\n",
r, &bus->busn_res,
(unsignedlonglong)size,
pci_name(downstream->self),
&downstream->busn_res);
}
returnfalse;
}
}
returntrue;
}
/** * pbus_size_mem() - Size the memory window of a given bus * * @bus: The bus * @mask: Mask the resource flag, then compare it with type * @type: The type of free resource from bridge * @type2: Second match type * @type3: Third match type * @min_size: The minimum memory window that must be allocated * @add_size: Additional optional memory window * @realloc_head: Track the additional memory window on this list * * Calculate the size of the bus and minimal alignment which guarantees * that all child resources fit in this size. * * Return -ENOSPC if there's no available bus resource of the desired * type. Otherwise, set the bus resource start/end to indicate the * required size, add things to realloc_head (if supplied), and return 0.
*/ staticint pbus_size_mem(struct pci_bus *bus, unsignedlong mask, unsignedlong type, unsignedlong type2, unsignedlong type3, resource_size_t min_size,
resource_size_t add_size, struct list_head *realloc_head)
{ struct pci_dev *dev;
resource_size_t min_align, win_align, align, size, size0, size1 = 0;
resource_size_t aligns[28]; /* Alignments from 1MB to 128TB */ int order, max_order; struct resource *b_res = find_bus_resource_of_type(bus,
mask | IORESOURCE_PREFETCH, type);
resource_size_t children_add_size = 0;
resource_size_t children_add_align = 0;
resource_size_t add_align = 0;
resource_size_t relaxed_align;
if (!b_res) return -ENOSPC;
/* If resource is already assigned, nothing more to do */ if (b_res->parent) return 0;
/* Put SRIOV requested res to the optional list */ if (realloc_head && pci_resource_is_optional(dev, i)) {
add_align = max(pci_resource_alignment(dev, r), add_align);
add_to_list(realloc_head, dev, r, 0, 0 /* Don't care */);
children_add_size += r_size; continue;
}
/* * aligns[0] is for 1MB (since bridge memory * windows are always at least 1MB aligned), so * keep "order" from being negative for smaller * resources.
*/
align = pci_resource_alignment(dev, r);
order = __ffs(align) - __ffs(SZ_1M); if (order < 0)
order = 0; if (order >= ARRAY_SIZE(aligns)) {
pci_warn(dev, "%s %pR: disabling; bad alignment %#llx\n",
r_name, r, (unsignedlonglong) align);
r->flags = 0; continue;
}
size += max(r_size, align); /* * Exclude ranges with size > align from calculation of * the alignment.
*/ if (r_size <= align)
aligns[order] += align; if (order > max_order)
max_order = order;
b_res = &bridge->resource[PCI_CB_BRIDGE_IO_0_WINDOW]; if (b_res->parent) 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;
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 (b_res->parent) 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;
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;
}
/* * If there's a 64-bit prefetchable MMIO window, compute * the size required to put all 64-bit prefetchable * resources in it.
*/
mask = IORESOURCE_MEM;
prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; if (pref && (pref->flags & IORESOURCE_MEM_64)) {
prefmask |= IORESOURCE_MEM_64;
ret = pbus_size_mem(bus, prefmask, prefmask,
prefmask, prefmask,
realloc_head ? 0 : additional_mmio_pref_size,
additional_mmio_pref_size, realloc_head);
/* * If successful, all non-prefetchable resources * and any 32-bit prefetchable resources will go in * the non-prefetchable window.
*/ if (ret == 0) {
mask = prefmask;
type2 = prefmask & ~IORESOURCE_MEM_64;
type3 = prefmask & ~IORESOURCE_PREFETCH;
}
}
/* * If there is no 64-bit prefetchable window, compute the * size required to put all prefetchable resources in the * 32-bit prefetchable window (if there is one).
*/ if (!type2) {
prefmask &= ~IORESOURCE_MEM_64;
ret = pbus_size_mem(bus, prefmask, prefmask,
prefmask, prefmask,
realloc_head ? 0 : additional_mmio_pref_size,
additional_mmio_pref_size, realloc_head);
/* * If successful, only non-prefetchable resources * will go in the non-prefetchable window.
*/ if (ret == 0)
mask = prefmask; else
additional_mmio_size += additional_mmio_pref_size;
type2 = type3 = IORESOURCE_MEM;
}
/* * Compute the size required to put everything else in the * non-prefetchable window. This includes: * * - all non-prefetchable resources * - 32-bit prefetchable resources if there's a 64-bit * prefetchable window or no prefetchable window at all * - 64-bit prefetchable resources if there's no prefetchable * window at all * * Note that the strategy in __pci_assign_resource() must match * that used here. Specifically, we cannot put a 32-bit * prefetchable resource in a 64-bit prefetchable window.
*/
pbus_size_mem(bus, mask, IORESOURCE_MEM, type2, type3,
realloc_head ? 0 : additional_mmio_size,
additional_mmio_size, realloc_head); break;
}
}
/* * Try to assign any resources marked as IORESOURCE_PCI_FIXED, as they are * skipped by pbus_assign_resources_sorted().
*/ staticvoid pdev_assign_fixed_resources(struct pci_dev *dev)
{ struct resource *r;
/* * Carry out a depth-first search on the PCI bus tree to allocate * bridge apertures. Read the programmed bridge bases and * recursively claim the respective bridge resources.
*/ if (b->self) {
pci_read_bridge_bases(b);
pci_claim_bridge_resources(b->self);
}
/* * 1. If IO port assignment fails, release bridge IO port. * 2. If non pref MMIO assignment fails, release bridge nonpref MMIO. * 3. If 64bit pref MMIO assignment fails, and bridge pref is 64bit, * release bridge pref MMIO. * 4. If pref MMIO assignment fails, and bridge pref is 32bit, * release bridge pref MMIO. * 5. If pref MMIO assignment fails, and bridge pref is not * assigned, release bridge nonpref MMIO.
*/ if (type & IORESOURCE_IO)
idx = 0; elseif (!(type & IORESOURCE_PREFETCH))
idx = 1; elseif ((type & IORESOURCE_MEM_64) &&
(b_res[2].flags & IORESOURCE_MEM_64))
idx = 2; elseif (!(b_res[2].flags & IORESOURCE_MEM_64) &&
(b_res[2].flags & IORESOURCE_PREFETCH))
idx = 2; else
idx = 1;
r = &b_res[idx];
if (!r->parent) return;
/* If there are children, release them all */
release_child_resources(r); if (!release_resource(r)) {
type = old_flags = r->flags & PCI_RES_TYPE_MASK;
pci_info(dev, "resource %d %pR released\n",
PCI_BRIDGE_RESOURCES + idx, r); /* Keep the old size */
resource_set_range(r, 0, resource_size(r));
r->flags = 0;
/* Avoiding touch the one without PREF */ if (type & IORESOURCE_PREFETCH)
type = IORESOURCE_PREFETCH;
__pci_setup_bridge(bus, type); /* For next child res under same bridge */
r->flags = old_flags;
}
}
enum release_type {
leaf_only,
whole_subtree,
};
/* * Try to release PCI bridge resources from leaf bridge, so we can allocate * a larger window later.
*/ staticvoid pci_bus_release_bridge_resources(struct pci_bus *bus, unsignedlong type, enum release_type rel_type)
{ struct pci_dev *dev; bool is_leaf_bridge = true;
list_for_each_entry(child_bus, &bus->children, node) { int ret;
ret = pci_bus_get_depth(child_bus); if (ret + 1 > depth)
depth = ret + 1;
}
return depth;
}
/* * -1: undefined, will auto detect later * 0: disabled by user * 1: disabled by auto detect * 2: enabled by user * 3: enabled by auto detect
*/ enum enable_type {
undefined = -1,
user_disabled,
auto_disabled,
user_enabled,
auto_enabled,
};
/* * Make sure prefetchable memory is reduced from * the correct resource. Specifically we put 32-bit * prefetchable memory in non-prefetchable window * if there is a 64-bit prefetchable window. * * See comments in __pci_bus_size_bridges() for * more information.
*/ if ((res->flags & IORESOURCE_PREFETCH) &&
((res->flags & IORESOURCE_MEM_64) ==
(mmio_pref->flags & IORESOURCE_MEM_64)))
remove_dev_resource(mmio_pref, dev, res); else
remove_dev_resource(mmio, dev, res);
}
}
}
/* * io, mmio and mmio_pref contain the total amount of bridge window space * available. This includes the minimal space needed to cover all the * existing devices on the bus and the possible extra space that can be * shared with the bridges.
*/ staticvoid pci_bus_distribute_available_resources(struct pci_bus *bus, struct list_head *add_list, struct resource io, struct resource mmio, struct resource mmio_pref)
{ unsignedint normal_bridges = 0, hotplug_bridges = 0; struct resource *io_res, *mmio_res, *mmio_pref_res; struct pci_dev *dev, *bridge = bus->self;
resource_size_t io_per_b, mmio_per_b, mmio_pref_per_b, align;
/* * The alignment of this bridge is yet to be considered, hence it must * be done now before extending its bridge window.
*/
align = pci_resource_alignment(bridge, io_res); if (!io_res->parent && align)
io.start = min(ALIGN(io.start, align), io.end + 1);
/* * Now that we have adjusted for alignment, update the bridge window * resources to fill as much remaining resource space as possible.
*/
adjust_bridge_window(bridge, io_res, add_list, resource_size(&io));
adjust_bridge_window(bridge, mmio_res, add_list, resource_size(&mmio));
adjust_bridge_window(bridge, mmio_pref_res, add_list,
resource_size(&mmio_pref));
/* * Calculate how many hotplug bridges and normal bridges there * are on this bus. We will distribute the additional available * resources between hotplug bridges.
*/
for_each_pci_bridge(dev, bus) { if (dev->is_hotplug_bridge)
hotplug_bridges++; else
normal_bridges++;
}
if (!(hotplug_bridges + normal_bridges)) return;
/* * Calculate the amount of space we can forward from "bus" to any * downstream buses, i.e., the space left over after assigning the * BARs and windows on "bus".
*/
list_for_each_entry(dev, &bus->devices, bus_list) { if (!dev->is_virtfn)
remove_dev_resources(dev, &io, &mmio, &mmio_pref);
}
/* * If there is at least one hotplug bridge on this bus it gets all * the extra resource space that was left after the reductions * above. * * If there are no hotplug bridges the extra resource space is * split between non-hotplug bridges. This is to allow possible * hotplug bridges below them to get the extra space as well.
*/ if (hotplug_bridges) {
io_per_b = div64_ul(resource_size(&io), hotplug_bridges);
mmio_per_b = div64_ul(resource_size(&mmio), hotplug_bridges);
mmio_pref_per_b = div64_ul(resource_size(&mmio_pref),
hotplug_bridges);
} else {
io_per_b = div64_ul(resource_size(&io), normal_bridges);
mmio_per_b = div64_ul(resource_size(&mmio), normal_bridges);
mmio_pref_per_b = div64_ul(resource_size(&mmio_pref),
normal_bridges);
}
b = dev->subordinate; if (!b) continue; if (hotplug_bridges && !dev->is_hotplug_bridge) continue;
res = &dev->resource[PCI_BRIDGE_IO_WINDOW];
/* * Make sure the split resource space is properly aligned * for bridge windows (align it down to avoid going above * what is available).
*/
align = pci_resource_alignment(dev, res);
resource_set_size(&io, ALIGN_DOWN_IF_NONZERO(io_per_b, align));
/* * The x_per_b holds the extra resource space that can be * added for each bridge but there is the minimal already * reserved as well so adjust x.start down accordingly to * cover the whole space.
*/
io.start -= resource_size(res);
pci_dbg(bridge, "distributing available resources\n");
/* Take the initial extra resources from the hotplug port */
available_io = bridge->resource[PCI_BRIDGE_IO_WINDOW];
available_mmio = bridge->resource[PCI_BRIDGE_MEM_WINDOW];
available_mmio_pref = bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
/* * If the child device's resources are not yet assigned it means we * are configuring them (not the boot firmware), so we should be * able to extend the upstream bridge resources in the same way we * do with the normal hotplug case.
*/
r = &dev->resource[PCI_BRIDGE_IO_WINDOW]; if (r->flags && !(r->flags & IORESOURCE_STARTALIGN)) returnfalse;
r = &dev->resource[PCI_BRIDGE_MEM_WINDOW]; if (r->flags && !(r->flags & IORESOURCE_STARTALIGN)) returnfalse;
r = &dev->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; if (r->flags && !(r->flags & IORESOURCE_STARTALIGN)) returnfalse;
/* * Need to check "bridge" here too because it is NULL * in case of root bus.
*/ if (bridge && pci_bridge_resources_not_assigned(dev))
pci_bridge_distribute_available_resources(dev, add_list); else
pci_root_bus_distribute_available_resources(b, add_list);
}
}
/* * First try will not touch PCI bridge res. * Second and later try will clear small leaf bridge res. * Will stop till to the max depth if can not find good one.
*/ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
{
LIST_HEAD(realloc_head); /* List of resources that want additional resources */ struct list_head *add_list = NULL; int tried_times = 0; enum release_type rel_type = leaf_only;
LIST_HEAD(fail_head); int pci_try_num = 1; enum enable_type enable_local;
/* Don't realloc if asked to do so */
enable_local = pci_realloc_detect(bus, pci_realloc_enable); if (pci_realloc_enabled(enable_local)) { int max_depth = pci_bus_get_depth(bus);
while (1) { /* * Last try will use add_list, otherwise will try good to * have as must have, so can realloc parent bridge resource
*/ if (tried_times + 1 == pci_try_num)
add_list = &realloc_head; /* * Depth first, calculate sizes and alignments of all * subordinate buses.
*/
__pci_bus_size_bridges(bus, add_list);
/* Depth last, allocate resources and update the hardware. */
__pci_bus_assign_resources(bus, add_list, &fail_head); if (WARN_ON_ONCE(add_list && !list_empty(add_list)))
free_list(add_list);
tried_times++;
/* Any device complain? */ if (list_empty(&fail_head)) break;
if (tried_times >= pci_try_num) { if (enable_local == undefined) {
dev_info(&bus->dev, "Some PCI device resources are unassigned, try booting with pci=realloc\n");
} elseif (enable_local == auto_enabled) {
dev_info(&bus->dev, "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
}
free_list(&fail_head); break;
}
/* Third times and later will not check if it is leaf */ if (tried_times + 1 > 2)
rel_type = whole_subtree;
/* Make sure the root bridge has a companion ACPI device */ if (ACPI_HANDLE(root_bus->bridge))
acpi_ioapic_add(ACPI_HANDLE(root_bus->bridge));
}
}
void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
{ struct pci_bus *parent = bridge->subordinate; /* List of resources that want additional resources */
LIST_HEAD(add_list); int tried_times = 0;
LIST_HEAD(fail_head); int ret;
while (1) {
__pci_bus_size_bridges(parent, &add_list);
/* * Distribute remaining resources (if any) equally between * hotplug bridges below. This makes it possible to extend * the hierarchy later without running out of resources.
*/
pci_bridge_distribute_available_resources(bridge, &add_list);
__pci_bridge_assign_resources(bridge, &add_list, &fail_head); if (WARN_ON_ONCE(!list_empty(&add_list)))
free_list(&add_list);
tried_times++;
if (list_empty(&fail_head)) break;
if (tried_times >= 2) { /* Still fail, don't need to try more */
free_list(&fail_head); break;
}
ret = pci_reenable_device(bridge); if (ret)
pci_err(bridge, "Error reenabling bridge (%d)\n", ret);
pci_set_master(bridge);
}
EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
int pci_reassign_bridge_resources(struct pci_dev *bridge, unsignedlong type)
{ struct pci_dev_resource *dev_res; struct pci_dev *next;
LIST_HEAD(saved);
LIST_HEAD(added);
LIST_HEAD(failed); unsignedint i; int ret;
down_read(&pci_bus_sem);
/* Walk to the root hub, releasing bridge BARs when possible */
next = bridge; do {
bridge = next; for (i = PCI_BRIDGE_RESOURCES; i < PCI_BRIDGE_RESOURCE_END;
i++) { struct resource *res = &bridge->resource[i];
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.25 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.