FILE
timex.h
File preview with syntax highlighting.
linux-6.19.14/arch/s390/include/asm/timex.h
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 22extern u64 clock_comparator_max; 23 24union 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. */ 44static 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 57static 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 70static __always_inline void store_tod_clock_ext(union tod_clock *tod) 71{ 72 asm volatile("stcke %0" : "=Q" (*tod) : : "cc"); 73} 74 75static inline void set_clock_comparator(__u64 time) 76{ 77 asm volatile("sckc %0" : : "Q" (time)); 78} 79 80static inline void set_tod_programmable_field(u16 val) 81{ 82 asm volatile( 83 " lgr 0,%[val]\n" 84 " sckpf" 85 : 86 : [val] "d" ((unsigned long)val) 87 : "0"); 88} 89 90void clock_comparator_work(void); 91 92void __init time_early_init(void); 93 94extern 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 */ 108struct 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 115static 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 */ 124struct 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 164static 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 174static 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 182typedef unsigned long cycles_t; 183 184static __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 192static 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} 199int get_phys_clock(unsigned long *clock); 200void init_cpu_timer(void); 201 202extern union tod_clock tod_clock_base; 203 204static __always_inline unsigned long __get_tod_clock_monotonic(void) 205{ 206 return get_tod_clock() - tod_clock_base.tod; 207} 208 209/** 210 * get_clock_monotonic - returns current time in clock rate units 211 * 212 * The clock and tod_clock_base get changed via stop_machine. 213 * Therefore preemption must be disabled, otherwise the returned 214 * value is not guaranteed to be monotonic. 215 */ 216static inline unsigned long get_tod_clock_monotonic(void) 217{ 218 unsigned long tod; 219 220 preempt_disable_notrace(); 221 tod = __get_tod_clock_monotonic(); 222 preempt_enable_notrace(); 223 return tod; 224} 225 226static inline cycles_t get_cycles(void) 227{ 228 return (cycles_t)get_tod_clock_monotonic() >> 2; 229} 230#define get_cycles get_cycles 231 232/** 233 * tod_to_ns - convert a TOD format value to nanoseconds 234 * @todval: to be converted TOD format value 235 * Returns: number of nanoseconds that correspond to the TOD format value 236 * 237 * Converting a 64 Bit TOD format value to nanoseconds means that the value 238 * must be divided by 4.096. In order to achieve that we multiply with 125 239 * and divide by 512: 240 * 241 * ns = (todval * 125) >> 9; 242 * 243 * In order to avoid an overflow with the multiplication we can rewrite this. 244 * With a split todval == 2^9 * th + tl (th upper 55 bits, tl lower 9 bits) 245 * we end up with 246 * 247 * ns = ((2^9 * th + tl) * 125 ) >> 9; 248 * -> ns = (th * 125) + ((tl * 125) >> 9); 249 * 250 */ 251static __always_inline unsigned long tod_to_ns(unsigned long todval) 252{ 253 return ((todval >> 9) * 125) + (((todval & 0x1ff) * 125) >> 9); 254} 255 256static __always_inline u128 eitod_to_ns(u128 todval) 257{ 258 return (todval * 125) >> 9; 259} 260 261/** 262 * tod_after - compare two 64 bit TOD values 263 * @a: first 64 bit TOD timestamp 264 * @b: second 64 bit TOD timestamp 265 * 266 * Returns: true if a is later than b 267 */ 268static inline int tod_after(unsigned long a, unsigned long b) 269{ 270 if (machine_has_scc()) 271 return (long) a > (long) b; 272 return a > b; 273} 274 275/** 276 * tod_after_eq - compare two 64 bit TOD values 277 * @a: first 64 bit TOD timestamp 278 * @b: second 64 bit TOD timestamp 279 * 280 * Returns: true if a is later than b 281 */ 282static inline int tod_after_eq(unsigned long a, unsigned long b) 283{ 284 if (machine_has_scc()) 285 return (long) a >= (long) b; 286 return a >= b; 287} 288 289#endif
~/
Read-only file preview.