xref: /linux/arch/sparc/include/asm/vdso/gettimeofday.h (revision f21f7b5162e9dbde6d3d5ce727d4ca2552d76ce9)
110fdbd95SThomas Weißschuh /* SPDX-License-Identifier: GPL-2.0 */
210fdbd95SThomas Weißschuh /*
310fdbd95SThomas Weißschuh  * Copyright 2006 Andi Kleen, SUSE Labs.
410fdbd95SThomas Weißschuh  */
510fdbd95SThomas Weißschuh 
610fdbd95SThomas Weißschuh #ifndef _ASM_SPARC_VDSO_GETTIMEOFDAY_H
710fdbd95SThomas Weißschuh #define _ASM_SPARC_VDSO_GETTIMEOFDAY_H
810fdbd95SThomas Weißschuh 
9d60c682bSThomas Weißschuh #include <uapi/linux/time.h>
10d60c682bSThomas Weißschuh #include <uapi/linux/unistd.h>
11d60c682bSThomas Weißschuh 
127c5fc16cSThomas Weißschuh #include <vdso/align.h>
137c5fc16cSThomas Weißschuh #include <vdso/clocksource.h>
147c5fc16cSThomas Weißschuh #include <vdso/datapage.h>
157c5fc16cSThomas Weißschuh #include <vdso/page.h>
167c5fc16cSThomas Weißschuh 
1710fdbd95SThomas Weißschuh #include <linux/types.h>
1810fdbd95SThomas Weißschuh 
1910fdbd95SThomas Weißschuh #ifdef	CONFIG_SPARC64
2010fdbd95SThomas Weißschuh static __always_inline u64 vread_tick(void)
2110fdbd95SThomas Weißschuh {
2210fdbd95SThomas Weißschuh 	u64	ret;
2310fdbd95SThomas Weißschuh 
2410fdbd95SThomas Weißschuh 	__asm__ __volatile__("rd %%tick, %0" : "=r" (ret));
2510fdbd95SThomas Weißschuh 	return ret;
2610fdbd95SThomas Weißschuh }
2710fdbd95SThomas Weißschuh 
2810fdbd95SThomas Weißschuh static __always_inline u64 vread_tick_stick(void)
2910fdbd95SThomas Weißschuh {
3010fdbd95SThomas Weißschuh 	u64	ret;
3110fdbd95SThomas Weißschuh 
3210fdbd95SThomas Weißschuh 	__asm__ __volatile__("rd %%asr24, %0" : "=r" (ret));
3310fdbd95SThomas Weißschuh 	return ret;
3410fdbd95SThomas Weißschuh }
3510fdbd95SThomas Weißschuh #else
3610fdbd95SThomas Weißschuh static __always_inline u64 vdso_shift_ns(u64 val, u32 amt)
3710fdbd95SThomas Weißschuh {
3810fdbd95SThomas Weißschuh 	u64 ret;
3910fdbd95SThomas Weißschuh 
4010fdbd95SThomas Weißschuh 	__asm__ __volatile__("sllx %H1, 32, %%g1\n\t"
4110fdbd95SThomas Weißschuh 			     "srl %L1, 0, %L1\n\t"
4210fdbd95SThomas Weißschuh 			     "or %%g1, %L1, %%g1\n\t"
4310fdbd95SThomas Weißschuh 			     "srlx %%g1, %2, %L0\n\t"
4410fdbd95SThomas Weißschuh 			     "srlx %L0, 32, %H0"
4510fdbd95SThomas Weißschuh 			     : "=r" (ret)
4610fdbd95SThomas Weißschuh 			     : "r" (val), "r" (amt)
4710fdbd95SThomas Weißschuh 			     : "g1");
4810fdbd95SThomas Weißschuh 	return ret;
4910fdbd95SThomas Weißschuh }
507c5fc16cSThomas Weißschuh #define vdso_shift_ns vdso_shift_ns
5110fdbd95SThomas Weißschuh 
5210fdbd95SThomas Weißschuh static __always_inline u64 vread_tick(void)
5310fdbd95SThomas Weißschuh {
5410fdbd95SThomas Weißschuh 	register unsigned long long ret asm("o4");
5510fdbd95SThomas Weißschuh 
5610fdbd95SThomas Weißschuh 	__asm__ __volatile__("rd %%tick, %L0\n\t"
5710fdbd95SThomas Weißschuh 			     "srlx %L0, 32, %H0"
5810fdbd95SThomas Weißschuh 			     : "=r" (ret));
5910fdbd95SThomas Weißschuh 	return ret;
6010fdbd95SThomas Weißschuh }
6110fdbd95SThomas Weißschuh 
6210fdbd95SThomas Weißschuh static __always_inline u64 vread_tick_stick(void)
6310fdbd95SThomas Weißschuh {
6410fdbd95SThomas Weißschuh 	register unsigned long long ret asm("o4");
6510fdbd95SThomas Weißschuh 
6610fdbd95SThomas Weißschuh 	__asm__ __volatile__("rd %%asr24, %L0\n\t"
6710fdbd95SThomas Weißschuh 			     "srlx %L0, 32, %H0"
6810fdbd95SThomas Weißschuh 			     : "=r" (ret));
6910fdbd95SThomas Weißschuh 	return ret;
7010fdbd95SThomas Weißschuh }
7110fdbd95SThomas Weißschuh #endif
7210fdbd95SThomas Weißschuh 
737c5fc16cSThomas Weißschuh static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, const struct vdso_time_data *vd)
7410fdbd95SThomas Weißschuh {
757c5fc16cSThomas Weißschuh 	if (likely(clock_mode == VDSO_CLOCKMODE_STICK))
7610fdbd95SThomas Weißschuh 		return vread_tick_stick();
7710fdbd95SThomas Weißschuh 	else
7810fdbd95SThomas Weißschuh 		return vread_tick();
7910fdbd95SThomas Weißschuh }
8010fdbd95SThomas Weißschuh 
81d60c682bSThomas Weißschuh #ifdef	CONFIG_SPARC64
82d60c682bSThomas Weißschuh #define SYSCALL_STRING							\
83d60c682bSThomas Weißschuh 	"ta	0x6d;"							\
84d60c682bSThomas Weißschuh 	"bcs,a	1f;"							\
85d60c682bSThomas Weißschuh 	" sub	%%g0, %%o0, %%o0;"					\
86d60c682bSThomas Weißschuh 	"1:"
87d60c682bSThomas Weißschuh #else
88d60c682bSThomas Weißschuh #define SYSCALL_STRING							\
89d60c682bSThomas Weißschuh 	"ta	0x10;"							\
90d60c682bSThomas Weißschuh 	"bcs,a	1f;"							\
91d60c682bSThomas Weißschuh 	" sub	%%g0, %%o0, %%o0;"					\
92d60c682bSThomas Weißschuh 	"1:"
93d60c682bSThomas Weißschuh #endif
94d60c682bSThomas Weißschuh 
95d60c682bSThomas Weißschuh #define SYSCALL_CLOBBERS						\
96d60c682bSThomas Weißschuh 	"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",			\
97d60c682bSThomas Weißschuh 	"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",		\
98d60c682bSThomas Weißschuh 	"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",		\
99d60c682bSThomas Weißschuh 	"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",		\
100d60c682bSThomas Weißschuh 	"f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46",		\
101d60c682bSThomas Weißschuh 	"f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",		\
102d60c682bSThomas Weißschuh 	"cc", "memory"
103d60c682bSThomas Weißschuh 
104*1628f6a7SThomas Weißschuh #ifdef CONFIG_SPARC64
105*1628f6a7SThomas Weißschuh 
106d60c682bSThomas Weißschuh static __always_inline
1077c5fc16cSThomas Weißschuh long clock_gettime_fallback(clockid_t clock, struct __kernel_timespec *ts)
108d60c682bSThomas Weißschuh {
109d60c682bSThomas Weißschuh 	register long num __asm__("g1") = __NR_clock_gettime;
110d60c682bSThomas Weißschuh 	register long o0 __asm__("o0") = clock;
111d60c682bSThomas Weißschuh 	register long o1 __asm__("o1") = (long) ts;
112d60c682bSThomas Weißschuh 
113d60c682bSThomas Weißschuh 	__asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num),
114d60c682bSThomas Weißschuh 			     "0" (o0), "r" (o1) : SYSCALL_CLOBBERS);
115d60c682bSThomas Weißschuh 	return o0;
116d60c682bSThomas Weißschuh }
117d60c682bSThomas Weißschuh 
118*1628f6a7SThomas Weißschuh #else /* !CONFIG_SPARC64 */
119*1628f6a7SThomas Weißschuh 
120*1628f6a7SThomas Weißschuh static __always_inline
121*1628f6a7SThomas Weißschuh long clock_gettime_fallback(clockid_t clock, struct __kernel_timespec *ts)
122*1628f6a7SThomas Weißschuh {
123*1628f6a7SThomas Weißschuh 	register long num __asm__("g1") = __NR_clock_gettime64;
124*1628f6a7SThomas Weißschuh 	register long o0 __asm__("o0") = clock;
125*1628f6a7SThomas Weißschuh 	register long o1 __asm__("o1") = (long) ts;
126*1628f6a7SThomas Weißschuh 
127*1628f6a7SThomas Weißschuh 	__asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num),
128*1628f6a7SThomas Weißschuh 			     "0" (o0), "r" (o1) : SYSCALL_CLOBBERS);
129*1628f6a7SThomas Weißschuh 	return o0;
130*1628f6a7SThomas Weißschuh }
131*1628f6a7SThomas Weißschuh 
1327c5fc16cSThomas Weißschuh static __always_inline
1337c5fc16cSThomas Weißschuh long clock_gettime32_fallback(clockid_t clock, struct old_timespec32 *ts)
1347c5fc16cSThomas Weißschuh {
1357c5fc16cSThomas Weißschuh 	register long num __asm__("g1") = __NR_clock_gettime;
1367c5fc16cSThomas Weißschuh 	register long o0 __asm__("o0") = clock;
1377c5fc16cSThomas Weißschuh 	register long o1 __asm__("o1") = (long) ts;
1387c5fc16cSThomas Weißschuh 
1397c5fc16cSThomas Weißschuh 	__asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num),
1407c5fc16cSThomas Weißschuh 			     "0" (o0), "r" (o1) : SYSCALL_CLOBBERS);
1417c5fc16cSThomas Weißschuh 	return o0;
1427c5fc16cSThomas Weißschuh }
143*1628f6a7SThomas Weißschuh 
144*1628f6a7SThomas Weißschuh #endif /* CONFIG_SPARC64 */
1457c5fc16cSThomas Weißschuh 
146d60c682bSThomas Weißschuh static __always_inline
147d60c682bSThomas Weißschuh long gettimeofday_fallback(struct __kernel_old_timeval *tv, struct timezone *tz)
148d60c682bSThomas Weißschuh {
149d60c682bSThomas Weißschuh 	register long num __asm__("g1") = __NR_gettimeofday;
150d60c682bSThomas Weißschuh 	register long o0 __asm__("o0") = (long) tv;
151d60c682bSThomas Weißschuh 	register long o1 __asm__("o1") = (long) tz;
152d60c682bSThomas Weißschuh 
153d60c682bSThomas Weißschuh 	__asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num),
154d60c682bSThomas Weißschuh 			     "0" (o0), "r" (o1) : SYSCALL_CLOBBERS);
155d60c682bSThomas Weißschuh 	return o0;
156d60c682bSThomas Weißschuh }
157d60c682bSThomas Weißschuh 
1587c5fc16cSThomas Weißschuh static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void)
1597c5fc16cSThomas Weißschuh {
1607c5fc16cSThomas Weißschuh 	unsigned long ret;
1617c5fc16cSThomas Weißschuh 
1627c5fc16cSThomas Weißschuh 	/*
1637c5fc16cSThomas Weißschuh 	 * SPARC does not support native PC-relative code relocations.
1647c5fc16cSThomas Weißschuh 	 * Calculate the address manually, works for 32 and 64 bit code.
1657c5fc16cSThomas Weißschuh 	 */
1667c5fc16cSThomas Weißschuh 	__asm__ __volatile__(
1677c5fc16cSThomas Weißschuh 		"1:\n"
1687c5fc16cSThomas Weißschuh 		"call 3f\n"                     // Jump over the embedded data and set up %o7
1697c5fc16cSThomas Weißschuh 		"nop\n"                         // Delay slot
1707c5fc16cSThomas Weißschuh 		"2:\n"
1717c5fc16cSThomas Weißschuh 		".word vdso_u_time_data - .\n"  // Embedded offset to external symbol
1727c5fc16cSThomas Weißschuh 		"3:\n"
1737c5fc16cSThomas Weißschuh 		"add %%o7, 2b - 1b, %%o7\n"     // Point %o7 to the embedded offset
1747c5fc16cSThomas Weißschuh 		"ldsw [%%o7], %0\n"             // Load the offset
1757c5fc16cSThomas Weißschuh 		"add %0, %%o7, %0\n"            // Calculate the absolute address
1767c5fc16cSThomas Weißschuh 		: "=r" (ret)
1777c5fc16cSThomas Weißschuh 		:
1787c5fc16cSThomas Weißschuh 		: "o7");
1797c5fc16cSThomas Weißschuh 
1807c5fc16cSThomas Weißschuh 	return (const struct vdso_time_data *)ret;
1817c5fc16cSThomas Weißschuh }
1827c5fc16cSThomas Weißschuh #define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data
1837c5fc16cSThomas Weißschuh 
18410fdbd95SThomas Weißschuh #endif /* _ASM_SPARC_VDSO_GETTIMEOFDAY_H */
185