• 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 #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