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