Skip to content

Commit 65d8f68

Browse files
committed
Merge branch 'pci/resource'
- Rename find_resource() to find_resource_space() to make it more descriptive for exporting outside resource.c (Ilpo Järvinen) - Document find_resource_space() and the resource_constraint struct it uses (Ilpo Järvinen) - Add typedef resource_alignf to make it simpler to declare allocation constraint alignf callbacks (Ilpo Järvinen) - Open-code the no-constraint simple alignment case to make the simple_align_resource() default callback unnecessary (Ilpo Järvinen) - Export find_resource_space() because PCI bridge window allocation needs to learn whether there's space for a window (Ilpo Järvinen) - Fix a double-counting problem in PCI calculate_memsize() that led to allocating larger windows each time a bus was removed and rescanned (Ilpo Järvinen) - When we don't have space to allocate larger bridge windows, allocate windows only large enough for the downstream devices to prevent cases where a device worked originally, but not after being removed and re-added (Ilpo Järvinen) * pci/resource: PCI: Relax bridge window tail sizing rules PCI: Make minimum bridge window alignment reference more obvious PCI: Fix resource double counting on remove & rescan resource: Export find_resource_space() resource: Handle simple alignment inside __find_resource_space() resource: Use typedef for alignf callback resource: Document find_resource_space() and resource_constraint resource: Rename find_resource() to find_resource_space()
2 parents 6228133 + 566f1dd commit 65d8f68

File tree

5 files changed

+157
-61
lines changed

5 files changed

+157
-61
lines changed

