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