32-bit powerpc vs. 64-bit FreeBDS powermac_smp_timebase_sync and mttb: sets upper part to zero vs. not
Mark Millard
marklmi at yahoo.com
Wed Apr 17 23:18:15 UTC 2019
[In exploring why there is the time problems that lead to
sleep-gets-stuck, I ran into the below. It seems odd but
I've not found it tied to the failures.]
Both 32-bit and 64-bit PowerPC have a 64-bit Time Base Register.
But how it is used is an odd mix above mttb(time) for how the TBR
register is set for 32-bit powerpc vs. powerpc64 FreeBSD. (32-bit
FreeBSD runs on some powerpc64 hardware, as well.)
32-bit powerpc FreeBSD uses types u_long and u_int in some places,
both 32-bits in that context:
typedef u_int timecounter_get_t(struct timecounter *)
powermac_smp_timebase_sync(platform_t plat, u_long tb, int ap)
That last even leads to the high 32-bits bits being set to zero
explicitly. (Shown later.)
64-bit powerpc does not do that last part: u_long is 64-bits
64-bit powerpc does truncate for timecounter_get_t: u_int is 32
bits for powerpc64.
The code:
static __inline void
mttb(u_quad_t time)
{
mtspr(TBR_TBWL, 0);
mtspr(TBR_TBWU, (uint32_t)(time >> 32));
mtspr(TBR_TBWL, (uint32_t)(time & 0xffffffff));
}
is used in powermac_smp_timebase_sync (which is bound to
platform_smp_timebase_sync for the context):
static void
powermac_smp_timebase_sync(platform_t plat, u_long tb, int ap)
{
mttb(tb);
}
32-bit powerpc: necessarily (time >> 32) == 0u because of the "u_long tb".
64-bit powerpc: not necessarily, u_long tb holds 64 bits.
The details for 32-bit powerpc FreeBSD are:
<powermac_smp_timebase_sync> stwu r1,-32(r1)
<powermac_smp_timebase_sync+0x4> stw r31,24(r1)
<powermac_smp_timebase_sync+0x8> mr r31,r1
<powermac_smp_timebase_sync+0xc> li r0,0
<powermac_smp_timebase_sync+0x10> mtsprg 4,r0
<powermac_smp_timebase_sync+0x14> li r9,0
<powermac_smp_timebase_sync+0x18> mtsprg 5,r9
<powermac_smp_timebase_sync+0x1c> mtsprg 4,r4
<powermac_smp_timebase_sync+0x20> lwz r11,0(r1)
<powermac_smp_timebase_sync+0x24> lwz r31,-8(r11)
<powermac_smp_timebase_sync+0x28> mr r1,r11
<powermac_smp_timebase_sync+0x2c> blr
which sets the upper 32 bits of the tbr to zero via
"mtsprg 5,r9", where previously "li r9,0".
But some parts of the code are u_quad_t based, with
platform_smp_timebase_sync use implicitly truncating:
(Note: mftb returns u_quad_t but timecounter_get_t
based access is truncated.)
volatile static u_quad_t ap_timebase;
. . .
platform_smp_timebase_sync(ap_timebase, 1); SO: truncated on 32-bit powerpc FreeBSD only
. . .
ap_timebase = mftb() + 10; SO: not truncating here.
. . .
platform_smp_timebase_sync(ap_timebase, 0); SO: 32-bit powerpc FreeBSD only: truncating
static u_quad_t timebase = 0;
. . .
timebase = mftb(); SO: not truncating here.
. . .
platform_smp_timebase_sync(timebase, 0); SO: 32-bit powerpc FreeBSD only: truncating
u_quad_t tb, ttb; NOTE: The code below is never-32-bit-truncating.
. . .
tb = mftb();
ttb = tb + howmany((uint64_t)n * 1000000, ps_per_tick);
while (tb < ttb)
tb = mftb();
I'm unclear on why ap_timebase and timebase above are
u_quad_t instead of u_long, given the intended use with
platform_smp_timebase_sync . Debugging ability to see
more?
Note: there is a:
/usr/src/sys/powerpc/aim/mp_cpudep.c: platform_smp_timebase_sync(0, 1);
but for both 32-bit powerpc FreeBSD and powerpc64 FreeBSD that sets
the TBR to zero for all 64 bits. (Removal of this on at least 32-bit
powerpc FreeBSD causes problems with wider TBR disagreements across
cpus.)
===
Mark Millard
marklmi at yahoo.com
( dsl-only.net went
away in early 2018-Mar)
More information about the freebsd-ppc
mailing list