FILE
jiffies.c
File preview with syntax highlighting.
linux-6.19.14/kernel/time/jiffies.c
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 16static 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 */ 32static 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) 48u64 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} 59EXPORT_SYMBOL(get_jiffies_64); 60#endif 61 62EXPORT_SYMBOL(jiffies); 63 64static int __init init_jiffies_clocksource(void) 65{ 66 return __clocksource_register(&clocksource_jiffies); 67} 68 69core_initcall(init_jiffies_clocksource); 70 71struct clocksource * __init __weak clocksource_default_clock(void) 72{ 73 return &clocksource_jiffies; 74} 75 76static struct clocksource refined_jiffies; 77 78void __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#define SYSCTL_CONV_MULT_HZ(val) ((val) * HZ) 104#define SYSCTL_CONV_DIV_HZ(val) ((val) / HZ) 105 106static SYSCTL_USER_TO_KERN_INT_CONV(_hz, SYSCTL_CONV_MULT_HZ) 107static SYSCTL_KERN_TO_USER_INT_CONV(_hz, SYSCTL_CONV_DIV_HZ) 108static SYSCTL_USER_TO_KERN_INT_CONV(_userhz, clock_t_to_jiffies) 109static SYSCTL_KERN_TO_USER_INT_CONV(_userhz, jiffies_to_clock_t) 110static SYSCTL_USER_TO_KERN_INT_CONV(_ms, msecs_to_jiffies) 111static SYSCTL_KERN_TO_USER_INT_CONV(_ms, jiffies_to_msecs) 112 113static SYSCTL_INT_CONV_CUSTOM(_jiffies, sysctl_user_to_kern_int_conv_hz, 114 sysctl_kern_to_user_int_conv_hz, false) 115static SYSCTL_INT_CONV_CUSTOM(_userhz_jiffies, 116 sysctl_user_to_kern_int_conv_userhz, 117 sysctl_kern_to_user_int_conv_userhz, false) 118static SYSCTL_INT_CONV_CUSTOM(_ms_jiffies, sysctl_user_to_kern_int_conv_ms, 119 sysctl_kern_to_user_int_conv_ms, false) 120static SYSCTL_INT_CONV_CUSTOM(_ms_jiffies_minmax, 121 sysctl_user_to_kern_int_conv_ms, 122 sysctl_kern_to_user_int_conv_ms, true) 123 124/** 125 * proc_dointvec_jiffies - read a vector of integers as seconds 126 * @table: the sysctl table 127 * @dir: %TRUE if this is a write to the sysctl file 128 * @buffer: the user buffer 129 * @lenp: the size of the user buffer 130 * @ppos: file position 131 * 132 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 133 * values from/to the user buffer, treated as an ASCII string. 134 * The values read are assumed to be in seconds, and are converted into 135 * jiffies. 136 * 137 * Returns 0 on success. 138 */ 139int proc_dointvec_jiffies(const struct ctl_table *table, int dir, 140 void *buffer, size_t *lenp, loff_t *ppos) 141{ 142 return proc_dointvec_conv(table, dir, buffer, lenp, ppos, 143 do_proc_int_conv_jiffies); 144} 145EXPORT_SYMBOL(proc_dointvec_jiffies); 146 147/** 148 * proc_dointvec_userhz_jiffies - read a vector of integers as 1/USER_HZ seconds 149 * @table: the sysctl table 150 * @dir: %TRUE if this is a write to the sysctl file 151 * @buffer: the user buffer 152 * @lenp: the size of the user buffer 153 * @ppos: pointer to the file position 154 * 155 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 156 * values from/to the user buffer, treated as an ASCII string. 157 * The values read are assumed to be in 1/USER_HZ seconds, and 158 * are converted into jiffies. 159 * 160 * Returns 0 on success. 161 */ 162int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int dir, 163 void *buffer, size_t *lenp, loff_t *ppos) 164{ 165 return proc_dointvec_conv(table, dir, buffer, lenp, ppos, 166 do_proc_int_conv_userhz_jiffies); 167} 168EXPORT_SYMBOL(proc_dointvec_userhz_jiffies); 169 170/** 171 * proc_dointvec_ms_jiffies - read a vector of integers as 1 milliseconds 172 * @table: the sysctl table 173 * @dir: %TRUE if this is a write to the sysctl file 174 * @buffer: the user buffer 175 * @lenp: the size of the user buffer 176 * @ppos: the current position in the file 177 * 178 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 179 * values from/to the user buffer, treated as an ASCII string. 180 * The values read are assumed to be in 1/1000 seconds, and 181 * are converted into jiffies. 182 * 183 * Returns 0 on success. 184 */ 185int proc_dointvec_ms_jiffies(const struct ctl_table *table, int dir, void *buffer, 186 size_t *lenp, loff_t *ppos) 187{ 188 return proc_dointvec_conv(table, dir, buffer, lenp, ppos, 189 do_proc_int_conv_ms_jiffies); 190} 191EXPORT_SYMBOL(proc_dointvec_ms_jiffies); 192 193int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int dir, 194 void *buffer, size_t *lenp, loff_t *ppos) 195{ 196 return proc_dointvec_conv(table, dir, buffer, lenp, ppos, 197 do_proc_int_conv_ms_jiffies_minmax); 198} 199 200/** 201 * proc_doulongvec_ms_jiffies_minmax - read a vector of millisecond values with min/max values 202 * @table: the sysctl table 203 * @dir: %TRUE if this is a write to the sysctl file 204 * @buffer: the user buffer 205 * @lenp: the size of the user buffer 206 * @ppos: file position 207 * 208 * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long 209 * values from/to the user buffer, treated as an ASCII string. The values 210 * are treated as milliseconds, and converted to jiffies when they are stored. 211 * 212 * This routine will ensure the values are within the range specified by 213 * table->extra1 (min) and table->extra2 (max). 214 * 215 * Returns 0 on success. 216 */ 217int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int dir, 218 void *buffer, size_t *lenp, loff_t *ppos) 219{ 220 return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos, 221 HZ, 1000l); 222} 223EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); 224
~/
Read-only file preview.