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