Skip to content

Commit c13704f

Browse files
PCI: Avoid double hpmemsize MMIO window assignment
Previously, the kernel sometimes assigned more MMIO or MMIO_PREF space than desired. For example, if the user requested 128M of space with "pci=realloc,hpmemsize=128M", we sometimes assigned 256M: pci 0000:06:01.0: BAR 14: assigned [mem 0x90100000-0xa00fffff] = 256M pci 0000:06:04.0: BAR 14: assigned [mem 0xa0200000-0xb01fffff] = 256M With this patch applied: pci 0000:06:01.0: BAR 14: assigned [mem 0x90100000-0x980fffff] = 128M pci 0000:06:04.0: BAR 14: assigned [mem 0x98200000-0xa01fffff] = 128M This happened when in the first pass, the MMIO_PREF succeeded but the MMIO failed. In the next pass, because MMIO_PREF was already assigned, the attempt to assign MMIO_PREF returned an error code instead of success (nothing more to do, already allocated). Hence, the size which was actually allocated, but thought to have failed, was placed in the MMIO window. The bug resulted in the MMIO_PREF being added to the MMIO window, which meant doubling if MMIO_PREF size = MMIO size. With a large MMIO_PREF, the MMIO window would likely fail to be assigned altogether due to lack of 32-bit address space. Change find_free_bus_resource() to do the following: - 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. Add checks in pbus_size_io() and pbus_size_mem() to return success if resource returned from find_free_bus_resource() is already allocated. This avoids pbus_size_io() and pbus_size_mem() returning error code to __pci_bus_size_bridges() when a resource has been successfully assigned in a previous pass. This fixes the existing behaviour where space for a resource could be reserved multiple times in different parent bridge windows. Link: https://lore.kernel.org/lkml/[email protected]/T/#u Link: https://bugzilla.kernel.org/show_bug.cgi?id=203243 Link: https://lore.kernel.org/r/PS2P216MB075563AA6AD242AA666EDC6A80760@PS2P216MB0755.KORP216.PROD.OUTLOOK.COM Reported-by: Kit Chow <[email protected]> Reported-by: Nicholas Johnson <[email protected]> Signed-off-by: Nicholas Johnson <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Mika Westerberg <[email protected]> Reviewed-by: Logan Gunthorpe <[email protected]>
1 parent d7b8a21 commit c13704f

File tree

1 file changed

+27
-11
lines changed

1 file changed

+27
-11
lines changed

drivers/pci/setup-bus.c

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -752,24 +752,32 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)
752752
}
753753

754754
/*
755-
* Helper function for sizing routines: find first available bus resource
756-
* of a given type. Note: we intentionally skip the bus resources which
757-
* have already been assigned (that is, have non-NULL parent resource).
755+
* Helper function for sizing routines. Assigned resources have non-NULL
756+
* parent resource.
757+
*
758+
* Return first unassigned resource of the correct type. If there is none,
759+
* return first assigned resource of the correct type. If none of the
760+
* above, return NULL.
761+
*
762+
* Returning an assigned resource of the correct type allows the caller to
763+
* distinguish between already assigned and no resource of the correct type.
758764
*/
759-
static struct resource *find_free_bus_resource(struct pci_bus *bus,
760-
unsigned long type_mask,
761-
unsigned long type)
765+
static struct resource *find_bus_resource_of_type(struct pci_bus *bus,
766+
unsigned long type_mask,
767+
unsigned long type)
762768
{
769+
struct resource *r, *r_assigned = NULL;
763770
int i;
764-
struct resource *r;
765771

766772
pci_bus_for_each_resource(bus, r, i) {
767773
if (r == &ioport_resource || r == &iomem_resource)
768774
continue;
769775
if (r && (r->flags & type_mask) == type && !r->parent)
770776
return r;
777+
if (r && (r->flags & type_mask) == type && !r_assigned)
778+
r_assigned = r;
771779
}
772-
return NULL;
780+
return r_assigned;
773781
}
774782

775783
static resource_size_t calculate_iosize(resource_size_t size,
@@ -866,15 +874,19 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
866874
struct list_head *realloc_head)
867875
{
868876
struct pci_dev *dev;
869-
struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO,
870-
IORESOURCE_IO);
877+
struct resource *b_res = find_bus_resource_of_type(bus, IORESOURCE_IO,
878+
IORESOURCE_IO);
871879
resource_size_t size = 0, size0 = 0, size1 = 0;
872880
resource_size_t children_add_size = 0;
873881
resource_size_t min_align, align;
874882

875883
if (!b_res)
876884
return;
877885

886+
/* If resource is already assigned, nothing more to do */
887+
if (b_res->parent)
888+
return;
889+
878890
min_align = window_alignment(bus, IORESOURCE_IO);
879891
list_for_each_entry(dev, &bus->devices, bus_list) {
880892
int i;
@@ -978,7 +990,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
978990
resource_size_t min_align, align, size, size0, size1;
979991
resource_size_t aligns[18]; /* Alignments from 1MB to 128GB */
980992
int order, max_order;
981-
struct resource *b_res = find_free_bus_resource(bus,
993+
struct resource *b_res = find_bus_resource_of_type(bus,
982994
mask | IORESOURCE_PREFETCH, type);
983995
resource_size_t children_add_size = 0;
984996
resource_size_t children_add_align = 0;
@@ -987,6 +999,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
987999
if (!b_res)
9881000
return -ENOSPC;
9891001

1002+
/* If resource is already assigned, nothing more to do */
1003+
if (b_res->parent)
1004+
return 0;
1005+
9901006
memset(aligns, 0, sizeof(aligns));
9911007
max_order = 0;
9921008
size = 0;

0 commit comments

Comments
 (0)