0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef _ASM_S390_TIMEX_H
0011 #define _ASM_S390_TIMEX_H
0012
0013 #include <linux/preempt.h>
0014 #include <linux/time64.h>
0015 #include <asm/lowcore.h>
0016
0017
0018 #define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
0019
0020 extern u64 clock_comparator_max;
0021
0022 union tod_clock {
0023 __uint128_t val;
0024 struct {
0025 __uint128_t ei : 8;
0026 __uint128_t tod : 64;
0027 __uint128_t : 40;
0028 __uint128_t pf : 16;
0029 };
0030 struct {
0031 __uint128_t eitod : 72;
0032 __uint128_t : 56;
0033 };
0034 struct {
0035 __uint128_t us : 60;
0036 __uint128_t sus : 12;
0037 __uint128_t : 56;
0038 };
0039 } __packed;
0040
0041
0042 static inline int set_tod_clock(__u64 time)
0043 {
0044 int cc;
0045
0046 asm volatile(
0047 " sck %1\n"
0048 " ipm %0\n"
0049 " srl %0,28\n"
0050 : "=d" (cc) : "Q" (time) : "cc");
0051 return cc;
0052 }
0053
0054 static inline int store_tod_clock_ext_cc(union tod_clock *clk)
0055 {
0056 int cc;
0057
0058 asm volatile(
0059 " stcke %1\n"
0060 " ipm %0\n"
0061 " srl %0,28\n"
0062 : "=d" (cc), "=Q" (*clk) : : "cc");
0063 return cc;
0064 }
0065
0066 static inline void store_tod_clock_ext(union tod_clock *tod)
0067 {
0068 asm volatile("stcke %0" : "=Q" (*tod) : : "cc");
0069 }
0070
0071 static inline void set_clock_comparator(__u64 time)
0072 {
0073 asm volatile("sckc %0" : : "Q" (time));
0074 }
0075
0076 static inline void set_tod_programmable_field(u16 val)
0077 {
0078 asm volatile(
0079 " lgr 0,%[val]\n"
0080 " sckpf\n"
0081 :
0082 : [val] "d" ((unsigned long)val)
0083 : "0");
0084 }
0085
0086 void clock_comparator_work(void);
0087
0088 void __init time_early_init(void);
0089
0090 extern unsigned char ptff_function_mask[16];
0091
0092
0093 #define PTFF_QAF 0x00
0094 #define PTFF_QTO 0x01
0095 #define PTFF_QSI 0x02
0096 #define PTFF_QUI 0x04
0097 #define PTFF_ATO 0x40
0098 #define PTFF_STO 0x41
0099 #define PTFF_SFS 0x42
0100 #define PTFF_SGS 0x43
0101
0102
0103 struct ptff_qto {
0104 unsigned long physical_clock;
0105 unsigned long tod_offset;
0106 unsigned long logical_tod_offset;
0107 unsigned long tod_epoch_difference;
0108 } __packed;
0109
0110 static inline int ptff_query(unsigned int nr)
0111 {
0112 unsigned char *ptr;
0113
0114 ptr = ptff_function_mask + (nr >> 3);
0115 return (*ptr & (0x80 >> (nr & 7))) != 0;
0116 }
0117
0118
0119 struct ptff_qui {
0120 unsigned int tm : 2;
0121 unsigned int ts : 2;
0122 unsigned int : 28;
0123 unsigned int pad_0x04;
0124 unsigned long leap_event;
0125 short old_leap;
0126 short new_leap;
0127 unsigned int pad_0x14;
0128 unsigned long prt[5];
0129 unsigned long cst[3];
0130 unsigned int skew;
0131 unsigned int pad_0x5c[41];
0132 } __packed;
0133
0134
0135
0136
0137
0138
0139
0140
0141 #define ptff(ptff_block, len, func) \
0142 ({ \
0143 struct addrtype { char _[len]; }; \
0144 unsigned int reg0 = func; \
0145 unsigned long reg1 = (unsigned long)(ptff_block); \
0146 int rc; \
0147 \
0148 asm volatile( \
0149 " lgr 0,%[reg0]\n" \
0150 " lgr 1,%[reg1]\n" \
0151 " ptff\n" \
0152 " ipm %[rc]\n" \
0153 " srl %[rc],28\n" \
0154 : [rc] "=&d" (rc), "+m" (*(struct addrtype *)reg1) \
0155 : [reg0] "d" (reg0), [reg1] "d" (reg1) \
0156 : "cc", "0", "1"); \
0157 rc; \
0158 })
0159
0160 static inline unsigned long local_tick_disable(void)
0161 {
0162 unsigned long old;
0163
0164 old = S390_lowcore.clock_comparator;
0165 S390_lowcore.clock_comparator = clock_comparator_max;
0166 set_clock_comparator(S390_lowcore.clock_comparator);
0167 return old;
0168 }
0169
0170 static inline void local_tick_enable(unsigned long comp)
0171 {
0172 S390_lowcore.clock_comparator = comp;
0173 set_clock_comparator(S390_lowcore.clock_comparator);
0174 }
0175
0176 #define CLOCK_TICK_RATE 1193180
0177
0178 typedef unsigned long cycles_t;
0179
0180 static inline unsigned long get_tod_clock(void)
0181 {
0182 union tod_clock clk;
0183
0184 store_tod_clock_ext(&clk);
0185 return clk.tod;
0186 }
0187
0188 static inline unsigned long get_tod_clock_fast(void)
0189 {
0190 unsigned long clk;
0191
0192 asm volatile("stckf %0" : "=Q" (clk) : : "cc");
0193 return clk;
0194 }
0195
0196 static inline cycles_t get_cycles(void)
0197 {
0198 return (cycles_t) get_tod_clock() >> 2;
0199 }
0200 #define get_cycles get_cycles
0201
0202 int get_phys_clock(unsigned long *clock);
0203 void init_cpu_timer(void);
0204
0205 extern union tod_clock tod_clock_base;
0206
0207
0208
0209
0210
0211
0212
0213
0214 static inline unsigned long get_tod_clock_monotonic(void)
0215 {
0216 unsigned long tod;
0217
0218 preempt_disable_notrace();
0219 tod = get_tod_clock() - tod_clock_base.tod;
0220 preempt_enable_notrace();
0221 return tod;
0222 }
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243 static inline unsigned long tod_to_ns(unsigned long todval)
0244 {
0245 return ((todval >> 9) * 125) + (((todval & 0x1ff) * 125) >> 9);
0246 }
0247
0248
0249
0250
0251
0252
0253
0254
0255 static inline int tod_after(unsigned long a, unsigned long b)
0256 {
0257 if (MACHINE_HAS_SCC)
0258 return (long) a > (long) b;
0259 return a > b;
0260 }
0261
0262
0263
0264
0265
0266
0267
0268
0269 static inline int tod_after_eq(unsigned long a, unsigned long b)
0270 {
0271 if (MACHINE_HAS_SCC)
0272 return (long) a >= (long) b;
0273 return a >= b;
0274 }
0275
0276 #endif