We encounter an issue about ARM generic timer back-off.
Test sequence:
Pseudo-code:
Core0
Core1/2/3
While(1) {
1. dsb
2. core0_ticks = read timer counter(CNTPCT)
}
While (1) {
2. tmp_tcicks = core0_ticks
3. dsb
4. corex_ticks = read timer counter(CNTPCT)
5. if (corex_ticks < tmp_ticks), then return error }
Error message:
core1_ticks[28b9d8f7] < core0_ticks[28b9d8f8]
core3_ticks[28b9dc58] < core0_ticks[28b9dc59]
core1_ticks[28bb6a38] < core0_ticks[28bb6a3b]
core3_ticks[28bcf400] < core0_ticks[28bcf401]
core1_ticks[28be89bd] < core0_ticks[28be89c0]
core3_ticks[28c01b51] < core0_ticks[28c01b54]
Questions:
Is this a common issue about ARM generic timer counter?
Or could you give some advice about the integration for ARM generic timer?
Or We have to do some additional configuration for ARM generic timer??
PS:
We also found that in Linux Kernel and U-boot, this issue existed in some other SoC, too. The following patch is from LS1043A form NXP and Hikey960 from Hisilicon.
/*
* FSL erratum A-008585 says that the ARM generic timer counter "has the
* potential to contain an erroneous value for a small number of core
* clock cycles every time the timer value changes".
* This sometimes leads to a consecutive counter read returning a lower
* value than the previous one, thus reporting the time to go backwards.
* The workaround is to read the counter twice and only return when the value
* was the same in both reads.
* Assumes that the CPU runs in much higher frequency than the timer.
*/
Erratum Hisilicon-161010101 says that the ARM generic timer counter "has
the potential to contain an erroneous value when the timer value
changes". Accesses to TVAL (both read and write) are also affected due
to the implicit counter read. Accesses to CVAL are not affected.
The workaround is to reread the system count registers until the value
of the second read is larger than the first one by less than 32, the
system counter can be guaranteed not to return wrong value twice by
back-to-back read and the error value is always larger than the correct
one by 32. Writes to TVAL are replaced with an equivalent write to CVAL.
Based on your original description, you hope Core-0 to read core0_ticks first. After core0_ticks is read, Core-1/2/3 can start their operations.
But it seems that your core-1/2/3 has no dependency for Core-0 core0_ticks result.
How about this test pseudo code ( if I understand your expectation correctly):
flag = -1
Core-0:
if flag == 1
core0_ticks = read timer counter(CNTPCT)
flag = 0
dsb // add this dsb
else wait
if flag == 0
tmp_tcicks = core0_ticks
flag = 1
dsb
corex_ticks = read timer counter(CNTPCT)
if (corex_ticks < tmp_ticks), then return error
else:
wait}