git: c1381f07f61a - main - Don't sync the I/D caches when they are coherent

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Mon, 20 Dec 2021 13:59:16 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=c1381f07f61a66979f1569995f37f2a0413c0413

commit c1381f07f61a66979f1569995f37f2a0413c0413
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2021-12-17 09:33:57 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2021-12-20 13:58:13 +0000

    Don't sync the I/D caches when they are coherent
    
    In the arm64 loader we need to syncronise the I and D caches. On some
    newer CPUs the I and D caches are coherent so we don't need to perform
    these operations.
    
    While here remove the arguments to cpu_inval_icache as they are unneeded.
    
    Reported by:    cperciva
    Tested by:      cperciva
    Sponsored by:   Innovate UK
---
 stand/arm64/libarm64/cache.c       | 67 ++++++++++++++++++++++++--------------
 stand/arm64/libarm64/cache.h       |  2 +-
 stand/efi/loader/arch/arm64/exec.c |  2 +-
 3 files changed, 45 insertions(+), 26 deletions(-)

diff --git a/stand/arm64/libarm64/cache.c b/stand/arm64/libarm64/cache.c
index 25766ef564dd..ff52572399ac 100644
--- a/stand/arm64/libarm64/cache.c
+++ b/stand/arm64/libarm64/cache.c
@@ -32,21 +32,30 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 
 #include <machine/armreg.h>
+#include <machine/atomic.h>
 
 #include <stand.h>
 #include <efi.h>
 
 #include "cache.h"
 
+static bool
+get_cache_dic(uint64_t ctr)
+{
+	return (CTR_DIC_VAL(ctr) != 0);
+}
+
+static bool
+get_cache_idc(uint64_t ctr)
+{
+	return (CTR_IDC_VAL(ctr) != 0);
+}
+
 static unsigned int
-get_dcache_line_size(void)
+get_dcache_line_size(uint64_t ctr)
 {
-	uint64_t ctr;
 	unsigned int dcl_size;
 
-	/* Accessible from all security levels */
-	ctr = READ_SPECIALREG(ctr_el0);
-
 	/*
 	 * Relevant field [19:16] is LOG2
 	 * of the number of words in DCache line
@@ -60,36 +69,46 @@ get_dcache_line_size(void)
 void
 cpu_flush_dcache(const void *ptr, size_t len)
 {
-
-	uint64_t cl_size;
+	uint64_t cl_size, ctr;
 	vm_offset_t addr, end;
 
-	cl_size = get_dcache_line_size();
-
-	/* Calculate end address to clean */
-	end = (vm_offset_t)ptr + (vm_offset_t)len;
-	/* Align start address to cache line */
-	addr = (vm_offset_t)ptr;
-	addr = rounddown2(addr, cl_size);
+	/* Accessible from all security levels */
+	ctr = READ_SPECIALREG(ctr_el0);
 
-	for (; addr < end; addr += cl_size)
-		__asm __volatile("dc	civac, %0" : : "r" (addr) : "memory");
-	/* Full system DSB */
-	__asm __volatile("dsb	sy" : : : "memory");
+	if (get_cache_idc(ctr)) {
+		dsb(ishst);
+	} else {
+		cl_size = get_dcache_line_size(ctr);
+
+		/* Calculate end address to clean */
+		end = (vm_offset_t)ptr + (vm_offset_t)len;
+		/* Align start address to cache line */
+		addr = (vm_offset_t)ptr;
+		addr = rounddown2(addr, cl_size);
+
+		for (; addr < end; addr += cl_size)
+			__asm __volatile("dc	civac, %0" : : "r" (addr) :
+			    "memory");
+		/* Full system DSB */
+		dsb(ish);
+	}
 }
 
 void
-cpu_inval_icache(const void *ptr, size_t len)
+cpu_inval_icache(void)
 {
+	uint64_t ctr;
 
-	/* NULL ptr or 0 len means all */
-	if (ptr == NULL || len == 0) {
+	/* Accessible from all security levels */
+	ctr = READ_SPECIALREG(ctr_el0);
+
+	if (get_cache_dic(ctr)) {
+		isb();
+	} else {
 		__asm __volatile(
 		    "ic		ialluis	\n"
 		    "dsb	ish	\n"
+		    "isb		\n"
 		    : : : "memory");
-		return;
 	}
-
-	/* TODO: Other cache ranges if necessary */
 }
diff --git a/stand/arm64/libarm64/cache.h b/stand/arm64/libarm64/cache.h
index 89b094b19c18..5e560c4d578d 100644
--- a/stand/arm64/libarm64/cache.h
+++ b/stand/arm64/libarm64/cache.h
@@ -33,6 +33,6 @@
 
 /* cache.c */
 void cpu_flush_dcache(const void *, size_t);
-void cpu_inval_icache(const void *, size_t);
+void cpu_inval_icache(void);
 
 #endif /* _CACHE_H_ */
diff --git a/stand/efi/loader/arch/arm64/exec.c b/stand/efi/loader/arch/arm64/exec.c
index 7783d46cd8e1..6cf4a4fd8e4d 100644
--- a/stand/efi/loader/arch/arm64/exec.c
+++ b/stand/efi/loader/arch/arm64/exec.c
@@ -128,7 +128,7 @@ elf64_exec(struct preloaded_file *fp)
 	clean_size = (vm_offset_t)efi_translate(kernendp) - clean_addr;
 
 	cpu_flush_dcache((void *)clean_addr, clean_size);
-	cpu_inval_icache(NULL, 0);
+	cpu_inval_icache();
 
 	(*entry)(modulep);
 	panic("exec returned");