• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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