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 #include "config.h"
8 #include "tst_test.h"
9 #include "tst_timer.h"
10 #include "tst_safe_clocks.h"
11 #include "lapi/syscalls.h"
12 #include "lapi/posix_clocks.h"
13 #include <time.h>
14 #include <pwd.h>
15 #include <sys/timex.h>
16 #include <sys/types.h>
17 #include <asm/posix_types.h>
18 #include "lapi/timex.h"
19
20 #ifndef __kernel_timex
21 struct __kernel_old_timex {
22 unsigned int modes; /* mode selector */
23 __kernel_long_t offset; /* time offset (usec) */
24 __kernel_long_t freq; /* frequency offset (scaled ppm) */
25 __kernel_long_t maxerror;/* maximum error (usec) */
26 __kernel_long_t esterror;/* estimated error (usec) */
27 int status; /* clock command/status */
28 __kernel_long_t constant;/* pll time constant */
29 __kernel_long_t precision;/* clock precision (usec) (read only) */
30 __kernel_long_t tolerance;/* clock frequency tolerance (ppm)
31 * (read only)
32 */
33 struct __kernel_old_timeval time; /* (read only, except for ADJ_SETOFFSET) */
34 __kernel_long_t tick; /* (modified) usecs between clock ticks */
35
36 __kernel_long_t ppsfreq;/* pps frequency (scaled ppm) (ro) */
37 __kernel_long_t jitter; /* pps jitter (us) (ro) */
38 int shift; /* interval duration (s) (shift) (ro) */
39 __kernel_long_t stabil; /* pps stability (scaled ppm) (ro) */
40 __kernel_long_t jitcnt; /* jitter limit exceeded (ro) */
41 __kernel_long_t calcnt; /* calibration intervals (ro) */
42 __kernel_long_t errcnt; /* calibration errors (ro) */
43 __kernel_long_t stbcnt; /* stability limit exceeded (ro) */
44
45 int tai; /* TAI offset (ro) */
46
47 int :32; int :32; int :32; int :32;
48 int :32; int :32; int :32; int :32;
49 int :32; int :32; int :32;
50 };
51
52 struct __kernel_timex_timeval {
53 __kernel_time64_t tv_sec;
54 long long tv_usec;
55 };
56
57 struct __kernel_timex {
58 unsigned int modes; /* mode selector */
59 int :32; /* pad */
60 long long offset; /* time offset (usec) */
61 long long freq; /* frequency offset (scaled ppm) */
62 long long maxerror;/* maximum error (usec) */
63 long long esterror;/* estimated error (usec) */
64 int status; /* clock command/status */
65 int :32; /* pad */
66 long long constant;/* pll time constant */
67 long long precision;/* clock precision (usec) (read only) */
68 long long tolerance;/* clock frequency tolerance (ppm)
69 * (read only)
70 */
71 struct __kernel_timex_timeval time; /* (read only, except for ADJ_SETOFFSET) */
72 long long tick; /* (modified) usecs between clock ticks */
73
74 long long ppsfreq;/* pps frequency (scaled ppm) (ro) */
75 long long jitter; /* pps jitter (us) (ro) */
76 int shift; /* interval duration (s) (shift) (ro) */
77 int :32; /* pad */
78 long long stabil; /* pps stability (scaled ppm) (ro) */
79 long long jitcnt; /* jitter limit exceeded (ro) */
80 long long calcnt; /* calibration intervals (ro) */
81 long long errcnt; /* calibration errors (ro) */
82 long long stbcnt; /* stability limit exceeded (ro) */
83
84 int tai; /* TAI offset (ro) */
85
86 int :32; int :32; int :32; int :32;
87 int :32; int :32; int :32; int :32;
88 int :32; int :32; int :32;
89 };
90 #endif
91
92 enum tst_timex_type {
93 TST_KERN_OLD_TIMEX,
94 TST_KERN_TIMEX
95 };
96
97 struct tst_timex {
98 enum tst_timex_type type;
99 union tx{
100 struct __kernel_old_timex kern_old_timex;
101 struct __kernel_timex kern_timex;
102 } tx;
103 };
104
tst_timex_get(struct tst_timex * t)105 static inline void *tst_timex_get(struct tst_timex *t)
106 {
107 switch (t->type) {
108 case TST_KERN_OLD_TIMEX:
109 return &t->tx.kern_old_timex;
110 case TST_KERN_TIMEX:
111 return &t->tx.kern_timex;
112 default:
113 tst_brk(TBROK, "Invalid type: %d", t->type);
114 return NULL;
115 }
116 }
117
sys_clock_adjtime(clockid_t clk_id,void * timex)118 static inline int sys_clock_adjtime(clockid_t clk_id, void *timex)
119 {
120 return tst_syscall(__NR_clock_adjtime, clk_id, timex);
121 }
122
sys_clock_adjtime64(clockid_t clk_id,void * timex)123 static inline int sys_clock_adjtime64(clockid_t clk_id, void *timex)
124 {
125 return tst_syscall(__NR_clock_adjtime64, clk_id, timex);
126 }
127
128 #define TIMEX_SHOW(tx, mode, fmt) \
129 tst_res(TINFO, "%s\n" \
130 " mode: %u\n" \
131 " offset: "fmt"\n" \
132 " frequency: "fmt"\n" \
133 " maxerror: "fmt"\n" \
134 " esterror: "fmt"\n" \
135 " status: %d (0x%x)\n" \
136 " time_constant: "fmt"\n" \
137 " precision: "fmt"\n" \
138 " tolerance: "fmt"\n" \
139 " tick: "fmt"\n" \
140 " raw time: "fmt"(s) "fmt"(us)", \
141 mode, \
142 tx.modes, \
143 tx.offset, \
144 tx.freq, \
145 tx.maxerror, \
146 tx.esterror, \
147 tx.status, \
148 tx.status, \
149 tx.constant, \
150 tx.precision, \
151 tx.tolerance, \
152 tx.tick, \
153 tx.time.tv_sec, \
154 tx.time.tv_usec)
155
timex_show(const char * mode,struct tst_timex * timex)156 static inline void timex_show(const char *mode, struct tst_timex *timex)
157 {
158 switch (timex->type) {
159 case TST_KERN_OLD_TIMEX:
160 TIMEX_SHOW(timex->tx.kern_old_timex, mode, "%ld");
161 return;
162 case TST_KERN_TIMEX:
163 TIMEX_SHOW(timex->tx.kern_timex, mode, "%lld");
164 return;
165 default:
166 tst_brk(TBROK, "Invalid type: %d", timex->type);
167 }
168 }
169
170 #undef TIMEX_SHOW
171
172 #define ADJ_MODES 0
173
174 #define SELECT_FIELD(tx, field) \
175 { \
176 switch (field) { \
177 case ADJ_MODES: \
178 return &tx.modes; \
179 case ADJ_OFFSET: \
180 return &tx.offset; \
181 case ADJ_FREQUENCY: \
182 return &tx.freq; \
183 case ADJ_MAXERROR: \
184 return &tx.maxerror; \
185 case ADJ_ESTERROR: \
186 return &tx.esterror; \
187 case ADJ_TIMECONST: \
188 return &tx.constant; \
189 case ADJ_TICK: \
190 return &tx.tick; \
191 case ADJ_STATUS: \
192 return &tx.status; \
193 default: \
194 tst_brk(TBROK, "Invalid type: %d", timex->type); \
195 return NULL; \
196 } \
197 }
198
timex_get_field(struct tst_timex * timex,unsigned int field)199 static inline void *timex_get_field(struct tst_timex *timex, unsigned int field)
200 {
201 switch (timex->type) {
202 case TST_KERN_OLD_TIMEX:
203 SELECT_FIELD(timex->tx.kern_old_timex, field);
204 case TST_KERN_TIMEX:
205 SELECT_FIELD(timex->tx.kern_timex, field);
206 default:
207 tst_brk(TBROK, "Invalid type: %d", timex->type);
208 return NULL;
209 }
210 }
211
212 #undef SELECT_FIELD
213
214 #define TIMEX_GET_SET_FIELD_TYPE(type_libc, type_kern) \
215 static inline type_kern \
216 timex_get_field_##type_libc(struct tst_timex *timex, unsigned int field) \
217 { \
218 switch (timex->type) { \
219 case TST_KERN_OLD_TIMEX: \
220 return *((type_libc*)timex_get_field(timex, field)); \
221 case TST_KERN_TIMEX: \
222 return *((type_kern*)timex_get_field(timex, field)); \
223 default: \
224 tst_res(TFAIL, "Invalid type: %d", timex->type); \
225 return 0; \
226 } \
227 } \
228 \
229 static inline void \
230 timex_set_field_##type_libc(struct tst_timex *timex, unsigned int field, \
231 type_kern value) \
232 { \
233 switch (timex->type) { \
234 case TST_KERN_OLD_TIMEX: \
235 *((type_libc*)timex_get_field(timex, field)) = value; \
236 return; \
237 case TST_KERN_TIMEX: \
238 *((type_kern*)timex_get_field(timex, field)) = value; \
239 return; \
240 default: \
241 tst_res(TFAIL, "Invalid type: %d", timex->type); \
242 } \
243 }
244
245 TIMEX_GET_SET_FIELD_TYPE(uint, uint);
246 TIMEX_GET_SET_FIELD_TYPE(long, long long);
247
248 #undef TIMEX_GET_SET_FIELD_TYPE
249