drivers/pci/bus.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,7 @@ static void pci_clip_resource_to_region(struct pci_bus *bus,
176176
static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
177177
resource_size_t size, resource_size_t align,
178178
resource_size_t min, unsigned long type_mask,
179-
resource_size_t (*alignf)(void *,
180-
const struct resource *,
181-
resource_size_t,
182-
resource_size_t),
179+
resource_alignf alignf,
183180
void *alignf_data,
184181
struct pci_bus_region *region)
185182
{
@@ -250,10 +247,7 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
250247
int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
251248
resource_size_t size, resource_size_t align,
252249
resource_size_t min, unsigned long type_mask,
253-
resource_size_t (*alignf)(void *,
254-
const struct resource *,
255-
resource_size_t,
256-
resource_size_t),
250+
resource_alignf alignf,
257251
void *alignf_data)
258252
{
259253
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT

drivers/pci/setup-bus.c

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,16 @@
1414
* tighter packing. Prefetchable range support.
1515
*/
1616

17+
#include <linux/bitops.h>
1718
#include <linux/init.h>
1819
#include <linux/kernel.h>
1920
#include <linux/module.h>
2021
#include <linux/pci.h>
2122
#include <linux/errno.h>
2223
#include <linux/ioport.h>
2324
#include <linux/cache.h>
25+
#include <linux/limits.h>
26+
#include <linux/sizes.h>
2427
#include <linux/slab.h>
2528
#include <linux/acpi.h>
2629
#include "pci.h"
@@ -829,11 +832,9 @@ static resource_size_t calculate_memsize(resource_size_t size,
829832
size = min_size;
830833
if (old_size == 1)
831834
old_size = 0;
832-
if (size < old_size)
833-
size = old_size;
834835

835-
size = ALIGN(max(size, add_size) + children_add_size, align);
836-
return size;
836+
size = max(size, add_size) + children_add_size;
837+
return ALIGN(max(size, old_size), align);
837838
}
838839

839840
resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
@@ -959,7 +960,7 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns,
959960
for (order = 0; order <= max_order; order++) {
960961
resource_size_t align1 = 1;
961962

962-
align1 <<= (order + 20);
963+
align1 <<= order + __ffs(SZ_1M);
963964

964965
if (!align)
965966
min_align = align1;
@@ -971,6 +972,67 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns,
971972
return min_align;
972973
}
973974

975+
/**
976+
* pbus_upstream_space_available - Check no upstream resource limits allocation
977+
* @bus: The bus
978+
* @mask: Mask the resource flag, then compare it with type
979+
* @type: The type of resource from bridge
980+
* @size: The size required from the bridge window
981+
* @align: Required alignment for the resource
982+
*
983+
* Checks that @size can fit inside the upstream bridge resources that are
984+
* already assigned.
985+
*
986+
* Return: %true if enough space is available on all assigned upstream
987+
* resources.
988+
*/
989+
static bool pbus_upstream_space_available(struct pci_bus *bus, unsigned long mask,
990+
unsigned long type, resource_size_t size,
991+
resource_size_t align)
992+
{
993+
struct resource_constraint constraint = {
994+
.max = RESOURCE_SIZE_MAX,
995+
.align = align,
996+
};
997+
struct pci_bus *downstream = bus;
998+
struct resource *r;
999+
1000+
while ((bus = bus->parent)) {
1001+
if (pci_is_root_bus(bus))
1002+
break;
1003+
1004+
pci_bus_for_each_resource(bus, r) {
1005+
if (!r || !r->parent || (r->flags & mask) != type)
1006+
continue;
1007+
1008+
if (resource_size(r) >= size) {
1009+
struct resource gap = {};
1010+
1011+
if (find_resource_space(r, &gap, size, &constraint) == 0) {
1012+
gap.flags = type;
1013+
pci_dbg(bus->self,
1014+
"Assigned bridge window %pR to %pR free space at %pR\n",
1015+
r, &bus->busn_res, &gap);
1016+
return true;
1017+
}
1018+
}
1019+
1020+
if (bus->self) {
1021+
pci_info(bus->self,
1022+
"Assigned bridge window %pR to %pR cannot fit 0x%llx required for %s bridging to %pR\n",
1023+
r, &bus->busn_res,
1024+
(unsigned long long)size,
1025+
pci_name(downstream->self),
1026+
&downstream->busn_res);
1027+
}
1028+
1029+
return false;
1030+
}
1031+
}
1032+
1033+
return true;
1034+
}
1035+
9741036
/**
9751037
* pbus_size_mem() - Size the memory window of a given bus
9761038
*
@@ -997,7 +1059,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
9971059
struct list_head *realloc_head)
9981060
{
9991061
struct pci_dev *dev;
1000-
resource_size_t min_align, align, size, size0, size1;
1062+
resource_size_t min_align, win_align, align, size, size0, size1;
10011063
resource_size_t aligns[24]; /* Alignments from 1MB to 8TB */
10021064
int order, max_order;
10031065
struct resource *b_res = find_bus_resource_of_type(bus,
@@ -1049,7 +1111,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
10491111
* resources.
10501112
*/
10511113
align = pci_resource_alignment(dev, r);
1052-
order = __ffs(align) - 20;
1114+
order = __ffs(align) - __ffs(SZ_1M);
10531115
if (order < 0)
10541116
order = 0;
10551117
if (order >= ARRAY_SIZE(aligns)) {
@@ -1076,10 +1138,23 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
10761138
}
10771139
}
10781140

1141+
win_align = window_alignment(bus, b_res->flags);
10791142
min_align = calculate_mem_align(aligns, max_order);
1080-
min_align = max(min_align, window_alignment(bus, b_res->flags));
1143+
min_align = max(min_align, win_align);
10811144
size0 = calculate_memsize(size, min_size, 0, 0, resource_size(b_res), min_align);
10821145
add_align = max(min_align, add_align);
1146+
1147+
if (bus->self && size0 &&
1148+
!pbus_upstream_space_available(bus, mask | IORESOURCE_PREFETCH, type,
1149+
size0, add_align)) {
1150+
min_align = 1ULL << (max_order + __ffs(SZ_1M));
1151+
min_align = max(min_align, win_align);
1152+
size0 = calculate_memsize(size, min_size, 0, 0, resource_size(b_res), win_align);
1153+
add_align = win_align;
1154+
pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n",
1155+
b_res, &bus->busn_res);
1156+
}
1157+
10831158
size1 = (!realloc_head || (realloc_head && !add_size && !children_add_size)) ? size0 :
10841159
calculate_memsize(size, min_size, add_size, children_add_size,
10851160
resource_size(b_res), add_align);

