xref: /linux/kernel/time/jiffies.c (revision 12f8069115d5ff9d292c6b00c74e1984b01b6fc1)
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 
jiffies_read(struct clocksource * cs)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)
get_jiffies_64(void)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 
init_jiffies_clocksource(void)63 static int __init init_jiffies_clocksource(void)
64 {
65 	return __clocksource_register(&clocksource_jiffies);
66 }
67 
68 core_initcall(init_jiffies_clocksource);
69 
clocksource_default_clock(void)70 struct clocksource * __init __weak clocksource_default_clock(void)
71 {
72 	return &clocksource_jiffies;
73 }
74 
75 static struct clocksource refined_jiffies;
76 
register_refined_jiffies(long cycles_per_second)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
mult_hz(const ulong val)103 static ulong mult_hz(const ulong val)
104 {
105 	return val * HZ;
106 }
107 
div_hz(const ulong val)108 static ulong div_hz(const ulong val)
109 {
110 	return val / HZ;
111 }
112 
sysctl_u2k_int_conv_hz(const bool * negp,const ulong * u_ptr,int * k_ptr)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 
sysctl_k2u_int_conv_hz(bool * negp,ulong * u_ptr,const int * k_ptr)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 
sysctl_u2k_int_conv_userhz(const bool * negp,const ulong * u_ptr,int * k_ptr)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 
sysctl_jiffies_to_clock_t(const ulong val)128 static ulong sysctl_jiffies_to_clock_t(const ulong val)
129 {
130 	return jiffies_to_clock_t(val);
131 }
132 
sysctl_k2u_int_conv_userhz(bool * negp,ulong * u_ptr,const int * k_ptr)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 
sysctl_msecs_to_jiffies(const ulong val)138 static ulong sysctl_msecs_to_jiffies(const ulong val)
139 {
140 	return msecs_to_jiffies(val);
141 }
142 
sysctl_u2k_int_conv_ms(const bool * negp,const ulong * u_ptr,int * k_ptr)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 
sysctl_jiffies_to_msecs(const ulong val)148 static ulong sysctl_jiffies_to_msecs(const ulong val)
149 {
150 	return jiffies_to_msecs(val);
151 }
152 
sysctl_k2u_int_conv_ms(bool * negp,ulong * u_ptr,const int * k_ptr)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 
do_proc_int_conv_jiffies(bool * negp,ulong * u_ptr,int * k_ptr,int dir,const struct ctl_table * tbl)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 
do_proc_int_conv_userhz_jiffies(bool * negp,ulong * u_ptr,int * k_ptr,int dir,const struct ctl_table * tbl)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 
do_proc_int_conv_ms_jiffies(bool * negp,ulong * u_ptr,int * k_ptr,int dir,const struct ctl_table * tbl)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 
do_proc_int_conv_ms_jiffies_minmax(bool * negp,ulong * u_ptr,int * k_ptr,int dir,const struct ctl_table * tbl)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
do_proc_int_conv_jiffies(bool * negp,ulong * u_ptr,int * k_ptr,int dir,const struct ctl_table * tbl)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 
do_proc_int_conv_userhz_jiffies(bool * negp,ulong * u_ptr,int * k_ptr,int dir,const struct ctl_table * tbl)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 
do_proc_int_conv_ms_jiffies(bool * negp,ulong * u_ptr,int * k_ptr,int dir,const struct ctl_table * tbl)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 
do_proc_int_conv_ms_jiffies_minmax(bool * negp,ulong * u_ptr,int * k_ptr,int dir,const struct ctl_table * tbl)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  */
proc_dointvec_jiffies(const struct ctl_table * table,int dir,void * buffer,size_t * lenp,loff_t * ppos)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  */
proc_dointvec_userhz_jiffies(const struct ctl_table * table,int dir,void * buffer,size_t * lenp,loff_t * ppos)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  */
proc_dointvec_ms_jiffies(const struct ctl_table * table,int dir,void * buffer,size_t * lenp,loff_t * ppos)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 
proc_dointvec_ms_jiffies_minmax(const struct ctl_table * table,int dir,void * buffer,size_t * lenp,loff_t * ppos)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  */
proc_doulongvec_ms_jiffies_minmax(const struct ctl_table * table,int dir,void * buffer,size_t * lenp,loff_t * ppos)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