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>
This commit is contained in:
parent
cfa93fb9c2
commit
20d330645c
|
@ -1099,6 +1099,10 @@ config DMA_MAYBE_COHERENT
|
||||||
select DMA_NONCOHERENT
|
select DMA_NONCOHERENT
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
config DMA_PERDEV_COHERENT
|
||||||
|
bool
|
||||||
|
select DMA_MAYBE_COHERENT
|
||||||
|
|
||||||
config DMA_COHERENT
|
config DMA_COHERENT
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,11 @@ struct dma_map_ops;
|
||||||
struct dev_archdata {
|
struct dev_archdata {
|
||||||
/* DMA operations on that device */
|
/* DMA operations on that device */
|
||||||
struct dma_map_ops *dma_ops;
|
struct dma_map_ops *dma_ops;
|
||||||
|
|
||||||
|
#ifdef CONFIG_DMA_PERDEV_COHERENT
|
||||||
|
/* Non-zero if DMA is coherent with CPU caches */
|
||||||
|
bool dma_coherent;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pdev_archdata {
|
struct pdev_archdata {
|
||||||
|
|
|
@ -15,7 +15,9 @@ enum coherent_io_user_state {
|
||||||
IO_COHERENCE_DISABLED,
|
IO_COHERENCE_DISABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_DMA_MAYBE_COHERENT
|
#if defined(CONFIG_DMA_PERDEV_COHERENT)
|
||||||
|
/* Don't provide (hw_)coherentio to avoid misuse */
|
||||||
|
#elif defined(CONFIG_DMA_MAYBE_COHERENT)
|
||||||
extern enum coherent_io_user_state coherentio;
|
extern enum coherent_io_user_state coherentio;
|
||||||
extern int hw_coherentio;
|
extern int hw_coherentio;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -32,4 +32,14 @@ static inline void dma_mark_clean(void *addr, size_t size) {}
|
||||||
extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
|
extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
|
||||||
enum dma_data_direction direction);
|
enum dma_data_direction direction);
|
||||||
|
|
||||||
|
#define arch_setup_dma_ops arch_setup_dma_ops
|
||||||
|
static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base,
|
||||||
|
u64 size, const struct iommu_ops *iommu,
|
||||||
|
bool coherent)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_DMA_PERDEV_COHERENT
|
||||||
|
dev->archdata.dma_coherent = coherent;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _ASM_DMA_MAPPING_H */
|
#endif /* _ASM_DMA_MAPPING_H */
|
||||||
|
|
|
@ -49,6 +49,9 @@ static inline int plat_dma_supported(struct device *dev, u64 mask)
|
||||||
|
|
||||||
static inline int plat_device_is_coherent(struct device *dev)
|
static inline int plat_device_is_coherent(struct device *dev)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_DMA_PERDEV_COHERENT
|
||||||
|
return dev->archdata.dma_coherent;
|
||||||
|
#else
|
||||||
switch (coherentio) {
|
switch (coherentio) {
|
||||||
default:
|
default:
|
||||||
case IO_COHERENCE_DEFAULT:
|
case IO_COHERENCE_DEFAULT:
|
||||||
|
@ -58,6 +61,7 @@ static inline int plat_device_is_coherent(struct device *dev)
|
||||||
case IO_COHERENCE_DISABLED:
|
case IO_COHERENCE_DISABLED:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef plat_post_dma_flush
|
#ifndef plat_post_dma_flush
|
||||||
|
|
|
@ -1935,8 +1935,12 @@ void r4k_cache_init(void)
|
||||||
__local_flush_icache_user_range = local_r4k_flush_icache_user_range;
|
__local_flush_icache_user_range = local_r4k_flush_icache_user_range;
|
||||||
|
|
||||||
#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT)
|
#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT)
|
||||||
|
# if defined(CONFIG_DMA_PERDEV_COHERENT)
|
||||||
|
if (0) {
|
||||||
|
# else
|
||||||
if ((coherentio == IO_COHERENCE_ENABLED) ||
|
if ((coherentio == IO_COHERENCE_ENABLED) ||
|
||||||
((coherentio == IO_COHERENCE_DEFAULT) && hw_coherentio)) {
|
((coherentio == IO_COHERENCE_DEFAULT) && hw_coherentio)) {
|
||||||
|
# endif
|
||||||
_dma_cache_wback_inv = (void *)cache_noop;
|
_dma_cache_wback_inv = (void *)cache_noop;
|
||||||
_dma_cache_wback = (void *)cache_noop;
|
_dma_cache_wback = (void *)cache_noop;
|
||||||
_dma_cache_inv = (void *)cache_noop;
|
_dma_cache_inv = (void *)cache_noop;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
#include <dma-coherence.h>
|
#include <dma-coherence.h>
|
||||||
|
|
||||||
#ifdef CONFIG_DMA_MAYBE_COHERENT
|
#if defined(CONFIG_DMA_MAYBE_COHERENT) && !defined(CONFIG_DMA_PERDEV_COHERENT)
|
||||||
/* User defined DMA coherency from command line. */
|
/* User defined DMA coherency from command line. */
|
||||||
enum coherent_io_user_state coherentio = IO_COHERENCE_DEFAULT;
|
enum coherent_io_user_state coherentio = IO_COHERENCE_DEFAULT;
|
||||||
EXPORT_SYMBOL_GPL(coherentio);
|
EXPORT_SYMBOL_GPL(coherentio);
|
||||||
|
|
Loading…
Reference in New Issue