| @@ -10,7 +10,9 @@ · 9 unmodified lines |
| 10 | #include <linux/genalloc.h> | 10 | #include <linux/genalloc.h> |
| 11 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
| 12 | | 12 | |
| 13 | static struct gen_pool *atomic_pool __ro_after_init; | 13 | static struct gen_pool *atomic_pool_dma __ro_after_init; |
| | 14 | static struct gen_pool *atomic_pool_dma32 __ro_after_init; |
| | 15 | static struct gen_pool *atomic_pool_kernel __ro_after_init; |
| 14 | | 16 | |
| 15 | #define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K | 17 | #define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K |
| 16 | static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE; | 18 | static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE; |
| @@ -22,89 +24,119 @@ static int __init early_coherent_pool(char *p) · 5 unmodified lines |
| 22 | } | 24 | } |
| 23 | early_param("coherent_pool", early_coherent_pool); | 25 | early_param("coherent_pool", early_coherent_pool); |
| 24 | | 26 | |
| 25 | static gfp_t dma_atomic_pool_gfp(void) | 27 | static int __init __dma_atomic_pool_init(struct gen_pool **pool, |
| | 28 | size_t pool_size, gfp_t gfp) |
| 26 | { | 29 | { |
| 27 | if (IS_ENABLED(CONFIG_ZONE_DMA)) | 30 | const unsigned int order = get_order(pool_size); |
| 28 | return GFP_DMA; | 31 | const unsigned long nr_pages = pool_size >> PAGE_SHIFT; |
| 29 | if (IS_ENABLED(CONFIG_ZONE_DMA32)) | | |
| 30 | return GFP_DMA32; | | |
| 31 | return GFP_KERNEL; | | |
| 32 | } | | |
| 33 | | | |
| 34 | static int __init dma_atomic_pool_init(void) | | |
| 35 | { | | |
| 36 | unsigned int pool_size_order = get_order(atomic_pool_size); | | |
| 37 | unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT; | | |
| 38 | struct page *page; | 32 | struct page *page; |
| 39 | void *addr; | 33 | void *addr; |
| 40 | int ret; | 34 | int ret; |
| 41 | | 35 | |
| 42 | if (dev_get_cma_area(NULL)) | 36 | if (dev_get_cma_area(NULL)) |
| 43 | page = dma_alloc_from_contiguous(NULL, nr_pages, | 37 | page = dma_alloc_from_contiguous(NULL, nr_pages, order, false); |
| 44 | pool_size_order, false); | | |
| 45 | else | 38 | else |
| 46 | page = alloc_pages(dma_atomic_pool_gfp(), pool_size_order); | 39 | page = alloc_pages(gfp, order); |
| 47 | if (!page) | 40 | if (!page) |
| 48 | goto out; | 41 | goto out; |
| 49 | | 42 | |
| 50 | arch_dma_prep_coherent(page, atomic_pool_size); | 43 | arch_dma_prep_coherent(page, pool_size); |
| 51 | | 44 | |
| 52 | atomic_pool = gen_pool_create(PAGE_SHIFT, -1); | 45 | *pool = gen_pool_create(PAGE_SHIFT, -1); |
| 53 | if (!atomic_pool) | 46 | if (!*pool) |
| 54 | goto free_page; | 47 | goto free_page; |
| 55 | | 48 | |
| 56 | addr = dma_common_contiguous_remap(page, atomic_pool_size, | 49 | addr = dma_common_contiguous_remap(page, pool_size, |
| 57 | pgprot_dmacoherent(PAGE_KERNEL), | 50 | pgprot_dmacoherent(PAGE_KERNEL), |
| 58 | __builtin_return_address(0)); | 51 | __builtin_return_address(0)); |
| 59 | if (!addr) | 52 | if (!addr) |
| 60 | goto destroy_genpool; | 53 | goto destroy_genpool; |
| 61 | | 54 | |
| 62 | ret = gen_pool_add_virt(atomic_pool, (unsigned long)addr, | 55 | ret = gen_pool_add_virt(*pool, (unsigned long)addr, page_to_phys(page), |
| 63 | page_to_phys(page), atomic_pool_size, -1); | 56 | pool_size, -1); |
| 64 | if (ret) | 57 | if (ret) |
| 65 | goto remove_mapping; | 58 | goto remove_mapping; |
| 66 | gen_pool_set_algo(atomic_pool, gen_pool_first_fit_order_align, NULL); | 59 | gen_pool_set_algo(*pool, gen_pool_first_fit_order_align, NULL); |
| 67 | | 60 | |
| 68 | pr_info("DMA: preallocated %zu KiB pool for atomic allocations\n", | 61 | pr_info("DMA: preallocated %zu KiB %pGg pool for atomic allocations\n", |
| 69 | atomic_pool_size / 1024); | 62 | pool_size >> 10, &gfp); |
| 70 | return 0; | 63 | return 0; |
| 71 | | 64 | |
| 72 | remove_mapping: | 65 | remove_mapping: |
| 73 | dma_common_free_remap(addr, atomic_pool_size); | 66 | dma_common_free_remap(addr, pool_size); |
| 74 | destroy_genpool: | 67 | destroy_genpool: |
| 75 | gen_pool_destroy(atomic_pool); | 68 | gen_pool_destroy(*pool); |
| 76 | atomic_pool = NULL; | 69 | *pool = NULL; |
| 77 | free_page: | 70 | free_page: |
| 78 | if (!dma_release_from_contiguous(NULL, page, nr_pages)) | 71 | if (!dma_release_from_contiguous(NULL, page, nr_pages)) |
| 79 | __free_pages(page, pool_size_order); | 72 | __free_pages(page, order); |
| 80 | out: | 73 | out: |
| 81 | pr_err("DMA: failed to allocate %zu KiB pool for atomic coherent allocation\n", | 74 | pr_err("DMA: failed to allocate %zu KiB %pGg pool for atomic allocation\n", |
| 82 | atomic_pool_size / 1024); | 75 | pool_size >> 10, &gfp); |
| 83 | return -ENOMEM; | 76 | return -ENOMEM; |
| 84 | } | 77 | } |
| | 78 | |
| | 79 | static int __init dma_atomic_pool_init(void) |
| | 80 | { |
| | 81 | int ret = 0; |
| | 82 | int err; |
| | 83 | |
| | 84 | ret = __dma_atomic_pool_init(&atomic_pool_kernel, atomic_pool_size, |
| | 85 | GFP_KERNEL); |
| | 86 | if (IS_ENABLED(CONFIG_ZONE_DMA)) { |
| | 87 | err = __dma_atomic_pool_init(&atomic_pool_dma, |
| | 88 | atomic_pool_size, GFP_DMA); |
| | 89 | if (!ret && err) |
| | 90 | ret = err; |
| | 91 | } |
| | 92 | if (IS_ENABLED(CONFIG_ZONE_DMA32)) { |
| | 93 | err = __dma_atomic_pool_init(&atomic_pool_dma32, |
| | 94 | atomic_pool_size, GFP_DMA32); |
| | 95 | if (!ret && err) |
| | 96 | ret = err; |
| | 97 | } |
| | 98 | return ret; |
| | 99 | } |
| 85 | postcore_initcall(dma_atomic_pool_init); | 100 | postcore_initcall(dma_atomic_pool_init); |
| 86 | | 101 | |
| 87 | bool dma_in_atomic_pool(void *start, size_t size) | 102 | static inline struct gen_pool *dev_to_pool(struct device *dev) |
| 88 | { | 103 | { |
| 89 | if (unlikely(!atomic_pool)) | 104 | u64 phys_mask; |
| 90 | return false; | 105 | gfp_t gfp; |
| | 106 | |
| | 107 | gfp = dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask, |
| | 108 | &phys_mask); |
| | 109 | if (IS_ENABLED(CONFIG_ZONE_DMA) && gfp == GFP_DMA) |
| | 110 | return atomic_pool_dma; |
| | 111 | if (IS_ENABLED(CONFIG_ZONE_DMA32) && gfp == GFP_DMA32) |
| | 112 | return atomic_pool_dma32; |
| | 113 | return atomic_pool_kernel; |
| | 114 | } |
| 91 | | 115 | |
| 92 | return gen_pool_has_addr(atomic_pool, (unsigned long)start, size); | 116 | static bool dma_in_atomic_pool(struct device *dev, void *start, size_t size) |
| | 117 | { |
| | 118 | struct gen_pool *pool = dev_to_pool(dev); |
| | 119 | |
| | 120 | if (unlikely(!pool)) |
| | 121 | return false; |
| | 122 | return gen_pool_has_addr(pool, (unsigned long)start, size); |
| 93 | } | 123 | } |
| 94 | | 124 | |
| 95 | void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags) | 125 | void *dma_alloc_from_pool(struct device *dev, size_t size, |
| | 126 | struct page **ret_page, gfp_t flags) |
| 96 | { | 127 | { |
| | 128 | struct gen_pool *pool = dev_to_pool(dev); |
| 97 | unsigned long val; | 129 | unsigned long val; |
| 98 | void *ptr = NULL; | 130 | void *ptr = NULL; |
| 99 | | 131 | |
| 100 | if (!atomic_pool) { | 132 | if (!pool) { |
| 101 | WARN(1, "coherent pool not initialised!\n"); | 133 | WARN(1, "%pGg atomic pool not initialised!\n", &flags); |
| 102 | return NULL; | 134 | return NULL; |
| 103 | } | 135 | } |
| 104 | | 136 | |
| 105 | val = gen_pool_alloc(atomic_pool, size); | 137 | val = gen_pool_alloc(pool, size); |
| 106 | if (val) { | 138 | if (val) { |
| 107 | phys_addr_t phys = gen_pool_virt_to_phys(atomic_pool, val); | 139 | phys_addr_t phys = gen_pool_virt_to_phys(pool, val); |
| 108 | | 140 | |
| 109 | *ret_page = pfn_to_page(__phys_to_pfn(phys)); | 141 | *ret_page = pfn_to_page(__phys_to_pfn(phys)); |
| 110 | ptr = (void *)val; | 142 | ptr = (void *)val; |
| @@ -114,10 +146,12 @@ void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags) · 3 unmodified lines |
| 114 | return ptr; | 146 | return ptr; |
| 115 | } | 147 | } |
| 116 | | 148 | |
| 117 | bool dma_free_from_pool(void *start, size_t size) | 149 | bool dma_free_from_pool(struct device *dev, void *start, size_t size) |
| 118 | { | 150 | { |
| 119 | if (!dma_in_atomic_pool(start, size)) | 151 | struct gen_pool *pool = dev_to_pool(dev); |
| | 152 | |
| | 153 | if (!dma_in_atomic_pool(dev, start, size)) |
| 120 | return false; | 154 | return false; |
| 121 | gen_pool_free(atomic_pool, (unsigned long)start, size); | 155 | gen_pool_free(pool, (unsigned long)start, size); |
| 122 | return true; | 156 | return true; |
| 123 | } | 157 | } |