(+), 9 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index a61d38777cdc4..99086980e102e 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1227,6 +1227,45 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns, return min_align; } +/* + * Calculate bridge window head alignment that leaves no gaps in between + * resources. + */ +static resource_size_t calculate_head_align(resource_size_t *aligns, + int max_order) +{ + resource_size_t head_align = 1; + resource_size_t remainder = 0; + int order; + + /* Take the largest alignment as the starting point. */ + head_align <<= max_order + __ffs(SZ_1M); + + for (order = max_order - 1; order >= 0; order--) { + resource_size_t align1 = 1; + + align1 <<= order + __ffs(SZ_1M); + + /* + * Account smaller resources with alignment < max_order that + * could be used to fill head room if alignment less than + * max_order is used. + */ + remainder += aligns[order]; + + /* + * Test if head fill is enough to satisfy the alignment of + * the larger resources after reducing the alignment. + */ + while ((head_align > align1) && (remainder >= head_align / 2)) { + head_align /= 2; + remainder -= head_align; + } + } + + return head_align; +} + /** * pbus_upstream_space_available - Check no upstream resource limits allocation * @bus: The bus @@ -1314,13 +1353,13 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, { 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 */ + resource_size_t aligns[28] = {}; /* Alignments from 1MB to 128TB */ + resource_size_t aligns2[28] = {};/* Alignments from 1MB to 128TB */ int order, max_order; struct resource *b_res = pbus_select_window_for_type(bus, 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; resource_size_t old_size; if (!b_res) @@ -1330,7 +1369,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, if (b_res->parent) return; - memset(aligns, 0, sizeof(aligns)); max_order = 0; size = 0; @@ -1381,6 +1419,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, */ if (r_size <= align) aligns[order] += align; + aligns2[order] += align; if (order > max_order) max_order = order; @@ -1405,9 +1444,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, if (bus->self && size0 && !pbus_upstream_space_available(bus, b_res, size0, min_align)) { - relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); - relaxed_align = max(relaxed_align, win_align); - min_align = min(min_align, relaxed_align); + min_align = calculate_head_align(aligns2, max_order); size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); resource_set_range(b_res, min_align, size0); pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n", @@ -1421,9 +1458,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, if (bus->self && size1 && !pbus_upstream_space_available(bus, b_res, size1, add_align)) { - relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); - relaxed_align = max(relaxed_align, win_align); - min_align = min(min_align, relaxed_align); + min_align = calculate_head_align(aligns2, max_order); size1 = calculate_memsize(size, min_size, add_size, children_add_size, old_size, win_align); pci_info(bus->self, -- 2.51.0[PATCH 6.19 368/781] PCI: Rewrite bridge window head alignment functionGreg Kroah-Hartman undefinedstable@vger.kernel.org undefined undefined undefined undefined undefined undefined™†™<