255 lines
7.1 KiB
C
255 lines
7.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (c) 2019 Linaro Limited. All rights reserved.
|
|
* Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
|
|
*/
|
|
|
|
#ifndef CLOCK_ADJTIME_H__
|
|
#define CLOCK_ADJTIME_H__
|
|
|
|
#include "config.h"
|
|
#include "tst_test.h"
|
|
#include "tst_timer.h"
|
|
#include "tst_safe_clocks.h"
|
|
#include "lapi/syscalls.h"
|
|
#include "lapi/posix_clocks.h"
|
|
#include <time.h>
|
|
#include <pwd.h>
|
|
#include <sys/timex.h>
|
|
#include <sys/types.h>
|
|
#include <asm/posix_types.h>
|
|
#include "lapi/timex.h"
|
|
|
|
struct __kernel_old_timex {
|
|
unsigned int modes; /* mode selector */
|
|
__kernel_long_t offset; /* time offset (usec) */
|
|
__kernel_long_t freq; /* frequency offset (scaled ppm) */
|
|
__kernel_long_t maxerror;/* maximum error (usec) */
|
|
__kernel_long_t esterror;/* estimated error (usec) */
|
|
int status; /* clock command/status */
|
|
__kernel_long_t constant;/* pll time constant */
|
|
__kernel_long_t precision;/* clock precision (usec) (read only) */
|
|
__kernel_long_t tolerance;/* clock frequency tolerance (ppm)
|
|
* (read only)
|
|
*/
|
|
struct __kernel_old_timeval time; /* (read only, except for ADJ_SETOFFSET) */
|
|
__kernel_long_t tick; /* (modified) usecs between clock ticks */
|
|
|
|
__kernel_long_t ppsfreq;/* pps frequency (scaled ppm) (ro) */
|
|
__kernel_long_t jitter; /* pps jitter (us) (ro) */
|
|
int shift; /* interval duration (s) (shift) (ro) */
|
|
__kernel_long_t stabil; /* pps stability (scaled ppm) (ro) */
|
|
__kernel_long_t jitcnt; /* jitter limit exceeded (ro) */
|
|
__kernel_long_t calcnt; /* calibration intervals (ro) */
|
|
__kernel_long_t errcnt; /* calibration errors (ro) */
|
|
__kernel_long_t stbcnt; /* stability limit exceeded (ro) */
|
|
|
|
int tai; /* TAI offset (ro) */
|
|
|
|
int :32; int :32; int :32; int :32;
|
|
int :32; int :32; int :32; int :32;
|
|
int :32; int :32; int :32;
|
|
};
|
|
|
|
#ifndef HAVE_STRUCT___KERNEL_TIMEX_TIMEVAL
|
|
struct __kernel_timex_timeval {
|
|
__kernel_time64_t tv_sec;
|
|
long long tv_usec;
|
|
};
|
|
#endif
|
|
|
|
#ifndef HAVE_STRUCT___KERNEL_TIMEX
|
|
struct __kernel_timex {
|
|
unsigned int modes; /* mode selector */
|
|
int :32; /* pad */
|
|
long long offset; /* time offset (usec) */
|
|
long long freq; /* frequency offset (scaled ppm) */
|
|
long long maxerror;/* maximum error (usec) */
|
|
long long esterror;/* estimated error (usec) */
|
|
int status; /* clock command/status */
|
|
int :32; /* pad */
|
|
long long constant;/* pll time constant */
|
|
long long precision;/* clock precision (usec) (read only) */
|
|
long long tolerance;/* clock frequency tolerance (ppm)
|
|
* (read only)
|
|
*/
|
|
struct __kernel_timex_timeval time; /* (read only, except for ADJ_SETOFFSET) */
|
|
long long tick; /* (modified) usecs between clock ticks */
|
|
|
|
long long ppsfreq;/* pps frequency (scaled ppm) (ro) */
|
|
long long jitter; /* pps jitter (us) (ro) */
|
|
int shift; /* interval duration (s) (shift) (ro) */
|
|
int :32; /* pad */
|
|
long long stabil; /* pps stability (scaled ppm) (ro) */
|
|
long long jitcnt; /* jitter limit exceeded (ro) */
|
|
long long calcnt; /* calibration intervals (ro) */
|
|
long long errcnt; /* calibration errors (ro) */
|
|
long long stbcnt; /* stability limit exceeded (ro) */
|
|
|
|
int tai; /* TAI offset (ro) */
|
|
|
|
int :32; int :32; int :32; int :32;
|
|
int :32; int :32; int :32; int :32;
|
|
int :32; int :32; int :32;
|
|
};
|
|
#endif
|
|
|
|
enum tst_timex_type {
|
|
TST_KERN_OLD_TIMEX,
|
|
TST_KERN_TIMEX
|
|
};
|
|
|
|
struct tst_timex {
|
|
enum tst_timex_type type;
|
|
union tx{
|
|
struct __kernel_old_timex kern_old_timex;
|
|
struct __kernel_timex kern_timex;
|
|
} tx;
|
|
};
|
|
|
|
static inline void *tst_timex_get(struct tst_timex *t)
|
|
{
|
|
switch (t->type) {
|
|
case TST_KERN_OLD_TIMEX:
|
|
return &t->tx.kern_old_timex;
|
|
case TST_KERN_TIMEX:
|
|
return &t->tx.kern_timex;
|
|
default:
|
|
tst_brk(TBROK, "Invalid type: %d", t->type);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static inline int sys_clock_adjtime(clockid_t clk_id, void *timex)
|
|
{
|
|
return tst_syscall(__NR_clock_adjtime, clk_id, timex);
|
|
}
|
|
|
|
static inline int sys_clock_adjtime64(clockid_t clk_id, void *timex)
|
|
{
|
|
return tst_syscall(__NR_clock_adjtime64, clk_id, timex);
|
|
}
|
|
|
|
#define TIMEX_SHOW(tx, mode, fmt) \
|
|
tst_res(TINFO, "%s\n" \
|
|
" mode: %u\n" \
|
|
" offset: "fmt"\n" \
|
|
" frequency: "fmt"\n" \
|
|
" maxerror: "fmt"\n" \
|
|
" esterror: "fmt"\n" \
|
|
" status: %d (0x%x)\n" \
|
|
" time_constant: "fmt"\n" \
|
|
" precision: "fmt"\n" \
|
|
" tolerance: "fmt"\n" \
|
|
" tick: "fmt"\n" \
|
|
" raw time: "fmt"(s) "fmt"(us)", \
|
|
mode, \
|
|
tx.modes, \
|
|
tx.offset, \
|
|
tx.freq, \
|
|
tx.maxerror, \
|
|
tx.esterror, \
|
|
tx.status, \
|
|
tx.status, \
|
|
tx.constant, \
|
|
tx.precision, \
|
|
tx.tolerance, \
|
|
tx.tick, \
|
|
tx.time.tv_sec, \
|
|
tx.time.tv_usec)
|
|
|
|
static inline void timex_show(const char *mode, struct tst_timex *timex)
|
|
{
|
|
switch (timex->type) {
|
|
case TST_KERN_OLD_TIMEX:
|
|
TIMEX_SHOW(timex->tx.kern_old_timex, mode, "%ld");
|
|
return;
|
|
case TST_KERN_TIMEX:
|
|
TIMEX_SHOW(timex->tx.kern_timex, mode, "%lld");
|
|
return;
|
|
default:
|
|
tst_brk(TBROK, "Invalid type: %d", timex->type);
|
|
}
|
|
}
|
|
|
|
#undef TIMEX_SHOW
|
|
|
|
#define ADJ_MODES 0
|
|
|
|
#define SELECT_FIELD(tx, field) \
|
|
{ \
|
|
switch (field) { \
|
|
case ADJ_MODES: \
|
|
return &tx.modes; \
|
|
case ADJ_OFFSET: \
|
|
return &tx.offset; \
|
|
case ADJ_FREQUENCY: \
|
|
return &tx.freq; \
|
|
case ADJ_MAXERROR: \
|
|
return &tx.maxerror; \
|
|
case ADJ_ESTERROR: \
|
|
return &tx.esterror; \
|
|
case ADJ_TIMECONST: \
|
|
return &tx.constant; \
|
|
case ADJ_TICK: \
|
|
return &tx.tick; \
|
|
case ADJ_STATUS: \
|
|
return &tx.status; \
|
|
default: \
|
|
tst_brk(TBROK, "Invalid type: %d", timex->type); \
|
|
return NULL; \
|
|
} \
|
|
}
|
|
|
|
static inline void *timex_get_field(struct tst_timex *timex, unsigned int field)
|
|
{
|
|
switch (timex->type) {
|
|
case TST_KERN_OLD_TIMEX:
|
|
SELECT_FIELD(timex->tx.kern_old_timex, field);
|
|
case TST_KERN_TIMEX:
|
|
SELECT_FIELD(timex->tx.kern_timex, field);
|
|
default:
|
|
tst_brk(TBROK, "Invalid type: %d", timex->type);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
#undef SELECT_FIELD
|
|
|
|
#define TIMEX_GET_SET_FIELD_TYPE(type_libc, type_kern) \
|
|
static inline type_kern \
|
|
timex_get_field_##type_libc(struct tst_timex *timex, unsigned int field) \
|
|
{ \
|
|
switch (timex->type) { \
|
|
case TST_KERN_OLD_TIMEX: \
|
|
return *((type_libc*)timex_get_field(timex, field)); \
|
|
case TST_KERN_TIMEX: \
|
|
return *((type_kern*)timex_get_field(timex, field)); \
|
|
default: \
|
|
tst_res(TFAIL, "Invalid type: %d", timex->type); \
|
|
return 0; \
|
|
} \
|
|
} \
|
|
\
|
|
static inline void \
|
|
timex_set_field_##type_libc(struct tst_timex *timex, unsigned int field, \
|
|
type_kern value) \
|
|
{ \
|
|
switch (timex->type) { \
|
|
case TST_KERN_OLD_TIMEX: \
|
|
*((type_libc*)timex_get_field(timex, field)) = value; \
|
|
return; \
|
|
case TST_KERN_TIMEX: \
|
|
*((type_kern*)timex_get_field(timex, field)) = value; \
|
|
return; \
|
|
default: \
|
|
tst_res(TFAIL, "Invalid type: %d", timex->type); \
|
|
} \
|
|
}
|
|
|
|
TIMEX_GET_SET_FIELD_TYPE(uint, uint);
|
|
TIMEX_GET_SET_FIELD_TYPE(long, long long);
|
|
|
|
#undef TIMEX_GET_SET_FIELD_TYPE
|
|
#endif
|