xref: /openbmc/linux/arch/s390/include/asm/timex.h (revision 97fb5e8d)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  *  S390 version
4  *    Copyright IBM Corp. 1999
5  *
6  *  Derived from "include/asm-i386/timex.h"
7  *    Copyright (C) 1992, Linus Torvalds
8  */
9 
10 #ifndef _ASM_S390_TIMEX_H
11 #define _ASM_S390_TIMEX_H
12 
13 #include <asm/lowcore.h>
14 #include <linux/time64.h>
15 
16 /* The value of the TOD clock for 1.1.1970. */
17 #define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
18 
19 extern u64 clock_comparator_max;
20 
21 /* Inline functions for clock register access. */
22 static inline int set_tod_clock(__u64 time)
23 {
24 	int cc;
25 
26 	asm volatile(
27 		"   sck   %1\n"
28 		"   ipm   %0\n"
29 		"   srl   %0,28\n"
30 		: "=d" (cc) : "Q" (time) : "cc");
31 	return cc;
32 }
33 
34 static inline int store_tod_clock(__u64 *time)
35 {
36 	int cc;
37 
38 	asm volatile(
39 		"   stck  %1\n"
40 		"   ipm   %0\n"
41 		"   srl   %0,28\n"
42 		: "=d" (cc), "=Q" (*time) : : "cc");
43 	return cc;
44 }
45 
46 static inline void set_clock_comparator(__u64 time)
47 {
48 	asm volatile("sckc %0" : : "Q" (time));
49 }
50 
51 static inline void store_clock_comparator(__u64 *time)
52 {
53 	asm volatile("stckc %0" : "=Q" (*time));
54 }
55 
56 void clock_comparator_work(void);
57 
58 void __init time_early_init(void);
59 
60 extern unsigned char ptff_function_mask[16];
61 
62 /* Function codes for the ptff instruction. */
63 #define PTFF_QAF	0x00	/* query available functions */
64 #define PTFF_QTO	0x01	/* query tod offset */
65 #define PTFF_QSI	0x02	/* query steering information */
66 #define PTFF_QUI	0x04	/* query UTC information */
67 #define PTFF_ATO	0x40	/* adjust tod offset */
68 #define PTFF_STO	0x41	/* set tod offset */
69 #define PTFF_SFS	0x42	/* set fine steering rate */
70 #define PTFF_SGS	0x43	/* set gross steering rate */
71 
72 /* Query TOD offset result */
73 struct ptff_qto {
74 	unsigned long long physical_clock;
75 	unsigned long long tod_offset;
76 	unsigned long long logical_tod_offset;
77 	unsigned long long tod_epoch_difference;
78 } __packed;
79 
80 static inline int ptff_query(unsigned int nr)
81 {
82 	unsigned char *ptr;
83 
84 	ptr = ptff_function_mask + (nr >> 3);
85 	return (*ptr & (0x80 >> (nr & 7))) != 0;
86 }
87 
88 /* Query UTC information result */
89 struct ptff_qui {
90 	unsigned int tm : 2;
91 	unsigned int ts : 2;
92 	unsigned int : 28;
93 	unsigned int pad_0x04;
94 	unsigned long leap_event;
95 	short old_leap;
96 	short new_leap;
97 	unsigned int pad_0x14;
98 	unsigned long prt[5];
99 	unsigned long cst[3];
100 	unsigned int skew;
101 	unsigned int pad_0x5c[41];
102 } __packed;
103 
104 /*
105  * ptff - Perform timing facility function
106  * @ptff_block: Pointer to ptff parameter block
107  * @len: Length of parameter block
108  * @func: Function code
109  * Returns: Condition code (0 on success)
110  */
111 #define ptff(ptff_block, len, func)					\
112 ({									\
113 	struct addrtype { char _[len]; };				\
114 	register unsigned int reg0 asm("0") = func;			\
115 	register unsigned long reg1 asm("1") = (unsigned long) (ptff_block);\
116 	int rc;								\
117 									\
118 	asm volatile(							\
119 		"	.word	0x0104\n"				\
120 		"	ipm	%0\n"					\
121 		"	srl	%0,28\n"				\
122 		: "=d" (rc), "+m" (*(struct addrtype *) reg1)		\
123 		: "d" (reg0), "d" (reg1) : "cc");			\
124 	rc;								\
125 })
126 
127 static inline unsigned long long local_tick_disable(void)
128 {
129 	unsigned long long old;
130 
131 	old = S390_lowcore.clock_comparator;
132 	S390_lowcore.clock_comparator = clock_comparator_max;
133 	set_clock_comparator(S390_lowcore.clock_comparator);
134 	return old;
135 }
136 
137 static inline void local_tick_enable(unsigned long long comp)
138 {
139 	S390_lowcore.clock_comparator = comp;
140 	set_clock_comparator(S390_lowcore.clock_comparator);
141 }
142 
143 #define CLOCK_TICK_RATE		1193180 /* Underlying HZ */
144 #define STORE_CLOCK_EXT_SIZE	16	/* stcke writes 16 bytes */
145 
146 typedef unsigned long long cycles_t;
147 
148 static inline void get_tod_clock_ext(char *clk)
149 {
150 	typedef struct { char _[STORE_CLOCK_EXT_SIZE]; } addrtype;
151 
152 	asm volatile("stcke %0" : "=Q" (*(addrtype *) clk) : : "cc");
153 }
154 
155 static inline unsigned long long get_tod_clock(void)
156 {
157 	unsigned char clk[STORE_CLOCK_EXT_SIZE];
158 
159 	get_tod_clock_ext(clk);
160 	return *((unsigned long long *)&clk[1]);
161 }
162 
163 static inline unsigned long long get_tod_clock_fast(void)
164 {
165 #ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES
166 	unsigned long long clk;
167 
168 	asm volatile("stckf %0" : "=Q" (clk) : : "cc");
169 	return clk;
170 #else
171 	return get_tod_clock();
172 #endif
173 }
174 
175 static inline cycles_t get_cycles(void)
176 {
177 	return (cycles_t) get_tod_clock() >> 2;
178 }
179 
180 int get_phys_clock(unsigned long *clock);
181 void init_cpu_timer(void);
182 unsigned long long monotonic_clock(void);
183 
184 extern unsigned char tod_clock_base[16] __aligned(8);
185 
186 /**
187  * get_clock_monotonic - returns current time in clock rate units
188  *
189  * The caller must ensure that preemption is disabled.
190  * The clock and tod_clock_base get changed via stop_machine.
191  * Therefore preemption must be disabled when calling this
192  * function, otherwise the returned value is not guaranteed to
193  * be monotonic.
194  */
195 static inline unsigned long long get_tod_clock_monotonic(void)
196 {
197 	return get_tod_clock() - *(unsigned long long *) &tod_clock_base[1];
198 }
199 
200 /**
201  * tod_to_ns - convert a TOD format value to nanoseconds
202  * @todval: to be converted TOD format value
203  * Returns: number of nanoseconds that correspond to the TOD format value
204  *
205  * Converting a 64 Bit TOD format value to nanoseconds means that the value
206  * must be divided by 4.096. In order to achieve that we multiply with 125
207  * and divide by 512:
208  *
209  *    ns = (todval * 125) >> 9;
210  *
211  * In order to avoid an overflow with the multiplication we can rewrite this.
212  * With a split todval == 2^9 * th + tl (th upper 55 bits, tl lower 9 bits)
213  * we end up with
214  *
215  *    ns = ((2^9 * th + tl) * 125 ) >> 9;
216  * -> ns = (th * 125) + ((tl * 125) >> 9);
217  *
218  */
219 static inline unsigned long long tod_to_ns(unsigned long long todval)
220 {
221 	return ((todval >> 9) * 125) + (((todval & 0x1ff) * 125) >> 9);
222 }
223 
224 /**
225  * tod_after - compare two 64 bit TOD values
226  * @a: first 64 bit TOD timestamp
227  * @b: second 64 bit TOD timestamp
228  *
229  * Returns: true if a is later than b
230  */
231 static inline int tod_after(unsigned long long a, unsigned long long b)
232 {
233 	if (MACHINE_HAS_SCC)
234 		return (long long) a > (long long) b;
235 	return a > b;
236 }
237 
238 /**
239  * tod_after_eq - compare two 64 bit TOD values
240  * @a: first 64 bit TOD timestamp
241  * @b: second 64 bit TOD timestamp
242  *
243  * Returns: true if a is later than b
244  */
245 static inline int tod_after_eq(unsigned long long a, unsigned long long b)
246 {
247 	if (MACHINE_HAS_SCC)
248 		return (long long) a >= (long long) b;
249 	return a >= b;
250 }
251 
252 #endif
253