xref: /linux/kernel/time/jiffies.c (revision ac20755937e037e586b1ca18a6717d31b1cbce93)
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 	.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)
get_jiffies_64(void)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 
init_jiffies_clocksource(void)64 static int __init init_jiffies_clocksource(void)
65 {
66 	return __clocksource_register(&clocksource_jiffies);
67 }
68 
69 core_initcall(init_jiffies_clocksource);
70 
clocksource_default_clock(void)71 struct clocksource * __init __weak clocksource_default_clock(void)
72 {
73 	return &clocksource_jiffies;
74 }
75 
76 static struct clocksource refined_jiffies;
77 
register_refined_jiffies(long cycles_per_second)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 #define SYSCTL_CONV_MULT_HZ(val) ((val) * HZ)
104 #define SYSCTL_CONV_DIV_HZ(val) ((val) / HZ)
105 
SYSCTL_USER_TO_KERN_INT_CONV(_hz,SYSCTL_CONV_MULT_HZ)106 static SYSCTL_USER_TO_KERN_INT_CONV(_hz, SYSCTL_CONV_MULT_HZ)
107 static SYSCTL_KERN_TO_USER_INT_CONV(_hz, SYSCTL_CONV_DIV_HZ)
108 static SYSCTL_USER_TO_KERN_INT_CONV(_userhz, clock_t_to_jiffies)
109 static SYSCTL_KERN_TO_USER_INT_CONV(_userhz, jiffies_to_clock_t)
110 static SYSCTL_USER_TO_KERN_INT_CONV(_ms, msecs_to_jiffies)
111 static SYSCTL_KERN_TO_USER_INT_CONV(_ms, jiffies_to_msecs)
112 
113 static SYSCTL_INT_CONV_CUSTOM(_jiffies, sysctl_user_to_kern_int_conv_hz,
114 			      sysctl_kern_to_user_int_conv_hz, false)
115 static SYSCTL_INT_CONV_CUSTOM(_userhz_jiffies,
116 			      sysctl_user_to_kern_int_conv_userhz,
117 			      sysctl_kern_to_user_int_conv_userhz, false)
118 static SYSCTL_INT_CONV_CUSTOM(_ms_jiffies, sysctl_user_to_kern_int_conv_ms,
119 			      sysctl_kern_to_user_int_conv_ms, false)
120 static 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  */
139 int 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 }
145 EXPORT_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  */
proc_dointvec_userhz_jiffies(const struct ctl_table * table,int dir,void * buffer,size_t * lenp,loff_t * ppos)162 int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int dir,
163 				 void *buffer, size_t *lenp, loff_t *ppos)
164 {
165 	if (SYSCTL_USER_TO_KERN(dir) && USER_HZ < HZ)
166 		return -EINVAL;
167 	return proc_dointvec_conv(table, dir, buffer, lenp, ppos,
168 				  do_proc_int_conv_userhz_jiffies);
169 }
170 EXPORT_SYMBOL(proc_dointvec_userhz_jiffies);
171 
172 /**
173  * proc_dointvec_ms_jiffies - read a vector of integers as 1 milliseconds
174  * @table: the sysctl table
175  * @dir: %TRUE if this is a write to the sysctl file
176  * @buffer: the user buffer
177  * @lenp: the size of the user buffer
178  * @ppos: the current position in the file
179  *
180  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
181  * values from/to the user buffer, treated as an ASCII string.
182  * The values read are assumed to be in 1/1000 seconds, and
183  * are converted into jiffies.
184  *
185  * Returns 0 on success.
186  */
proc_dointvec_ms_jiffies(const struct ctl_table * table,int dir,void * buffer,size_t * lenp,loff_t * ppos)187 int proc_dointvec_ms_jiffies(const struct ctl_table *table, int dir, void *buffer,
188 		size_t *lenp, loff_t *ppos)
189 {
190 	return proc_dointvec_conv(table, dir, buffer, lenp, ppos,
191 				  do_proc_int_conv_ms_jiffies);
192 }
193 EXPORT_SYMBOL(proc_dointvec_ms_jiffies);
194 
proc_dointvec_ms_jiffies_minmax(const struct ctl_table * table,int dir,void * buffer,size_t * lenp,loff_t * ppos)195 int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int dir,
196 			  void *buffer, size_t *lenp, loff_t *ppos)
197 {
198 	return proc_dointvec_conv(table, dir, buffer, lenp, ppos,
199 				  do_proc_int_conv_ms_jiffies_minmax);
200 }
201 
202 /**
203  * proc_doulongvec_ms_jiffies_minmax - read a vector of millisecond values with min/max values
204  * @table: the sysctl table
205  * @dir: %TRUE if this is a write to the sysctl file
206  * @buffer: the user buffer
207  * @lenp: the size of the user buffer
208  * @ppos: file position
209  *
210  * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
211  * values from/to the user buffer, treated as an ASCII string. The values
212  * are treated as milliseconds, and converted to jiffies when they are stored.
213  *
214  * This routine will ensure the values are within the range specified by
215  * table->extra1 (min) and table->extra2 (max).
216  *
217  * Returns 0 on success.
218  */
proc_doulongvec_ms_jiffies_minmax(const struct ctl_table * table,int dir,void * buffer,size_t * lenp,loff_t * ppos)219 int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int dir,
220 				      void *buffer, size_t *lenp, loff_t *ppos)
221 {
222 	return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos,
223 					   HZ, 1000l);
224 }
225 EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
226 
227