[U-Boot] [PATCH v2] riscv: cache: Implement i/dcache [status, enable, disable]

Rick Chen rickchen36 at gmail.com
Tue Nov 6 02:28:00 UTC 2018


Auer, Lukas <lukas.auer at aisec.fraunhofer.de> 於 2018年11月4日 週日 下午10:21寫道:
>
> Hi Rick,
>
> On Thu, 2018-11-01 at 12:08 +0800, Andes wrote:
> > From: Rick Chen <rick at andestech.com>
> >
> > AndeStar RISC-V(V5) provide mcache_ctl register which
> > can configure I/D cache as enabled or disabled.
> >
> > This CSR will be encapsulated by CONFIG_RISCV_NDS.
> > If you want to configure cache on AndeStar V5
> > AE350 platform. YOu can enable [*] AndeStar V5 ISA support
> > by make menuconfig.
> >
> > This approach also provide the expansion when the
> > vender specific features are going to join in.
> >
> > Signed-off-by: Rick Chen <rick at andestech.com>
> > Cc: Greentime Hu <greentime at andestech.com>
> > ---
> >  arch/riscv/Kconfig             |  8 ++++
> >  arch/riscv/cpu/ax25/Makefile   |  1 +
> >  arch/riscv/cpu/ax25/cache.c    | 89
> > ++++++++++++++++++++++++++++++++++++++++++
> >  arch/riscv/cpu/ax25/cpu.c      |  4 ++
> >  arch/riscv/cpu/qemu/cpu.c      |  2 +-
> >  arch/riscv/cpu/start.S         |  6 +++
> >  arch/riscv/include/asm/cache.h |  9 +++++
> >  arch/riscv/lib/cache.c         | 30 +++++++++-----
> >  8 files changed, 138 insertions(+), 11 deletions(-)
> >  create mode 100644 arch/riscv/cpu/ax25/cache.c
> >
> > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> > index 371921b..a356729 100644
> > --- a/arch/riscv/Kconfig
> > +++ b/arch/riscv/Kconfig
> > @@ -74,4 +74,12 @@ config 32BIT
> >  config 64BIT
> >       bool
> >
> > +config RISCV_NDS
> > +     bool "AndeStar V5 ISA support"
> > +     default n
> > +     help
> > +             Say Y here if you plan to run U-Boot on AndeStar v5
> > +             platforms and use some specific features which are
> > +             provided by Andes Technology AndeStar V5 Families.
> > +
> >  endmenu
> > diff --git a/arch/riscv/cpu/ax25/Makefile
> > b/arch/riscv/cpu/ax25/Makefile
> > index 2ab0342..318bacc 100644
> > --- a/arch/riscv/cpu/ax25/Makefile
> > +++ b/arch/riscv/cpu/ax25/Makefile
> > @@ -4,3 +4,4 @@
> >  # Rick Chen, Andes Technology Corporation <rick at andestech.com>
> >
> >  obj-y        := cpu.o
> > +obj-y        += cache.o
> > diff --git a/arch/riscv/cpu/ax25/cache.c
> > b/arch/riscv/cpu/ax25/cache.c
> > new file mode 100644
> > index 0000000..e0bcaa2
> > --- /dev/null
> > +++ b/arch/riscv/cpu/ax25/cache.c
> > @@ -0,0 +1,89 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2017 Andes Technology Corporation
> > + * Rick Chen, Andes Technology Corporation <rick at andestech.com>
> > + */
> > +
> > +#include <common.h>
> > +
> > +void icache_enable(void)
> > +{
> > +#ifndef CONFIG_SYS_ICACHE_OFF
> > +#ifdef CONFIG_RISCV_NDS
> > +     asm volatile (
> > +             "csrr t1, mcache_ctl\n\t"
> > +             "ori t0, t1, 0x1\n\t"
> > +             "csrw mcache_ctl, t0\n\t"
> > +     );
> > +#endif
> > +#endif
> > +}
> > +
> > +void icache_disable(void)
>
> Just wondering, why do you not have the same #ifndef
> CONFIG_SYS_ICACHE_OFF as above here?
>

I only add CONFIG_SYS_XXX_OFF in enable function, not in disable funtion.
This can control cache enable or disable when u-boot start-up, on other reason.
If you care about this, I can add CONFIG_SYS_XXX_OFF for all.

