[PATCH] ARM: DMA-mapping: mark all !DMA_TO_DEVICE pages in unmapping as clean
Nicolas Pitre
nicolas.pitre at linaro.org
Tue May 14 15:28:13 EDT 2013
On Fri, 3 May 2013, Ming Lei wrote:
> It is common for one sg to include many pages, so mark all these
> pages as clean to avoid unnecessary flushing on them in
> set_pte_at() or update_mmu_cache().
[...]
> diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> index e9db6b4..e63124a 100644
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -879,10 +879,23 @@ static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
> dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
>
> /*
> - * Mark the D-cache clean for this page to avoid extra flushing.
> + * Mark the D-cache clean for these pages to avoid extra flushing.
> */
> - if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE)
> - set_bit(PG_dcache_clean, &page->flags);
> + if (dir != DMA_TO_DEVICE && size >= PAGE_SIZE) {
> + unsigned long pfn;
> + size_t left = size;
> +
> + pfn = page_to_pfn(page);
Could the offset ever be greater than a page? The code in
dma_cache_maint_page() appears to be written with that possibility in
mind. So you should have:
pfn = page_to_pfn(page) + off / PAGE_SIZE;
> + if (off) {
> + pfn++;
> + left -= PAGE_SIZE - off % PAGE_SIZE;
> + }
> + while (left >= PAGE_SIZE) {
> + page = pfn_to_page(pfn++);
> + set_bit(PG_dcache_clean, &page->flags);
> + left -= PAGE_SIZE;
> + }
> + }
> }
Otherwise this looks fine to me.
Nicolas
More information about the linux-arm-kernel
mailing list