Hi Aneesh,

Le 22/12/2010 12:54, Aneesh V a écrit :
> - Add a framework for layered cache maintenance
>       - separate out SOC specific outer cache maintenance from
>         maintenance of caches known to CPU
>
> - Add generic ARMv7 cache maintenance operations that affect all
>    caches known to ARMv7 CPUs. For instance in Cortex-A8 these
>    opertions will affect both L1 and L2 caches. In Cortex-A9
>    these will affect only L1 cache
>
> - D-cache operations supported:
>       - Invalidate entire D-cache
>       - Invalidate D-cache range
>       - Flush(clean&  invalidate) entire D-cache
>       - Flush D-cache range
> - I-cache operations supported:
>       - Invalidate entire I-cache
>
> - Add maintenance functions for TLB, branch predictor array etc.
>
> - Enable -march=armv7-a so that armv7 assembly instructions can be
>    used
>
> Signed-off-by: Aneesh V<ane...@ti.com>
> ---
>   arch/arm/cpu/armv7/Makefile   |    2 +-
>   arch/arm/cpu/armv7/cache_v7.c |  359 
> +++++++++++++++++++++++++++++++++++++++++
>   arch/arm/cpu/armv7/config.mk  |    2 +-
>   arch/arm/include/asm/armv7.h  |   63 +++++++
>   include/common.h              |    5 +-
>   5 files changed, 428 insertions(+), 3 deletions(-)
>   create mode 100644 arch/arm/cpu/armv7/cache_v7.c
>   create mode 100644 arch/arm/include/asm/armv7.h
>
> diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
> index 8c0e915..299792a 100644
> --- a/arch/arm/cpu/armv7/Makefile
> +++ b/arch/arm/cpu/armv7/Makefile
> @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk
>   LIB = $(obj)lib$(CPU).o
>
>   START       := start.o
> -COBJS        := cpu.o
> +COBJS        := cpu.o cache_v7.o
>   COBJS  += syslib.o
>
>   SRCS        := $(START:.o=.S) $(COBJS:.o=.c)
> diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c
> new file mode 100644
> index 0000000..0521d66
> --- /dev/null
> +++ b/arch/arm/cpu/armv7/cache_v7.c
> @@ -0,0 +1,359 @@
> +/*
> + * (C) Copyright 2010
> + * Texas Instruments Incorporated - http://www.ti.com/
> + * Aneesh V<ane...@ti.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +#include<linux/types.h>
> +#include<common.h>
> +#include<asm/armv7.h>
> +
> +#define ARMV7_DCACHE_INVAL_ALL               1
> +#define ARMV7_DCACHE_CLEAN_INVAL_ALL 2
> +#define ARMV7_DCACHE_INVAL_RANGE     3
> +#define ARMV7_DCACHE_CLEAN_INVAL_RANGE       4
> +
> +struct v7_outer_cache_ops v7_outer_cache;
> +
> +#ifndef CONFIG_SYS_NO_DCACHE
> +/*
> + * Write the level and type you want to Cache Size Selection Register(CSSELR)
> + * to get size details from Current Cache Size ID Register(CCSIDR)
> + */
> +static void set_csselr(u32 level, u32 type)
> +{    u32 csselr = level<<  1 | type;
> +     /* Write to Cache Size Selection Register(CSSELR) */
> +     asm volatile ("mcr p15, 2, %0, c0, c0, 0" : : "r" (csselr));
> +}
> +
> +static u32 get_ccsidr(void)
> +{
> +     u32 ccsidr;
> +     /* Read current CP15 Cache Size ID Register */
> +     asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr));
> +     return ccsidr;
> +}
> +
> +static u32 get_clidr(void)
> +{
> +     u32 clidr;
> +     /* Read current CP15 Cache Level ID Register */
> +     asm volatile ("mrc p15,1,%0,c0,c0,1" : "=r" (clidr));
> +     return clidr;
> +}
> +
> +/* round up the input number to a power of 2 and get the log2 */
> +static inline u32 log_2_round_up(u32 num)
> +{
> +     /* count leading zeros */
> +     asm volatile ("CLZ %0, %0" : "+r" (num));
> +
> +     /* position of most significant 1 */
> +     num = 31 - num;
> +
> +     return num;
> +}
> +
> +static void v7_inval_dcache_level_setway(u32 level, u32 num_sets,
> +                                      u32 num_ways, u32 way_shift,
> +                                      u32 log2_line_len)
> +{
> +     int way, set, setway;
> +     /*
> +      * For optimal assembly code:
> +      *      a. count down
> +      *      b. have bigger loop inside
> +      */

Out of curiosity, can you elaborate on why the compiler would optimize 
better in these cases?

> +     for (way = num_ways - 1; way>= 0 ; way--)
> +             for (set = num_sets - 1; set>= 0; set--) {

Please fix whitespacing around operators. The best way to ''catch'em 
all'' is to run Linux' checkpatch.pl (I do this with option --no-tree) 
on all patches that you submit to u-boot and, fix all warning and errors 
and if some are left that you think should not be fixed, mention them 
and explain why they're wrongly emitted.

> +                     setway = (level<<  1) | (set<<  log2_line_len) |
> +                              (way<<  way_shift);
> +                     /* Invalidate data/unified cache line by set/way */
> +                     asm volatile (" mcr p15, 0, %0, c7, c6, 2"
> +                                     : : "r" (setway));
> +             }
> +     /* Make sure the operation is complete */
> +     asm volatile ("DMB");
> +}
> +
> +static void v7_clean_inval_dcache_level_setway(u32 level, u32 num_sets,
> +                                            u32 num_ways, u32 way_shift,
> +                                            u32 log2_line_len)
> +{
> +     int way, set, setway;
> +     /*
> +      * For optimal assembly code:
> +      *      a. count down
> +      *      b. have bigger loop inside
> +      */
> +     for (way = num_ways - 1; way>= 0 ; way--)
> +             for (set = num_sets - 1; set>= 0; set--) {
> +                     setway = (level<<  1) | (set<<  log2_line_len) |
> +                              (way<<  way_shift);
> +                     /*
> +                      * Clean&  Invalidate data/unified
> +                      * cache line by set/way
> +                      */
> +                     asm volatile (" mcr p15, 0, %0, c7, c14, 2"
> +                                     : : "r" (setway));
> +             }
> +     /* Make sure the operation is complete */
> +     asm volatile ("DMB");
> +}
> +
> +static void v7_maint_dcache_level_setway(u32 level, u32 operation)
> +{
> +     u32 ccsidr;
> +     u32 num_sets, num_ways, log2_line_len, log2_num_ways;
> +     u32 way_shift;
> +     set_csselr(level, ARMV7_CSSELR_IND_DATA_UNIFIED);
> +
> +     ccsidr = get_ccsidr();
> +
> +     log2_line_len = mask_n_get(ccsidr, 0, 2) + 2;
> +     /* Converting from words to bytes */
> +     log2_line_len += 2;
> +
> +     num_ways  = mask_n_get(ccsidr, 3, 12) + 1;
> +     num_sets  = mask_n_get(ccsidr, 13, 27) + 1;
> +     /*
> +      * According to ARMv7 ARM number of sets and number of ways need
> +      * not be a power of 2
> +      */
> +     log2_num_ways = log_2_round_up(num_ways);
> +
> +     way_shift = (32 - log2_num_ways);
> +     if (operation == ARMV7_DCACHE_INVAL_ALL)
> +             v7_inval_dcache_level_setway(level, num_sets, num_ways,
> +                                   way_shift, log2_line_len);
> +     else if (operation == ARMV7_DCACHE_CLEAN_INVAL_ALL)
> +             v7_clean_inval_dcache_level_setway(level, num_sets, num_ways,
> +                                                way_shift, log2_line_len);
> +}
> +
> +static void v7_maint_dcache_all(u32 operation)
> +{
> +     u32 level, cache_type, level_start_bit = 0;
> +
> +     u32 clidr = get_clidr();
> +
> +     for (level = 0; level<  7; level++) {
> +             cache_type = mask_n_get(clidr, level_start_bit,
> +                                     level_start_bit + 2);
> +             if ((cache_type == ARMV7_CLIDR_CTYPE_DATA_ONLY) ||
> +                 (cache_type == ARMV7_CLIDR_CTYPE_INSTRUCTION_DATA) ||
> +                 (cache_type == ARMV7_CLIDR_CTYPE_UNIFIED))
> +                     v7_maint_dcache_level_setway(level, operation);
> +             level_start_bit += 3;
> +     }
> +}
> +
> +static void v7_dcache_clean_inval_range(u32 start,
> +                                     u32 stop, u32 line_len)
> +{
> +     u32 mva;
> +     /* Align start to cache line boundary */
> +     start&= ~(line_len - 1);
> +     for (mva = start; mva<  stop; mva = mva + line_len)
> +             /* DCCIMVAC - Clean&  Invalidate data cache by MVA to PoC */
> +             asm volatile ("mcr p15, 0, %0, c7, c14, 1" : : "r" (mva));
> +}
> +
> +static void v7_dcache_inval_range(u32 start, u32 stop, u32 line_len)
> +{
> +     u32 mva;
> +
> +     /*
> +      * If start address is not aligned to cache-line flush the first
> +      * line to prevent affecting somebody else's buffer
> +      */
> +     if (start&  (line_len - 1)) {
> +             v7_dcache_clean_inval_range(start, start + 1, line_len);
> +             /* move to next cache line */
> +             start = (start + line_len - 1)&  ~(line_len - 1);
> +     }
> +
> +     /*
> +      * If stop address is not aligned to cache-line flush the last
> +      * line to prevent affecting somebody else's buffer
> +      */
> +     if (stop&  (line_len - 1)) {
> +             v7_dcache_clean_inval_range(stop, stop + 1, line_len);
> +             /* align to the beginning of this cache line */
> +             stop&= ~(line_len - 1);
> +     }
> +
> +     for (mva = start; mva<  stop; mva = mva + line_len)
> +             /* DCIMVAC - Invalidate data cache by MVA to PoC */
> +             asm volatile ("mcr p15, 0, %0, c7, c6, 1" : : "r" (mva));
> +}
> +
> +static void v7_dcache_maint_range(u32 start, u32 stop, u32 range_op)
> +{
> +     u32 line_len, ccsidr;
> +     ccsidr = get_ccsidr();
> +     line_len = mask_n_get(ccsidr, 0, 2) + 2;
> +     /* Converting from words to bytes */
> +     line_len += 2;
> +     /* converting from log2(linelen) to linelen */
> +     line_len = 1<<  line_len;
> +
> +     switch (range_op) {
> +     case ARMV7_DCACHE_CLEAN_INVAL_RANGE:
> +             v7_dcache_clean_inval_range(start, stop, line_len);
> +             break;
> +     case ARMV7_DCACHE_INVAL_RANGE:
> +             v7_dcache_inval_range(start, stop, line_len);
> +             break;
> +     }
> +
> +     /* Make sure the operation is complete */
> +     asm volatile ("DMB");
> +}
> +
> +/* Invalidate TLB */
> +static void v7_inval_tlb(void)
> +{
> +     /* Invalidate entire unified TLB */
> +     asm volatile ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0));
> +     /* Invalidate entire data TLB */
> +     asm volatile ("mcr p15, 0, %0, c8, c6, 0" : : "r" (0));
> +     /* Invalidate entire instruction TLB */
> +     asm volatile ("mcr p15, 0, %0, c8, c5, 0" : : "r" (0));
> +     /* Full system DSB - make sure that the invalidation is complete */
> +     asm volatile ("DSB");
> +     /* Full system ISB - make sure the instruction stream sees it */
> +     asm volatile ("ISB");
> +}
> +
> +void invalidate_dcache_all(void)
> +{
> +     v7_maint_dcache_all(ARMV7_DCACHE_INVAL_ALL);
> +     if (v7_outer_cache.inval_all)
> +             v7_outer_cache.inval_all();

Why use pointers here rather than weak functions?

> +}
> +
> +/*
> + * Performs a clean&  invalidation of the entire data cache
> + * at all levels
> + */
> +void flush_dcache_all(void)
> +{
> +     v7_maint_dcache_all(ARMV7_DCACHE_CLEAN_INVAL_ALL);
> +     if (v7_outer_cache.flush_all)
> +             v7_outer_cache.flush_all();
> +}
> +
> +/*
> + * Invalidates range in all levels of D-cache/unified cache used:
> + * Affects the range [start, stop - 1]
> + */
> +void invalidate_dcache_range(unsigned long start, unsigned long stop)
> +{
> +
> +     v7_dcache_maint_range(start, stop, ARMV7_DCACHE_INVAL_RANGE);
> +     if (v7_outer_cache.inval_range)
> +             /* physical address is same as virtual address */
> +             v7_outer_cache.inval_range(start, stop);
> +}
> +
> +/*
> + * Flush range(clean&  invalidate) from all levels of D-cache/unified
> + * cache used:
> + * Affects the range [start, stop - 1]
> + */
> +void flush_dcache_range(unsigned long start, unsigned long stop)
> +{
> +     v7_dcache_maint_range(start, stop, ARMV7_DCACHE_CLEAN_INVAL_RANGE);
> +     if (v7_outer_cache.flush_range)
> +             /* physical address is same as virtual address */
> +             v7_outer_cache.flush_range(start, stop);
> +}
> +static void __v7_setup_outer_cache_ops(void)
> +{
> +     puts("v7_setup_outer_cache_ops: dummy implementation! "
> +          "real implementation not available!!\n");
> +}
> +
> +void v7_setup_outer_cache_ops(void)
> +     __attribute__((weak, alias("__v7_setup_outer_cache_ops")));
> +
> +void arm_init_before_mmu(void)
> +{
> +     v7_setup_outer_cache_ops();
> +     if (v7_outer_cache.enable)
> +             v7_outer_cache.enable();
> +     invalidate_dcache_all();
> +     v7_inval_tlb();
> +}
> +#else
> +void invalidate_dcache_all(void)
> +{
> +}
> +
> +void flush_dcache_all(void)
> +{
> +}
> +
> +void invalidate_dcache_range(unsigned long start, unsigned long stop)
> +{
> +}
> +
> +void flush_dcache_range(unsigned long start, unsigned long stop)
> +{
> +}
> +
> +void arm_init_before_mmu(void)
> +{
> +}
> +#endif
> +
> +#ifndef CONFIG_SYS_NO_ICACHE
> +/* Invalidate entire I-cache and branch predictor array */
> +void invalidate_icache_all(void)
> +{
> +     /*
> +      * Invalidate all instruction caches to PoU.
> +      * Also flushes branch target cache.
> +      */
> +     asm volatile ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
> +
> +     /* Invalidate entire branch predictor array */
> +     asm volatile ("mcr p15, 0, %0, c7, c5, 6" : : "r" (0));
> +
> +     /* Full system DSB - make sure that the invalidation is complete */
> +     asm volatile ("DSB");
> +     /* Full system ISB - make sure the instruction stream sees it */
> +     asm volatile ("ISB");
> +}
> +#else
> +void invalidate_icache_all(void)
> +{
> +}
> +#endif
> +
> +/*
> + * Flush range from all levels of d-cache/unified-cache used:
> + * Affects the range [start, start + size - 1]
> + */
> +void  flush_cache(unsigned long start, unsigned long size)
> +{
> +     flush_dcache_range(start, start + size);
> +}

