diff options
| author | Bjorn Helgaas <bhelgaas@google.com> | 2026-04-13 12:50:05 -0500 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2026-04-13 12:50:05 -0500 |
| commit | 6cf4941ba9b11c28bbd7c9a7c1a461b94cd486c3 (patch) | |
| tree | d7a48bf700c47930685502f300b93a24ab2adabd | |
| parent | 12b56ec723d2d736feb16ea6ea2505520de3cc58 (diff) | |
| parent | 8cb081667377709f4924ab6b3a88a0d7a761fe91 (diff) | |
| download | lwn-6cf4941ba9b11c28bbd7c9a7c1a461b94cd486c3.tar.gz lwn-6cf4941ba9b11c28bbd7c9a7c1a461b94cd486c3.zip | |
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
| -rw-r--r-- | arch/alpha/kernel/pci.c | 1 | ||||
| -rw-r--r-- | arch/arm/kernel/bios32.c | 9 | ||||
| -rw-r--r-- | arch/m68k/kernel/pcibios.c | 8 | ||||
| -rw-r--r-- | arch/mips/pci/pci-generic.c | 8 | ||||
| -rw-r--r-- | arch/mips/pci/pci-legacy.c | 3 | ||||
| -rw-r--r-- | arch/parisc/kernel/pci.c | 17 | ||||
| -rw-r--r-- | arch/powerpc/kernel/pci-common.c | 6 | ||||
| -rw-r--r-- | arch/s390/pci/pci.c | 1 | ||||
| -rw-r--r-- | arch/sh/drivers/pci/pci.c | 6 | ||||
| -rw-r--r-- | arch/x86/pci/i386.c | 5 | ||||
| -rw-r--r-- | arch/xtensa/kernel/pci.c | 3 | ||||
| -rw-r--r-- | drivers/pci/pci.h | 3 | ||||
| -rw-r--r-- | drivers/pci/probe.c | 6 | ||||
| -rw-r--r-- | drivers/pci/setup-bus.c | 65 | ||||
| -rw-r--r-- | drivers/pci/setup-res.c | 40 | ||||
| -rw-r--r-- | drivers/pcmcia/rsrc_nonstatic.c | 3 | ||||
| -rw-r--r-- | include/linux/ioport.h | 22 | ||||
| -rw-r--r-- | include/linux/pci.h | 12 | ||||
| -rw-r--r-- | kernel/resource.c | 33 |
19 files changed, 199 insertions, 52 deletions
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 51a8a4c4572a..11df411b1d18 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -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; diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index b5793e8fbdc1..ac0e890510da 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -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; } diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c index e6ab3f9ff5d8..7a9e60df79c5 100644 --- a/arch/m68k/kernel/pcibios.c +++ b/arch/m68k/kernel/pcibios.c @@ -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; } diff --git a/arch/mips/pci/pci-generic.c b/arch/mips/pci/pci-generic.c index d2d68bac3d25..c2e23d0c1d77 100644 --- a/arch/mips/pci/pci-generic.c +++ b/arch/mips/pci/pci-generic.c @@ -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; } diff --git a/arch/mips/pci/pci-legacy.c b/arch/mips/pci/pci-legacy.c index d04b7c1294b6..dae6dafdd6e0 100644 --- a/arch/mips/pci/pci-legacy.c +++ b/arch/mips/pci/pci-legacy.c @@ -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; diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c index cf285b17a5ae..b8007c7400d4 100644 --- a/arch/parisc/kernel/pci.c +++ b/arch/parisc/kernel/pci.c @@ -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; } diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index a7a2fb605971..8efe95a0c4ff 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -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; diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 2a430722cbe4..39bd2adfc240 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -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) { diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index a3903304f33f..878a27a1acfb 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -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; diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index c4ec39ad276b..e2de26b82940 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -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; diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c index 62c900e400d6..305031551136 100644 --- a/arch/xtensa/kernel/pci.c +++ b/arch/xtensa/kernel/pci.c @@ -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; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index a1d2ecb56207..9540f1f1709a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -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 diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 19d73f6132fb..675713548431 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -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; diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 61f769aaa2f6..4cf120ebe5ad 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -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; } diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index bb2aef373d6f..fbc05cda96ee 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -245,16 +245,54 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev, } /* + * 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 * eventually go away. */ 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, diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 0679dd434719..949e69921fe9 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -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; diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 5533a5debf3f..3c73c9c0d4f7 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -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 */ diff --git a/include/linux/pci.h b/include/linux/pci.h index cc98713e3ce8..5aa1695fb4fe 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -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 */ diff --git a/kernel/resource.c b/kernel/resource.c index bb966699da31..d02a53fb95d8 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -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; |
