0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <stdio.h>
0020 #include <unistd.h>
0021 #include <stdlib.h>
0022 #include <sys/time.h>
0023 #include <sys/timex.h>
0024 #include <time.h>
0025
0026 #include "../kselftest.h"
0027
0028 #define CLOCK_MONOTONIC_RAW 4
0029
0030 #define NSEC_PER_SEC 1000000000LL
0031 #define USEC_PER_SEC 1000000
0032
0033 #define MILLION 1000000
0034
0035 long systick;
0036
0037 long long llabs(long long val)
0038 {
0039 if (val < 0)
0040 val = -val;
0041 return val;
0042 }
0043
0044 unsigned long long ts_to_nsec(struct timespec ts)
0045 {
0046 return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
0047 }
0048
0049 struct timespec nsec_to_ts(long long ns)
0050 {
0051 struct timespec ts;
0052
0053 ts.tv_sec = ns/NSEC_PER_SEC;
0054 ts.tv_nsec = ns%NSEC_PER_SEC;
0055
0056 return ts;
0057 }
0058
0059 long long diff_timespec(struct timespec start, struct timespec end)
0060 {
0061 long long start_ns, end_ns;
0062
0063 start_ns = ts_to_nsec(start);
0064 end_ns = ts_to_nsec(end);
0065
0066 return end_ns - start_ns;
0067 }
0068
0069 void get_monotonic_and_raw(struct timespec *mon, struct timespec *raw)
0070 {
0071 struct timespec start, mid, end;
0072 long long diff = 0, tmp;
0073 int i;
0074
0075 clock_gettime(CLOCK_MONOTONIC, mon);
0076 clock_gettime(CLOCK_MONOTONIC_RAW, raw);
0077
0078
0079 for (i = 0; i < 3; i++) {
0080 long long newdiff;
0081
0082 clock_gettime(CLOCK_MONOTONIC, &start);
0083 clock_gettime(CLOCK_MONOTONIC_RAW, &mid);
0084 clock_gettime(CLOCK_MONOTONIC, &end);
0085
0086 newdiff = diff_timespec(start, end);
0087 if (diff == 0 || newdiff < diff) {
0088 diff = newdiff;
0089 *raw = mid;
0090 tmp = (ts_to_nsec(start) + ts_to_nsec(end))/2;
0091 *mon = nsec_to_ts(tmp);
0092 }
0093 }
0094 }
0095
0096 long long get_ppm_drift(void)
0097 {
0098 struct timespec mon_start, raw_start, mon_end, raw_end;
0099 long long delta1, delta2, eppm;
0100
0101 get_monotonic_and_raw(&mon_start, &raw_start);
0102
0103 sleep(15);
0104
0105 get_monotonic_and_raw(&mon_end, &raw_end);
0106
0107 delta1 = diff_timespec(mon_start, mon_end);
0108 delta2 = diff_timespec(raw_start, raw_end);
0109
0110 eppm = (delta1*MILLION)/delta2 - MILLION;
0111
0112 return eppm;
0113 }
0114
0115 int check_tick_adj(long tickval)
0116 {
0117 long long eppm, ppm;
0118 struct timex tx1;
0119
0120 tx1.modes = ADJ_TICK;
0121 tx1.modes |= ADJ_OFFSET;
0122 tx1.modes |= ADJ_FREQUENCY;
0123 tx1.modes |= ADJ_STATUS;
0124
0125 tx1.status = STA_PLL;
0126 tx1.offset = 0;
0127 tx1.freq = 0;
0128 tx1.tick = tickval;
0129
0130 adjtimex(&tx1);
0131
0132 sleep(1);
0133
0134 ppm = ((long long)tickval * MILLION)/systick - MILLION;
0135 printf("Estimating tick (act: %ld usec, %lld ppm): ", tickval, ppm);
0136
0137 eppm = get_ppm_drift();
0138 printf("%lld usec, %lld ppm", systick + (systick * eppm / MILLION), eppm);
0139 fflush(stdout);
0140
0141 tx1.modes = 0;
0142 adjtimex(&tx1);
0143
0144 if (tx1.offset || tx1.freq || tx1.tick != tickval) {
0145 printf(" [ERROR]\n");
0146 printf("\tUnexpected adjtimex return values, make sure ntpd is not running.\n");
0147 return -1;
0148 }
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 if (llabs(eppm - ppm) > 100) {
0160 printf(" [FAILED]\n");
0161 return -1;
0162 }
0163 printf(" [OK]\n");
0164
0165 return 0;
0166 }
0167
0168 int main(int argc, char **argv)
0169 {
0170 struct timespec raw;
0171 long tick, max, interval, err;
0172 struct timex tx1;
0173
0174 err = 0;
0175 setbuf(stdout, NULL);
0176
0177 if (clock_gettime(CLOCK_MONOTONIC_RAW, &raw)) {
0178 printf("ERR: NO CLOCK_MONOTONIC_RAW\n");
0179 return -1;
0180 }
0181
0182 printf("Each iteration takes about 15 seconds\n");
0183
0184 systick = sysconf(_SC_CLK_TCK);
0185 systick = USEC_PER_SEC/sysconf(_SC_CLK_TCK);
0186 max = systick/10;
0187 interval = max/4;
0188
0189 for (tick = (systick - max); tick < (systick + max); tick += interval) {
0190 if (check_tick_adj(tick)) {
0191 err = 1;
0192 break;
0193 }
0194 }
0195
0196
0197 tx1.modes = ADJ_TICK;
0198 tx1.modes |= ADJ_OFFSET;
0199 tx1.modes |= ADJ_FREQUENCY;
0200
0201 tx1.offset = 0;
0202 tx1.freq = 0;
0203 tx1.tick = systick;
0204
0205 adjtimex(&tx1);
0206
0207 if (err)
0208 return ksft_exit_fail();
0209
0210 return ksft_exit_pass();
0211 }