Message ID | 1359984182-6307-1-git-send-email-m.szyprowski@samsung.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Mon, Feb 04 2013, Marek Szyprowski wrote: > @@ -186,13 +186,24 @@ static u64 get_coherent_dma_mask(struct device *dev) > > static void __dma_clear_buffer(struct page *page, size_t size) > { > - void *ptr; > /* > * Ensure that the allocated pages are zeroed, and that any data > * lurking in the kernel direct-mapped region is invalidated. > */ > - ptr = page_address(page); > - if (ptr) { > + if (PageHighMem(page)) { > + phys_addr_t base = __pfn_to_phys(page_to_pfn(page)); > + phys_addr_t end = base + size; > + while (size > 0) { > + void *ptr = kmap_atomic(page); > + memset(ptr, 0, PAGE_SIZE); > + dmac_flush_range(ptr, ptr + PAGE_SIZE); > + kunmap_atomic(ptr); > + page++; > + size -= PAGE_SIZE; > + } > + outer_flush_range(base, end); > + } else { > + void *ptr = page_address(page); There used to be a “if (ptr)” check which is now missing. Why is that? > memset(ptr, 0, size); > dmac_flush_range(ptr, ptr + size); > outer_flush_range(__pa(ptr), __pa(ptr) + size);
On Mon, Feb 04, 2013 at 02:51:52PM +0100, Michal Nazarewicz wrote: > On Mon, Feb 04 2013, Marek Szyprowski wrote: > > @@ -186,13 +186,24 @@ static u64 get_coherent_dma_mask(struct device *dev) > > > > static void __dma_clear_buffer(struct page *page, size_t size) > > { > > - void *ptr; > > /* > > * Ensure that the allocated pages are zeroed, and that any data > > * lurking in the kernel direct-mapped region is invalidated. > > */ > > - ptr = page_address(page); > > - if (ptr) { > > + if (PageHighMem(page)) { > > + phys_addr_t base = __pfn_to_phys(page_to_pfn(page)); > > + phys_addr_t end = base + size; > > + while (size > 0) { > > + void *ptr = kmap_atomic(page); > > + memset(ptr, 0, PAGE_SIZE); > > + dmac_flush_range(ptr, ptr + PAGE_SIZE); > > + kunmap_atomic(ptr); > > + page++; > > + size -= PAGE_SIZE; > > + } > > + outer_flush_range(base, end); > > + } else { > > + void *ptr = page_address(page); > > There used to be a “if (ptr)” check which is now missing. Why is that? Because lowmem pages always have an address.
On Mon, Feb 04 2013, Russell King - ARM Linux wrote: > On Mon, Feb 04, 2013 at 02:51:52PM +0100, Michal Nazarewicz wrote: >> On Mon, Feb 04 2013, Marek Szyprowski wrote: >> > @@ -186,13 +186,24 @@ static u64 get_coherent_dma_mask(struct device *dev) >> > >> > static void __dma_clear_buffer(struct page *page, size_t size) >> > { >> > - void *ptr; >> > /* >> > * Ensure that the allocated pages are zeroed, and that any data >> > * lurking in the kernel direct-mapped region is invalidated. >> > */ >> > - ptr = page_address(page); >> > - if (ptr) { >> > + if (PageHighMem(page)) { >> > + phys_addr_t base = __pfn_to_phys(page_to_pfn(page)); >> > + phys_addr_t end = base + size; >> > + while (size > 0) { >> > + void *ptr = kmap_atomic(page); >> > + memset(ptr, 0, PAGE_SIZE); >> > + dmac_flush_range(ptr, ptr + PAGE_SIZE); >> > + kunmap_atomic(ptr); >> > + page++; >> > + size -= PAGE_SIZE; >> > + } >> > + outer_flush_range(base, end); >> > + } else { >> > + void *ptr = page_address(page); >> >> There used to be a “if (ptr)” check which is now missing. Why is that? > > Because lowmem pages always have an address. Perhaps it should use lowmem_page_address() then?
On Mon, Feb 04, 2013 at 03:24:51PM +0100, Michal Nazarewicz wrote: > On Mon, Feb 04 2013, Russell King - ARM Linux wrote: > > On Mon, Feb 04, 2013 at 02:51:52PM +0100, Michal Nazarewicz wrote: > >> On Mon, Feb 04 2013, Marek Szyprowski wrote: > >> > @@ -186,13 +186,24 @@ static u64 get_coherent_dma_mask(struct device *dev) > >> > > >> > static void __dma_clear_buffer(struct page *page, size_t size) > >> > { > >> > - void *ptr; > >> > /* > >> > * Ensure that the allocated pages are zeroed, and that any data > >> > * lurking in the kernel direct-mapped region is invalidated. > >> > */ > >> > - ptr = page_address(page); > >> > - if (ptr) { > >> > + if (PageHighMem(page)) { > >> > + phys_addr_t base = __pfn_to_phys(page_to_pfn(page)); > >> > + phys_addr_t end = base + size; > >> > + while (size > 0) { > >> > + void *ptr = kmap_atomic(page); > >> > + memset(ptr, 0, PAGE_SIZE); > >> > + dmac_flush_range(ptr, ptr + PAGE_SIZE); > >> > + kunmap_atomic(ptr); > >> > + page++; > >> > + size -= PAGE_SIZE; > >> > + } > >> > + outer_flush_range(base, end); > >> > + } else { > >> > + void *ptr = page_address(page); > >> > >> There used to be a “if (ptr)” check which is now missing. Why is that? > > > > Because lowmem pages always have an address. > > Perhaps it should use lowmem_page_address() then? It's well defined that page_address() will be non-NULL for lowmem pages. There is nothing wrong with the above.
On Mon, Feb 04 2013, Marek Szyprowski wrote: > This patch adds missing pieces to correctly support memory pages served > from CMA regions placed in high memory zones. Please note that the default > global CMA area is still put into lowmem and is limited by optional > architecture specific DMA zone. One can however put device specific CMA > regions in high memory zone to reduce lowmem usage. > > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Acked-by: Michal Nazarewicz <mina86@mina86.com>
> On Mon, Feb 04, 2013 at 03:24:51PM +0100, Michal Nazarewicz wrote: >> Perhaps it should use lowmem_page_address() then? On Mon, Feb 04 2013, Russell King - ARM Linux wrote: > It's well defined that page_address() will be non-NULL for lowmem pages. > There is nothing wrong with the above. It would save on a branch and a function call though.
On Mon, Feb 04, 2013 at 03:42:26PM +0100, Michal Nazarewicz wrote: > > On Mon, Feb 04, 2013 at 03:24:51PM +0100, Michal Nazarewicz wrote: > >> Perhaps it should use lowmem_page_address() then? > > On Mon, Feb 04 2013, Russell King - ARM Linux wrote: > > It's well defined that page_address() will be non-NULL for lowmem pages. > > There is nothing wrong with the above. > > It would save on a branch and a function call though. Depending on the size of struct page, if we care that much, we can probably enable WANT_PAGE_VIRTUAL which'll make it even cheaper as it's just a dereference.
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 076c26d..90e059b 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -186,13 +186,24 @@ static u64 get_coherent_dma_mask(struct device *dev) static void __dma_clear_buffer(struct page *page, size_t size) { - void *ptr; /* * Ensure that the allocated pages are zeroed, and that any data * lurking in the kernel direct-mapped region is invalidated. */ - ptr = page_address(page); - if (ptr) { + if (PageHighMem(page)) { + phys_addr_t base = __pfn_to_phys(page_to_pfn(page)); + phys_addr_t end = base + size; + while (size > 0) { + void *ptr = kmap_atomic(page); + memset(ptr, 0, PAGE_SIZE); + dmac_flush_range(ptr, ptr + PAGE_SIZE); + kunmap_atomic(ptr); + page++; + size -= PAGE_SIZE; + } + outer_flush_range(base, end); + } else { + void *ptr = page_address(page); memset(ptr, 0, size); dmac_flush_range(ptr, ptr + size); outer_flush_range(__pa(ptr), __pa(ptr) + size); @@ -243,7 +254,8 @@ static void __dma_free_buffer(struct page *page, size_t size) #endif static void *__alloc_from_contiguous(struct device *dev, size_t size, - pgprot_t prot, struct page **ret_page); + pgprot_t prot, struct page **ret_page, + const void *caller); static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp, pgprot_t prot, struct page **ret_page, @@ -346,10 +358,11 @@ static int __init atomic_pool_init(void) goto no_pages; if (IS_ENABLED(CONFIG_CMA)) - ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page); + ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page, + atomic_pool_init); else ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot, - &page, NULL); + &page, atomic_pool_init); if (ptr) { int i; @@ -542,27 +555,41 @@ static int __free_from_pool(void *start, size_t size) } static void *__alloc_from_contiguous(struct device *dev, size_t size, - pgprot_t prot, struct page **ret_page) + pgprot_t prot, struct page **ret_page, + const void *caller) { unsigned long order = get_order(size); size_t count = size >> PAGE_SHIFT; struct page *page; + void *ptr; page = dma_alloc_from_contiguous(dev, count, order); if (!page) return NULL; __dma_clear_buffer(page, size); - __dma_remap(page, size, prot); + if (PageHighMem(page)) { + ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller); + if (!ptr) { + dma_release_from_contiguous(dev, page, count); + return NULL; + } + } else { + __dma_remap(page, size, prot); + ptr = page_address(page); + } *ret_page = page; - return page_address(page); + return ptr; } static void __free_from_contiguous(struct device *dev, struct page *page, - size_t size) + void *cpu_addr, size_t size) { - __dma_remap(page, size, pgprot_kernel); + if (PageHighMem(page)) + __dma_free_remap(cpu_addr, size); + else + __dma_remap(page, size, pgprot_kernel); dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT); } @@ -645,7 +672,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, else if (!IS_ENABLED(CONFIG_CMA)) addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller); else - addr = __alloc_from_contiguous(dev, size, prot, &page); + addr = __alloc_from_contiguous(dev, size, prot, &page, caller); if (addr) *handle = pfn_to_dma(dev, page_to_pfn(page)); @@ -739,7 +766,7 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr, * Non-atomic allocations cannot be freed with IRQs disabled */ WARN_ON(irqs_disabled()); - __free_from_contiguous(dev, page, size); + __free_from_contiguous(dev, page, cpu_addr, size); } }