So far, whether device DMA is coherent was a one-time global decision. This is insufficient, because some platforms: - are cache coherent, while the architecture isn't in general, e.g. barebox support for ARM with CONFIG_MMU=y assumes non-coherent DMA, but LS1046A can be fully coherent. - have a mix of devices that snoop caches and devices that don't (StarFive JH7100). To enable dev_dma_(map|unmap)_single to take the correct device-specific action with regards to cache maintenance, provide dev_is_dma_coherent() with semantics similar to what Linux provides. Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> --- v1 -> v2: - make dma_coherent a boolean (Sascha) - add dma_coherent unconditionally (Sascha) - Only print dma_coherent status for devices with OF node --- commands/devinfo.c | 4 ++++ drivers/of/platform.c | 1 + include/driver.h | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/commands/devinfo.c b/commands/devinfo.c index aeb9c5533931..6001b00cfac8 100644 --- a/commands/devinfo.c +++ b/commands/devinfo.c @@ -105,6 +105,10 @@ static int do_devinfo(int argc, char *argv[]) if (dev->of_node) { struct device *main_dev = dev->of_node->dev; + printf("DMA Coherent: %s%s\n", + dev_is_dma_coherent(dev) ? "true" : "false", + dev->dma_coherent == DEV_DMA_COHERENCE_DEFAULT ? " (default)" : ""); + printf("Device node: %pOF", dev->of_node); if (!main_dev) { printf(" (unpopulated)\n"); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index edfeb192d434..060fa3458bd2 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -129,6 +129,7 @@ static void of_dma_configure(struct device *dev, struct device_node *np) } dev->dma_offset = offset; + dev->dma_coherent = of_dma_is_coherent(np); } /** diff --git a/include/driver.h b/include/driver.h index b37b0ab192a3..c23404ca16fb 100644 --- a/include/driver.h +++ b/include/driver.h @@ -25,6 +25,12 @@ struct platform_device_id { unsigned long driver_data; }; +enum dev_dma_coherence { + DEV_DMA_COHERENCE_DEFAULT = 0, + DEV_DMA_COHERENT, + DEV_DMA_NON_COHERENT, +}; + /** @brief Describes a particular device present in the system */ struct device { /*! This member (and 'type' described below) is used to match @@ -45,6 +51,8 @@ struct device { * something like eth0 or nor0. */ int id; + enum dev_dma_coherence dma_coherent; + struct resource *resource; int num_resources; @@ -720,6 +728,20 @@ static inline struct device_node *dev_of_node(struct device *dev) return IS_ENABLED(CONFIG_OFDEVICE) ? dev->of_node : NULL; } +static inline bool dev_is_dma_coherent(struct device *dev) +{ + switch (dev->dma_coherent) { + case DEV_DMA_NON_COHERENT: + return false; + case DEV_DMA_COHERENT: + return true; + case DEV_DMA_COHERENCE_DEFAULT: + break; + } + + return IS_ENABLED(CONFIG_ARCH_DMA_DEFAULT_COHERENT); +} + static inline void *dev_get_priv(const struct device *dev) { return dev->priv; -- 2.39.2