[PATCH v2 2/2] common/memsize.c: Fix get_ram_size() when cache is enabled
Michael Nazzareno Trimarchi
michael at amarulasolutions.com
Tue May 30 16:04:47 CEST 2023
Hi
On Tue, May 30, 2023 at 3:49 PM Francesco Dolcini <francesco at dolcini.it> wrote:
>
> On Tue, May 30, 2023 at 03:42:18PM +0200, Michael Nazzareno Trimarchi wrote:
> > On Tue, May 30, 2023 at 3:34 PM Francesco Dolcini <francesco at dolcini.it> wrote:
> > >
> > > From: Emanuele Ghidoli <emanuele.ghidoli at toradex.com>
> > >
> > > 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").
> > >
> > > Signed-off-by: Emanuele Ghidoli <emanuele.ghidoli at toradex.com>
> > > Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
> > > ---
> > > v2:
> > > * check if CONFIG_SYS_CACHELINE_SIZE is defined
> > > * do flush only when cache is enabled
> > > ---
> > > common/memsize.c | 24 ++++++++++++++++++++++++
> > > 1 file changed, 24 insertions(+)
> > >
> > > diff --git a/common/memsize.c b/common/memsize.c
> > > index 66d5be6a1ff3..d646df8b04cb 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);
> >
> > Why this should be done on every increment if the invalidate keep a
> > range of address?
>
> We do invalidate/flush the current write, the granularity of the
> flush/invalidate is the page size.
>
> This is required since we need to ensure ordering of the writes. How
> would you know where the aliasing is going to happen if you flush all at
> once at the end?
>
I see, I read the code properly of get_mem_size now.
> > Can be possible just to enable/disable cache around memory test?
> In theory yes. In practice this proved some architecture to just crash
> badly because the stack was "corrupted" after re-enabling the cache.
>
> We'll submit a separate bug fix for that, bug given that this pattern
> (disable AND enable) is normally not done in U-Boot it seems like
> looking for trouble doing it in such a commonly used routine.
>
Thank you
More information about the U-Boot
mailing list