18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2018 ARM Limited 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Imagination Technologies 48c2ecf20Sopenharmony_ci * Author: Alex Smith <alex.smith@imgtec.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License as published by the 88c2ecf20Sopenharmony_ci * Free Software Foundation; either version 2 of the License, or (at your 98c2ecf20Sopenharmony_ci * option) any later version. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#ifndef __ASM_VDSO_GETTIMEOFDAY_H 128c2ecf20Sopenharmony_ci#define __ASM_VDSO_GETTIMEOFDAY_H 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <asm/vdso/vdso.h> 178c2ecf20Sopenharmony_ci#include <asm/clocksource.h> 188c2ecf20Sopenharmony_ci#include <asm/unistd.h> 198c2ecf20Sopenharmony_ci#include <asm/vdso.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define VDSO_HAS_CLOCK_GETRES 1 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#if MIPS_ISA_REV < 6 248c2ecf20Sopenharmony_ci#define VDSO_SYSCALL_CLOBBERS "hi", "lo", 258c2ecf20Sopenharmony_ci#else 268c2ecf20Sopenharmony_ci#define VDSO_SYSCALL_CLOBBERS 278c2ecf20Sopenharmony_ci#endif 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic __always_inline long gettimeofday_fallback( 308c2ecf20Sopenharmony_ci struct __kernel_old_timeval *_tv, 318c2ecf20Sopenharmony_ci struct timezone *_tz) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci register struct timezone *tz asm("a1") = _tz; 348c2ecf20Sopenharmony_ci register struct __kernel_old_timeval *tv asm("a0") = _tv; 358c2ecf20Sopenharmony_ci register long ret asm("v0"); 368c2ecf20Sopenharmony_ci register long nr asm("v0") = __NR_gettimeofday; 378c2ecf20Sopenharmony_ci register long error asm("a3"); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci asm volatile( 408c2ecf20Sopenharmony_ci " syscall\n" 418c2ecf20Sopenharmony_ci : "=r" (ret), "=r" (error) 428c2ecf20Sopenharmony_ci : "r" (tv), "r" (tz), "r" (nr) 438c2ecf20Sopenharmony_ci : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 448c2ecf20Sopenharmony_ci "$14", "$15", "$24", "$25", 458c2ecf20Sopenharmony_ci VDSO_SYSCALL_CLOBBERS 468c2ecf20Sopenharmony_ci "memory"); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci return error ? -ret : ret; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic __always_inline long clock_gettime_fallback( 528c2ecf20Sopenharmony_ci clockid_t _clkid, 538c2ecf20Sopenharmony_ci struct __kernel_timespec *_ts) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci register struct __kernel_timespec *ts asm("a1") = _ts; 568c2ecf20Sopenharmony_ci register clockid_t clkid asm("a0") = _clkid; 578c2ecf20Sopenharmony_ci register long ret asm("v0"); 588c2ecf20Sopenharmony_ci#if _MIPS_SIM == _MIPS_SIM_ABI64 598c2ecf20Sopenharmony_ci register long nr asm("v0") = __NR_clock_gettime; 608c2ecf20Sopenharmony_ci#else 618c2ecf20Sopenharmony_ci register long nr asm("v0") = __NR_clock_gettime64; 628c2ecf20Sopenharmony_ci#endif 638c2ecf20Sopenharmony_ci register long error asm("a3"); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci asm volatile( 668c2ecf20Sopenharmony_ci " syscall\n" 678c2ecf20Sopenharmony_ci : "=r" (ret), "=r" (error) 688c2ecf20Sopenharmony_ci : "r" (clkid), "r" (ts), "r" (nr) 698c2ecf20Sopenharmony_ci : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 708c2ecf20Sopenharmony_ci "$14", "$15", "$24", "$25", 718c2ecf20Sopenharmony_ci VDSO_SYSCALL_CLOBBERS 728c2ecf20Sopenharmony_ci "memory"); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return error ? -ret : ret; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic __always_inline int clock_getres_fallback( 788c2ecf20Sopenharmony_ci clockid_t _clkid, 798c2ecf20Sopenharmony_ci struct __kernel_timespec *_ts) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci register struct __kernel_timespec *ts asm("a1") = _ts; 828c2ecf20Sopenharmony_ci register clockid_t clkid asm("a0") = _clkid; 838c2ecf20Sopenharmony_ci register long ret asm("v0"); 848c2ecf20Sopenharmony_ci#if _MIPS_SIM == _MIPS_SIM_ABI64 858c2ecf20Sopenharmony_ci register long nr asm("v0") = __NR_clock_getres; 868c2ecf20Sopenharmony_ci#else 878c2ecf20Sopenharmony_ci register long nr asm("v0") = __NR_clock_getres_time64; 888c2ecf20Sopenharmony_ci#endif 898c2ecf20Sopenharmony_ci register long error asm("a3"); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci asm volatile( 928c2ecf20Sopenharmony_ci " syscall\n" 938c2ecf20Sopenharmony_ci : "=r" (ret), "=r" (error) 948c2ecf20Sopenharmony_ci : "r" (clkid), "r" (ts), "r" (nr) 958c2ecf20Sopenharmony_ci : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 968c2ecf20Sopenharmony_ci "$14", "$15", "$24", "$25", 978c2ecf20Sopenharmony_ci VDSO_SYSCALL_CLOBBERS 988c2ecf20Sopenharmony_ci "memory"); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return error ? -ret : ret; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#if _MIPS_SIM != _MIPS_SIM_ABI64 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic __always_inline long clock_gettime32_fallback( 1068c2ecf20Sopenharmony_ci clockid_t _clkid, 1078c2ecf20Sopenharmony_ci struct old_timespec32 *_ts) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci register struct old_timespec32 *ts asm("a1") = _ts; 1108c2ecf20Sopenharmony_ci register clockid_t clkid asm("a0") = _clkid; 1118c2ecf20Sopenharmony_ci register long ret asm("v0"); 1128c2ecf20Sopenharmony_ci register long nr asm("v0") = __NR_clock_gettime; 1138c2ecf20Sopenharmony_ci register long error asm("a3"); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci asm volatile( 1168c2ecf20Sopenharmony_ci " syscall\n" 1178c2ecf20Sopenharmony_ci : "=r" (ret), "=r" (error) 1188c2ecf20Sopenharmony_ci : "r" (clkid), "r" (ts), "r" (nr) 1198c2ecf20Sopenharmony_ci : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 1208c2ecf20Sopenharmony_ci "$14", "$15", "$24", "$25", 1218c2ecf20Sopenharmony_ci VDSO_SYSCALL_CLOBBERS 1228c2ecf20Sopenharmony_ci "memory"); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return error ? -ret : ret; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic __always_inline int clock_getres32_fallback( 1288c2ecf20Sopenharmony_ci clockid_t _clkid, 1298c2ecf20Sopenharmony_ci struct old_timespec32 *_ts) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci register struct old_timespec32 *ts asm("a1") = _ts; 1328c2ecf20Sopenharmony_ci register clockid_t clkid asm("a0") = _clkid; 1338c2ecf20Sopenharmony_ci register long ret asm("v0"); 1348c2ecf20Sopenharmony_ci register long nr asm("v0") = __NR_clock_getres; 1358c2ecf20Sopenharmony_ci register long error asm("a3"); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci asm volatile( 1388c2ecf20Sopenharmony_ci " syscall\n" 1398c2ecf20Sopenharmony_ci : "=r" (ret), "=r" (error) 1408c2ecf20Sopenharmony_ci : "r" (clkid), "r" (ts), "r" (nr) 1418c2ecf20Sopenharmony_ci : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 1428c2ecf20Sopenharmony_ci "$14", "$15", "$24", "$25", 1438c2ecf20Sopenharmony_ci VDSO_SYSCALL_CLOBBERS 1448c2ecf20Sopenharmony_ci "memory"); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return error ? -ret : ret; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci#endif 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#ifdef CONFIG_CSRC_R4K 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic __always_inline u64 read_r4k_count(void) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci unsigned int count; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci __asm__ __volatile__( 1578c2ecf20Sopenharmony_ci " .set push\n" 1588c2ecf20Sopenharmony_ci " .set mips32r2\n" 1598c2ecf20Sopenharmony_ci " rdhwr %0, $2\n" 1608c2ecf20Sopenharmony_ci " .set pop\n" 1618c2ecf20Sopenharmony_ci : "=r" (count)); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return count; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#endif 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#ifdef CONFIG_CLKSRC_MIPS_GIC 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic __always_inline u64 read_gic_count(const struct vdso_data *data) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci void __iomem *gic = get_gic(data); 1738c2ecf20Sopenharmony_ci u32 hi, hi2, lo; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci do { 1768c2ecf20Sopenharmony_ci hi = __raw_readl(gic + sizeof(lo)); 1778c2ecf20Sopenharmony_ci lo = __raw_readl(gic); 1788c2ecf20Sopenharmony_ci hi2 = __raw_readl(gic + sizeof(lo)); 1798c2ecf20Sopenharmony_ci } while (hi2 != hi); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return (((u64)hi) << 32) + lo; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#endif 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic __always_inline u64 __arch_get_hw_counter(s32 clock_mode, 1878c2ecf20Sopenharmony_ci const struct vdso_data *vd) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci#ifdef CONFIG_CSRC_R4K 1908c2ecf20Sopenharmony_ci if (clock_mode == VDSO_CLOCKMODE_R4K) 1918c2ecf20Sopenharmony_ci return read_r4k_count(); 1928c2ecf20Sopenharmony_ci#endif 1938c2ecf20Sopenharmony_ci#ifdef CONFIG_CLKSRC_MIPS_GIC 1948c2ecf20Sopenharmony_ci if (clock_mode == VDSO_CLOCKMODE_GIC) 1958c2ecf20Sopenharmony_ci return read_gic_count(vd); 1968c2ecf20Sopenharmony_ci#endif 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * Core checks mode already. So this raced against a concurrent 1998c2ecf20Sopenharmony_ci * update. Return something. Core will do another round see the 2008c2ecf20Sopenharmony_ci * change and fallback to syscall. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic inline bool mips_vdso_hres_capable(void) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci return IS_ENABLED(CONFIG_CSRC_R4K) || 2088c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_CLKSRC_MIPS_GIC); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci#define __arch_vdso_hres_capable mips_vdso_hres_capable 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic __always_inline const struct vdso_data *__arch_get_vdso_data(void) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci return get_vdso_data(); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci#endif /* !__ASSEMBLY__ */ 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci#endif /* __ASM_VDSO_GETTIMEOFDAY_H */ 220