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