This function is the only one which is defined to something non-empty 
when CONFIG_SYS_NO_DCACHE is defined. Why is it not in the big #ifndef 
for dcache above ?

> diff --git a/arch/arm/cpu/armv7/config.mk b/arch/arm/cpu/armv7/config.mk
> index 49ac9c7..7f9b171 100644
> --- a/arch/arm/cpu/armv7/config.mk
> +++ b/arch/arm/cpu/armv7/config.mk
> @@ -23,7 +23,7 @@
>   PLATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-float
>
>   # Make ARMv5 to allow more compilers to work, even though its v7a.
> -PLATFORM_CPPFLAGS += -march=armv5
> +PLATFORM_CPPFLAGS += -march=armv7-a

Did you check that this does not break any board using armv7?

>   # =========================================================================
>   #
>   # Supply options according to compiler version
> diff --git a/arch/arm/include/asm/armv7.h b/arch/arm/include/asm/armv7.h
> new file mode 100644
> index 0000000..57409b6
> --- /dev/null
> +++ b/arch/arm/include/asm/armv7.h
> @@ -0,0 +1,63 @@
> +/*
> + * (C) Copyright 2010
> + * Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * Aneesh V<ane...@ti.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +#ifndef ARMV7_H
> +#define ARMV7_H
> +
> +#include<linux/types.h>
> +
> +/*
> + * Values for InD field in CSSELR
> + * Selects the type of cache
> + */
> +#define ARMV7_CSSELR_IND_DATA_UNIFIED        0
> +#define ARMV7_CSSELR_IND_INSTRUCTION 1
> +
> +/* Values for Ctype fields in CLIDR */
> +#define ARMV7_CLIDR_CTYPE_NO_CACHE           0
> +#define ARMV7_CLIDR_CTYPE_INSTRUCTION_ONLY   1
> +#define ARMV7_CLIDR_CTYPE_DATA_ONLY          2
> +#define ARMV7_CLIDR_CTYPE_INSTRUCTION_DATA   3
> +#define ARMV7_CLIDR_CTYPE_UNIFIED            4
> +
> +/* some utility macros */
> +#define mask(start, end) \
> +     (((1<<  ((end) - (start) + 1)) - 1)<<  (start))
> +
> +#define mask_n_get(reg, start, end) \
> +     (((reg)&  mask(start, end))>>  (start))

