[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