124640f23SVincenzo Frascino /* 224640f23SVincenzo Frascino * Copyright (C) 2018 ARM Limited 324640f23SVincenzo Frascino * Copyright (C) 2015 Imagination Technologies 424640f23SVincenzo Frascino * Author: Alex Smith <alex.smith@imgtec.com> 524640f23SVincenzo Frascino * 624640f23SVincenzo Frascino * This program is free software; you can redistribute it and/or modify it 724640f23SVincenzo Frascino * under the terms of the GNU General Public License as published by the 824640f23SVincenzo Frascino * Free Software Foundation; either version 2 of the License, or (at your 924640f23SVincenzo Frascino * option) any later version. 1024640f23SVincenzo Frascino */ 1124640f23SVincenzo Frascino #ifndef __ASM_VDSO_GETTIMEOFDAY_H 1224640f23SVincenzo Frascino #define __ASM_VDSO_GETTIMEOFDAY_H 1324640f23SVincenzo Frascino 1424640f23SVincenzo Frascino #ifndef __ASSEMBLY__ 1524640f23SVincenzo Frascino 1624640f23SVincenzo Frascino #include <asm/vdso/vdso.h> 1724640f23SVincenzo Frascino #include <asm/clocksource.h> 1824640f23SVincenzo Frascino #include <asm/unistd.h> 1924640f23SVincenzo Frascino #include <asm/vdso.h> 2024640f23SVincenzo Frascino 21abed3d82SVincenzo Frascino #define VDSO_HAS_CLOCK_GETRES 1 22abed3d82SVincenzo Frascino 2324640f23SVincenzo Frascino static __always_inline long gettimeofday_fallback( 2424640f23SVincenzo Frascino struct __kernel_old_timeval *_tv, 2524640f23SVincenzo Frascino struct timezone *_tz) 2624640f23SVincenzo Frascino { 2724640f23SVincenzo Frascino register struct timezone *tz asm("a1") = _tz; 2824640f23SVincenzo Frascino register struct __kernel_old_timeval *tv asm("a0") = _tv; 2924640f23SVincenzo Frascino register long ret asm("v0"); 3024640f23SVincenzo Frascino register long nr asm("v0") = __NR_gettimeofday; 3124640f23SVincenzo Frascino register long error asm("a3"); 3224640f23SVincenzo Frascino 3324640f23SVincenzo Frascino asm volatile( 3424640f23SVincenzo Frascino " syscall\n" 3524640f23SVincenzo Frascino : "=r" (ret), "=r" (error) 3624640f23SVincenzo Frascino : "r" (tv), "r" (tz), "r" (nr) 3724640f23SVincenzo Frascino : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 3824640f23SVincenzo Frascino "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 3924640f23SVincenzo Frascino 4024640f23SVincenzo Frascino return error ? -ret : ret; 4124640f23SVincenzo Frascino } 4224640f23SVincenzo Frascino 4324640f23SVincenzo Frascino static __always_inline long clock_gettime_fallback( 4424640f23SVincenzo Frascino clockid_t _clkid, 4524640f23SVincenzo Frascino struct __kernel_timespec *_ts) 4624640f23SVincenzo Frascino { 4724640f23SVincenzo Frascino register struct __kernel_timespec *ts asm("a1") = _ts; 4824640f23SVincenzo Frascino register clockid_t clkid asm("a0") = _clkid; 4924640f23SVincenzo Frascino register long ret asm("v0"); 5024640f23SVincenzo Frascino #if _MIPS_SIM == _MIPS_SIM_ABI64 5124640f23SVincenzo Frascino register long nr asm("v0") = __NR_clock_gettime; 5224640f23SVincenzo Frascino #else 5324640f23SVincenzo Frascino register long nr asm("v0") = __NR_clock_gettime64; 5424640f23SVincenzo Frascino #endif 5524640f23SVincenzo Frascino register long error asm("a3"); 5624640f23SVincenzo Frascino 5724640f23SVincenzo Frascino asm volatile( 5824640f23SVincenzo Frascino " syscall\n" 5924640f23SVincenzo Frascino : "=r" (ret), "=r" (error) 6024640f23SVincenzo Frascino : "r" (clkid), "r" (ts), "r" (nr) 6124640f23SVincenzo Frascino : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 6224640f23SVincenzo Frascino "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 6324640f23SVincenzo Frascino 6424640f23SVincenzo Frascino return error ? -ret : ret; 6524640f23SVincenzo Frascino } 6624640f23SVincenzo Frascino 67abed3d82SVincenzo Frascino static __always_inline int clock_getres_fallback( 68abed3d82SVincenzo Frascino clockid_t _clkid, 69abed3d82SVincenzo Frascino struct __kernel_timespec *_ts) 70abed3d82SVincenzo Frascino { 71abed3d82SVincenzo Frascino register struct __kernel_timespec *ts asm("a1") = _ts; 72abed3d82SVincenzo Frascino register clockid_t clkid asm("a0") = _clkid; 73abed3d82SVincenzo Frascino register long ret asm("v0"); 74abed3d82SVincenzo Frascino #if _MIPS_SIM == _MIPS_SIM_ABI64 75abed3d82SVincenzo Frascino register long nr asm("v0") = __NR_clock_getres; 76abed3d82SVincenzo Frascino #else 77abed3d82SVincenzo Frascino register long nr asm("v0") = __NR_clock_getres_time64; 78abed3d82SVincenzo Frascino #endif 79abed3d82SVincenzo Frascino register long error asm("a3"); 80abed3d82SVincenzo Frascino 81abed3d82SVincenzo Frascino asm volatile( 82abed3d82SVincenzo Frascino " syscall\n" 83abed3d82SVincenzo Frascino : "=r" (ret), "=r" (error) 84abed3d82SVincenzo Frascino : "r" (clkid), "r" (ts), "r" (nr) 85abed3d82SVincenzo Frascino : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 86abed3d82SVincenzo Frascino "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 87abed3d82SVincenzo Frascino 88abed3d82SVincenzo Frascino return error ? -ret : ret; 89abed3d82SVincenzo Frascino } 90abed3d82SVincenzo Frascino 91932bb934SVincenzo Frascino #if _MIPS_SIM != _MIPS_SIM_ABI64 92932bb934SVincenzo Frascino 93932bb934SVincenzo Frascino static __always_inline long clock_gettime32_fallback( 94932bb934SVincenzo Frascino clockid_t _clkid, 95932bb934SVincenzo Frascino struct old_timespec32 *_ts) 96932bb934SVincenzo Frascino { 97932bb934SVincenzo Frascino register struct old_timespec32 *ts asm("a1") = _ts; 98932bb934SVincenzo Frascino register clockid_t clkid asm("a0") = _clkid; 99932bb934SVincenzo Frascino register long ret asm("v0"); 100932bb934SVincenzo Frascino register long nr asm("v0") = __NR_clock_gettime; 101932bb934SVincenzo Frascino register long error asm("a3"); 102932bb934SVincenzo Frascino 103932bb934SVincenzo Frascino asm volatile( 104932bb934SVincenzo Frascino " syscall\n" 105932bb934SVincenzo Frascino : "=r" (ret), "=r" (error) 106932bb934SVincenzo Frascino : "r" (clkid), "r" (ts), "r" (nr) 107932bb934SVincenzo Frascino : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 108932bb934SVincenzo Frascino "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 109932bb934SVincenzo Frascino 110932bb934SVincenzo Frascino return error ? -ret : ret; 111932bb934SVincenzo Frascino } 112932bb934SVincenzo Frascino 113932bb934SVincenzo Frascino static __always_inline int clock_getres32_fallback( 114932bb934SVincenzo Frascino clockid_t _clkid, 115932bb934SVincenzo Frascino struct old_timespec32 *_ts) 116932bb934SVincenzo Frascino { 117932bb934SVincenzo Frascino register struct old_timespec32 *ts asm("a1") = _ts; 118932bb934SVincenzo Frascino register clockid_t clkid asm("a0") = _clkid; 119932bb934SVincenzo Frascino register long ret asm("v0"); 120932bb934SVincenzo Frascino register long nr asm("v0") = __NR_clock_getres; 121932bb934SVincenzo Frascino register long error asm("a3"); 122932bb934SVincenzo Frascino 123932bb934SVincenzo Frascino asm volatile( 124932bb934SVincenzo Frascino " syscall\n" 125932bb934SVincenzo Frascino : "=r" (ret), "=r" (error) 126932bb934SVincenzo Frascino : "r" (clkid), "r" (ts), "r" (nr) 127932bb934SVincenzo Frascino : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 128932bb934SVincenzo Frascino "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 129932bb934SVincenzo Frascino 130932bb934SVincenzo Frascino return error ? -ret : ret; 131932bb934SVincenzo Frascino } 132932bb934SVincenzo Frascino #endif 133932bb934SVincenzo Frascino 13424640f23SVincenzo Frascino #ifdef CONFIG_CSRC_R4K 13524640f23SVincenzo Frascino 13624640f23SVincenzo Frascino static __always_inline u64 read_r4k_count(void) 13724640f23SVincenzo Frascino { 13824640f23SVincenzo Frascino unsigned int count; 13924640f23SVincenzo Frascino 14024640f23SVincenzo Frascino __asm__ __volatile__( 14124640f23SVincenzo Frascino " .set push\n" 14224640f23SVincenzo Frascino " .set mips32r2\n" 14324640f23SVincenzo Frascino " rdhwr %0, $2\n" 14424640f23SVincenzo Frascino " .set pop\n" 14524640f23SVincenzo Frascino : "=r" (count)); 14624640f23SVincenzo Frascino 14724640f23SVincenzo Frascino return count; 14824640f23SVincenzo Frascino } 14924640f23SVincenzo Frascino 15024640f23SVincenzo Frascino #endif 15124640f23SVincenzo Frascino 15224640f23SVincenzo Frascino #ifdef CONFIG_CLKSRC_MIPS_GIC 15324640f23SVincenzo Frascino 15424640f23SVincenzo Frascino static __always_inline u64 read_gic_count(const struct vdso_data *data) 15524640f23SVincenzo Frascino { 15624640f23SVincenzo Frascino void __iomem *gic = get_gic(data); 15724640f23SVincenzo Frascino u32 hi, hi2, lo; 15824640f23SVincenzo Frascino 15924640f23SVincenzo Frascino do { 16024640f23SVincenzo Frascino hi = __raw_readl(gic + sizeof(lo)); 16124640f23SVincenzo Frascino lo = __raw_readl(gic); 16224640f23SVincenzo Frascino hi2 = __raw_readl(gic + sizeof(lo)); 16324640f23SVincenzo Frascino } while (hi2 != hi); 16424640f23SVincenzo Frascino 16524640f23SVincenzo Frascino return (((u64)hi) << 32) + lo; 16624640f23SVincenzo Frascino } 16724640f23SVincenzo Frascino 16824640f23SVincenzo Frascino #endif 16924640f23SVincenzo Frascino 170*4c5a116aSThomas Gleixner static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, 171*4c5a116aSThomas Gleixner const struct vdso_data *vd) 17224640f23SVincenzo Frascino { 17324640f23SVincenzo Frascino #ifdef CONFIG_CSRC_R4K 174e1bdb22eSThomas Gleixner if (clock_mode == VDSO_CLOCKMODE_R4K) 175e1bdb22eSThomas Gleixner return read_r4k_count(); 17624640f23SVincenzo Frascino #endif 17724640f23SVincenzo Frascino #ifdef CONFIG_CLKSRC_MIPS_GIC 178e1bdb22eSThomas Gleixner if (clock_mode == VDSO_CLOCKMODE_GIC) 179*4c5a116aSThomas Gleixner return read_gic_count(vd); 18024640f23SVincenzo Frascino #endif 181e1bdb22eSThomas Gleixner /* 182e1bdb22eSThomas Gleixner * Core checks mode already. So this raced against a concurrent 183e1bdb22eSThomas Gleixner * update. Return something. Core will do another round see the 184e1bdb22eSThomas Gleixner * change and fallback to syscall. 185e1bdb22eSThomas Gleixner */ 186e1bdb22eSThomas Gleixner return 0; 18724640f23SVincenzo Frascino } 18824640f23SVincenzo Frascino 18925a2a656SThomas Gleixner static inline bool mips_vdso_hres_capable(void) 19025a2a656SThomas Gleixner { 19125a2a656SThomas Gleixner return IS_ENABLED(CONFIG_CSRC_R4K) || 19225a2a656SThomas Gleixner IS_ENABLED(CONFIG_CLKSRC_MIPS_GIC); 19325a2a656SThomas Gleixner } 19425a2a656SThomas Gleixner #define __arch_vdso_hres_capable mips_vdso_hres_capable 19525a2a656SThomas Gleixner 19624640f23SVincenzo Frascino static __always_inline const struct vdso_data *__arch_get_vdso_data(void) 19724640f23SVincenzo Frascino { 19824640f23SVincenzo Frascino return get_vdso_data(); 19924640f23SVincenzo Frascino } 20024640f23SVincenzo Frascino 20124640f23SVincenzo Frascino #endif /* !__ASSEMBLY__ */ 20224640f23SVincenzo Frascino 20324640f23SVincenzo Frascino #endif /* __ASM_VDSO_GETTIMEOFDAY_H */ 204