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 <linux/preempt.h> 14 #include <linux/time64.h> 15 #include <asm/lowcore.h> 16 #include <asm/machine.h> 17 #include <asm/asm.h> 18 19 /* The value of the TOD clock for 1.1.1970. */ 20 #define TOD_UNIX_EPOCH 0x7d91048bca000000ULL 21 22 extern u64 clock_comparator_max; 23 24 union tod_clock { 25 __uint128_t val; 26 struct { 27 __uint128_t ei : 8; /* epoch index */ 28 __uint128_t tod : 64; /* bits 0-63 of tod clock */ 29 __uint128_t : 40; 30 __uint128_t pf : 16; /* programmable field */ 31 }; 32 struct { 33 __uint128_t eitod : 72; /* epoch index + bits 0-63 tod clock */ 34 __uint128_t : 56; 35 }; 36 struct { 37 __uint128_t us : 60; /* micro-seconds */ 38 __uint128_t sus : 12; /* sub-microseconds */ 39 __uint128_t : 56; 40 }; 41 } __packed; 42 43 /* Inline functions for clock register access. */ 44 static inline int set_tod_clock(__u64 time) 45 { 46 int cc; 47 48 asm volatile( 49 " sck %[time]\n" 50 CC_IPM(cc) 51 : CC_OUT(cc, cc) 52 : [time] "Q" (time) 53 : CC_CLOBBER); 54 return CC_TRANSFORM(cc); 55 } 56 57 static inline int store_tod_clock_ext_cc(union tod_clock *clk) 58 { 59 int cc; 60 61 asm volatile( 62 " stcke %[clk]\n" 63 CC_IPM(cc) 64 : CC_OUT(cc, cc), [clk] "=Q" (*clk) 65 : 66 : CC_CLOBBER); 67 return CC_TRANSFORM(cc); 68 } 69 70 static __always_inline void store_tod_clock_ext(union tod_clock *tod) 71 { 72 asm volatile("stcke %0" : "=Q" (*tod) : : "cc"); 73 } 74 75 static inline void set_clock_comparator(__u64 time) 76 { 77 asm volatile("sckc %0" : : "Q" (time)); 78 } 79 80 static inline void set_tod_programmable_field(u16 val) 81 { 82 asm volatile( 83 " lgr 0,%[val]\n" 84 " sckpf\n" 85 : 86 : [val] "d" ((unsigned long)val) 87 : "0"); 88 } 89 90 void clock_comparator_work(void); 91 92 void __init time_early_init(void); 93 94 extern unsigned char ptff_function_mask[16]; 95 96 /* Function codes for the ptff instruction. */ 97 #define PTFF_QAF 0x00 /* query available functions */ 98 #define PTFF_QTO 0x01 /* query tod offset */ 99 #define PTFF_QSI 0x02 /* query steering information */ 100 #define PTFF_QPT 0x03 /* query physical clock */ 101 #define PTFF_QUI 0x04 /* query UTC information */ 102 #define PTFF_ATO 0x40 /* adjust tod offset */ 103 #define PTFF_STO 0x41 /* set tod offset */ 104 #define PTFF_SFS 0x42 /* set fine steering rate */ 105 #define PTFF_SGS 0x43 /* set gross steering rate */ 106 107 /* Query TOD offset result */ 108 struct ptff_qto { 109 unsigned long physical_clock; 110 unsigned long tod_offset; 111 unsigned long logical_tod_offset; 112 unsigned long tod_epoch_difference; 113 } __packed; 114 115 static inline int ptff_query(unsigned int nr) 116 { 117 unsigned char *ptr; 118 119 ptr = ptff_function_mask + (nr >> 3); 120 return (*ptr & (0x80 >> (nr & 7))) != 0; 121 } 122 123 /* Query UTC information result */ 124 struct ptff_qui { 125 unsigned int tm : 2; 126 unsigned int ts : 2; 127 unsigned int : 28; 128 unsigned int pad_0x04; 129 unsigned long leap_event; 130 short old_leap; 131 short new_leap; 132 unsigned int pad_0x14; 133 unsigned long prt[5]; 134 unsigned long cst[3]; 135 unsigned int skew; 136 unsigned int pad_0x5c[41]; 137 } __packed; 138 139 /* 140 * ptff - Perform timing facility function 141 * @ptff_block: Pointer to ptff parameter block 142 * @len: Length of parameter block 143 * @func: Function code 144 * Returns: Condition code (0 on success) 145 */ 146 #define ptff(ptff_block, len, func) \ 147 ({ \ 148 struct addrtype { char _[len]; }; \ 149 unsigned int reg0 = func; \ 150 unsigned long reg1 = (unsigned long)(ptff_block); \ 151 int rc; \ 152 \ 153 asm volatile( \ 154 " lgr 0,%[reg0]\n" \ 155 " lgr 1,%[reg1]\n" \ 156 " ptff\n" \ 157 CC_IPM(rc) \ 158 : CC_OUT(rc, rc), "+m" (*(struct addrtype *)reg1) \ 159 : [reg0] "d" (reg0), [reg1] "d" (reg1) \ 160 : CC_CLOBBER_LIST("0", "1")); \ 161 CC_TRANSFORM(rc); \ 162 }) 163 164 static inline unsigned long local_tick_disable(void) 165 { 166 unsigned long old; 167 168 old = get_lowcore()->clock_comparator; 169 get_lowcore()->clock_comparator = clock_comparator_max; 170 set_clock_comparator(get_lowcore()->clock_comparator); 171 return old; 172 } 173 174 static inline void local_tick_enable(unsigned long comp) 175 { 176 get_lowcore()->clock_comparator = comp; 177 set_clock_comparator(get_lowcore()->clock_comparator); 178 } 179 180 #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ 181 182 typedef unsigned long cycles_t; 183 184 static __always_inline unsigned long get_tod_clock(void) 185 { 186 union tod_clock clk; 187 188 store_tod_clock_ext(&clk); 189 return clk.tod; 190 } 191 192 static inline unsigned long get_tod_clock_fast(void) 193 { 194 unsigned long clk; 195 196 asm volatile("stckf %0" : "=Q" (clk) : : "cc"); 197 return clk; 198 } 199 200 static inline cycles_t get_cycles(void) 201 { 202 return (cycles_t) get_tod_clock() >> 2; 203 } 204 #define get_cycles get_cycles 205 206 int get_phys_clock(unsigned long *clock); 207 void init_cpu_timer(void); 208 209 extern union tod_clock tod_clock_base; 210 211 static __always_inline unsigned long __get_tod_clock_monotonic(void) 212 { 213 return get_tod_clock() - tod_clock_base.tod; 214 } 215 216 /** 217 * get_clock_monotonic - returns current time in clock rate units 218 * 219 * The clock and tod_clock_base get changed via stop_machine. 220 * Therefore preemption must be disabled, otherwise the returned 221 * value is not guaranteed to be monotonic. 222 */ 223 static inline unsigned long get_tod_clock_monotonic(void) 224 { 225 unsigned long tod; 226 227 preempt_disable_notrace(); 228 tod = __get_tod_clock_monotonic(); 229 preempt_enable_notrace(); 230 return tod; 231 } 232 233 /** 234 * tod_to_ns - convert a TOD format value to nanoseconds 235 * @todval: to be converted TOD format value 236 * Returns: number of nanoseconds that correspond to the TOD format value 237 * 238 * Converting a 64 Bit TOD format value to nanoseconds means that the value 239 * must be divided by 4.096. In order to achieve that we multiply with 125 240 * and divide by 512: 241 * 242 * ns = (todval * 125) >> 9; 243 * 244 * In order to avoid an overflow with the multiplication we can rewrite this. 245 * With a split todval == 2^9 * th + tl (th upper 55 bits, tl lower 9 bits) 246 * we end up with 247 * 248 * ns = ((2^9 * th + tl) * 125 ) >> 9; 249 * -> ns = (th * 125) + ((tl * 125) >> 9); 250 * 251 */ 252 static __always_inline unsigned long tod_to_ns(unsigned long todval) 253 { 254 return ((todval >> 9) * 125) + (((todval & 0x1ff) * 125) >> 9); 255 } 256 257 static __always_inline u128 eitod_to_ns(u128 todval) 258 { 259 return (todval * 125) >> 9; 260 } 261 262 /** 263 * tod_after - compare two 64 bit TOD values 264 * @a: first 64 bit TOD timestamp 265 * @b: second 64 bit TOD timestamp 266 * 267 * Returns: true if a is later than b 268 */ 269 static inline int tod_after(unsigned long a, unsigned long b) 270 { 271 if (machine_has_scc()) 272 return (long) a > (long) b; 273 return a > b; 274 } 275 276 /** 277 * tod_after_eq - compare two 64 bit TOD values 278 * @a: first 64 bit TOD timestamp 279 * @b: second 64 bit TOD timestamp 280 * 281 * Returns: true if a is later than b 282 */ 283 static inline int tod_after_eq(unsigned long a, unsigned long b) 284 { 285 if (machine_has_scc()) 286 return (long) a >= (long) b; 287 return a >= b; 288 } 289 290 #endif 291