Files
openwrt-R7800-nss/target/linux/ipq806x/patches-6.6/990-0187-arm-arm64-Add-new-APIs-to-perform-dma-cache-maintena.patch
SqTER-PL 5536c2039e Updated and refreshed patches.
Renamed patches to keep their original numbering from codelinaro.org
Fixed minor bugs and added support for the qca-nss-drv-l2tpv2 module
2025-08-04 18:52:30 +02:00

380 lines
11 KiB
Diff

From da352a66ee871ddba0e1970f029ca17d5b4fd99b Mon Sep 17 00:00:00 2001
From: Suman Ghosh <quic_sumaghos@quicinc.com>
Date: Sat, 4 Sep 2021 01:09:20 +0530
Subject: [PATCH 095/500] arm/arm64: Add new APIs to perform dma cache
maintenance operation without dsb.
Change-Id: I511657af343c8dc668ab7280362b3cdd57579360
Signed-off-by: Suman Ghosh <quic_sumaghos@quicinc.com>
Signed-off-by: Tushar Ganatra <quic_tganatra@quicinc.com>
Signed-off-by: Pavithra R <quic_pavir@quicinc.com>
Signed-off-by: Tushar Ganatra <quic_tganatra@quicinc.com>
---
arch/arm/include/asm/cacheflush.h | 11 ++++
arch/arm/include/asm/glue-cache.h | 3 +
arch/arm/mm/cache-v7.S | 98 +++++++++++++++++++++++++++--
arch/arm/mm/proc-syms.c | 3 +
arch/arm64/include/asm/assembler.h | 39 ++++++++++++
arch/arm64/include/asm/cacheflush.h | 9 +++
arch/arm64/mm/cache.S | 58 +++++++++++++++++
arch/arm64/mm/flush.c | 24 +++++++
8 files changed, 239 insertions(+), 6 deletions(-)
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -130,6 +130,10 @@ struct cpu_cache_fns {
void (*dma_inv_range)(const void *, const void *);
void (*dma_clean_range)(const void *, const void *);
void (*dma_flush_range)(const void *, const void *);
+
+ void (*dma_inv_range_no_dsb)(const void *, const void *);
+ void (*dma_clean_range_no_dsb)(const void *, const void *);
+ void (*dma_flush_range_no_dsb)(const void *, const void *);
} __no_randomize_layout;
/*
@@ -158,6 +162,10 @@ extern struct cpu_cache_fns cpu_cache;
#define dmac_clean_range cpu_cache.dma_clean_range
#define dmac_flush_range cpu_cache.dma_flush_range
+#define dmac_inv_range_no_dsb cpu_cache.dma_inv_range_no_dsb
+#define dmac_clean_range_no_dsb cpu_cache.dma_clean_range_no_dsb
+#define dmac_flush_range_no_dsb cpu_cache.dma_flush_range_no_dsb
+
#else
extern void __cpuc_flush_icache_all(void);
@@ -178,6 +186,9 @@ extern void __cpuc_flush_dcache_area(voi
extern void dmac_inv_range(const void *, const void *);
extern void dmac_clean_range(const void *, const void *);
extern void dmac_flush_range(const void *, const void *);
+extern void dmac_inv_range_no_dsb(const void *, const void *);
+extern void dmac_clean_range_no_dsb(const void *, const void *);
+extern void dmac_flush_range_no_dsb(const void *, const void *);
#endif
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -156,8 +156,11 @@ static inline void nop_dma_unmap_area(co
#define __cpuc_flush_dcache_area __glue(_CACHE,_flush_kern_dcache_area)
#define dmac_flush_range __glue(_CACHE,_dma_flush_range)
+#define dmac_flush_range_no_dsb __glue(_CACHE,_dma_flush_range_no_dsb)
#define dmac_inv_range __glue(_CACHE, _dma_inv_range)
+#define dmac_inv_range_no_dsb __glue(_CACHE, _dma_inv_range_no_dsb)
#define dmac_clean_range __glue(_CACHE, _dma_clean_range)
+#define dmac_clean_range_no_dsb __glue(_CACHE, _dma_clean_range_no_dsb)
#endif
#endif
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -387,6 +387,42 @@ ENTRY(v7_dma_inv_range)
ENDPROC(v7_dma_inv_range)
/*
+ * v7_dma_inv_range_no_dsb(start,end)
+ *
+ * Invalidate the data cache within the specified region; we will
+ * be performing a DMA operation in this region and we want to
+ * purge old data in the cache. This API does not do
+ * "data synchronization barrier". The caller is responsible to
+ * do dsb after the transaction.
+ *
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+ENTRY(v7_dma_inv_range_no_dsb)
+ dcache_line_size r2, r3
+ sub r3, r2, #1
+ tst r0, r3
+ bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
+ mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
+ addne r0, r0, r2
+
+ tst r1, r3
+ bic r1, r1, r3
+ mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D / U line
+ cmp r0, r1
+1:
+ mcrlo p15, 0, r0, c7, c6, 1 @ invalidate D / U line
+ addlo r0, r0, r2
+ cmplo r0, r1
+ blo 1b
+ ret lr
+ENDPROC(v7_dma_inv_range_no_dsb)
+
+/*
* v7_dma_clean_range(start,end)
* - start - virtual start address of region
* - end - virtual end address of region
@@ -409,12 +445,16 @@ ENTRY(v7_dma_clean_range)
ENDPROC(v7_dma_clean_range)
/*
- * v7_dma_flush_range(start,end)
+ * v7_dma_clean_range_no_dsb(start,end)
+ *
+ * This API does not do "data synchronization barrier".
+ * The caller is responsible to do dsb after the transaction.
+ *
* - start - virtual start address of region
* - end - virtual end address of region
*/
-ENTRY(v7_dma_flush_range)
- dcache_line_size r2, r3
+ENTRY(v7_dma_clean_range_no_dsb)
+ dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3
#ifdef CONFIG_ARM_ERRATA_764369
@@ -422,6 +462,27 @@ ENTRY(v7_dma_flush_range)
ALT_UP(W(nop))
#endif
1:
+ mcr p15, 0, r0, c7, c10, 1 @ clean D / U line
+ add r0, r0, r2
+ cmp r0, r1
+ blo 1b
+ ret lr
+ENDPROC(v7_dma_clean_range_no_dsb)
+
+/*
+ * v7_dma_flush_range(start,end)
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+ENTRY(v7_dma_flush_range)
+ dcache_line_size r2, r3
+ sub r3, r2, #1
+ bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
+1:
mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
add r0, r0, r2
cmp r0, r1
@@ -431,10 +492,35 @@ ENTRY(v7_dma_flush_range)
ENDPROC(v7_dma_flush_range)
/*
+ * v7_dma_flush_range_no_dsb(start,end)
+ *
+ * This API does not do "data synchronization barrier".
+ * The caller is responsible to do dsb after the transaction.
+ *
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+ENTRY(v7_dma_flush_range_no_dsb)
+ dcache_line_size r2, r3
+ sub r3, r2, #1
+ bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
+1:
+ mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
+ add r0, r0, r2
+ cmp r0, r1
+ blo 1b
+ ret lr
+ENDPROC(v7_dma_flush_range_no_dsb)
+
+/*
* dma_map_area(start, size, dir)
- * - start - kernel virtual start address
- * - size - size of region
- * - dir - DMA direction
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
*/
ENTRY(v7_dma_map_area)
add r1, r1, r0
--- a/arch/arm/mm/proc-syms.c
+++ b/arch/arm/mm/proc-syms.c
@@ -28,8 +28,11 @@ EXPORT_SYMBOL(__cpuc_flush_user_range);
EXPORT_SYMBOL(__cpuc_coherent_kern_range);
EXPORT_SYMBOL(__cpuc_flush_dcache_area);
EXPORT_SYMBOL(dmac_inv_range);
+EXPORT_SYMBOL(dmac_inv_range_no_dsb);
EXPORT_SYMBOL(dmac_clean_range);
+EXPORT_SYMBOL(dmac_clean_range_no_dsb);
EXPORT_SYMBOL(dmac_flush_range);
+EXPORT_SYMBOL(dmac_flush_range_no_dsb);
#else
EXPORT_SYMBOL(cpu_cache);
#endif
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -428,6 +428,45 @@ alternative_endif
/*
* Macro to perform a data cache maintenance for the interval
+ * [kaddr, kaddr + size)
+ * This macro does not do "data synchronization barrier". Caller should
+ * do "dsb" after transaction.
+ *
+ * op: operation passed to dc instruction
+ * kaddr: starting virtual address of the region
+ * size: size of the region
+ * Corrupts: kaddr, size, tmp1, tmp2
+ */
+ .macro dcache_by_line_op_no_dsb op, kaddr, size, tmp1, tmp2
+ dcache_line_size \tmp1, \tmp2
+ add \size, \kaddr, \size
+ sub \tmp2, \tmp1, #1
+ bic \kaddr, \kaddr, \tmp2
+9998:
+ .ifc \op, cvau
+ __dcache_op_workaround_clean_cache \op, \kaddr
+ .else
+ .ifc \op, cvac
+ __dcache_op_workaround_clean_cache \op, \kaddr
+ .else
+ .ifc \op, cvap
+ sys 3, c7, c12, 1, \kaddr // dc cvap
+ .else
+ .ifc \op, cvadp
+ sys 3, c7, c13, 1, \kaddr // dc cvadp
+ .else
+ dc \op, \kaddr
+ .endif
+ .endif
+ .endif
+ .endif
+ add \kaddr, \kaddr, \tmp1
+ cmp \kaddr, \size
+ b.lo 9998b
+ .endm
+
+/*
+ * Macro to perform a data cache maintenance for the interval
* [start, end)
*
* op: operation passed to dc instruction
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -79,6 +79,15 @@ extern void dcache_clean_pou(unsigned lo
extern long caches_clean_inval_user_pou(unsigned long start, unsigned long end);
extern void sync_icache_aliases(unsigned long start, unsigned long end);
+extern void dmac_inv_range(const void *start, const void *end);
+extern void __dma_flush_area_no_dsb(const void *start, size_t size);
+extern void __dma_inv_area_no_dsb(const void *start, size_t size);
+extern void __dma_clean_area_no_dsb(const void *start, size_t size);
+
+extern void dmac_flush_range_no_dsb(const void *start, const void *end);
+extern void dmac_inv_range_no_dsb(const void *start, const void *end);
+extern void dmac_clean_range_no_dsb(const void *start, const void *end);
+
static inline void flush_icache_range(unsigned long start, unsigned long end)
{
caches_clean_inval_pou(start, end);
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -164,6 +164,64 @@ SYM_FUNC_END(__pi_dcache_inval_poc)
SYM_FUNC_ALIAS(dcache_inval_poc, __pi_dcache_inval_poc)
/*
+ * __dma_inv_area_no_dsb(start, size)
+ *
+ * This macro does not do "data synchronization barrier". Caller should
+ * do "dsb" after transaction.
+ *
+ * start - virtual start address of region
+ * size - size in question
+ */
+SYM_FUNC_START(__dma_inv_area_no_dsb)
+ add x1, x1, x0
+ dcache_line_size x2, x3
+ sub x3, x2, #1
+ tst x1, x3 // end cache line aligned?
+ bic x1, x1, x3
+ b.eq 1f
+ dc civac, x1 // clean & invalidate D / U line
+1: tst x0, x3 // start cache line aligned?
+ bic x0, x0, x3
+ b.eq 2f
+ dc civac, x0 // clean & invalidate D / U line
+ b 3f
+2: dc ivac, x0 // invalidate D / U line
+3: add x0, x0, x2
+ cmp x0, x1
+ b.lo 2b
+ ret
+SYM_FUNC_END(__dma_inv_area_no_dsb)
+
+/*
+ * __dma_clean_area_no_dsb(start, size)
+ *
+ * his macro does not do "data synchronization barrier". Caller should
+ * o "dsb" after transaction.
+ *
+ * start - virtual start address of region
+ * size - size in question
+ */
+SYM_FUNC_START(__dma_clean_area_no_dsb)
+ dcache_by_line_op_no_dsb cvac, x0, x1, x2, x3
+ ret
+SYM_FUNC_END(__dma_clean_area_no_dsb)
+
+/*
+ * __dma_flush_area_no_dsb(start, size)
+ *
+ * clean & invalidate D / U line
+ * his macro does not do "data synchronization barrier". Caller should
+ * o "dsb" after transaction.
+ *
+ * start - virtual start address of region
+ * size - size in question
+ */
+SYM_FUNC_START(__dma_flush_area_no_dsb)
+ dcache_by_line_op_no_dsb civac, x0, x1, x2, x3
+ ret
+SYM_FUNC_END(__dma_flush_area_no_dsb)
+
+/*
* dcache_clean_poc(start, end)
*
* Ensure that any D-cache lines for the interval [start, end)
--- a/arch/arm64/mm/flush.c
+++ b/arch/arm64/mm/flush.c
@@ -100,3 +100,27 @@ void arch_invalidate_pmem(void *addr, si
}
EXPORT_SYMBOL_GPL(arch_invalidate_pmem);
#endif
+
+void dmac_flush_range_no_dsb(const void *start, const void *end)
+{
+ __dma_flush_area_no_dsb(start, (void *)(end) - (void *)(start));
+}
+EXPORT_SYMBOL(dmac_flush_range_no_dsb);
+
+void dmac_inv_range(const void *start, const void *end)
+{
+ dcache_inval_poc((unsigned long)start, (unsigned long)(end));
+}
+EXPORT_SYMBOL(dmac_inv_range);
+
+void dmac_inv_range_no_dsb(const void *start, const void *end)
+{
+ __dma_inv_area_no_dsb(start, (void *)(end) - (void *)(start));
+}
+EXPORT_SYMBOL(dmac_inv_range_no_dsb);
+
+void dmac_clean_range_no_dsb(const void *start, const void *end)
+{
+ __dma_clean_area_no_dsb(start, (void *)(end) - (void *)(start));
+}
+EXPORT_SYMBOL(dmac_clean_range_no_dsb);