From b7b349c452ebbb07f26d563f5fc9c9583ea69486 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Mon, 19 Mar 2018 20:02:23 +0530 Subject: [PATCH 1/4] arm: dma-mapping: DMA buf may not have cpu virtual addr DMA buffers may not have cpu virtual addresses when allocated using DMA_ATTR_NO_KERNEL_MAPPING attribute. Page address should therefore be looked up while searching for such dma bufs. Also fix the printk format specifier to '%pK' to print kernel pointers. Change-Id: I5754cde63ace19aed88624a36186d012309d475b Signed-off-by: Shiraz Hashim Signed-off-by: Charan Teja Reddy Signed-off-by: Vijayanand Jitta Signed-off-by: Qingqing Zhou --- arch/arm/mm/dma-mapping.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index dd76f6e85db3..7d1a39d51966 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -858,9 +858,10 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr, .page = page, .want_vaddr = ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0), }; + void *addr = (args.want_vaddr) ? cpu_addr : page; - buf = arm_dma_buffer_find(cpu_addr); - if (WARN(!buf, "Freeing invalid buffer %p\n", cpu_addr)) + buf = arm_dma_buffer_find(addr); + if (WARN(!buf, "Freeing invalid buffer %pK\n", addr)) return; buf->allocator->free(&args); From cdc7377df2f1c08c765d39eec5635995f2339971 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Sun, 21 Feb 2016 12:45:34 +0530 Subject: [PATCH 2/4] arm: dma-mapping: fix data types to hold size_t size_t type data should not be held under variable of type int, as this can truncate large values especially on a 64bit system. Fix it. Change-Id: I5ad1ab321738772a99920e3fa287bda266cb05ed Signed-off-by: Shiraz Hashim Signed-off-by: Patrick Daly Signed-off-by: Charan Teja Reddy Signed-off-by: Vijayanand Jitta Signed-off-by: Qingqing Zhou --- arch/arm/mm/dma-mapping.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 7d1a39d51966..630260a325d7 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1256,8 +1256,8 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, int coherent_flag) { struct page **pages; - int count = size >> PAGE_SHIFT; - int array_size = count * sizeof(struct page *); + size_t count = size >> PAGE_SHIFT; + size_t array_size = count * sizeof(struct page *); int i = 0; int order_idx = 0; From 84df8c8f74ec86c239f7aea54ec0d98b0a4a421d Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Thu, 26 Jan 2017 16:46:14 -0800 Subject: [PATCH 3/4] arm: dma-mapping: map_page map to nearest page Since the page offset can be greater than the size of a page fix arm_coherent_iommu_map_page so that it maps to nearest page boundary. This both prevents unnecessarily mapping memory we don't need to map and fixes a issue where the unmap wasn't unmapping this extra memory. Change-Id: Iaa69aff7505ee75d1f2e69bb0cda814bc6211bd3 Signed-off-by: Liam Mark Signed-off-by: Patrick Daly Signed-off-by: Charan Teja Reddy Signed-off-by: Vijayanand Jitta Signed-off-by: Qingqing Zhou --- arch/arm/mm/dma-mapping.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 630260a325d7..5443a6c72a63 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1893,7 +1893,11 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p { struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); dma_addr_t dma_addr; - int ret, prot, len = PAGE_ALIGN(size + offset); + int ret, prot, len, start_offset, map_offset; + + map_offset = offset & ~PAGE_MASK; + start_offset = offset & PAGE_MASK; + len = PAGE_ALIGN(map_offset + size); dma_addr = __alloc_iova(mapping, len); if (dma_addr == DMA_MAPPING_ERROR) @@ -1901,11 +1905,12 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p prot = __dma_info_to_prot(dir, attrs); - ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, prot); + ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page) + + start_offset, len, prot); if (ret < 0) goto fail; - return dma_addr + offset; + return dma_addr + map_offset; fail: __free_iova(mapping, dma_addr, len); return DMA_MAPPING_ERROR; From 0b06cd5ca5801698b7fd9fa94d2b419d02dd126e Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Wed, 17 Feb 2016 15:58:22 -0800 Subject: [PATCH 4/4] arm: dma: Allow CMA pages to not have a kernel mapping Currently, there are use cases where not having any kernel mapping is required; if the CMA memory needs to be used as a pool which can have both cached and uncached mappings we need to remove the mapping to avoid the multiple mapping problem. Extend the dma APIs to use the DMA_ATTR_NO_KERNEL_MAPPING with CMA. This doesn't end up saving any virtual address space but the mapping will still not be present. Change-Id: I64d21250abbe615c43e2b5b1272ee2b6d106705a Signed-off-by: Laura Abbott Signed-off-by: Patrick Daly Signed-off-by: Vijayanand Jitta Signed-off-by: Charan Teja Reddy Signed-off-by: Qingqing Zhou --- arch/arm/mm/dma-mapping.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 5443a6c72a63..66a46e9d0126 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -484,12 +484,26 @@ static int __dma_update_pte(pte_t *pte, unsigned long addr, void *data) return 0; } -static void __dma_remap(struct page *page, size_t size, pgprot_t prot) +static int __dma_clear_pte(pte_t *pte, unsigned long addr, void *data) +{ + pte_clear(&init_mm, addr, pte); + return 0; +} + +static void __dma_remap(struct page *page, size_t size, pgprot_t prot, + bool want_vaddr) { unsigned long start = (unsigned long) page_address(page); unsigned end = start + size; + int (*func)(pte_t *pte, unsigned long addr, void *data); - apply_to_page_range(&init_mm, start, size, __dma_update_pte, &prot); + if (!want_vaddr) + func = __dma_clear_pte; + else + func = __dma_update_pte; + + apply_to_page_range(&init_mm, start, size, func, &prot); + mb(); /*Ensure pte's are updated */ flush_tlb_kernel_range(start, end); } @@ -572,9 +586,6 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, __dma_clear_buffer(page, size, coherent_flag); - if (!want_vaddr) - goto out; - if (PageHighMem(page)) { ptr = dma_common_contiguous_remap(page, size, prot, caller); if (!ptr) { @@ -582,11 +593,10 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, return NULL; } } else { - __dma_remap(page, size, prot); + __dma_remap(page, size, prot, want_vaddr); ptr = page_address(page); } - out: *ret_page = page; return ptr; } @@ -594,12 +604,10 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, static void __free_from_contiguous(struct device *dev, struct page *page, void *cpu_addr, size_t size, bool want_vaddr) { - if (want_vaddr) { - if (PageHighMem(page)) - dma_common_free_remap(cpu_addr, size); - else - __dma_remap(page, size, PAGE_KERNEL); - } + if (PageHighMem(page)) + dma_common_free_remap(cpu_addr, size); + else + __dma_remap(page, size, PAGE_KERNEL, true); dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT); }