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