include/linux/ioport.h

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,42 @@ enum {
188188
#define DEFINE_RES_DMA(_dma) \
189189
DEFINE_RES_DMA_NAMED((_dma), NULL)
190190

191+
/**
192+
* typedef resource_alignf - Resource alignment callback
193+
* @data: Private data used by the callback
194+
* @res: Resource candidate range (an empty resource space)
195+
* @size: The minimum size of the empty space
196+
* @align: Alignment from the constraints
197+
*
198+
* Callback allows calculating resource placement and alignment beyond min,
199+
* max, and align fields in the struct resource_constraint.
200+
*
201+
* Return: Start address for the resource.
202+
*/
203+
typedef resource_size_t (*resource_alignf)(void *data,
204+
const struct resource *res,
205+
resource_size_t size,
206+
resource_size_t align);
207+
208+
/**
209+
* struct resource_constraint - constraints to be met while searching empty
210+
* resource space
211+
* @min: The minimum address for the memory range
212+
* @max: The maximum address for the memory range
213+
* @align: Alignment for the start address of the empty space
214+
* @alignf: Additional alignment constraints callback
215+
* @alignf_data: Data provided for @alignf callback
216+
*
217+
* Contains the range and alignment constraints that have to be met during
218+
* find_resource_space(). @alignf can be NULL indicating no alignment beyond
219+
* @align is necessary.
220+
*/
221+
struct resource_constraint {
222+
resource_size_t min, max, align;
223+
resource_alignf alignf;
224+
void *alignf_data;
225+
};
226+
191227
/* PC/ISA/whatever - the normal PC address spaces: IO and memory */
192228
extern struct resource ioport_resource;
193229
extern struct resource iomem_resource;
@@ -207,10 +243,7 @@ extern void arch_remove_reservations(struct resource *avail);
207243
extern int allocate_resource(struct resource *root, struct resource *new,
208244
resource_size_t size, resource_size_t min,
209245
resource_size_t max, resource_size_t align,
210-
resource_size_t (*alignf)(void *,
211-
const struct resource *,
212-
resource_size_t,
213-
resource_size_t),
246+
resource_alignf alignf,
214247
void *alignf_data);
215248
struct resource *lookup_resource(struct resource *root, resource_size_t start);
216249
int adjust_resource(struct resource *res, resource_size_t start,
@@ -264,6 +297,9 @@ static inline bool resource_union(const struct resource *r1, const struct resour
264297
return true;
265298
}
266299

300+
int find_resource_space(struct resource *root, struct resource *new,
301+
resource_size_t size, struct resource_constraint *constraint);
302+
267303
/* Convenience shorthand with allocation */
268304
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0)
269305
#define request_muxed_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED)

include/linux/pci.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,10 +1552,7 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
15521552
struct resource *res, resource_size_t size,
15531553
resource_size_t align, resource_size_t min,
15541554
unsigned long type_mask,
1555-
resource_size_t (*alignf)(void *,
1556-
const struct resource *,
1557-
resource_size_t,
1558-
resource_size_t),
1555+
resource_alignf alignf,
15591556
void *alignf_data);
15601557

15611558

kernel/resource.c

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,6 @@ struct resource iomem_resource = {
4848
};
4949
EXPORT_SYMBOL(iomem_resource);
5050

51-
/* constraints to be met while allocating resources */
52-
struct resource_constraint {
53-
resource_size_t min, max, align;
54-
resource_size_t (*alignf)(void *, const struct resource *,
55-
resource_size_t, resource_size_t);
56-
void *alignf_data;
57-
};
58-
5951
static DEFINE_RWLOCK(resource_lock);
6052

6153
static struct resource *next_resource(struct resource *p, bool skip_children)
@@ -610,14 +602,6 @@ void __weak arch_remove_reservations(struct resource *avail)
610602
{
611603
}
612604

