kernel/0005-riscv-mm-dma-noncoherent-Add-arch_dma_set_uncached.patch
2025-02-11 21:42:49 -05:00

133 lines
3.7 KiB
Diff

From b64c74ac5d26a1b55d0d343ca344f805591b0991 Mon Sep 17 00:00:00 2001
From: Min Lin <linmin@eswincomputing.com>
Date: Mon, 29 Jul 2024 14:19:28 +0000
Subject: [PATCH 005/128] riscv: mm: dma-noncoherent: Add arch_dma_set_uncached
Add arch_dma_set_uncached and arch_dma_clear_uncached
Signed-off-by: Min Lin <linmin@eswincomputing.com>
Signed-off-by: Pritesh Patel <pritesh.patel@einfochips.com>
---
arch/riscv/mm/dma-noncoherent.c | 82 +++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/arch/riscv/mm/dma-noncoherent.c b/arch/riscv/mm/dma-noncoherent.c
index 341bd6706b4c..39b2bea86960 100644
--- a/arch/riscv/mm/dma-noncoherent.c
+++ b/arch/riscv/mm/dma-noncoherent.c
@@ -10,6 +10,10 @@
#include <linux/mm.h>
#include <asm/cacheflush.h>
#include <asm/dma-noncoherent.h>
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
+#include <linux/io.h>
+#include <linux/iommu.h>
+#endif
static bool noncoherent_supported __ro_after_init;
int dma_cache_alignment __ro_after_init = ARCH_DMA_MINALIGN;
@@ -128,6 +132,13 @@ void arch_dma_prep_coherent(struct page *page, size_t size)
ALT_CMO_OP(flush, flush_addr, size, riscv_cbom_block_size);
}
+#ifdef CONFIG_IOMMU_DMA
+void arch_teardown_dma_ops(struct device *dev)
+{
+ dev->dma_ops = NULL;
+}
+#endif
+
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
const struct iommu_ops *iommu, bool coherent)
{
@@ -137,11 +148,18 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
dev_driver_string(dev), dev_name(dev),
ARCH_DMA_MINALIGN, riscv_cbom_block_size);
+#ifndef CONFIG_SOC_SIFIVE_EIC7700
WARN_TAINT(!coherent && !noncoherent_supported, TAINT_CPU_OUT_OF_SPEC,
"%s %s: device non-coherent but no non-coherent operations supported",
dev_driver_string(dev), dev_name(dev));
+#endif
dev->dma_coherent = coherent;
+
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
+ if (iommu)
+ iommu_setup_dma_ops(dev, dma_base, size);
+#endif
}
void riscv_noncoherent_supported(void)
@@ -156,3 +174,67 @@ void __init riscv_set_dma_cache_alignment(void)
if (!noncoherent_supported)
dma_cache_alignment = 1;
}
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
+static struct page **__iommu_dma_common_find_pages(void *cpu_addr)
+{
+ struct vm_struct *area = find_vm_area(cpu_addr);
+
+ if (!area || area->flags != VM_DMA_COHERENT)
+ return NULL;
+ return area->pages;
+}
+
+void arch_dma_clear_uncached(void *addr, size_t size)
+{
+ struct page **pages = NULL;
+
+ pages = __iommu_dma_common_find_pages(addr);
+ if (!pages) { // todo: supposed to handle this error
+ pr_err( "smmu_dbg, fail to find pages\n");
+
+ return;
+ }
+ kvfree(pages);
+ memunmap(addr);
+}
+
+void *arch_dma_set_uncached(void *addr, size_t size)
+{
+ struct page **pages = NULL;
+ static struct page *page = NULL;
+ struct vm_struct *area = NULL;
+ phys_addr_t phys_addr = convert_pha_from_mem_to_sys_port(__pa(addr));
+ void *mem_base = NULL;
+
+ mem_base = memremap(phys_addr, size, MEMREMAP_WT);
+ if (!mem_base) {
+ pr_err("%s memremap failed for addr %px\n", __func__, addr);
+ return ERR_PTR(-EINVAL);
+ }
+
+ pages = kvzalloc(sizeof(*pages), GFP_KERNEL);
+ if (!pages) {
+ pr_err("smmu_dbg, failed to alloc memory!\n");
+ goto err_pages_alloc;
+ }
+ page = virt_to_page(addr);
+ area = find_vm_area(mem_base);
+ if (!area) {
+ pr_err("smmu_dbg, failed to find vm area!\n");
+ goto err_find_vm_area;
+ }
+ pages[0] = page;
+ area->pages = pages;
+ area->flags = VM_DMA_COHERENT;
+
+ return mem_base;
+
+err_find_vm_area:
+ kvfree(pages);
+
+err_pages_alloc:
+ memunmap(mem_base);
+
+ return NULL;
+}
+#endif
--
2.47.0