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