mirror of
https://github.com/torvalds/linux.git
synced 2026-05-29 17:43:52 +02:00
Merge branch 'pci/resource'
- Prevent assigning space to unimplemented bridge windows; previously we mistakenly assumed prefetchable window existed and assigned space and put a BAR there (Ahmed Naseef) - Avoid shrinking bridge windows to fit in the initial Root Port window; this fixes one problem with devices with large BARs connected via switches, e.g., Thunderbolt (Ilpo Järvinen) - Retain information about optional resources to make assignment during rescan more likely to succeed (Ilpo Järvinen) - Add __resource_contains_unbound() for use in finding space for resources with no address assigned (Ilpo Järvinen) - Pass full extent of empty space, not just the aligned space, to resource_alignf callback so free space before the requested alignment can be used (Ilpo Järvinen) - Remove unnecessary second alignment from ARM, m68k, MIPS (Ilpo Järvinen) - Place small resources before larger ones for better utilization of address space (Ilpo Järvinen) - Fix alignment calculation for resource size larger than align, e.g., bridge windows larger than the 1MB required alignment (Ilpo Järvinen) * pci/resource: PCI: Fix alignment calculation for resource size larger than align PCI: Align head space better PCI: Rename window_alignment() to pci_min_window_alignment() parisc/PCI: Clean up align handling MIPS: PCI: Remove unnecessary second application of align m68k/PCI: Remove unnecessary second application of align ARM/PCI: Remove unnecessary second application of align resource: Rename 'tmp' variable to 'full_avail' resource: Pass full extent of empty space to resource_alignf callback resource: Add __resource_contains_unbound() for internal contains checks PCI: Fix premature removal from realloc_head list during resource assignment PCI: Prevent shrinking bridge window from its required size PCI: Prevent assignment to unsupported bridge windows
This commit is contained in:
commit
6cf4941ba9
|
|
@ -125,6 +125,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_final);
|
|||
|
||||
resource_size_t
|
||||
pcibios_align_resource(void *data, const struct resource *res,
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
struct pci_dev *dev = data;
|
||||
|
|
|
|||
|
|
@ -560,7 +560,9 @@ char * __init pcibios_setup(char *str)
|
|||
* which might be mirrored at 0x0100-0x03ff..
|
||||
*/
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size,
|
||||
resource_size_t align)
|
||||
{
|
||||
struct pci_dev *dev = data;
|
||||
resource_size_t start = res->start;
|
||||
|
|
@ -569,14 +571,15 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
|||
if (res->flags & IORESOURCE_IO && start & 0x300)
|
||||
start = (start + 0x3ff) & ~0x3ff;
|
||||
|
||||
start = (start + align - 1) & ~(align - 1);
|
||||
|
||||
host_bridge = pci_find_host_bridge(dev->bus);
|
||||
|
||||
if (host_bridge->align_resource)
|
||||
return host_bridge->align_resource(dev, res,
|
||||
start, size, align);
|
||||
|
||||
if (res->flags & IORESOURCE_MEM)
|
||||
return pci_align_resource(dev, res, empty_res, size, align);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,14 +27,18 @@
|
|||
* which might be mirrored at 0x0100-0x03ff..
|
||||
*/
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size,
|
||||
resource_size_t align)
|
||||
{
|
||||
struct pci_dev *dev = data;
|
||||
resource_size_t start = res->start;
|
||||
|
||||
if ((res->flags & IORESOURCE_IO) && (start & 0x300))
|
||||
start = (start + 0x3ff) & ~0x3ff;
|
||||
|
||||
start = (start + align - 1) & ~(align - 1);
|
||||
if (res->flags & IORESOURCE_MEM)
|
||||
return pci_align_resource(dev, res, empty_res, size, align);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@
|
|||
* which might have be mirrored at 0x0100-0x03ff..
|
||||
*/
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
struct pci_dev *dev = data;
|
||||
resource_size_t start = res->start;
|
||||
|
|
@ -31,14 +32,15 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
|||
if (res->flags & IORESOURCE_IO && start & 0x300)
|
||||
start = (start + 0x3ff) & ~0x3ff;
|
||||
|
||||
start = (start + align - 1) & ~(align - 1);
|
||||
|
||||
host_bridge = pci_find_host_bridge(dev->bus);
|
||||
|
||||
if (host_bridge->align_resource)
|
||||
return host_bridge->align_resource(dev, res,
|
||||
start, size, align);
|
||||
|
||||
if (res->flags & IORESOURCE_MEM)
|
||||
return pci_align_resource(dev, res, empty_res, size, align);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ unsigned long pci_address_to_pio(phys_addr_t address)
|
|||
*/
|
||||
resource_size_t
|
||||
pcibios_align_resource(void *data, const struct resource *res,
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
struct pci_dev *dev = data;
|
||||
|
|
@ -69,6 +70,8 @@ pcibios_align_resource(void *data, const struct resource *res,
|
|||
if (start & 0x300)
|
||||
start = (start + 0x3ff) & ~0x3ff;
|
||||
} else if (res->flags & IORESOURCE_MEM) {
|
||||
start = pci_align_resource(dev, res, empty_res, size, align);
|
||||
|
||||
/* Make sure we start at our min on all hoses */
|
||||
if (start < PCIBIOS_MIN_MEM + hose->mem_resource->start)
|
||||
start = PCIBIOS_MIN_MEM + hose->mem_resource->start;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
* Copyright (C) 1999-2001 Hewlett-Packard Company
|
||||
* Copyright (C) 1999-2001 Grant Grundler
|
||||
*/
|
||||
#include <linux/align.h>
|
||||
#include <linux/eisa.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -196,9 +197,12 @@ void __ref pcibios_init_bridge(struct pci_dev *dev)
|
|||
* than res->start.
|
||||
*/
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t alignment)
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size,
|
||||
resource_size_t alignment)
|
||||
{
|
||||
resource_size_t mask, align, start = res->start;
|
||||
struct pci_dev *dev = data;
|
||||
resource_size_t align, start = res->start;
|
||||
|
||||
DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx, 0x%lx)\n",
|
||||
pci_name(((struct pci_dev *) data)),
|
||||
|
|
@ -207,11 +211,10 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
|||
|
||||
/* If it's not IO, then it's gotta be MEM */
|
||||
align = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
|
||||
|
||||
/* Align to largest of MIN or input size */
|
||||
mask = max(alignment, align) - 1;
|
||||
start += mask;
|
||||
start &= ~mask;
|
||||
if (align > alignment)
|
||||
start = ALIGN(start, align);
|
||||
else
|
||||
start = pci_align_resource(dev, res, empty_res, size, alignment);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1132,7 +1132,9 @@ static int skip_isa_ioresource_align(struct pci_dev *dev)
|
|||
* which might have be mirrored at 0x0100-0x03ff..
|
||||
*/
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size,
|
||||
resource_size_t align)
|
||||
{
|
||||
struct pci_dev *dev = data;
|
||||
resource_size_t start = res->start;
|
||||
|
|
@ -1142,6 +1144,8 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
|||
return start;
|
||||
if (start & 0x300)
|
||||
start = (start + 0x3ff) & ~0x3ff;
|
||||
} else if (res->flags & IORESOURCE_MEM) {
|
||||
start = pci_align_resource(dev, res, empty_res, size, align);
|
||||
}
|
||||
|
||||
return start;
|
||||
|
|
|
|||
|
|
@ -266,6 +266,7 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)
|
|||
}
|
||||
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size,
|
||||
resource_size_t align)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -168,7 +168,9 @@ subsys_initcall(pcibios_init);
|
|||
* modulo 0x400.
|
||||
*/
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size,
|
||||
resource_size_t align)
|
||||
{
|
||||
struct pci_dev *dev = data;
|
||||
struct pci_channel *hose = dev->sysdata;
|
||||
|
|
@ -183,6 +185,8 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
|||
*/
|
||||
if (start & 0x300)
|
||||
start = (start + 0x3ff) & ~0x3ff;
|
||||
} else if (res->flags & IORESOURCE_MEM) {
|
||||
start = pci_align_resource(dev, res, empty_res, size, align);
|
||||
}
|
||||
|
||||
return start;
|
||||
|
|
|
|||
|
|
@ -153,7 +153,8 @@ skip_isa_ioresource_align(struct pci_dev *dev) {
|
|||
*/
|
||||
resource_size_t
|
||||
pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
struct pci_dev *dev = data;
|
||||
resource_size_t start = res->start;
|
||||
|
|
@ -164,6 +165,8 @@ pcibios_align_resource(void *data, const struct resource *res,
|
|||
if (start & 0x300)
|
||||
start = (start + 0x3ff) & ~0x3ff;
|
||||
} else if (res->flags & IORESOURCE_MEM) {
|
||||
start = pci_align_resource(dev, res, empty_res, size, align);
|
||||
|
||||
/* The low 1MB range is reserved for ISA cards */
|
||||
if (start < BIOS_END)
|
||||
start = BIOS_END;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
*/
|
||||
resource_size_t
|
||||
pcibios_align_resource(void *data, const struct resource *res,
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
struct pci_dev *dev = data;
|
||||
|
|
@ -53,6 +54,8 @@ pcibios_align_resource(void *data, const struct resource *res,
|
|||
|
||||
if (start & 0x300)
|
||||
start = (start + 0x3ff) & ~0x3ff;
|
||||
} else if (res->flags & IORESOURCE_MEM) {
|
||||
start = pci_align_resource(dev, res, empty_res, size, align);
|
||||
}
|
||||
|
||||
return start;
|
||||
|
|
|
|||
|
|
@ -1053,6 +1053,9 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
|
|||
return resource_alignment(res);
|
||||
}
|
||||
|
||||
resource_size_t pci_min_window_alignment(struct pci_bus *bus,
|
||||
unsigned long type);
|
||||
|
||||
void pci_acs_init(struct pci_dev *dev);
|
||||
void pci_enable_acs(struct pci_dev *dev);
|
||||
#ifdef CONFIG_PCI_QUIRKS
|
||||
|
|
|
|||
|
|
@ -378,6 +378,9 @@ static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res,
|
|||
unsigned long io_mask, io_granularity, base, limit;
|
||||
struct pci_bus_region region;
|
||||
|
||||
if (!dev->io_window)
|
||||
return;
|
||||
|
||||
io_mask = PCI_IO_RANGE_MASK;
|
||||
io_granularity = 0x1000;
|
||||
if (dev->io_window_1k) {
|
||||
|
|
@ -448,6 +451,9 @@ static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res,
|
|||
pci_bus_addr_t base, limit;
|
||||
struct pci_bus_region region;
|
||||
|
||||
if (!dev->pref_window)
|
||||
return;
|
||||
|
||||
pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
|
||||
pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
|
||||
base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
|
||||
|
|
|
|||
|
|
@ -434,6 +434,10 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
|
|||
dev = add_res->dev;
|
||||
idx = pci_resource_num(dev, res);
|
||||
|
||||
/* Skip this resource if not found in head list */
|
||||
if (!res_to_dev_res(head, res))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Skip resource that failed the earlier assignment and is
|
||||
* not optional as it would just fail again.
|
||||
|
|
@ -442,10 +446,6 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
|
|||
!pci_resource_is_optional(dev, idx))
|
||||
goto out;
|
||||
|
||||
/* Skip this resource if not found in head list */
|
||||
if (!res_to_dev_res(head, res))
|
||||
continue;
|
||||
|
||||
res_name = pci_resource_name(dev, idx);
|
||||
add_size = add_res->add_size;
|
||||
align = add_res->min_align;
|
||||
|
|
@ -1035,7 +1035,7 @@ resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
|
|||
#define PCI_P2P_DEFAULT_IO_ALIGN SZ_4K
|
||||
#define PCI_P2P_DEFAULT_IO_ALIGN_1K SZ_1K
|
||||
|
||||
static resource_size_t window_alignment(struct pci_bus *bus, unsigned long type)
|
||||
resource_size_t pci_min_window_alignment(struct pci_bus *bus, unsigned long type)
|
||||
{
|
||||
resource_size_t align = 1, arch_align;
|
||||
|
||||
|
|
@ -1084,7 +1084,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t add_size,
|
|||
if (resource_assigned(b_res))
|
||||
return;
|
||||
|
||||
min_align = window_alignment(bus, IORESOURCE_IO);
|
||||
min_align = pci_min_window_alignment(bus, IORESOURCE_IO);
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
struct resource *r;
|
||||
|
||||
|
|
@ -1333,13 +1333,20 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
|
|||
r_size = resource_size(r);
|
||||
size += max(r_size, align);
|
||||
|
||||
aligns[order] += align;
|
||||
/*
|
||||
* If resource's size is larger than its alignment,
|
||||
* some configurations result in an unwanted gap in
|
||||
* the head space that the larger resource cannot
|
||||
* fill.
|
||||
*/
|
||||
if (r_size <= align)
|
||||
aligns[order] += align;
|
||||
if (order > max_order)
|
||||
max_order = order;
|
||||
}
|
||||
}
|
||||
|
||||
win_align = window_alignment(bus, b_res->flags);
|
||||
win_align = pci_min_window_alignment(bus, b_res->flags);
|
||||
min_align = calculate_head_align(aligns, max_order);
|
||||
min_align = max(min_align, win_align);
|
||||
size0 = calculate_memsize(size, realloc_head ? 0 : add_size,
|
||||
|
|
@ -1837,6 +1844,7 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res,
|
|||
resource_size_t new_size)
|
||||
{
|
||||
resource_size_t add_size, size = resource_size(res);
|
||||
struct pci_dev_resource *dev_res;
|
||||
|
||||
if (resource_assigned(res))
|
||||
return;
|
||||
|
|
@ -1849,9 +1857,46 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res,
|
|||
pci_dbg(bridge, "bridge window %pR extended by %pa\n", res,
|
||||
&add_size);
|
||||
} else if (new_size < size) {
|
||||
int idx = pci_resource_num(bridge, res);
|
||||
|
||||
/*
|
||||
* hpio/mmio/mmioprefsize hasn't been included at all? See the
|
||||
* add_size param at the callsites of calculate_memsize().
|
||||
*/
|
||||
if (!add_list)
|
||||
return;
|
||||
|
||||
/* Only shrink if the hotplug extra relates to window size. */
|
||||
switch (idx) {
|
||||
case PCI_BRIDGE_IO_WINDOW:
|
||||
if (size > pci_hotplug_io_size)
|
||||
return;
|
||||
break;
|
||||
case PCI_BRIDGE_MEM_WINDOW:
|
||||
if (size > pci_hotplug_mmio_size)
|
||||
return;
|
||||
break;
|
||||
case PCI_BRIDGE_PREF_MEM_WINDOW:
|
||||
if (size > pci_hotplug_mmio_pref_size)
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dev_res = res_to_dev_res(add_list, res);
|
||||
add_size = size - new_size;
|
||||
pci_dbg(bridge, "bridge window %pR shrunken by %pa\n", res,
|
||||
&add_size);
|
||||
if (add_size < dev_res->add_size) {
|
||||
dev_res->add_size -= add_size;
|
||||
pci_dbg(bridge, "bridge window %pR optional size shrunken by %pa\n",
|
||||
res, &add_size);
|
||||
} else {
|
||||
pci_dbg(bridge, "bridge window %pR optional size removed\n",
|
||||
res);
|
||||
pci_dev_res_remove_from_list(add_list, res);
|
||||
}
|
||||
return;
|
||||
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,6 +244,41 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For mem bridge windows, try to relocate tail remainder space to space
|
||||
* before res->start if there's enough free space there. This enables
|
||||
* tighter packing for resources.
|
||||
*/
|
||||
resource_size_t pci_align_resource(struct pci_dev *dev,
|
||||
const struct resource *res,
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size,
|
||||
resource_size_t align)
|
||||
{
|
||||
resource_size_t remainder, start_addr;
|
||||
|
||||
if (!(res->flags & IORESOURCE_MEM))
|
||||
return res->start;
|
||||
|
||||
if (IS_ALIGNED(size, align))
|
||||
return res->start;
|
||||
|
||||
remainder = size - ALIGN_DOWN(size, align);
|
||||
/* Don't mess with size that doesn't align with window size granularity */
|
||||
if (!IS_ALIGNED(remainder, pci_min_window_alignment(dev->bus, res->flags)))
|
||||
return res->start;
|
||||
/* Try to place remainder that doesn't fill align before */
|
||||
if (res->start < remainder)
|
||||
return res->start;
|
||||
start_addr = res->start - remainder;
|
||||
if (empty_res->start > start_addr)
|
||||
return res->start;
|
||||
|
||||
pci_dbg(dev, "%pR: moving candidate start address below align to %llx\n",
|
||||
res, (unsigned long long)start_addr);
|
||||
return start_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't have to worry about legacy ISA devices, so nothing to do here.
|
||||
* This is marked as __weak because multiple architectures define it; it should
|
||||
|
|
@ -251,10 +286,13 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
|
|||
*/
|
||||
resource_size_t __weak pcibios_align_resource(void *data,
|
||||
const struct resource *res,
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size,
|
||||
resource_size_t align)
|
||||
{
|
||||
return res->start;
|
||||
struct pci_dev *dev = data;
|
||||
|
||||
return pci_align_resource(dev, res, empty_res, size, align);
|
||||
}
|
||||
|
||||
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
|
||||
|
|
|
|||
|
|
@ -602,7 +602,8 @@ static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
|
|||
|
||||
static resource_size_t
|
||||
pcmcia_align(void *align_data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
struct pcmcia_align_data *data = align_data;
|
||||
struct resource_map *m;
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ enum {
|
|||
* typedef resource_alignf - Resource alignment callback
|
||||
* @data: Private data used by the callback
|
||||
* @res: Resource candidate range (an empty resource space)
|
||||
* @empty_res: Empty resource range without alignment applied
|
||||
* @size: The minimum size of the empty space
|
||||
* @align: Alignment from the constraints
|
||||
*
|
||||
|
|
@ -212,6 +213,7 @@ enum {
|
|||
*/
|
||||
typedef resource_size_t (*resource_alignf)(void *data,
|
||||
const struct resource *res,
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size,
|
||||
resource_size_t align);
|
||||
|
||||
|
|
@ -304,14 +306,28 @@ static inline unsigned long resource_ext_type(const struct resource *res)
|
|||
{
|
||||
return res->flags & IORESOURCE_EXT_TYPE_BITS;
|
||||
}
|
||||
/* True iff r1 completely contains r2 */
|
||||
static inline bool resource_contains(const struct resource *r1, const struct resource *r2)
|
||||
|
||||
/*
|
||||
* For checking if @r1 completely contains @r2 for resources that have real
|
||||
* addresses but are not yet crafted into the resource tree. Normally
|
||||
* resource_contains() should be used instead of this function as it checks
|
||||
* also IORESOURCE_UNSET flag.
|
||||
*/
|
||||
static inline bool __resource_contains_unbound(const struct resource *r1,
|
||||
const struct resource *r2)
|
||||
{
|
||||
if (resource_type(r1) != resource_type(r2))
|
||||
return false;
|
||||
|
||||
return r1->start <= r2->start && r1->end >= r2->end;
|
||||
}
|
||||
/* True iff r1 completely contains r2 */
|
||||
static inline bool resource_contains(const struct resource *r1, const struct resource *r2)
|
||||
{
|
||||
if (r1->flags & IORESOURCE_UNSET || r2->flags & IORESOURCE_UNSET)
|
||||
return false;
|
||||
return r1->start <= r2->start && r1->end >= r2->end;
|
||||
|
||||
return __resource_contains_unbound(r1, r2);
|
||||
}
|
||||
|
||||
/* True if any part of r1 overlaps r2 */
|
||||
|
|
|
|||
|
|
@ -1212,9 +1212,15 @@ int __must_check pcibios_enable_device(struct pci_dev *, int mask);
|
|||
char *pcibios_setup(char *str);
|
||||
|
||||
/* Used only when drivers/pci/setup.c is used */
|
||||
resource_size_t pcibios_align_resource(void *, const struct resource *,
|
||||
resource_size_t,
|
||||
resource_size_t);
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size,
|
||||
resource_size_t align);
|
||||
resource_size_t pci_align_resource(struct pci_dev *dev,
|
||||
const struct resource *res,
|
||||
const struct resource *empty_res,
|
||||
resource_size_t size,
|
||||
resource_size_t align);
|
||||
|
||||
/* Generic PCI functions used internally */
|
||||
|
||||
|
|
|
|||
|
|
@ -727,45 +727,46 @@ static int __find_resource_space(struct resource *root, struct resource *old,
|
|||
struct resource_constraint *constraint)
|
||||
{
|
||||
struct resource *this = root->child;
|
||||
struct resource tmp = *new, avail, alloc;
|
||||
struct resource full_avail = *new, avail, alloc;
|
||||
resource_alignf alignf = constraint->alignf;
|
||||
|
||||
tmp.start = root->start;
|
||||
full_avail.start = root->start;
|
||||
/*
|
||||
* Skip past an allocated resource that starts at 0, since the assignment
|
||||
* of this->start - 1 to tmp->end below would cause an underflow.
|
||||
* of this->start - 1 to full_avail->end below would cause an underflow.
|
||||
*/
|
||||
if (this && this->start == root->start) {
|
||||
tmp.start = (this == old) ? old->start : this->end + 1;
|
||||
full_avail.start = (this == old) ? old->start : this->end + 1;
|
||||
this = this->sibling;
|
||||
}
|
||||
for(;;) {
|
||||
if (this)
|
||||
tmp.end = (this == old) ? this->end : this->start - 1;
|
||||
full_avail.end = (this == old) ? this->end : this->start - 1;
|
||||
else
|
||||
tmp.end = root->end;
|
||||
full_avail.end = root->end;
|
||||
|
||||
if (tmp.end < tmp.start)
|
||||
if (full_avail.end < full_avail.start)
|
||||
goto next;
|
||||
|
||||
resource_clip(&tmp, constraint->min, constraint->max);
|
||||
arch_remove_reservations(&tmp);
|
||||
resource_clip(&full_avail, constraint->min, constraint->max);
|
||||
arch_remove_reservations(&full_avail);
|
||||
|
||||
/* Check for overflow after ALIGN() */
|
||||
avail.start = ALIGN(tmp.start, constraint->align);
|
||||
avail.end = tmp.end;
|
||||
avail.flags = new->flags & ~IORESOURCE_UNSET;
|
||||
if (avail.start >= tmp.start) {
|
||||
avail.start = ALIGN(full_avail.start, constraint->align);
|
||||
avail.end = full_avail.end;
|
||||
avail.flags = new->flags;
|
||||
if (avail.start >= full_avail.start) {
|
||||
alloc.flags = avail.flags;
|
||||
if (alignf) {
|
||||
alloc.start = alignf(constraint->alignf_data,
|
||||
&avail, size, constraint->align);
|
||||
&avail, &full_avail,
|
||||
size, constraint->align);
|
||||
} else {
|
||||
alloc.start = avail.start;
|
||||
}
|
||||
alloc.end = alloc.start + size - 1;
|
||||
if (alloc.start <= alloc.end &&
|
||||
resource_contains(&avail, &alloc)) {
|
||||
__resource_contains_unbound(&full_avail, &alloc)) {
|
||||
new->start = alloc.start;
|
||||
new->end = alloc.end;
|
||||
return 0;
|
||||
|
|
@ -776,7 +777,7 @@ next: if (!this || this->end == root->end)
|
|||
break;
|
||||
|
||||
if (this != old)
|
||||
tmp.start = this->end + 1;
|
||||
full_avail.start = this->end + 1;
|
||||
this = this->sibling;
|
||||
}
|
||||
return -EBUSY;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user