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