Seeing as these functions are only used in the ARMv7 cache C file, they 
should be moved there.

> +struct v7_outer_cache_ops {
> +     void (*enable)(void);
> +     void (*disable)(void);
> +     void (*flush_all)(void);
> +     void (*inval_all)(void);
> +     void (*flush_range)(u32 start, u32 end);
> +     void (*inval_range)(u32 start, u32 end);
> +};
> +
> +extern struct v7_outer_cache_ops v7_outer_cache;
> +
> +void v7_setup_outer_cache_ops(void);
> +#endif
> diff --git a/include/common.h b/include/common.h
> index 189ad81..d750ff9 100644
> --- a/include/common.h
> +++ b/include/common.h
> @@ -411,6 +411,7 @@ void      icache_disable(void);
>   int dcache_status (void);
>   void        dcache_enable (void);
>   void        dcache_disable(void);
> +void mmu_disable(void);
>   void        relocate_code (ulong, gd_t *, ulong) __attribute__ ((noreturn));
>   ulong       get_endaddr   (void);
>   void        trap_init     (ulong);
> @@ -603,9 +604,11 @@ ulong    video_setmem (ulong);
>
>   /* arch/$(ARCH)/lib/cache.c */
>   void        flush_cache   (unsigned long, unsigned long);
> +void flush_dcache_all(void);
>   void        flush_dcache_range(unsigned long start, unsigned long stop);
>   void        invalidate_dcache_range(unsigned long start, unsigned long 
> stop);
> -
> +void invalidate_dcache_all(void);
> +void invalidate_icache_all(void);
>
>   /* arch/$(ARCH)/lib/ticks.S */
>   unsigned long long get_ticks(void);

Amicalement,
-- 
Albert.
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to