1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * This file contains the jiffies based clocksource. 4 * 5 * Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com) 6 */ 7 #include <linux/clocksource.h> 8 #include <linux/jiffies.h> 9 #include <linux/module.h> 10 #include <linux/init.h> 11 12 #include "timekeeping.h" 13 #include "tick-internal.h" 14 15 16 static u64 jiffies_read(struct clocksource *cs) 17 { 18 return (u64) jiffies; 19 } 20 21 /* 22 * The Jiffies based clocksource is the lowest common 23 * denominator clock source which should function on 24 * all systems. It has the same coarse resolution as 25 * the timer interrupt frequency HZ and it suffers 26 * inaccuracies caused by missed or lost timer 27 * interrupts and the inability for the timer 28 * interrupt hardware to accurately tick at the 29 * requested HZ value. It is also not recommended 30 * for "tick-less" systems. 31 */ 32 static struct clocksource clocksource_jiffies = { 33 .name = "jiffies", 34 .rating = 1, /* lowest valid rating*/ 35 .read = jiffies_read, 36 .mask = CLOCKSOURCE_MASK(32), 37 .mult = TICK_NSEC << JIFFIES_SHIFT, /* details above */ 38 .shift = JIFFIES_SHIFT, 39 .max_cycles = 10, 40 }; 41 42 __cacheline_aligned_in_smp DEFINE_RAW_SPINLOCK(jiffies_lock); 43 __cacheline_aligned_in_smp seqcount_raw_spinlock_t jiffies_seq = 44 SEQCNT_RAW_SPINLOCK_ZERO(jiffies_seq, &jiffies_lock); 45 46 #if (BITS_PER_LONG < 64) 47 u64 get_jiffies_64(void) 48 { 49 unsigned int seq; 50 u64 ret; 51 52 do { 53 seq = read_seqcount_begin(&jiffies_seq); 54 ret = jiffies_64; 55 } while (read_seqcount_retry(&jiffies_seq, seq)); 56 return ret; 57 } 58 EXPORT_SYMBOL(get_jiffies_64); 59 #endif 60 61 EXPORT_SYMBOL(jiffies); 62 63 static bool cs_jiffies_registered __initdata; 64 65 struct clocksource * __init __weak clocksource_default_clock(void) 66 { 67 if (!cs_jiffies_registered) { 68 __clocksource_register(&clocksource_jiffies); 69 cs_jiffies_registered = true; 70 } 71 return &clocksource_jiffies; 72 } 73 74 static struct clocksource refined_jiffies; 75 76 void __init register_refined_jiffies(long cycles_per_second) 77 { 78 u64 nsec_per_tick, shift_hz; 79 long cycles_per_tick; 80 81 refined_jiffies = clocksource_jiffies; 82 refined_jiffies.name = "refined-jiffies"; 83 refined_jiffies.rating++; 84 85 /* Calc cycles per tick */ 86 cycles_per_tick = (cycles_per_second + HZ/2)/HZ; 87 /* shift_hz stores hz<<8 for extra accuracy */ 88 shift_hz = (u64)cycles_per_second << 8; 89 shift_hz += cycles_per_tick/2; 90 do_div(shift_hz, cycles_per_tick); 91 /* Calculate nsec_per_tick using shift_hz */ 92 nsec_per_tick = (u64)NSEC_PER_SEC << 8; 93 nsec_per_tick += (u32)shift_hz/2; 94 do_div(nsec_per_tick, (u32)shift_hz); 95 96 refined_jiffies.mult = ((u32)nsec_per_tick) << JIFFIES_SHIFT; 97 98 __clocksource_register(&refined_jiffies); 99 } 100 101 #ifdef CONFIG_PROC_SYSCTL 102 static ulong mult_hz(const ulong val) 103 { 104 return val * HZ; 105 } 106 107 static ulong div_hz(const ulong val) 108 { 109 return val / HZ; 110 } 111 112 static int sysctl_u2k_int_conv_hz(const bool *negp, const ulong *u_ptr, int *k_ptr) 113 { 114 return proc_int_u2k_conv_uop(u_ptr, k_ptr, negp, mult_hz); 115 } 116 117 static int sysctl_k2u_int_conv_hz(bool *negp, ulong *u_ptr, const int *k_ptr) 118 { 119 return proc_int_k2u_conv_kop(u_ptr, k_ptr, negp, div_hz); 120 } 121 122 static int sysctl_u2k_int_conv_userhz(const bool *negp, const ulong *u_ptr, int *k_ptr) 123 { 124 return proc_int_u2k_conv_uop(u_ptr, k_ptr, negp, clock_t_to_jiffies); 125 } 126 127 static ulong sysctl_jiffies_to_clock_t(const ulong val) 128 { 129 return jiffies_to_clock_t(val); 130 } 131 132 static int sysctl_k2u_int_conv_userhz(bool *negp, ulong *u_ptr, const int *k_ptr) 133 { 134 return proc_int_k2u_conv_kop(u_ptr, k_ptr, negp, sysctl_jiffies_to_clock_t); 135 } 136 137 static ulong sysctl_msecs_to_jiffies(const ulong val) 138 { 139 return msecs_to_jiffies(val); 140 } 141 142 static int sysctl_u2k_int_conv_ms(const bool *negp, const ulong *u_ptr, int *k_ptr) 143 { 144 return proc_int_u2k_conv_uop(u_ptr, k_ptr, negp, sysctl_msecs_to_jiffies); 145 } 146 147 static ulong sysctl_jiffies_to_msecs(const ulong val) 148 { 149 return jiffies_to_msecs(val); 150 } 151 152 static int sysctl_k2u_int_conv_ms(bool *negp, ulong *u_ptr, const int *k_ptr) 153 { 154 return proc_int_k2u_conv_kop(u_ptr, k_ptr, negp, sysctl_jiffies_to_msecs); 155 } 156 157 static int do_proc_int_conv_jiffies(bool *negp, ulong *u_ptr, int *k_ptr, 158 int dir, const struct ctl_table *tbl) 159 { 160 return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, false, 161 sysctl_u2k_int_conv_hz, sysctl_k2u_int_conv_hz); 162 } 163 164 static int do_proc_int_conv_userhz_jiffies(bool *negp, ulong *u_ptr, 165 int *k_ptr, int dir, 166 const struct ctl_table *tbl) 167 { 168 return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, false, 169 sysctl_u2k_int_conv_userhz, 170 sysctl_k2u_int_conv_userhz); 171 } 172 173 static int do_proc_int_conv_ms_jiffies(bool *negp, ulong *u_ptr, int *k_ptr, 174 int dir, const struct ctl_table *tbl) 175 { 176 return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, false, 177 sysctl_u2k_int_conv_ms, sysctl_k2u_int_conv_ms); 178 } 179 180 static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr, 181 int *k_ptr, int dir, 182 const struct ctl_table *tbl) 183 { 184 return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, false, 185 sysctl_u2k_int_conv_ms, sysctl_k2u_int_conv_ms); 186 } 187 188 #else // CONFIG_PROC_SYSCTL 189 static int do_proc_int_conv_jiffies(bool *negp, ulong *u_ptr, int *k_ptr, 190 int dir, const struct ctl_table *tbl) 191 { 192 return -ENOSYS; 193 } 194 195 static int do_proc_int_conv_userhz_jiffies(bool *negp, ulong *u_ptr, 196 int *k_ptr, int dir, 197 const struct ctl_table *tbl) 198 { 199 return -ENOSYS; 200 } 201 202 static int do_proc_int_conv_ms_jiffies(bool *negp, ulong *u_ptr, int *k_ptr, 203 int dir, const struct ctl_table *tbl) 204 { 205 return -ENOSYS; 206 } 207 208 static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr, 209 int *k_ptr, int dir, 210 const struct ctl_table *tbl) 211 { 212 return -ENOSYS; 213 } 214 #endif 215 216 /** 217 * proc_dointvec_jiffies - read a vector of integers as seconds 218 * @table: the sysctl table 219 * @dir: %TRUE if this is a write to the sysctl file 220 * @buffer: the user buffer 221 * @lenp: the size of the user buffer 222 * @ppos: file position 223 * 224 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 225 * values from/to the user buffer, treated as an ASCII string. 226 * The values read are assumed to be in seconds, and are converted into 227 * jiffies. 228 * 229 * Returns 0 on success. 230 */ 231 int proc_dointvec_jiffies(const struct ctl_table *table, int dir, 232 void *buffer, size_t *lenp, loff_t *ppos) 233 { 234 return proc_dointvec_conv(table, dir, buffer, lenp, ppos, 235 do_proc_int_conv_jiffies); 236 } 237 EXPORT_SYMBOL(proc_dointvec_jiffies); 238 239 /** 240 * proc_dointvec_userhz_jiffies - read a vector of integers as 1/USER_HZ seconds 241 * @table: the sysctl table 242 * @dir: %TRUE if this is a write to the sysctl file 243 * @buffer: the user buffer 244 * @lenp: the size of the user buffer 245 * @ppos: pointer to the file position 246 * 247 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 248 * values from/to the user buffer, treated as an ASCII string. 249 * The values read are assumed to be in 1/USER_HZ seconds, and 250 * are converted into jiffies. 251 * 252 * Returns 0 on success. 253 */ 254 int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int dir, 255 void *buffer, size_t *lenp, loff_t *ppos) 256 { 257 return proc_dointvec_conv(table, dir, buffer, lenp, ppos, 258 do_proc_int_conv_userhz_jiffies); 259 } 260 EXPORT_SYMBOL(proc_dointvec_userhz_jiffies); 261 262 /** 263 * proc_dointvec_ms_jiffies - read a vector of integers as 1 milliseconds 264 * @table: the sysctl table 265 * @dir: %TRUE if this is a write to the sysctl file 266 * @buffer: the user buffer 267 * @lenp: the size of the user buffer 268 * @ppos: the current position in the file 269 * 270 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 271 * values from/to the user buffer, treated as an ASCII string. 272 * The values read are assumed to be in 1/1000 seconds, and 273 * are converted into jiffies. 274 * 275 * Returns 0 on success. 276 */ 277 int proc_dointvec_ms_jiffies(const struct ctl_table *table, int dir, void *buffer, 278 size_t *lenp, loff_t *ppos) 279 { 280 return proc_dointvec_conv(table, dir, buffer, lenp, ppos, 281 do_proc_int_conv_ms_jiffies); 282 } 283 EXPORT_SYMBOL(proc_dointvec_ms_jiffies); 284 285 int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int dir, 286 void *buffer, size_t *lenp, loff_t *ppos) 287 { 288 return proc_dointvec_conv(table, dir, buffer, lenp, ppos, 289 do_proc_int_conv_ms_jiffies_minmax); 290 } 291 292 /** 293 * proc_doulongvec_ms_jiffies_minmax - read a vector of millisecond values with min/max values 294 * @table: the sysctl table 295 * @dir: %TRUE if this is a write to the sysctl file 296 * @buffer: the user buffer 297 * @lenp: the size of the user buffer 298 * @ppos: file position 299 * 300 * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long 301 * values from/to the user buffer, treated as an ASCII string. The values 302 * are treated as milliseconds, and converted to jiffies when they are stored. 303 * 304 * This routine will ensure the values are within the range specified by 305 * table->extra1 (min) and table->extra2 (max). 306 * 307 * Returns 0 on success. 308 */ 309 int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int dir, 310 void *buffer, size_t *lenp, loff_t *ppos) 311 { 312 return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos, 313 HZ, 1000l); 314 } 315 EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); 316 317