> > +{
> > +#ifdef CONFIG_RISCV_NDS
> > +     asm volatile (
> > +             "csrr t1, mcache_ctl\n\t"
> > +             "andi t0, t1, ~0x1\n\t"
> > +             "csrw mcache_ctl, t0\n\t"
> > +     );
> > +#endif
> > +}
> > +
> > +void dcache_enable(void)
> > +{
> > +#ifndef CONFIG_SYS_ICACHE_OFF
> > +#ifdef CONFIG_RISCV_NDS
> > +     asm volatile (
> > +             "csrr t1, mcache_ctl\n\t"
> > +             "ori t0, t1, 0x2\n\t"
> > +             "csrw mcache_ctl, t0\n\t"
> > +     );
> > +#endif
> > +#endif
> > +}
> > +
> > +void dcache_disable(void)
> > +{
> > +#ifdef CONFIG_RISCV_NDS
> > +     asm volatile (
> > +             "csrr t1, mcache_ctl\n\t"
> > +             "andi t0, t1, ~0x2\n\t"
> > +             "csrw mcache_ctl, t0\n\t"
> > +     );
> > +#endif
> > +}
> > +
> > +int icache_status(void)
> > +{
> > +     int ret = 0;
> > +
> > +#ifdef CONFIG_RISCV_NDS
> > +     asm volatile (
> > +             "csrr t1, mcache_ctl\n\t"
> > +             "andi   %0, t1, 0x01\n\t"
> > +             : "=r" (ret)
> > +             :
> > +             : "memory"
> > +     );
> > +#endif
> > +
> > +     return ret;
> > +}
> > +
> > +int dcache_status(void)
> > +{
> > +     int ret = 0;
> > +
> > +#ifdef CONFIG_RISCV_NDS
> > +     asm volatile (
> > +             "csrr t1, mcache_ctl\n\t"
> > +             "andi   %0, t1, 0x02\n\t"
> > +             : "=r" (ret)
> > +             :
> > +             : "memory"
> > +     );
> > +#endif
> > +
> > +     return ret;
> > +}
> > diff --git a/arch/riscv/cpu/ax25/cpu.c b/arch/riscv/cpu/ax25/cpu.c
> > index fddcc15..76689b2 100644
> > --- a/arch/riscv/cpu/ax25/cpu.c
> > +++ b/arch/riscv/cpu/ax25/cpu.c
> > @@ -6,6 +6,7 @@
> >
> >  /* CPU specific code */
> >  #include <common.h>
> > +#include <asm/cache.h>
> >
> >  /*
> >   * cleanup_before_linux() is called just before we call linux
> > @@ -18,6 +19,9 @@ int cleanup_before_linux(void)
> >       disable_interrupts();
> >
> >       /* turn off I/D-cache */
> > +     cache_flush();
> > +     icache_disable();
> > +     dcache_disable();
>
> This is a separate change from the one described in the commit message,
> please move this into a new patch.
>
> I think we should do the same thing as ARM here. This is the
> implementation on armv8, for example. This sequence is chosen so that
> any new entries to the cache just before it is disabled get invalidated
> as well.

This is RISC-V not armv8.
/lib/cache.c is for RISC-V generic cache implement.
/cpu/ax25/cache.c is for Andes RISC-V cache implement.

You can add a platform which is armv8 relative as below
And modify the necessary flow as you want
/cpu/armv8/cache.c

>
> /*
>  * Turn off I-cache and invalidate it
>  */
> icache_disable();
> invalidate_icache_all();
>
> /*
>  * turn off D-cache
>  * dcache_disable() in turn flushes the d-cache and disables MMU
>  */
> dcache_disable();
> invalidate_dcache_all();
>
> >
> >       return 0;
> >  }
> > diff --git a/arch/riscv/cpu/qemu/cpu.c b/arch/riscv/cpu/qemu/cpu.c
> > index 6c7a327..25d97d0 100644
> > --- a/arch/riscv/cpu/qemu/cpu.c
> > +++ b/arch/riscv/cpu/qemu/cpu.c
> > @@ -15,7 +15,7 @@ int cleanup_before_linux(void)
> >  {
> >       disable_interrupts();
> >
> > -     /* turn off I/D-cache */
> > +     cache_flush();
> >
> >       return 0;
> >  }
> > diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
> > index 331a534..0e21679 100644
> > --- a/arch/riscv/cpu/start.S
> > +++ b/arch/riscv/cpu/start.S
> > @@ -46,6 +46,10 @@ _start:
> >       /* mask all interrupts */
> >       csrw    mie, zero
> >
> > +/* Enable cache */
> > +jal  icache_enable
> > +jal  dcache_enable
> > +
>
> I think we should also define a enable_caches() function, like on ARM,
> to enable the caches. This works as well, but I think it makes sense to
> copy what other architectures do. What do you think?
>

Both coding style are exist in whole U-Boot
I can not find enable_caches be used in start.S
But it can be found
bl dcache_enable
in arch\powerpc\cpu\mpc86xx\start.S
So I prefer to not modify this flow.
Unless it indeed affect your platform and cause some error.

And I modify it as jal  icache_enable the coding flow.
It is because you do not like CONFIG_SYS_ICACHE_OFF.
It may let you make some mistakes.
So I move CONFIG_SYS_ICACHE_OFF in /cpi/ax25/cache.c


