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