Some notes about get_cntxct_a64_unstable: looks like the masks should be 0x3FF.

Mark Millard marklmi at yahoo.com
Fri May 17 19:20:40 UTC 2019


Head -r335156 added the following (later sidestepped
for one use by not using CNTPCT_EL0 or CNTVCT_EL0
for the timecounter, as I understand):

static uint64_t
get_cntxct_a64_unstable(bool physical)
{
	uint64_t val
;
	isb();
	if (physical) {
		do {
			val = get_el0(cntpct);
		}
		while (((val + 1) & 0x7FF) <= 1);
	}
	else {
		do {
			val = get_el0(cntvct);
		}
		while (((val + 1) & 0x7FF) <= 1);
	}

	return (val);
}

(This code and a reference to it in arm_tmr_attach still
exist in sys/arm/arm/generic_timer.c .)

An extreme example listed in https://patchwork.kernel.org/patch/10761197/
for observed readback errors was the sequence was:

   0x0000007fffffffff
-> 0x00000093feffffff
-> 0x0000008000000000
. . .

While no examples of the smallest-odd-values observed
for a sequencing error are listed there, the code in
the involved patch uses the mask 0x3ff [bits 9 through
0 as GENMASK(9,0)] instead of 0x7ff:

while (((_val + 1) & GENMASK(9, 0)) <= 1 && _retries)

This matches up with some of the description's wording:

QUOTE
the low 10 bits checked
by the function in this patch have never been observed with any other
value.
. . .
since there is a distinct pattern to the bad values, we can
optimize the common case (1022/1024 of the time) to a single read by
simply ignoring values that match the error pattern.
END QUOTE

(good vs. bad value counts are after masking:)
((val + 1) & 0x7FF) <= 1 would be: 2046 of 2048 good values, 2 bad
((val + 1) & 0x3FF) <= 1 would be: 1022 of 1024 good values, 2 bad

So I expect that the masks in get_cntxct_a64_unstable should be
adjusted to be 0x3FF if the routine is not strictly dead-code.


===
Mark Millard
marklmi at yahoo.com
( dsl-only.net went
away in early 2018-Mar)



More information about the freebsd-arm mailing list