diff options
author | Paul Burton <paul.burton@imgtec.com> | 2016-10-05 13:18:16 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2016-10-06 12:02:01 -0400 |
commit | 20d330645cfb8cfecfb82b369e4d3084e429e68a (patch) | |
tree | c2e0661dbbb76ad83b2645db4291954bbd19c69d | |
parent | cfa93fb9c2eae805f2c16d72bad04ca49b6e16d2 (diff) |
MIPS: Support per-device DMA coherence
On some MIPS systems, a subset of devices may have DMA coherent with CPU
caches. For example in systems including a MIPS I/O Coherence Unit
(IOCU), some devices may be connected to that IOCU whilst others are
not.
Prior to this patch, we have a plat_device_is_coherent() function but no
implementation which does anything besides return a global true or
false, optionally chosen at runtime. For devices such as those described
above this is insufficient.
Fix this by tracking DMA coherence on a per-device basis with a
dma_coherent field in struct dev_archdata. Setting this from
arch_setup_dma_ops() takes care of devices which set the dma-coherent
property via device tree, and any PCI devices beneath a bridge described
in DT, automatically.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/14349/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | arch/mips/Kconfig | 4 | ||||
-rw-r--r-- | arch/mips/include/asm/device.h | 5 | ||||
-rw-r--r-- | arch/mips/include/asm/dma-coherence.h | 4 | ||||
-rw-r--r-- | arch/mips/include/asm/dma-mapping.h | 10 | ||||
-rw-r--r-- | arch/mips/include/asm/mach-generic/dma-coherence.h | 4 | ||||
-rw-r--r-- | arch/mips/mm/c-r4k.c | 4 | ||||
-rw-r--r-- | arch/mips/mm/dma-default.c | 2 |
7 files changed, 31 insertions, 2 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 86d5b3930531..235643970517 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -1099,6 +1099,10 @@ config DMA_MAYBE_COHERENT | |||
1099 | select DMA_NONCOHERENT | 1099 | select DMA_NONCOHERENT |
1100 | bool | 1100 | bool |
1101 | 1101 | ||
1102 | config DMA_PERDEV_COHERENT | ||
1103 | bool | ||
1104 | select DMA_MAYBE_COHERENT | ||
1105 | |||
1102 | config DMA_COHERENT | 1106 | config DMA_COHERENT |
1103 | bool | 1107 | bool |
1104 | 1108 | ||
diff --git a/arch/mips/include/asm/device.h b/arch/mips/include/asm/device.h index c94fafba9e62..21c2082a0dfb 100644 --- a/arch/mips/include/asm/device.h +++ b/arch/mips/include/asm/device.h | |||
@@ -11,6 +11,11 @@ struct dma_map_ops; | |||
11 | struct dev_archdata { | 11 | struct dev_archdata { |
12 | /* DMA operations on that device */ | 12 | /* DMA operations on that device */ |
13 | struct dma_map_ops *dma_ops; | 13 | struct dma_map_ops *dma_ops; |
14 | |||
15 | #ifdef CONFIG_DMA_PERDEV_COHERENT | ||
16 | /* Non-zero if DMA is coherent with CPU caches */ | ||
17 | bool dma_coherent; | ||
18 | #endif | ||
14 | }; | 19 | }; |
15 | 20 | ||
16 | struct pdev_archdata { | 21 | struct pdev_archdata { |
diff --git a/arch/mips/include/asm/dma-coherence.h b/arch/mips/include/asm/dma-coherence.h index 4fbce79fb57f..72d0eab02afc 100644 --- a/arch/mips/include/asm/dma-coherence.h +++ b/arch/mips/include/asm/dma-coherence.h | |||
@@ -15,7 +15,9 @@ enum coherent_io_user_state { | |||
15 | IO_COHERENCE_DISABLED, | 15 | IO_COHERENCE_DISABLED, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | #ifdef CONFIG_DMA_MAYBE_COHERENT | 18 | #if defined(CONFIG_DMA_PERDEV_COHERENT) |
19 | /* Don't provide (hw_)coherentio to avoid misuse */ | ||
20 | #elif defined(CONFIG_DMA_MAYBE_COHERENT) | ||
19 | extern enum coherent_io_user_state coherentio; | 21 | extern enum coherent_io_user_state coherentio; |
20 | extern int hw_coherentio; | 22 | extern int hw_coherentio; |
21 | #else | 23 | #else |
diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index 12fa79e2f1b4..7aa71b9b0258 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h | |||
@@ -32,4 +32,14 @@ static inline void dma_mark_clean(void *addr, size_t size) {} | |||
32 | extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, | 32 | extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, |
33 | enum dma_data_direction direction); | 33 | enum dma_data_direction direction); |
34 | 34 | ||
35 | #define arch_setup_dma_ops arch_setup_dma_ops | ||
36 | static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, | ||
37 | u64 size, const struct iommu_ops *iommu, | ||
38 | bool coherent) | ||
39 | { | ||
40 | #ifdef CONFIG_DMA_PERDEV_COHERENT | ||
41 | dev->archdata.dma_coherent = coherent; | ||
42 | #endif | ||
43 | } | ||
44 | |||
35 | #endif /* _ASM_DMA_MAPPING_H */ | 45 | #endif /* _ASM_DMA_MAPPING_H */ |
diff --git a/arch/mips/include/asm/mach-generic/dma-coherence.h b/arch/mips/include/asm/mach-generic/dma-coherence.h index 8484f82fc794..61addb1677e9 100644 --- a/arch/mips/include/asm/mach-generic/dma-coherence.h +++ b/arch/mips/include/asm/mach-generic/dma-coherence.h | |||
@@ -49,6 +49,9 @@ static inline int plat_dma_supported(struct device *dev, u64 mask) | |||
49 | 49 | ||
50 | static inline int plat_device_is_coherent(struct device *dev) | 50 | static inline int plat_device_is_coherent(struct device *dev) |
51 | { | 51 | { |
52 | #ifdef CONFIG_DMA_PERDEV_COHERENT | ||
53 | return dev->archdata.dma_coherent; | ||
54 | #else | ||
52 | switch (coherentio) { | 55 | switch (coherentio) { |
53 | default: | 56 | default: |
54 | case IO_COHERENCE_DEFAULT: | 57 | case IO_COHERENCE_DEFAULT: |
@@ -58,6 +61,7 @@ static inline int plat_device_is_coherent(struct device *dev) | |||
58 | case IO_COHERENCE_DISABLED: | 61 | case IO_COHERENCE_DISABLED: |
59 | return 0; | 62 | return 0; |
60 | } | 63 | } |
64 | #endif | ||
61 | } | 65 | } |
62 | 66 | ||
63 | #ifndef plat_post_dma_flush | 67 | #ifndef plat_post_dma_flush |
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 78ac033a0f07..88cfaf81c958 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c | |||
@@ -1935,8 +1935,12 @@ void r4k_cache_init(void) | |||
1935 | __local_flush_icache_user_range = local_r4k_flush_icache_user_range; | 1935 | __local_flush_icache_user_range = local_r4k_flush_icache_user_range; |
1936 | 1936 | ||
1937 | #if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT) | 1937 | #if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT) |
1938 | # if defined(CONFIG_DMA_PERDEV_COHERENT) | ||
1939 | if (0) { | ||
1940 | # else | ||
1938 | if ((coherentio == IO_COHERENCE_ENABLED) || | 1941 | if ((coherentio == IO_COHERENCE_ENABLED) || |
1939 | ((coherentio == IO_COHERENCE_DEFAULT) && hw_coherentio)) { | 1942 | ((coherentio == IO_COHERENCE_DEFAULT) && hw_coherentio)) { |
1943 | # endif | ||
1940 | _dma_cache_wback_inv = (void *)cache_noop; | 1944 | _dma_cache_wback_inv = (void *)cache_noop; |
1941 | _dma_cache_wback = (void *)cache_noop; | 1945 | _dma_cache_wback = (void *)cache_noop; |
1942 | _dma_cache_inv = (void *)cache_noop; | 1946 | _dma_cache_inv = (void *)cache_noop; |
diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 7ae4c55c935a..46d5696c4f27 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | #include <dma-coherence.h> | 25 | #include <dma-coherence.h> |
26 | 26 | ||
27 | #ifdef CONFIG_DMA_MAYBE_COHERENT | 27 | #if defined(CONFIG_DMA_MAYBE_COHERENT) && !defined(CONFIG_DMA_PERDEV_COHERENT) |
28 | /* User defined DMA coherency from command line. */ | 28 | /* User defined DMA coherency from command line. */ |
29 | enum coherent_io_user_state coherentio = IO_COHERENCE_DEFAULT; | 29 | enum coherent_io_user_state coherentio = IO_COHERENCE_DEFAULT; |
30 | EXPORT_SYMBOL_GPL(coherentio); | 30 | EXPORT_SYMBOL_GPL(coherentio); |