In order to correctly handle cache-coherent systems on ARM, we need to be able to determine whether a device instantiated from DT is DMA coherent. Port the Linux helper that does this check. Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> --- of_dma_is_coherent is still unused, but it will be used in future. --- arch/riscv/Kconfig | 1 + drivers/of/Kconfig | 4 ++++ drivers/of/platform.c | 41 +++++++++++++++++++++++++++++++++++++++++ include/of_address.h | 6 ++++++ 4 files changed, 52 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index cd7f4abf5694..afbd55aa3e6f 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -10,6 +10,7 @@ config RISCV select COMMON_CLK_OF_PROVIDER select CLKDEV_LOOKUP select HAS_DMA + select OF_DMA_DEFAULT_COHERENT select HAVE_PBL_IMAGE select HAVE_PBL_MULTI_IMAGES select HAVE_IMAGE_COMPRESSION diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 7283331ba9ce..4dc40b27f442 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -31,6 +31,10 @@ config FEATURE_CONTROLLER_FIXUP config OF_ADDRESS_PCI bool +config OF_DMA_DEFAULT_COHERENT + # arches should select this if DMA is coherent by default for OF devices + bool + config OF_GPIO depends on GPIOLIB depends on OFDEVICE diff --git a/drivers/of/platform.c b/drivers/of/platform.c index a9a5d4c2daf2..2b5ad08c124b 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -73,6 +73,47 @@ static void of_device_make_bus_id(struct device_d *dev) } } +static struct device_node *of_get_next_dma_parent(const struct device_node *np) +{ + struct of_phandle_args args; + int ret, index; + + index = of_property_match_string(np, "interconnect-names", "dma-mem"); + if (index < 0) + return of_get_parent(np); + + ret = of_parse_phandle_with_args(np, "interconnects", + "#interconnect-cells", + index, &args); + if (ret < 0) + return of_get_parent(np); + + return args.np; +} + +/** + * of_dma_is_coherent - Check if device is coherent + * @np: device node + * + * It returns true if "dma-coherent" property was found + * for this device in the DT, or if DMA is coherent by + * default for OF devices on the current platform and no + * "dma-noncoherent" property was found for this device. + */ +bool of_dma_is_coherent(struct device_node *node) +{ + while (node) { + if (of_property_read_bool(node, "dma-coherent")) + return true; + if (of_property_read_bool(node, "dma-noncoherent")) + return false; + node = of_get_next_dma_parent(node); + } + + return IS_ENABLED(CONFIG_OF_DMA_DEFAULT_COHERENT); +} +EXPORT_SYMBOL_GPL(of_dma_is_coherent); + static void of_dma_configure(struct device_d *dev, struct device_node *np) { u64 dma_addr, paddr, size = 0; diff --git a/include/of_address.h b/include/of_address.h index 66117b1fa7f8..4e5faf6f7783 100644 --- a/include/of_address.h +++ b/include/of_address.h @@ -60,6 +60,8 @@ extern void __iomem *of_iomap(struct device_node *np, int index); extern int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *size); +extern bool of_dma_is_coherent(struct device_node *np); + #else /* CONFIG_OFTREE */ static inline u64 of_translate_address(struct device_node *dev, @@ -109,6 +111,10 @@ static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr, return -ENOSYS; } +static inline bool of_dma_is_coherent(struct device_node *np) +{ + return false; +} #endif /* CONFIG_OFTREE */ #ifdef CONFIG_OF_PCI -- 2.30.2