Skip to content

Commit 2f83fca

Browse files
Rongronggg9Fearyncess
authored andcommitted
AOSCOS: MIPS: Loongson: Prevent o32 vDSO from using constant timer
HWR $30 (Loongson64 constant timer) is 64 bits wide. However, some hardware doesn't properly sign-extend its value before copying it into a GPR in o32 mode (Status.UX==1). This "shadow" on the higher half breaks most subsequent instructions relying on the GPR. Aside from the HW bug, it is never possible to retrieve the higher half of the constant timer in o32 mode, which implies that the masks of timer cycles differentiate in o32 versus n32/n64 modes. Considering that a clocksource can only have a single mask, we are unable to make the o32 vDSO parse the timer delta properly anyway. Moreover, the timer frequency is simply too high that 32-bit timer cycles wrap crazily -- it's fundamentally unreliable without the higher half. Fix this by preventing o32 vDSO from using the constant timer. Fixes: "AOSCOS: MIPS: Loongson: Add constant timer support" Signed-off-by: Rong Zhang <i@rong.moe>
1 parent f803fa8 commit 2f83fca

1 file changed

Lines changed: 33 additions & 1 deletion

File tree

arch/mips/include/asm/vdso/gettimeofday.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,42 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
225225
static inline bool mips_vdso_hres_capable(void)
226226
{
227227
return IS_ENABLED(CONFIG_CSRC_R4K) ||
228-
IS_ENABLED(CONFIG_CLKSRC_MIPS_GIC);
228+
IS_ENABLED(CONFIG_CLKSRC_MIPS_GIC) ||
229+
IS_ENABLED(CONFIG_CPU_LOONGSON64);
229230
}
230231
#define __arch_vdso_hres_capable mips_vdso_hres_capable
231232

233+
/*
234+
* HWR $30 (Loongson64 constant timer) is 64 bits wide. However, some hardware
235+
* doesn't properly sign-extend its value before copying it into a GPR in o32
236+
* mode (Status.UX==1). This "shadow" on the higher half breaks most subsequent
237+
* instructions relying on the GPR.
238+
*
239+
* Aside from the HW bug, it is never possible to retrieve the higher half of
240+
* the constant timer in o32 mode, which implies that the masks of timer cycles
241+
* differentiate in o32 versus n32/n64 modes. Considering that a clocksource can
242+
* only have a single mask, we are unable to make the o32 vDSO parse the timer
243+
* delta properly anyway.
244+
*
245+
* Moreover, the timer frequency is simply too high that 32-bit timer cycles
246+
* wrap crazily -- it's fundamentally unreliable without the higher half.
247+
*
248+
* Let's prevent o32 vDSO from using the constant timer.
249+
*
250+
* Note: the likely() here is to prevent GCC from emitting calls to libgcc.
251+
* Despite that, the hint itself also tells the truth.
252+
*/
253+
#if defined(CONFIG_CPU_LOONGSON64) && _MIPS_SIM == _MIPS_SIM_ABI32
254+
255+
static inline bool mips_vdso_clocksource_ok(const struct vdso_clock *vc)
256+
{
257+
return (likely(vc->clock_mode != VDSO_CLOCKMODE_NONE) &&
258+
vc->clock_mode != VDSO_CLOCKMODE_CONST);
259+
}
260+
#define vdso_clocksource_ok mips_vdso_clocksource_ok
261+
262+
#endif /* defined(CONFIG_CPU_LOONGSON64) && _MIPS_SIM == _MIPS_SIM_ABI32 */
263+
232264
static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void)
233265
{
234266
return get_vdso_time_data();

0 commit comments

Comments
 (0)