> >  /*
> >   * Set stackpointer in internal/ex RAM to call board_init_f
> >   */
> > @@ -181,6 +185,8 @@ clbss_l:
> >   * initialization, now running from RAM.
> >   */
> >  call_board_init_r:
> > +     jal     invalidate_icache_all
> > +     jal     flush_dcache_all
>
> Is this required, perhaps this should be called from
> icache/dcache_enable?

Yes. It is required.
It can not be called to icache/dcache_enable
Cache shall be inval and flush after relocation.

>
> >       la      t0, board_init_r
> >       mv      t4, t0                  /* offset of board_init_r()
> > */
> >       add     t4, t4, t6              /* real address of
> > board_init_r() */
> > diff --git a/arch/riscv/include/asm/cache.h
> > b/arch/riscv/include/asm/cache.h
> > index ca83dd6..e76ca13 100644
> > --- a/arch/riscv/include/asm/cache.h
> > +++ b/arch/riscv/include/asm/cache.h
> > @@ -7,6 +7,15 @@
> >  #ifndef _ASM_RISCV_CACHE_H
> >  #define _ASM_RISCV_CACHE_H
> >
> > +/* cache */
> > +int  icache_status(void);
> > +void icache_enable(void);
> > +void icache_disable(void);
> > +int  dcache_status(void);
> > +void dcache_enable(void);
> > +void dcache_disable(void);
>
> These are not required, include/common.h already has the function
> prototypes.
>

I will remove them from cache.h.


> > +void cache_flush(void);
> > +
> >  /*
> >   * The current upper bound for RISCV L1 data cache line sizes is 32
> > bytes.
> >   * We use that value for aligning DMA buffers unless the board
> > config has
> > diff --git a/arch/riscv/lib/cache.c b/arch/riscv/lib/cache.c
> > index d642a38..121db09 100644
> > --- a/arch/riscv/lib/cache.c
> > +++ b/arch/riscv/lib/cache.c
> > @@ -6,6 +6,15 @@
> >
> >  #include <common.h>
> >
> > +void invalidate_icache_all(void)
> > +{
> > +     asm volatile ("fence.i" ::: "memory");
> > +}
> > +
> > +void flush_dcache_all(void)
> > +{
> > +     asm volatile("fence" :::"memory");
>
> nit: there should be a space after "volatile" and ":::" to match the
> style from invalidate_icache_all :)

I will modify it.

>
> > +}
> >  void flush_dcache_range(unsigned long start, unsigned long end)
>
> Can you also implement the flush_dcache_range and flush_cache
> functions? We might run into unexpected behavior if we don't flush the
> cache here.
>

I do not modify it for the reason:
I separate one cache.c to
/lib/cache.c
/cpu/ax25/cache.c

I plan /lib/cache.c will be maintained by you
That is why I do not implement this two function.

If you said that I will implement flush_dcache_range and flush_cache in V2


> >  {
> >  }
> > @@ -19,41 +28,42 @@ void invalidate_icache_range(unsigned long start,
> > unsigned long end)
> >       invalidate_icache_all();
> >  }
> >
> > -void invalidate_icache_all(void)
> > +void invalidate_dcache_range(unsigned long start, unsigned long end)
> >  {
> > -     asm volatile ("fence.i" ::: "memory");
> >  }
> >
> > -void invalidate_dcache_range(unsigned long start, unsigned long end)
> > +void cache_flush(void)
> >  {
> > +     invalidate_icache_all();
> > +     flush_dcache_all();
> >  }
> >
> > -void flush_cache(unsigned long addr, unsigned long size)
> > +__weak void flush_cache(unsigned long addr, unsigned long size)
>
> You are not overwriting this function, so it doesn't have to be defined
> as weak.
>

Actually I will have a
flush_cache(unsigned long addr, unsigned long size)
in /cpu/ax25/cache.c in the future.

And I declare it as weak in /lib/cache.c
So next time when I send a patch
/lib/cache.c can't be modified anymore.

Maybe it is not a good idea.
I will recovery it as not weak here in V2.



> Thanks,
> Lukas
>
> >  {
> >  }
> >
> > -void icache_enable(void)
> > +__weak void icache_enable(void)
> >  {
> >  }
> >
> > -void icache_disable(void)
> > +__weak void icache_disable(void)
> >  {
> >  }
> >
> > -int icache_status(void)
> > +__weak int icache_status(void)
> >  {
> >       return 0;
> >  }
> >
> > -void dcache_enable(void)
> > +__weak void dcache_enable(void)
> >  {
> >  }
> >
> > -void dcache_disable(void)
> > +__weak void dcache_disable(void)
> >  {
> >  }
> >
> > -int dcache_status(void)
> > +__weak int dcache_status(void)
> >  {
> >       return 0;
> >  }


More information about the U-Boot mailing list