1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2019 Linaro Limited. All rights reserved.
4 * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
5 */
6
7 /*
8 * clock_adjtime() syscall might have as execution path:
9 *
10 * 1) a regular POSIX clock (only REALTIME clock implements adjtime())
11 * - will behave exactly like adjtimex() system call.
12 * - only one being tested here.
13 *
14 * 2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
15 * - will trigger the PTP clock driver function "adjtime()"
16 * - different implementations from one PTP clock to another
17 * - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
18 * - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
19 *
20 * so it is sane to check possible adjustments:
21 *
22 * - ADJ_OFFSET - usec or nsec, kernel adjusts time gradually by offset
23 * (-512000 < offset < 512000)
24 * - ADJ_FREQUENCY - system clock frequency offset
25 * - ADJ_MAXERROR - maximum error (usec)
26 * - ADJ_ESTERROR - estimated time error in us
27 * - ADJ_STATUS - clock command/status of ntp implementation
28 * - ADJ_TIMECONST - PLL stiffness (jitter dependent) + poll int for PLL
29 * - ADJ_TICK - us between clock ticks
30 * (>= 900000/HZ, <= 1100000/HZ)
31 *
32 * and also the standalone ones (using .offset variable):
33 *
34 * - ADJ_OFFSET_SINGLESHOT - behave like adjtime()
35 * - ADJ_OFFSET_SS_READ - ret remaining time for completion after SINGLESHOT
36 *
37 * For ADJ_STATUS, consider the following flags:
38 *
39 * rw STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
40 * rw STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
41 * rw STA_PPSTIME - enable PPS time discipline
42 * rw STA_FLL - select freq-locked loop mode.
43 * rw STA_INS - ins leap sec after the last sec of UTC day (all days)
44 * rw STA_DEL - del leap sec at last sec of UTC day (all days)
45 * rw STA_UNSYNC - clock unsynced
46 * rw STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
47 * ro STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
48 * ro STA_PPSJITTER - PPS signal jitter exceeded.
49 * ro STA_PPSWANDER - PPS signal wander exceeded.
50 * ro STA_PPSERROR - PPS signal calibration error.
51 * ro STA_CLOKERR - clock HW fault.
52 * ro STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
53 * rw STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
54 * ro STA_CLK - clock source. unused.
55 */
56
57 #include "clock_adjtime.h"
58
59 static long hz;
60 static struct tst_timex saved, ttxc;
61 static int supported;
62
63 struct test_case {
64 unsigned int modes;
65 long highlimit;
66 long delta;
67 };
68
69 struct test_case tc[] = {
70 {
71 .modes = ADJ_OFFSET_SINGLESHOT,
72 },
73 {
74 .modes = ADJ_OFFSET_SS_READ,
75 },
76 {
77 .modes = ADJ_ALL,
78 },
79 {
80 .modes = ADJ_OFFSET,
81 .highlimit = 500000,
82 .delta = 10000,
83 },
84 {
85 .modes = ADJ_FREQUENCY,
86 .delta = 100,
87 },
88 {
89 .modes = ADJ_MAXERROR,
90 .delta = 100,
91 },
92 {
93 .modes = ADJ_ESTERROR,
94 .delta = 100,
95 },
96 {
97 .modes = ADJ_TIMECONST,
98 .delta = 1,
99 },
100 {
101 .modes = ADJ_TICK,
102 .highlimit = 1100000,
103 .delta = 1000,
104 },
105 };
106
107 static struct test_variants {
108 int (*clock_adjtime)(clockid_t clk_id, void *timex);
109 enum tst_timex_type type;
110 char *desc;
111 } variants[] = {
112 #if (__NR_clock_adjtime != __LTP__NR_INVALID_SYSCALL)
113 {.clock_adjtime = sys_clock_adjtime, .type = TST_KERN_OLD_TIMEX, .desc = "syscall with old kernel spec"},
114 #endif
115
116 #if (__NR_clock_adjtime64 != __LTP__NR_INVALID_SYSCALL)
117 {.clock_adjtime = sys_clock_adjtime64, .type = TST_KERN_TIMEX, .desc = "syscall time64 with kernel spec"},
118 #endif
119 };
120
verify_clock_adjtime(unsigned int i)121 static void verify_clock_adjtime(unsigned int i)
122 {
123 struct test_variants *tv = &variants[tst_variant];
124 struct tst_timex verify;
125 long long val;
126 int rval;
127
128 memset(&ttxc, 0, sizeof(ttxc));
129 memset(&verify, 0, sizeof(verify));
130
131 ttxc.type = verify.type = tv->type;
132
133 rval = tv->clock_adjtime(CLOCK_REALTIME, tst_timex_get(&ttxc));
134 if (rval < 0) {
135 tst_res(TFAIL | TERRNO, "clock_adjtime() failed %i", rval);
136 return;
137 }
138
139 timex_show("GET", &ttxc);
140
141 timex_set_field_uint(&ttxc, ADJ_MODES, tc[i].modes);
142
143 if (tc[i].delta) {
144 val = timex_get_field_long(&ttxc, tc[i].modes);
145 val += tc[i].delta;
146
147 /* fix limits, if existent, so no errors occur */
148 if (tc[i].highlimit && val >= tc[i].highlimit)
149 val = tc[i].highlimit;
150
151 timex_set_field_long(&ttxc, tc[i].modes, val);
152 }
153
154 rval = tv->clock_adjtime(CLOCK_REALTIME, tst_timex_get(&ttxc));
155 if (rval < 0) {
156 tst_res(TFAIL | TERRNO, "clock_adjtime() failed %i", rval);
157 return;
158 }
159
160 timex_show("SET", &ttxc);
161
162 rval = tv->clock_adjtime(CLOCK_REALTIME, tst_timex_get(&verify));
163 if (rval < 0) {
164 tst_res(TFAIL | TERRNO, "clock_adjtime() failed %i", rval);
165 return;
166 }
167
168 timex_show("VERIFY", &verify);
169
170 if (tc[i].delta &&
171 timex_get_field_long(&ttxc, tc[i].modes) !=
172 timex_get_field_long(&verify, tc[i].modes)) {
173 tst_res(TFAIL, "clock_adjtime(): could not set value (mode=%x)",
174 tc[i].modes);
175 }
176
177 tst_res(TPASS, "clock_adjtime(): success (mode=%x)", tc[i].modes);
178 }
179
setup(void)180 static void setup(void)
181 {
182 struct test_variants *tv = &variants[tst_variant];
183 size_t i;
184 int rval;
185
186 tst_res(TINFO, "Testing variant: %s", tv->desc);
187
188 saved.type = tv->type;
189 rval = tv->clock_adjtime(CLOCK_REALTIME, tst_timex_get(&saved));
190 if (rval < 0) {
191 tst_res(TFAIL | TERRNO, "clock_adjtime() failed %i", rval);
192 return;
193 }
194
195 supported = 1;
196
197 if (rval != TIME_OK && rval != TIME_ERROR) {
198 timex_show("SAVE_STATUS", &saved);
199 tst_brk(TBROK | TERRNO, "clock has on-going leap changes, "
200 "returned: %i", rval);
201 }
202
203 hz = SAFE_SYSCONF(_SC_CLK_TCK);
204
205 for (i = 0; i < ARRAY_SIZE(tc); i++) {
206
207 /* fix high and low limits by dividing it per HZ value */
208
209 if (tc[i].modes == ADJ_TICK)
210 tc[i].highlimit /= hz;
211
212 /* fix usec as being test default resolution */
213
214 if (timex_get_field_uint(&saved, ADJ_MODES) & ADJ_NANO) {
215 if (tc[i].modes == ADJ_OFFSET) {
216 tc[i].highlimit *= 1000;
217 tc[i].delta *= 1000;
218 }
219 }
220 }
221 }
222
cleanup(void)223 static void cleanup(void)
224 {
225 struct test_variants *tv = &variants[tst_variant];
226 unsigned int modes = ADJ_ALL;
227 int rval;
228
229 if (supported == 0)
230 return;
231
232 /* restore clock resolution based on original status flag */
233
234 if (timex_get_field_uint(&saved, ADJ_STATUS) & STA_NANO)
235 modes |= ADJ_NANO;
236 else
237 modes |= ADJ_MICRO;
238
239 timex_set_field_uint(&saved, ADJ_MODES, modes);
240
241 /* restore original clock flags */
242
243 rval = tv->clock_adjtime(CLOCK_REALTIME, tst_timex_get(&saved));
244 if (rval < 0) {
245 tst_res(TFAIL | TERRNO, "clock_adjtime() failed %i", rval);
246 return;
247 }
248 }
249
250 static struct tst_test test = {
251 .test = verify_clock_adjtime,
252 .setup = setup,
253 .cleanup = cleanup,
254 .tcnt = ARRAY_SIZE(tc),
255 .test_variants = ARRAY_SIZE(variants),
256 .needs_root = 1,
257 .restore_wallclock = 1,
258 };
259