aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-01-27 12:18:05 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2019-01-27 12:18:05 -0500
commitc180f1b04be01d025aa1e6e53e1a8b6626bd90c4 (patch)
tree77abc4c9d95a153aff653b470a642aa921c1fa7f
parent6a2651b55bcf5b56177d4ccaeb52adeeadb142ea (diff)
parent60d8cd572f655aac6107a2330dced004ad1fe3d7 (diff)
Merge tag 'dma-mapping-5.0-2' of git://git.infradead.org/users/hch/dma-mapping
Pull dma-mapping fix from Christoph Hellwig: "Fix a xen-swiotlb regression on arm64" * tag 'dma-mapping-5.0-2' of git://git.infradead.org/users/hch/dma-mapping: arm64/xen: fix xen-swiotlb cache flushing
-rw-r--r--arch/arm/include/asm/xen/page-coherent.h94
-rw-r--r--arch/arm64/include/asm/device.h3
-rw-r--r--arch/arm64/include/asm/xen/page-coherent.h76
-rw-r--r--arch/arm64/mm/dma-mapping.c4
-rw-r--r--drivers/xen/swiotlb-xen.c4
-rw-r--r--include/xen/arm/page-coherent.h97
6 files changed, 176 insertions, 102 deletions
diff --git a/arch/arm/include/asm/xen/page-coherent.h b/arch/arm/include/asm/xen/page-coherent.h
index b3ef061d8b74..2c403e7c782d 100644
--- a/arch/arm/include/asm/xen/page-coherent.h
+++ b/arch/arm/include/asm/xen/page-coherent.h
@@ -1 +1,95 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_ARM_XEN_PAGE_COHERENT_H
3#define _ASM_ARM_XEN_PAGE_COHERENT_H
4
5#include <linux/dma-mapping.h>
6#include <asm/page.h>
1#include <xen/arm/page-coherent.h> 7#include <xen/arm/page-coherent.h>
8
9static inline const struct dma_map_ops *xen_get_dma_ops(struct device *dev)
10{
11 if (dev && dev->archdata.dev_dma_ops)
12 return dev->archdata.dev_dma_ops;
13 return get_arch_dma_ops(NULL);
14}
15
16static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size,
17 dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs)
18{
19 return xen_get_dma_ops(hwdev)->alloc(hwdev, size, dma_handle, flags, attrs);
20}
21
22static inline void xen_free_coherent_pages(struct device *hwdev, size_t size,
23 void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs)
24{
25 xen_get_dma_ops(hwdev)->free(hwdev, size, cpu_addr, dma_handle, attrs);
26}
27
28static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
29 dma_addr_t dev_addr, unsigned long offset, size_t size,
30 enum dma_data_direction dir, unsigned long attrs)
31{
32 unsigned long page_pfn = page_to_xen_pfn(page);
33 unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr);
34 unsigned long compound_pages =
35 (1<<compound_order(page)) * XEN_PFN_PER_PAGE;
36 bool local = (page_pfn <= dev_pfn) &&
37 (dev_pfn - page_pfn < compound_pages);
38
39 /*
40 * Dom0 is mapped 1:1, while the Linux page can span across
41 * multiple Xen pages, it's not possible for it to contain a
42 * mix of local and foreign Xen pages. So if the first xen_pfn
43 * == mfn the page is local otherwise it's a foreign page
44 * grant-mapped in dom0. If the page is local we can safely
45 * call the native dma_ops function, otherwise we call the xen
46 * specific function.
47 */
48 if (local)
49 xen_get_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs);
50 else
51 __xen_dma_map_page(hwdev, page, dev_addr, offset, size, dir, attrs);
52}
53
54static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
55 size_t size, enum dma_data_direction dir, unsigned long attrs)
56{
57 unsigned long pfn = PFN_DOWN(handle);
58 /*
59 * Dom0 is mapped 1:1, while the Linux page can be spanned accross
60 * multiple Xen page, it's not possible to have a mix of local and
61 * foreign Xen page. Dom0 is mapped 1:1, so calling pfn_valid on a
62 * foreign mfn will always return false. If the page is local we can
63 * safely call the native dma_ops function, otherwise we call the xen
64 * specific function.
65 */
66 if (pfn_valid(pfn)) {
67 if (xen_get_dma_ops(hwdev)->unmap_page)
68 xen_get_dma_ops(hwdev)->unmap_page(hwdev, handle, size, dir, attrs);
69 } else
70 __xen_dma_unmap_page(hwdev, handle, size, dir, attrs);
71}
72
73static inline void xen_dma_sync_single_for_cpu(struct device *hwdev,
74 dma_addr_t handle, size_t size, enum dma_data_direction dir)
75{
76 unsigned long pfn = PFN_DOWN(handle);
77 if (pfn_valid(pfn)) {
78 if (xen_get_dma_ops(hwdev)->sync_single_for_cpu)
79 xen_get_dma_ops(hwdev)->sync_single_for_cpu(hwdev, handle, size, dir);
80 } else
81 __xen_dma_sync_single_for_cpu(hwdev, handle, size, dir);
82}
83
84static inline void xen_dma_sync_single_for_device(struct device *hwdev,
85 dma_addr_t handle, size_t size, enum dma_data_direction dir)
86{
87 unsigned long pfn = PFN_DOWN(handle);
88 if (pfn_valid(pfn)) {
89 if (xen_get_dma_ops(hwdev)->sync_single_for_device)
90 xen_get_dma_ops(hwdev)->sync_single_for_device(hwdev, handle, size, dir);
91 } else
92 __xen_dma_sync_single_for_device(hwdev, handle, size, dir);
93}
94
95#endif /* _ASM_ARM_XEN_PAGE_COHERENT_H */
diff --git a/arch/arm64/include/asm/device.h b/arch/arm64/include/asm/device.h
index 3dd3d664c5c5..4658c937e173 100644
--- a/arch/arm64/include/asm/device.h
+++ b/arch/arm64/include/asm/device.h
@@ -20,9 +20,6 @@ struct dev_archdata {
20#ifdef CONFIG_IOMMU_API 20#ifdef CONFIG_IOMMU_API
21 void *iommu; /* private IOMMU data */ 21 void *iommu; /* private IOMMU data */
22#endif 22#endif
23#ifdef CONFIG_XEN
24 const struct dma_map_ops *dev_dma_ops;
25#endif
26}; 23};
27 24
28struct pdev_archdata { 25struct pdev_archdata {
diff --git a/arch/arm64/include/asm/xen/page-coherent.h b/arch/arm64/include/asm/xen/page-coherent.h
index b3ef061d8b74..d88e56b90b93 100644
--- a/arch/arm64/include/asm/xen/page-coherent.h
+++ b/arch/arm64/include/asm/xen/page-coherent.h
@@ -1 +1,77 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_ARM64_XEN_PAGE_COHERENT_H
3#define _ASM_ARM64_XEN_PAGE_COHERENT_H
4
5#include <linux/dma-mapping.h>
6#include <asm/page.h>
1#include <xen/arm/page-coherent.h> 7#include <xen/arm/page-coherent.h>
8
9static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size,
10 dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs)
11{
12 return dma_direct_alloc(hwdev, size, dma_handle, flags, attrs);
13}
14
15static inline void xen_free_coherent_pages(struct device *hwdev, size_t size,
16 void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs)
17{
18 dma_direct_free(hwdev, size, cpu_addr, dma_handle, attrs);
19}
20
21static inline void xen_dma_sync_single_for_cpu(struct device *hwdev,
22 dma_addr_t handle, size_t size, enum dma_data_direction dir)
23{
24 unsigned long pfn = PFN_DOWN(handle);
25
26 if (pfn_valid(pfn))
27 dma_direct_sync_single_for_cpu(hwdev, handle, size, dir);
28 else
29 __xen_dma_sync_single_for_cpu(hwdev, handle, size, dir);
30}
31
32static inline void xen_dma_sync_single_for_device(struct device *hwdev,
33 dma_addr_t handle, size_t size, enum dma_data_direction dir)
34{
35 unsigned long pfn = PFN_DOWN(handle);
36 if (pfn_valid(pfn))
37 dma_direct_sync_single_for_device(hwdev, handle, size, dir);
38 else
39 __xen_dma_sync_single_for_device(hwdev, handle, size, dir);
40}
41
42static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
43 dma_addr_t dev_addr, unsigned long offset, size_t size,
44 enum dma_data_direction dir, unsigned long attrs)
45{
46 unsigned long page_pfn = page_to_xen_pfn(page);
47 unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr);
48 unsigned long compound_pages =
49 (1<<compound_order(page)) * XEN_PFN_PER_PAGE;
50 bool local = (page_pfn <= dev_pfn) &&
51 (dev_pfn - page_pfn < compound_pages);
52
53 if (local)
54 dma_direct_map_page(hwdev, page, offset, size, dir, attrs);
55 else
56 __xen_dma_map_page(hwdev, page, dev_addr, offset, size, dir, attrs);
57}
58
59static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
60 size_t size, enum dma_data_direction dir, unsigned long attrs)
61{
62 unsigned long pfn = PFN_DOWN(handle);
63 /*
64 * Dom0 is mapped 1:1, while the Linux page can be spanned accross
65 * multiple Xen page, it's not possible to have a mix of local and
66 * foreign Xen page. Dom0 is mapped 1:1, so calling pfn_valid on a
67 * foreign mfn will always return false. If the page is local we can
68 * safely call the native dma_ops function, otherwise we call the xen
69 * specific function.
70 */
71 if (pfn_valid(pfn))
72 dma_direct_unmap_page(hwdev, handle, size, dir, attrs);
73 else
74 __xen_dma_unmap_page(hwdev, handle, size, dir, attrs);
75}
76
77#endif /* _ASM_ARM64_XEN_PAGE_COHERENT_H */
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index fb0908456a1f..78c0a72f822c 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -466,9 +466,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
466 __iommu_setup_dma_ops(dev, dma_base, size, iommu); 466 __iommu_setup_dma_ops(dev, dma_base, size, iommu);
467 467
468#ifdef CONFIG_XEN 468#ifdef CONFIG_XEN
469 if (xen_initial_domain()) { 469 if (xen_initial_domain())
470 dev->archdata.dev_dma_ops = dev->dma_ops;
471 dev->dma_ops = xen_dma_ops; 470 dev->dma_ops = xen_dma_ops;
472 }
473#endif 471#endif
474} 472}
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 989cf872b98c..bb7888429be6 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -645,7 +645,7 @@ xen_swiotlb_dma_mmap(struct device *dev, struct vm_area_struct *vma,
645 void *cpu_addr, dma_addr_t dma_addr, size_t size, 645 void *cpu_addr, dma_addr_t dma_addr, size_t size,
646 unsigned long attrs) 646 unsigned long attrs)
647{ 647{
648#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) 648#ifdef CONFIG_ARM
649 if (xen_get_dma_ops(dev)->mmap) 649 if (xen_get_dma_ops(dev)->mmap)
650 return xen_get_dma_ops(dev)->mmap(dev, vma, cpu_addr, 650 return xen_get_dma_ops(dev)->mmap(dev, vma, cpu_addr,
651 dma_addr, size, attrs); 651 dma_addr, size, attrs);
@@ -662,7 +662,7 @@ xen_swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt,
662 void *cpu_addr, dma_addr_t handle, size_t size, 662 void *cpu_addr, dma_addr_t handle, size_t size,
663 unsigned long attrs) 663 unsigned long attrs)
664{ 664{
665#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) 665#ifdef CONFIG_ARM
666 if (xen_get_dma_ops(dev)->get_sgtable) { 666 if (xen_get_dma_ops(dev)->get_sgtable) {
667#if 0 667#if 0
668 /* 668 /*
diff --git a/include/xen/arm/page-coherent.h b/include/xen/arm/page-coherent.h
index 59a260712a56..2ca9164a79bf 100644
--- a/include/xen/arm/page-coherent.h
+++ b/include/xen/arm/page-coherent.h
@@ -1,17 +1,6 @@
1/* SPDX-License-Identifier: GPL-2.0 */ 1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_ARM_XEN_PAGE_COHERENT_H 2#ifndef _XEN_ARM_PAGE_COHERENT_H
3#define _ASM_ARM_XEN_PAGE_COHERENT_H 3#define _XEN_ARM_PAGE_COHERENT_H
4
5#include <asm/page.h>
6#include <asm/dma-mapping.h>
7#include <linux/dma-mapping.h>
8
9static inline const struct dma_map_ops *xen_get_dma_ops(struct device *dev)
10{
11 if (dev && dev->archdata.dev_dma_ops)
12 return dev->archdata.dev_dma_ops;
13 return get_arch_dma_ops(NULL);
14}
15 4
16void __xen_dma_map_page(struct device *hwdev, struct page *page, 5void __xen_dma_map_page(struct device *hwdev, struct page *page,
17 dma_addr_t dev_addr, unsigned long offset, size_t size, 6 dma_addr_t dev_addr, unsigned long offset, size_t size,
@@ -21,87 +10,7 @@ void __xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
21 unsigned long attrs); 10 unsigned long attrs);
22void __xen_dma_sync_single_for_cpu(struct device *hwdev, 11void __xen_dma_sync_single_for_cpu(struct device *hwdev,
23 dma_addr_t handle, size_t size, enum dma_data_direction dir); 12 dma_addr_t handle, size_t size, enum dma_data_direction dir);
24
25void __xen_dma_sync_single_for_device(struct device *hwdev, 13void __xen_dma_sync_single_for_device(struct device *hwdev,
26 dma_addr_t handle, size_t size, enum dma_data_direction dir); 14 dma_addr_t handle, size_t size, enum dma_data_direction dir);
27 15
28static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size, 16#endif /* _XEN_ARM_PAGE_COHERENT_H */
29 dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs)
30{
31 return xen_get_dma_ops(hwdev)->alloc(hwdev, size, dma_handle, flags, attrs);
32}
33
34static inline void xen_free_coherent_pages(struct device *hwdev, size_t size,
35 void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs)
36{
37 xen_get_dma_ops(hwdev)->free(hwdev, size, cpu_addr, dma_handle, attrs);
38}
39
40static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
41 dma_addr_t dev_addr, unsigned long offset, size_t size,
42 enum dma_data_direction dir, unsigned long attrs)
43{
44 unsigned long page_pfn = page_to_xen_pfn(page);
45 unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr);
46 unsigned long compound_pages =
47 (1<<compound_order(page)) * XEN_PFN_PER_PAGE;
48 bool local = (page_pfn <= dev_pfn) &&
49 (dev_pfn - page_pfn < compound_pages);
50
51 /*
52 * Dom0 is mapped 1:1, while the Linux page can span across
53 * multiple Xen pages, it's not possible for it to contain a
54 * mix of local and foreign Xen pages. So if the first xen_pfn
55 * == mfn the page is local otherwise it's a foreign page
56 * grant-mapped in dom0. If the page is local we can safely
57 * call the native dma_ops function, otherwise we call the xen
58 * specific function.
59 */
60 if (local)
61 xen_get_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs);
62 else
63 __xen_dma_map_page(hwdev, page, dev_addr, offset, size, dir, attrs);
64}
65
66static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
67 size_t size, enum dma_data_direction dir, unsigned long attrs)
68{
69 unsigned long pfn = PFN_DOWN(handle);
70 /*
71 * Dom0 is mapped 1:1, while the Linux page can be spanned accross
72 * multiple Xen page, it's not possible to have a mix of local and
73 * foreign Xen page. Dom0 is mapped 1:1, so calling pfn_valid on a
74 * foreign mfn will always return false. If the page is local we can
75 * safely call the native dma_ops function, otherwise we call the xen
76 * specific function.
77 */
78 if (pfn_valid(pfn)) {
79 if (xen_get_dma_ops(hwdev)->unmap_page)
80 xen_get_dma_ops(hwdev)->unmap_page(hwdev, handle, size, dir, attrs);
81 } else
82 __xen_dma_unmap_page(hwdev, handle, size, dir, attrs);
83}
84
85static inline void xen_dma_sync_single_for_cpu(struct device *hwdev,
86 dma_addr_t handle, size_t size, enum dma_data_direction dir)
87{
88 unsigned long pfn = PFN_DOWN(handle);
89 if (pfn_valid(pfn)) {
90 if (xen_get_dma_ops(hwdev)->sync_single_for_cpu)
91 xen_get_dma_ops(hwdev)->sync_single_for_cpu(hwdev, handle, size, dir);
92 } else
93 __xen_dma_sync_single_for_cpu(hwdev, handle, size, dir);
94}
95
96static inline void xen_dma_sync_single_for_device(struct device *hwdev,
97 dma_addr_t handle, size_t size, enum dma_data_direction dir)
98{
99 unsigned long pfn = PFN_DOWN(handle);
100 if (pfn_valid(pfn)) {
101 if (xen_get_dma_ops(hwdev)->sync_single_for_device)
102 xen_get_dma_ops(hwdev)->sync_single_for_device(hwdev, handle, size, dir);
103 } else
104 __xen_dma_sync_single_for_device(hwdev, handle, size, dir);
105}
106
107#endif /* _ASM_ARM_XEN_PAGE_COHERENT_H */