1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
* $FreeBSD$
*/
#ifndef _SYS_TIMETC_H_
#define _SYS_TIMETC_H_
/*
* Structure used to interface to the machine dependent hardware support
* for timekeeping.
*
* A timecounter is a (hard or soft) binary counter which has two properties:
* * it runs at a fixed, known frequency.
* * it must not roll over in less than (1 + delta)/HZ seconds. "delta"
* is expected to be less than 20 msec, but no hard data has been
* collected on this. 16 bit at 5 MHz (31 msec) is known to work.
*
* get_timecount() reads the counter.
*
* counter_mask removes unimplemented bits from the count value.
*
* frequency is the counter frequency in hz.
*
* name is a short mnemonic name for this counter.
*
* cost is a measure of how long time it takes to read the counter.
*
* adjustment [PPM << 16] which means that the smallest unit of correction
* you can apply amounts to 481.5 usec/year.
*
* scale_micro [2^32 * usec/tick].
* scale_nano_i [ns/tick].
* scale_nano_f [(ns/2^32)/tick].
*
* offset_count is the contents of the counter which corresponds to the
* rest of the offset_* values.
*
* offset_sec [s].
* offset_micro [usec].
* offset_nano [ns/2^32] is misnamed, the real unit is .23283064365...
* attoseconds (10E-18) and before you ask: yes, they are in fact
* called attoseconds, it comes from "atten" for 18 in Danish/Swedish.
*
* Each timecounter must supply an array of three timecounters, this is needed
* to guarantee atomicity in the code. Index zero is used to transport
* modifications, for instance done with sysctl, into the timecounter being
* used in a safe way. Such changes may be adopted with a delay of up to 1/HZ,
* index one & two are used alternately for the actual timekeeping.
*
* 'tc_avail' points to the next available (external) timecounter in a
* circular queue. This is only valid for index 0.
*
* `tc_other' points to the next "work" timecounter in a circular queue,
* i.e., for index i > 0 it points to index 1 + (i - 1) % NTIMECOUNTER.
* We also use it to point from index 0 to index 1.
*
* `tc_tweak' points to index 0.
*/
struct timecounter;
typedef unsigned timecounter_get_t(struct timecounter *);
typedef void timecounter_pps_t(struct timecounter *);
struct timecounter {
/* These fields must be initialized by the driver. */
timecounter_get_t *tc_get_timecount;
timecounter_pps_t *tc_poll_pps;
unsigned tc_counter_mask;
u_int32_t tc_frequency;
char *tc_name;
void *tc_priv;
/* These fields will be managed by the generic code. */
int64_t tc_adjustment;
u_int64_t tc_scale;
unsigned tc_offset_count;
struct bintime tc_offset;
struct timeval tc_microtime;
struct timespec tc_nanotime;
struct timecounter *tc_avail;
struct timecounter *tc_tweak;
/* Fields not to be copied in tc_windup start with tc_generation */
volatile unsigned tc_generation;
struct timecounter *tc_next;
};
#ifdef _KERNEL
extern struct timecounter *volatile timecounter;
void tc_init(struct timecounter *tc);
void tc_setclock(struct timespec *ts);
void tc_windup(void);
void tc_update(struct timecounter *tc);
#endif /* !_KERNEL */
#endif /* !_SYS_TIMETC_H_ */
|