Commit 52ba0746 authored by Ian Campbell's avatar Ian Campbell Committed by Stefano Stabellini

xen/arm: correctly handle DMA mapping of compound pages

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 3567258d ("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: default avatarIan Campbell <ian.campbell@citrix.com>
Reviewed-by: default avatarStefano Stabellini <stefano.stabellini@eu.citrix.com>
Cc: xen-devel@lists.xenproject.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: stable@vger.kernel.org # v3.19+
parent c9e2f531
...@@ -35,14 +35,21 @@ static inline void xen_dma_map_page(struct device *hwdev, struct page *page, ...@@ -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, dma_addr_t dev_addr, unsigned long offset, size_t size,
enum dma_data_direction dir, struct dma_attrs *attrs) 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 * Dom0 is mapped 1:1, while the Linux page can span across
* multiple Xen page, it's not possible to have a mix of local and * multiple Xen pages, it's not possible for it to contain a
* foreign Xen page. So if the first xen_pfn == mfn the page is local * mix of local and foreign Xen pages. So if the first xen_pfn
* otherwise it's a foreign page grant-mapped in dom0. If the page is * == mfn the page is local otherwise it's a foreign page
* local we can safely call the native dma_ops function, otherwise we * grant-mapped in dom0. If the page is local we can safely
* call the xen specific function. * call the native dma_ops function, otherwise we call the xen
* specific function.
*/ */
if (local) if (local)
__generic_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs); __generic_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment