diff options
author | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2014-11-21 06:08:39 -0500 |
---|---|---|
committer | David Vrabel <david.vrabel@citrix.com> | 2014-12-04 07:41:54 -0500 |
commit | da095a996090a412c3b6292c7a8680661dca157d (patch) | |
tree | 02247bce77b50867c227384ed023bab81ffe77c4 /arch/arm/xen/mm.c | |
parent | a4dba130891271084344c12537731542ec77cb85 (diff) |
xen/arm: introduce GNTTABOP_cache_flush
Introduce support for new hypercall GNTTABOP_cache_flush.
Use it to perform cache flashing on pages used for dma when necessary.
If GNTTABOP_cache_flush is supported by the hypervisor, we don't need to
bounce dma map operations that involve foreign grants and non-coherent
devices.
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Diffstat (limited to 'arch/arm/xen/mm.c')
-rw-r--r-- | arch/arm/xen/mm.c | 34 |
1 files changed, 32 insertions, 2 deletions
diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c index 28ebf3ecee4e..351b24a979d4 100644 --- a/arch/arm/xen/mm.c +++ b/arch/arm/xen/mm.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/swiotlb.h> | 12 | #include <linux/swiotlb.h> |
13 | 13 | ||
14 | #include <xen/xen.h> | 14 | #include <xen/xen.h> |
15 | #include <xen/interface/grant_table.h> | ||
15 | #include <xen/interface/memory.h> | 16 | #include <xen/interface/memory.h> |
16 | #include <xen/swiotlb-xen.h> | 17 | #include <xen/swiotlb-xen.h> |
17 | 18 | ||
@@ -24,12 +25,14 @@ enum dma_cache_op { | |||
24 | DMA_UNMAP, | 25 | DMA_UNMAP, |
25 | DMA_MAP, | 26 | DMA_MAP, |
26 | }; | 27 | }; |
28 | static bool hypercall_cflush = false; | ||
27 | 29 | ||
28 | /* functions called by SWIOTLB */ | 30 | /* functions called by SWIOTLB */ |
29 | 31 | ||
30 | static void dma_cache_maint(dma_addr_t handle, unsigned long offset, | 32 | static void dma_cache_maint(dma_addr_t handle, unsigned long offset, |
31 | size_t size, enum dma_data_direction dir, enum dma_cache_op op) | 33 | size_t size, enum dma_data_direction dir, enum dma_cache_op op) |
32 | { | 34 | { |
35 | struct gnttab_cache_flush cflush; | ||
33 | unsigned long pfn; | 36 | unsigned long pfn; |
34 | size_t left = size; | 37 | size_t left = size; |
35 | 38 | ||
@@ -39,7 +42,26 @@ static void dma_cache_maint(dma_addr_t handle, unsigned long offset, | |||
39 | do { | 42 | do { |
40 | size_t len = left; | 43 | size_t len = left; |
41 | 44 | ||
42 | /* TODO: cache flush */ | 45 | /* buffers in highmem or foreign pages cannot cross page |
46 | * boundaries */ | ||
47 | if (len + offset > PAGE_SIZE) | ||
48 | len = PAGE_SIZE - offset; | ||
49 | |||
50 | cflush.op = 0; | ||
51 | cflush.a.dev_bus_addr = pfn << PAGE_SHIFT; | ||
52 | cflush.offset = offset; | ||
53 | cflush.length = len; | ||
54 | |||
55 | if (op == DMA_UNMAP && dir != DMA_TO_DEVICE) | ||
56 | cflush.op = GNTTAB_CACHE_INVAL; | ||
57 | if (op == DMA_MAP) { | ||
58 | if (dir == DMA_FROM_DEVICE) | ||
59 | cflush.op = GNTTAB_CACHE_INVAL; | ||
60 | else | ||
61 | cflush.op = GNTTAB_CACHE_CLEAN; | ||
62 | } | ||
63 | if (cflush.op) | ||
64 | HYPERVISOR_grant_table_op(GNTTABOP_cache_flush, &cflush, 1); | ||
43 | 65 | ||
44 | offset = 0; | 66 | offset = 0; |
45 | pfn++; | 67 | pfn++; |
@@ -104,7 +126,7 @@ bool xen_arch_need_swiotlb(struct device *dev, | |||
104 | unsigned long pfn, | 126 | unsigned long pfn, |
105 | unsigned long mfn) | 127 | unsigned long mfn) |
106 | { | 128 | { |
107 | return ((pfn != mfn) && !is_device_dma_coherent(dev)); | 129 | return (!hypercall_cflush && (pfn != mfn) && !is_device_dma_coherent(dev)); |
108 | } | 130 | } |
109 | 131 | ||
110 | int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order, | 132 | int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order, |
@@ -147,10 +169,18 @@ static struct dma_map_ops xen_swiotlb_dma_ops = { | |||
147 | 169 | ||
148 | int __init xen_mm_init(void) | 170 | int __init xen_mm_init(void) |
149 | { | 171 | { |
172 | struct gnttab_cache_flush cflush; | ||
150 | if (!xen_initial_domain()) | 173 | if (!xen_initial_domain()) |
151 | return 0; | 174 | return 0; |
152 | xen_swiotlb_init(1, false); | 175 | xen_swiotlb_init(1, false); |
153 | xen_dma_ops = &xen_swiotlb_dma_ops; | 176 | xen_dma_ops = &xen_swiotlb_dma_ops; |
177 | |||
178 | cflush.op = 0; | ||
179 | cflush.a.dev_bus_addr = 0; | ||
180 | cflush.offset = 0; | ||
181 | cflush.length = 0; | ||
182 | if (HYPERVISOR_grant_table_op(GNTTABOP_cache_flush, &cflush, 1) != -ENOSYS) | ||
183 | hypercall_cflush = true; | ||
154 | return 0; | 184 | return 0; |
155 | } | 185 | } |
156 | arch_initcall(xen_mm_init); | 186 | arch_initcall(xen_mm_init); |