xref: /kvm-unit-tests/lib/s390x/asm/time.h (revision 5bf99cb38621d44b0a7d2204ecd9326b3209ab73)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Clock utilities for s390
4  *
5  * Authors:
6  *  Thomas Huth <thuth@redhat.com>
7  *
8  * Copied from the s390/intercept test by:
9  *  Pierre Morel <pmorel@linux.ibm.com>
10  */
11 #ifndef _ASMS390X_TIME_H_
12 #define _ASMS390X_TIME_H_
13 
14 #define S390_CLOCK_SHIFT_US	(63 - 51)
15 
16 #define STCK_SHIFT_US	S390_CLOCK_SHIFT_US
17 #define STCK_MAX	((1UL << 52) - 1)
18 
19 #define CPU_TIMER_SHIFT_US	S390_CLOCK_SHIFT_US
20 
sck(uint64_t * time)21 static inline int sck(uint64_t *time)
22 {
23 	int cc;
24 
25 	asm volatile(
26 		"	sck %[time]\n"
27 		"	ipm %[cc]\n"
28 		"	srl %[cc],28\n"
29 		: [cc] "=d"(cc)
30 		: [time] "Q"(*time)
31 		: "cc"
32 	);
33 
34 	return cc;
35 }
36 
stck(uint64_t * time)37 static inline int stck(uint64_t *time)
38 {
39 	int cc;
40 
41 	asm volatile(
42 		"	stck %[time]\n"
43 		"	ipm %[cc]\n"
44 		"	srl %[cc],28\n"
45 		: [cc] "=d" (cc), [time] "=Q" (*time)
46 		:
47 		: "cc"
48 	);
49 
50 	return cc;
51 }
52 
stckf(uint64_t * time)53 static inline int stckf(uint64_t *time)
54 {
55 	int cc;
56 
57 	asm volatile(
58 		"	stckf %[time]\n"
59 		"	ipm %[cc]\n"
60 		"	srl %[cc],28\n"
61 		: [cc] "=d" (cc), [time] "=Q" (*time)
62 		:
63 		: "cc"
64 	);
65 
66 	return cc;
67 }
68 
get_clock_us(void)69 static inline uint64_t get_clock_us(void)
70 {
71 	uint64_t clk;
72 
73 	stck(&clk);
74 
75 	return clk >> STCK_SHIFT_US;
76 }
77 
get_clock_ms(void)78 static inline uint64_t get_clock_ms(void)
79 {
80 	return get_clock_us() / 1000;
81 }
82 
udelay(unsigned long us)83 static inline void udelay(unsigned long us)
84 {
85 	unsigned long startclk = get_clock_us();
86 	unsigned long c;
87 
88 	do {
89 		c = get_clock_us();
90 		if (c < startclk)
91 			c += STCK_MAX;
92 	} while (c < startclk + us);
93 }
94 
mdelay(unsigned long ms)95 static inline void mdelay(unsigned long ms)
96 {
97 	udelay(ms * 1000);
98 }
99 
cpu_timer_set_ms(int64_t timeout_ms)100 static inline void cpu_timer_set_ms(int64_t timeout_ms)
101 {
102 	int64_t timer_value = (timeout_ms * 1000) << CPU_TIMER_SHIFT_US;
103 
104 	asm volatile (
105 		"spt %[timer_value]\n"
106 		:
107 		: [timer_value] "Q" (timer_value)
108 	);
109 }
110 
111 #endif
112