Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  *  S390 version
0004  *    Copyright IBM Corp. 1999
0005  *
0006  *  Derived from "include/asm-i386/timex.h"
0007  *    Copyright (C) 1992, Linus Torvalds
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 /* The value of the TOD clock for 1.1.1970. */
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; /* epoch index */
0026         __uint128_t tod : 64; /* bits 0-63 of tod clock */
0027         __uint128_t : 40;
0028         __uint128_t pf  : 16; /* programmable field */
0029     };
0030     struct {
0031         __uint128_t eitod : 72; /* epoch index + bits 0-63 tod clock */
0032         __uint128_t   : 56;
0033     };
0034     struct {
0035         __uint128_t us  : 60; /* micro-seconds */
0036         __uint128_t sus : 12; /* sub-microseconds */
0037         __uint128_t : 56;
0038     };
0039 } __packed;
0040 
0041 /* Inline functions for clock register access. */
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 /* Function codes for the ptff instruction. */
0093 #define PTFF_QAF    0x00    /* query available functions */
0094 #define PTFF_QTO    0x01    /* query tod offset */
0095 #define PTFF_QSI    0x02    /* query steering information */
0096 #define PTFF_QUI    0x04    /* query UTC information */
0097 #define PTFF_ATO    0x40    /* adjust tod offset */
0098 #define PTFF_STO    0x41    /* set tod offset */
0099 #define PTFF_SFS    0x42    /* set fine steering rate */
0100 #define PTFF_SGS    0x43    /* set gross steering rate */
0101 
0102 /* Query TOD offset result */
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 /* Query UTC information result */
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  * ptff - Perform timing facility function
0136  * @ptff_block: Pointer to ptff parameter block
0137  * @len: Length of parameter block
0138  * @func: Function code
0139  * Returns: Condition code (0 on success)
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 /* Underlying HZ */
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  * get_clock_monotonic - returns current time in clock rate units
0209  *
0210  * The clock and tod_clock_base get changed via stop_machine.
0211  * Therefore preemption must be disabled, otherwise the returned
0212  * value is not guaranteed to be monotonic.
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  * tod_to_ns - convert a TOD format value to nanoseconds
0226  * @todval: to be converted TOD format value
0227  * Returns: number of nanoseconds that correspond to the TOD format value
0228  *
0229  * Converting a 64 Bit TOD format value to nanoseconds means that the value
0230  * must be divided by 4.096. In order to achieve that we multiply with 125
0231  * and divide by 512:
0232  *
0233  *    ns = (todval * 125) >> 9;
0234  *
0235  * In order to avoid an overflow with the multiplication we can rewrite this.
0236  * With a split todval == 2^9 * th + tl (th upper 55 bits, tl lower 9 bits)
0237  * we end up with
0238  *
0239  *    ns = ((2^9 * th + tl) * 125 ) >> 9;
0240  * -> ns = (th * 125) + ((tl * 125) >> 9);
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  * tod_after - compare two 64 bit TOD values
0250  * @a: first 64 bit TOD timestamp
0251  * @b: second 64 bit TOD timestamp
0252  *
0253  * Returns: true if a is later than b
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  * tod_after_eq - compare two 64 bit TOD values
0264  * @a: first 64 bit TOD timestamp
0265  * @b: second 64 bit TOD timestamp
0266  *
0267  * Returns: true if a is later than b
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