613-
static resource_size_t simple_align_resource(void *data,
614-
const struct resource *avail,
615-
resource_size_t size,
616-
resource_size_t align)
617-
{
618-
return avail->start;
619-
}
620-
621605
static void resource_clip(struct resource *res, resource_size_t min,
622606
resource_size_t max)
623607
{
@@ -628,16 +612,16 @@ static void resource_clip(struct resource *res, resource_size_t min,
628612
}
629613

630614
/*
631-
* Find empty slot in the resource tree with the given range and
615+
* Find empty space in the resource tree with the given range and
632616
* alignment constraints
633617
*/
634-
static int __find_resource(struct resource *root, struct resource *old,
635-
struct resource *new,
636-
resource_size_t size,
637-
struct resource_constraint *constraint)
618+
static int __find_resource_space(struct resource *root, struct resource *old,
619+
struct resource *new, resource_size_t size,
620+
struct resource_constraint *constraint)
638621
{
639622
struct resource *this = root->child;
640623
struct resource tmp = *new, avail, alloc;
624+
resource_alignf alignf = constraint->alignf;
641625

642626
tmp.start = root->start;
643627
/*
@@ -666,8 +650,12 @@ static int __find_resource(struct resource *root, struct resource *old,
666650
avail.flags = new->flags & ~IORESOURCE_UNSET;
667651
if (avail.start >= tmp.start) {
668652
alloc.flags = avail.flags;
669-
alloc.start = constraint->alignf(constraint->alignf_data, &avail,
670-
size, constraint->align);
653+
if (alignf) {
654+
alloc.start = alignf(constraint->alignf_data,
655+
&avail, size, constraint->align);
656+
} else {
657+
alloc.start = avail.start;
658+
}
671659
alloc.end = alloc.start + size - 1;
672660
if (alloc.start <= alloc.end &&
673661
resource_contains(&avail, &alloc)) {
@@ -687,15 +675,27 @@ next: if (!this || this->end == root->end)
687675
return -EBUSY;
688676
}
689677

690-
/*
691-
* Find empty slot in the resource tree given range and alignment.
678+
/**
679+
* find_resource_space - Find empty space in the resource tree
680+
* @root: Root resource descriptor
681+
* @new: Resource descriptor awaiting an empty resource space
682+
* @size: The minimum size of the empty space
683+
* @constraint: The range and alignment constraints to be met
684+
*
685+
* Finds an empty space under @root in the resource tree satisfying range and
686+
* alignment @constraints.
687+
*
688+
* Return:
689+
* * %0 - if successful, @new members start, end, and flags are altered.
690+
* * %-EBUSY - if no empty space was found.
692691
*/
693-
static int find_resource(struct resource *root, struct resource *new,
692+
int find_resource_space(struct resource *root, struct resource *new,
694693
resource_size_t size,
695-
struct resource_constraint *constraint)
694+
struct resource_constraint *constraint)
696695
{
697-
return __find_resource(root, NULL, new, size, constraint);
696+
return __find_resource_space(root, NULL, new, size, constraint);
698697
}
698+
EXPORT_SYMBOL_GPL(find_resource_space);
699699

700700
/**
701701
* reallocate_resource - allocate a slot in the resource tree given range & alignment.
@@ -717,7 +717,7 @@ static int reallocate_resource(struct resource *root, struct resource *old,
717717

718718
write_lock(&resource_lock);
719719

720-
if ((err = __find_resource(root, old, &new, newsize, constraint)))
720+
if ((err = __find_resource_space(root, old, &new, newsize, constraint)))
721721
goto out;
722722

723723
if (resource_contains(&new, old)) {
@@ -761,18 +761,12 @@ static int reallocate_resource(struct resource *root, struct resource *old,
761761
int allocate_resource(struct resource *root, struct resource *new,
762762
resource_size_t size, resource_size_t min,
763763
resource_size_t max, resource_size_t align,
764-
resource_size_t (*alignf)(void *,
765-
const struct resource *,
766-
resource_size_t,
767-
resource_size_t),
764+
resource_alignf alignf,
768765
void *alignf_data)
769766
{
770767
int err;
771768
struct resource_constraint constraint;
772769

773-
if (!alignf)
774-
alignf = simple_align_resource;
775-
776770
constraint.min = min;
777771
constraint.max = max;
778772
constraint.align = align;
@@ -786,7 +780,7 @@ int allocate_resource(struct resource *root, struct resource *new,
786780
}
787781

788782
write_lock(&resource_lock);
789-
err = find_resource(root, new, size, &constraint);
783+
err = find_resource_space(root, new, size, &constraint);
790784
if (err >= 0 && __request_resource(root, new))
791785
err = -EBUSY;
792786
write_unlock(&resource_lock);

0 commit comments

Comments
 (0)