summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2023-06-22 09:59:43 -0400
committerTom Rini <[email protected]>2023-06-22 09:59:43 -0400
commiteef4a771e85fc30a18719316a23d0ad1476ae1a5 (patch)
tree723604929d4149b1e926fd6ecebc85ac4a513caf
parent43dc016497ff9fd39139833852b0214f625fa4ca (diff)
parent1c64b98c1ec40d2c9eb68af2d190e989dded8919 (diff)
Merge branch '2023-06-21-fix-get_ram_size-with-cache-enabled' into next
To quote the author: Ensure that every write is flushed to memory and afterward reads are from memory. Since the algorithm rely on the fact that accessing to not existent memory lead to write at addr / 2 without this modification accesses to aliased (not physically present) addresses are cached and wrong size is returned. This was discovered while working on a TI AM625 based board where cache is normally enabled, see commit c02712a74849 ("arm: mach-k3: Enable dcache in SPL").
-rw-r--r--arch/sandbox/cpu/cpu.c5
-rw-r--r--common/memsize.c24
2 files changed, 29 insertions, 0 deletions
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index 51496338ad6..a1c5c7c4311 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -286,6 +286,11 @@ void sandbox_set_enable_pci_map(int enable)
enable_pci_map = enable;
}
+int dcache_status(void)
+{
+ return 1;
+}
+
void flush_dcache_range(unsigned long start, unsigned long stop)
{
}
diff --git a/common/memsize.c b/common/memsize.c
index 66d5be6a1ff..d646df8b04c 100644
--- a/common/memsize.c
+++ b/common/memsize.c
@@ -7,9 +7,18 @@
#include <common.h>
#include <init.h>
#include <asm/global_data.h>
+#include <cpu_func.h>
+#include <stdint.h>
DECLARE_GLOBAL_DATA_PTR;
+#ifdef CONFIG_SYS_CACHELINE_SIZE
+# define MEMSIZE_CACHELINE_SIZE CONFIG_SYS_CACHELINE_SIZE
+#else
+/* Just use the greatest cache flush alignment requirement I'm aware of */
+# define MEMSIZE_CACHELINE_SIZE 128
+#endif
+
#ifdef __PPC__
/*
* At least on G2 PowerPC cores, sequential accesses to non-existent
@@ -20,6 +29,15 @@ DECLARE_GLOBAL_DATA_PTR;
# define sync() /* nothing */
#endif
+static void dcache_flush_invalidate(volatile long *p)
+{
+ uintptr_t start, stop;
+ start = ALIGN_DOWN((uintptr_t)p, MEMSIZE_CACHELINE_SIZE);
+ stop = start + MEMSIZE_CACHELINE_SIZE;
+ flush_dcache_range(start, stop);
+ invalidate_dcache_range(start, stop);
+}
+
/*
* Check memory range for valid RAM. A simple memory test determines
* the actually available RAM size between addresses `base' and
@@ -34,6 +52,7 @@ long get_ram_size(long *base, long maxsize)
long val;
long size;
int i = 0;
+ int dcache_en = dcache_status();
for (cnt = (maxsize / sizeof(long)) >> 1; cnt > 0; cnt >>= 1) {
addr = base + cnt; /* pointer arith! */
@@ -41,6 +60,8 @@ long get_ram_size(long *base, long maxsize)
save[i++] = *addr;
sync();
*addr = ~cnt;
+ if (dcache_en)
+ dcache_flush_invalidate(addr);
}
addr = base;
@@ -50,6 +71,9 @@ long get_ram_size(long *base, long maxsize)
*addr = 0;
sync();
+ if (dcache_en)
+ dcache_flush_invalidate(addr);
+
if ((val = *addr) != 0) {
/* Restore the original data before leaving the function. */
sync();