18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * S390 version 48c2ecf20Sopenharmony_ci * Copyright IBM Corp. 1999 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Derived from "include/asm-i386/timex.h" 78c2ecf20Sopenharmony_ci * Copyright (C) 1992, Linus Torvalds 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#ifndef _ASM_S390_TIMEX_H 118c2ecf20Sopenharmony_ci#define _ASM_S390_TIMEX_H 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/preempt.h> 148c2ecf20Sopenharmony_ci#include <linux/time64.h> 158c2ecf20Sopenharmony_ci#include <asm/lowcore.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* The value of the TOD clock for 1.1.1970. */ 188c2ecf20Sopenharmony_ci#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciextern u64 clock_comparator_max; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Inline functions for clock register access. */ 238c2ecf20Sopenharmony_cistatic inline int set_tod_clock(__u64 time) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci int cc; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci asm volatile( 288c2ecf20Sopenharmony_ci " sck %1\n" 298c2ecf20Sopenharmony_ci " ipm %0\n" 308c2ecf20Sopenharmony_ci " srl %0,28\n" 318c2ecf20Sopenharmony_ci : "=d" (cc) : "Q" (time) : "cc"); 328c2ecf20Sopenharmony_ci return cc; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic inline int store_tod_clock(__u64 *time) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci int cc; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci asm volatile( 408c2ecf20Sopenharmony_ci " stck %1\n" 418c2ecf20Sopenharmony_ci " ipm %0\n" 428c2ecf20Sopenharmony_ci " srl %0,28\n" 438c2ecf20Sopenharmony_ci : "=d" (cc), "=Q" (*time) : : "cc"); 448c2ecf20Sopenharmony_ci return cc; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic inline void set_clock_comparator(__u64 time) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci asm volatile("sckc %0" : : "Q" (time)); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_civoid clock_comparator_work(void); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_civoid __init time_early_init(void); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciextern unsigned char ptff_function_mask[16]; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* Function codes for the ptff instruction. */ 598c2ecf20Sopenharmony_ci#define PTFF_QAF 0x00 /* query available functions */ 608c2ecf20Sopenharmony_ci#define PTFF_QTO 0x01 /* query tod offset */ 618c2ecf20Sopenharmony_ci#define PTFF_QSI 0x02 /* query steering information */ 628c2ecf20Sopenharmony_ci#define PTFF_QUI 0x04 /* query UTC information */ 638c2ecf20Sopenharmony_ci#define PTFF_ATO 0x40 /* adjust tod offset */ 648c2ecf20Sopenharmony_ci#define PTFF_STO 0x41 /* set tod offset */ 658c2ecf20Sopenharmony_ci#define PTFF_SFS 0x42 /* set fine steering rate */ 668c2ecf20Sopenharmony_ci#define PTFF_SGS 0x43 /* set gross steering rate */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Query TOD offset result */ 698c2ecf20Sopenharmony_cistruct ptff_qto { 708c2ecf20Sopenharmony_ci unsigned long long physical_clock; 718c2ecf20Sopenharmony_ci unsigned long long tod_offset; 728c2ecf20Sopenharmony_ci unsigned long long logical_tod_offset; 738c2ecf20Sopenharmony_ci unsigned long long tod_epoch_difference; 748c2ecf20Sopenharmony_ci} __packed; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic inline int ptff_query(unsigned int nr) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci unsigned char *ptr; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci ptr = ptff_function_mask + (nr >> 3); 818c2ecf20Sopenharmony_ci return (*ptr & (0x80 >> (nr & 7))) != 0; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* Query UTC information result */ 858c2ecf20Sopenharmony_cistruct ptff_qui { 868c2ecf20Sopenharmony_ci unsigned int tm : 2; 878c2ecf20Sopenharmony_ci unsigned int ts : 2; 888c2ecf20Sopenharmony_ci unsigned int : 28; 898c2ecf20Sopenharmony_ci unsigned int pad_0x04; 908c2ecf20Sopenharmony_ci unsigned long leap_event; 918c2ecf20Sopenharmony_ci short old_leap; 928c2ecf20Sopenharmony_ci short new_leap; 938c2ecf20Sopenharmony_ci unsigned int pad_0x14; 948c2ecf20Sopenharmony_ci unsigned long prt[5]; 958c2ecf20Sopenharmony_ci unsigned long cst[3]; 968c2ecf20Sopenharmony_ci unsigned int skew; 978c2ecf20Sopenharmony_ci unsigned int pad_0x5c[41]; 988c2ecf20Sopenharmony_ci} __packed; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* 1018c2ecf20Sopenharmony_ci * ptff - Perform timing facility function 1028c2ecf20Sopenharmony_ci * @ptff_block: Pointer to ptff parameter block 1038c2ecf20Sopenharmony_ci * @len: Length of parameter block 1048c2ecf20Sopenharmony_ci * @func: Function code 1058c2ecf20Sopenharmony_ci * Returns: Condition code (0 on success) 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci#define ptff(ptff_block, len, func) \ 1088c2ecf20Sopenharmony_ci({ \ 1098c2ecf20Sopenharmony_ci struct addrtype { char _[len]; }; \ 1108c2ecf20Sopenharmony_ci register unsigned int reg0 asm("0") = func; \ 1118c2ecf20Sopenharmony_ci register unsigned long reg1 asm("1") = (unsigned long) (ptff_block);\ 1128c2ecf20Sopenharmony_ci int rc; \ 1138c2ecf20Sopenharmony_ci \ 1148c2ecf20Sopenharmony_ci asm volatile( \ 1158c2ecf20Sopenharmony_ci " .word 0x0104\n" \ 1168c2ecf20Sopenharmony_ci " ipm %0\n" \ 1178c2ecf20Sopenharmony_ci " srl %0,28\n" \ 1188c2ecf20Sopenharmony_ci : "=d" (rc), "+m" (*(struct addrtype *) reg1) \ 1198c2ecf20Sopenharmony_ci : "d" (reg0), "d" (reg1) : "cc"); \ 1208c2ecf20Sopenharmony_ci rc; \ 1218c2ecf20Sopenharmony_ci}) 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic inline unsigned long long local_tick_disable(void) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci unsigned long long old; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci old = S390_lowcore.clock_comparator; 1288c2ecf20Sopenharmony_ci S390_lowcore.clock_comparator = clock_comparator_max; 1298c2ecf20Sopenharmony_ci set_clock_comparator(S390_lowcore.clock_comparator); 1308c2ecf20Sopenharmony_ci return old; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic inline void local_tick_enable(unsigned long long comp) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci S390_lowcore.clock_comparator = comp; 1368c2ecf20Sopenharmony_ci set_clock_comparator(S390_lowcore.clock_comparator); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ 1408c2ecf20Sopenharmony_ci#define STORE_CLOCK_EXT_SIZE 16 /* stcke writes 16 bytes */ 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_citypedef unsigned long long cycles_t; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic inline void get_tod_clock_ext(char *clk) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci typedef struct { char _[STORE_CLOCK_EXT_SIZE]; } addrtype; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci asm volatile("stcke %0" : "=Q" (*(addrtype *) clk) : : "cc"); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic inline unsigned long long get_tod_clock(void) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci char clk[STORE_CLOCK_EXT_SIZE]; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci get_tod_clock_ext(clk); 1568c2ecf20Sopenharmony_ci return *((unsigned long long *)&clk[1]); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic inline unsigned long long get_tod_clock_fast(void) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES 1628c2ecf20Sopenharmony_ci unsigned long long clk; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci asm volatile("stckf %0" : "=Q" (clk) : : "cc"); 1658c2ecf20Sopenharmony_ci return clk; 1668c2ecf20Sopenharmony_ci#else 1678c2ecf20Sopenharmony_ci return get_tod_clock(); 1688c2ecf20Sopenharmony_ci#endif 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic inline cycles_t get_cycles(void) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci return (cycles_t) get_tod_clock() >> 2; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci#define get_cycles get_cycles 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ciint get_phys_clock(unsigned long *clock); 1788c2ecf20Sopenharmony_civoid init_cpu_timer(void); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ciextern unsigned char tod_clock_base[16] __aligned(8); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/** 1838c2ecf20Sopenharmony_ci * get_clock_monotonic - returns current time in clock rate units 1848c2ecf20Sopenharmony_ci * 1858c2ecf20Sopenharmony_ci * The clock and tod_clock_base get changed via stop_machine. 1868c2ecf20Sopenharmony_ci * Therefore preemption must be disabled, otherwise the returned 1878c2ecf20Sopenharmony_ci * value is not guaranteed to be monotonic. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_cistatic inline unsigned long long get_tod_clock_monotonic(void) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci unsigned long long tod; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci preempt_disable_notrace(); 1948c2ecf20Sopenharmony_ci tod = get_tod_clock() - *(unsigned long long *) &tod_clock_base[1]; 1958c2ecf20Sopenharmony_ci preempt_enable_notrace(); 1968c2ecf20Sopenharmony_ci return tod; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/** 2008c2ecf20Sopenharmony_ci * tod_to_ns - convert a TOD format value to nanoseconds 2018c2ecf20Sopenharmony_ci * @todval: to be converted TOD format value 2028c2ecf20Sopenharmony_ci * Returns: number of nanoseconds that correspond to the TOD format value 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci * Converting a 64 Bit TOD format value to nanoseconds means that the value 2058c2ecf20Sopenharmony_ci * must be divided by 4.096. In order to achieve that we multiply with 125 2068c2ecf20Sopenharmony_ci * and divide by 512: 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * ns = (todval * 125) >> 9; 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * In order to avoid an overflow with the multiplication we can rewrite this. 2118c2ecf20Sopenharmony_ci * With a split todval == 2^9 * th + tl (th upper 55 bits, tl lower 9 bits) 2128c2ecf20Sopenharmony_ci * we end up with 2138c2ecf20Sopenharmony_ci * 2148c2ecf20Sopenharmony_ci * ns = ((2^9 * th + tl) * 125 ) >> 9; 2158c2ecf20Sopenharmony_ci * -> ns = (th * 125) + ((tl * 125) >> 9); 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_cistatic inline unsigned long long tod_to_ns(unsigned long long todval) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci return ((todval >> 9) * 125) + (((todval & 0x1ff) * 125) >> 9); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/** 2248c2ecf20Sopenharmony_ci * tod_after - compare two 64 bit TOD values 2258c2ecf20Sopenharmony_ci * @a: first 64 bit TOD timestamp 2268c2ecf20Sopenharmony_ci * @b: second 64 bit TOD timestamp 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * Returns: true if a is later than b 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_cistatic inline int tod_after(unsigned long long a, unsigned long long b) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci if (MACHINE_HAS_SCC) 2338c2ecf20Sopenharmony_ci return (long long) a > (long long) b; 2348c2ecf20Sopenharmony_ci return a > b; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/** 2388c2ecf20Sopenharmony_ci * tod_after_eq - compare two 64 bit TOD values 2398c2ecf20Sopenharmony_ci * @a: first 64 bit TOD timestamp 2408c2ecf20Sopenharmony_ci * @b: second 64 bit TOD timestamp 2418c2ecf20Sopenharmony_ci * 2428c2ecf20Sopenharmony_ci * Returns: true if a is later than b 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic inline int tod_after_eq(unsigned long long a, unsigned long long b) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci if (MACHINE_HAS_SCC) 2478c2ecf20Sopenharmony_ci return (long long) a >= (long long) b; 2488c2ecf20Sopenharmony_ci return a >= b; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci#endif 252