[U-Boot] [PATCH 2/8] armv7: cache maintenance operations for armv7

Aneesh V
2011-01-08T10:06:53Z

Hi Albert,

On Saturday 08 January 2011 12:06 PM, Albert ARIBAUD wrote:
> 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<aneesh@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<aneesh@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?

While counting down the termination condition check is against 0. So
you can just decrement the loop count using a 'subs' and do a 'bne'.
When you count up you have to do a comparison with a non-zero value. So
you will need one 'cmp' instruction extra:-)

bigger loop inside because that reduces the frequency at which your
outer parameter changes and hence the overall number of instructions
executed. Consider this:
1. We encode both the loop counts along with other data into a register
that is finally written to CP15 register.
2. outer loop has the code for shifting and ORing the outer variable to
this register.
3. Inner loop has the code for shifting and ORing the inner variable.
Step (3) has to be executed 'way x set' number of times anyways.
But having bigger loop inside makes sure that 2 is executed fewer times!

With these tweaks the assembly code generated by this C code is as good
as the original hand-written assembly code with my compiler.

>
>> + 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.

I religiously do checkpatch whenever I send out a patch. Please note
that my original mail seems to be fine. I saved it and ran checkpatch
again. No errors, no warnings! Something amiss?

Best regards,
Aneesh