Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20d33064 authored by Paul Burton's avatar Paul Burton Committed by Ralf Baechle
Browse files

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: default avatarPaul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/14349/


Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent cfa93fb9
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1099,6 +1099,10 @@ config DMA_MAYBE_COHERENT
	select DMA_NONCOHERENT
	bool

config DMA_PERDEV_COHERENT
	bool
	select DMA_MAYBE_COHERENT

config DMA_COHERENT
	bool

+5 −0
Original line number Diff line number Diff line
@@ -11,6 +11,11 @@ struct dma_map_ops;
struct dev_archdata {
	/* DMA operations on that device */
	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 {
+3 −1
Original line number Diff line number Diff line
@@ -15,7 +15,9 @@ enum coherent_io_user_state {
	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 int hw_coherentio;
#else
+10 −0
Original line number Diff line number Diff line
@@ -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,
	       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 */
+4 −0
Original line number Diff line number Diff line
@@ -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)
{
#ifdef CONFIG_DMA_PERDEV_COHERENT
	return dev->archdata.dma_coherent;
#else
	switch (coherentio) {
	default:
	case IO_COHERENCE_DEFAULT:
@@ -58,6 +61,7 @@ static inline int plat_device_is_coherent(struct device *dev)
	case IO_COHERENCE_DISABLED:
		return 0;
	}
#endif
}

#ifndef plat_post_dma_flush
Loading