With SYS/BIOS 6.45.1.29 was attempting to call the ti.sysbios.family.arm.a15.Cache Cache_inv and Cache_wb functions for a Cortex-A15 in a 66AK2H14 to operate on the upper 2Gbytes of the virtual address space using the following parameters :
Cache_inv (0x80000000, 0x80000000, Cache_Type_ALL, TRUE); Cache_wb (0x80000000, 0x80000000, Cache_Type_ALL, TRUE);
As part of the test program, the Cortex-A15 PMU counters were configured to measure the cache operation events around calls to the Cache_inv and Cache_wb functions:
- 0x46 : Level 1 data cache Write-Back - Victim
- 0x47 : Level 1 data cache Write-Back - Cleaning and coherency
- 0x48 : Level 1 data cache invalidate
- 0x56 : Level 2 data cache Write-Back - Victim
- 0x57 : Level 2 data cache Write-Back - Cleaning and coherency
- 0x58 : Level 2 data cache invalidate
However, when the Cache_wb and Cache_inv arguments were set to blockPtr = 0x80000000 and byteCnt = 0x80000000 the PMU counters showed that only one cache line was operated on. Single stepping into the Cache_wb and Cache_inv functions confirmed that with blockPtr = 0x80000000 and byteCnt = 0x80000000 only a single cache line was being operated on. The Cache_wb and Cache_inv functions end up calling the ti_sysbios_family_arm_a15_Cache_wb__E and ti_sysbios_family_arm_a15_Cache_invL1d__I assembler routines with the following loop structure:
@ @ ======== Cache_wb ======== @ Writes back the range of MVA in data cache. First, wait on any previous cache @ operation. @ @ Cache_wb(Ptr blockPtr, SizeT byteCnt, Type type, Bool wait) @ @ r0 - contains blockPtr @ r1 - contains byteCnt @ r2 - contains bit mask of cache type (unused) @ r3 - contains wait @ .text SMP_ASM(.func ti_sysbios_family_arm_a15_smp_Cache_wb__E) UP_ASM(.func ti_sysbios_family_arm_a15_Cache_wb__E) SMP_ASM(ti_sysbios_family_arm_a15_smp_Cache_wb__E:) UP_ASM(ti_sysbios_family_arm_a15_Cache_wb__E:) add r1, r0, r1 @ calculate last address bic r0, r0, #Cache_sizeL1dCacheLine - 1 @ align address to cache line 1: mcr p15, #0, r0, c7, c10, #1 @ write back a cache line add r0, r0, #Cache_sizeL1dCacheLine @ increment address by cache line size cmp r0, r1 @ compare to last address blo 1b @ loop if count > 0 tst r3, #0x1 @ check if wait param is TRUE beq 2f dsb @ drain write buffer 2: bx lr .endfunc
@ @ ======== Cache_invL1d ======== @ Invalidates a range of MVA (modified virtual addresses) in the L1 data cache @ Cache_invL1d(Ptr blockPtr, SizeT byteCnt, Bool wait) @ @ r0 - contains blockPtr @ r1 - contains byteCnt @ r2 - contains wait @ .text SMP_ASM(.func ti_sysbios_family_arm_a15_smp_Cache_invL1d__I) UP_ASM(.func ti_sysbios_family_arm_a15_Cache_invL1d__I) SMP_ASM(ti_sysbios_family_arm_a15_smp_Cache_invL1d__I:) UP_ASM(ti_sysbios_family_arm_a15_Cache_invL1d__I:) add r1, r0, r1 @ calculate last address bic r0, r0, #Cache_sizeL1dCacheLine - 1 @ align blockPtr to cache line 1: mcr p15, #0, r0, c7, c6, #1 @ invalidate single entry in DCache add r0, r0, #Cache_sizeL1dCacheLine @ increment address by cache line size cmp r0, r1 @ compare to last address blo 1b @ loop if > 0 tst r2, #0x1 @ check if wait param is TRUE beq 2f dsb @ drain write buffer 2: bx lr @ return .endfunc
The problem is that the loops in the assembler routines calculate the end address as zero when blockPtr = 0x80000000 and byteCnt = 0x80000000, leading to only one cache line being operated on.
Initially attempted to work-around the problem by setting the byteCnt argument to one byte less. However, a Data Abort due to a Translation Fault occurred when the assembler routines then attempted to perform a cache operation on address zero:
Cache_inv (0x80000000, 0x7FFFFFFF, Cache_Type_ALL, TRUE); Cache_wb (0x80000000, 0x7FFFFFFF, Cache_Type_ALL, TRUE);
The work-around which ended up using was making two calls to the Cache_inv and Cache_wb functions, the first performed operations on all but the final cache line and then a second which operated only on the last cache line:
Cache_inv (0x80000000, 0x7FFFFFC0, Cache_Type_ALL, TRUE); Cache_inv (0xFFFFFFC0, 0x40, Cache_Type_ALL, TRUE); Cache_wb (0x80000000, 0x7FFFFFC0, Cache_Type_ALL, TRUE); Cache_wb (0xFFFFFFC0, 0x40, Cache_Type_ALL, TRUE);
Is it a bug that Cache_inv and Cache_wb only operate on one cache line when called with blockPtr = 0x80000000 and byteCnt = 0x80000000?