Other Parts Discussed in Thread: SYSBIOS, 66AK2H14
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?