[PATCH v2] xen/arm: correctly handle DMA mapping of compound pages

Stefano Stabellini stefano.stabellini at eu.citrix.com
Mon Feb 8 08:59:10 PST 2016


On Mon, 8 Feb 2016, Ian Campbell wrote:
> Currently xen_dma_map_page concludes that DMA to anything other than
> the head page of a compound page must be foreign, since the PFN of the
> page is that of the head.
> 
> Fix the check to instead consider the whole of a compound page to be
> local if the PFN of the head passes the 1:1 check.
> 
> We can never see a compound page which is a mixture of foreign and
> local sub-pages.
> 
> The comment already correctly described the intention, but fixup the
> spelling and some grammar.
> 
> This fixes the various SSH protocol errors which we have been seeing
> on the cubietrucks in our automated test infrastructure.
> 
> This has been broken since commit 3567258d281b ("xen/arm: use
> hypercall to flush caches in map_page"), which was in v3.19-rc1.
> 
> NB arch/arm64/.../xen/page-coherent.h also includes this file.
> 
> Signed-off-by: Ian Campbell <ian.campbell at citrix.com>
> Cc: xen-devel at lists.xenproject.org
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: stable at vger.kernel.org # v3.19+

Reviewed-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>

I'll add it to my queue.


> v2: Placate checkpatch
>     Handle 64K pages
>     Add some ()s
> ---
>  arch/arm/include/asm/xen/page-coherent.h | 21 ++++++++++++++-------
>  1 file changed, 14 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/arm/include/asm/xen/page-coherent.h b/arch/arm/include/asm/xen/page-coherent.h
> index 0375c8c..9408a99 100644
> --- a/arch/arm/include/asm/xen/page-coherent.h
> +++ b/arch/arm/include/asm/xen/page-coherent.h
> @@ -35,14 +35,21 @@ static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
>  	     dma_addr_t dev_addr, unsigned long offset, size_t size,
>  	     enum dma_data_direction dir, struct dma_attrs *attrs)
>  {
> -	bool local = XEN_PFN_DOWN(dev_addr) == page_to_xen_pfn(page);
> +	unsigned long page_pfn = page_to_xen_pfn(page);
> +	unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr);
> +	unsigned long compound_pages =
> +		(1<<compound_order(page)) * XEN_PFN_PER_PAGE;
> +	bool local = (page_pfn <= dev_pfn) &&
> +		(dev_pfn - page_pfn < compound_pages);
> +
>  	/*
> -	 * Dom0 is mapped 1:1, while the Linux page can be spanned accross
> -	 * multiple Xen page, it's not possible to have a mix of local and
> -	 * foreign Xen page. So if the first xen_pfn == mfn the page is local
> -	 * otherwise it's a foreign page grant-mapped in dom0. If the page is
> -	 * local we can safely call the native dma_ops function, otherwise we
> -	 * call the xen specific function.
> +	 * Dom0 is mapped 1:1, while the Linux page can span across
> +	 * multiple Xen pages, it's not possible for it to contain a
> +	 * mix of local and foreign Xen pages. So if the first xen_pfn
> +	 * == mfn the page is local otherwise it's a foreign page
> +	 * grant-mapped in dom0. If the page is local we can safely
> +	 * call the native dma_ops function, otherwise we call the xen
> +	 * specific function.
>  	 */
>  	if (local)
>  		__generic_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs);
> -- 
> 2.1.4
> 



More information about the linux-arm-kernel mailing list