This change sets the allocation orders for the different page sizes (4k, 16k, 64k) based on PAGE_SHIFT. Before this change, the orders for large page sizes were calculated incorrectly, this caused system heap to allocate from 2% to 4% more memory on 16KiB page size kernels.
This change was tested on 4k/16k page size kernels. Signed-off-by: Juan Yescas <[email protected]> Acked-by: John Stultz <[email protected]> Reviewed-by: T.J. Mercier <[email protected]> --- Changes in v2: - Add John's Acked-by tag. - Add TJ's Reviewed-by tag - Use dma-buf: system_heap: in the subject since this is specific to the system heap, as per TJ. - Remove extra space in if statement. Changes in v3: - Remove defines for the orders as per Christian. - Update the order array for 64k page sizes as per TJ drivers/dma-buf/heaps/system_heap.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c index 26d5dc89ea16..8c10c0f2b473 100644 --- a/drivers/dma-buf/heaps/system_heap.c +++ b/drivers/dma-buf/heaps/system_heap.c @@ -18,6 +18,7 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/scatterlist.h> +#include <linux/sizes.h> #include <linux/slab.h> #include <linux/vmalloc.h> @@ -44,14 +45,28 @@ struct dma_heap_attachment { #define HIGH_ORDER_GFP (((GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN \ | __GFP_NORETRY) & ~__GFP_RECLAIM) \ | __GFP_COMP) -static gfp_t order_flags[] = {HIGH_ORDER_GFP, HIGH_ORDER_GFP, LOW_ORDER_GFP}; /* * The selection of the orders used for allocation (1MB, 64K, 4K) is designed * to match with the sizes often found in IOMMUs. Using order 4 pages instead * of order 0 pages can significantly improve the performance of many IOMMUs * by reducing TLB pressure and time spent updating page tables. + * + * Note: When the order is 0, the minimum allocation is PAGE_SIZE. The possible + * page sizes for ARM devices could be 4K, 16K and 64K. + */ +#if (PAGE_SIZE == SZ_64K) +static gfp_t order_flags[] = {HIGH_ORDER_GFP, LOW_ORDER_GFP}; +/* 1MiB allocs are calculated with (2 ^ (20 - PAGE_SHIFT)) * PAGE_SIZE = 1MiB */ +static const unsigned int orders[] = {20 - PAGE_SHIFT, 0}; +#else +static gfp_t order_flags[] = {HIGH_ORDER_GFP, HIGH_ORDER_GFP, LOW_ORDER_GFP}; +/* + * 1MiB allocs are calculated with (2 ^ (20 - PAGE_SHIFT)) * PAGE_SIZE = 1MiB + * 64KiB allocs are calculated with (2 ^ (16 - PAGE_SHIFT)) * PAGE_SIZE = 64KiB */ -static const unsigned int orders[] = {8, 4, 0}; +static const unsigned int orders[] = {20 - PAGE_SHIFT, 16 - PAGE_SHIFT, 0}; +#endif + #define NUM_ORDERS ARRAY_SIZE(orders) static struct sg_table *dup_sg_table(struct sg_table *table) @@ -318,7 +333,7 @@ static struct page *alloc_largest_available(unsigned long size, int i; for (i = 0; i < NUM_ORDERS; i++) { - if (size < (PAGE_SIZE << orders[i])) + if (size < (PAGE_SIZE << orders[i])) continue; if (max_order < orders[i]) continue; -- 2.49.0.805.g082f7c87e0-goog
