summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_tc.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2002-04-26 21:51:08 +0000
committerphk <phk@FreeBSD.org>2002-04-26 21:51:08 +0000
commit4c421c0b9ae9234da0ad13acf4a33aa4662ef007 (patch)
tree890bc477fd4a5ecd5e183c28ced6c68423e4e581 /sys/kern/kern_tc.c
parentd1d55e6cb9412612405c83d273cf677819a841a5 (diff)
downloadFreeBSD-src-4c421c0b9ae9234da0ad13acf4a33aa4662ef007.zip
FreeBSD-src-4c421c0b9ae9234da0ad13acf4a33aa4662ef007.tar.gz
Now that the private parts of timecounters are no longer being fingered
by other bits of code, split struct timecounter into two. struct timecounter contains just the bits which pertains to the hardware counter and the reading of it. struct timehands (as in "the hands on a clock") contains all the ugly bit fidling stuff. Statically compile ten timehands. This commit is the functional part. A later cosmetic patch will rename various variables and fieldnames.
Diffstat (limited to 'sys/kern/kern_tc.c')
-rw-r--r--sys/kern/kern_tc.c252
1 files changed, 109 insertions, 143 deletions
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c
index 23c85cf..e441159 100644
--- a/sys/kern/kern_tc.c
+++ b/sys/kern/kern_tc.c
@@ -13,7 +13,6 @@
#include <sys/param.h>
#include <sys/timetc.h>
-#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
@@ -21,14 +20,58 @@
#include <sys/timepps.h>
/*
- * Number of timecounters used to implement stable storage
+ * Implement a dummy timecounter which we can use until we get a real one
+ * in the air. This allows the console and other early stuff to use
+ * timeservices.
*/
-#ifndef NTIMECOUNTER
-#define NTIMECOUNTER hz
-#endif
-static MALLOC_DEFINE(M_TIMECOUNTER, "timecounter",
- "Timecounter stable storage");
+static unsigned
+dummy_get_timecount(struct timecounter *tc)
+{
+ static unsigned now;
+
+ return (++now);
+}
+
+static struct timecounter dummy_timecounter = {
+ dummy_get_timecount,
+ 0,
+ ~0u,
+ 1000000,
+ "dummy"
+};
+
+struct timehands {
+ /* These fields must be initialized by the driver. */
+ struct timecounter *tc_counter;
+ 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;
+ /* Fields not to be copied in tc_windup start with tc_generation */
+ volatile unsigned tc_generation;
+ struct timehands *tc_next;
+};
+
+
+extern struct timehands th0;
+static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th0};
+static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th9};
+static struct timehands th7 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th8};
+static struct timehands th6 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th7};
+static struct timehands th5 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th6};
+static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th5};
+static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th4};
+static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th3};
+static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th2};
+static struct timehands th0 =
+ { &dummy_timecounter, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th1};
+
+static struct timehands *volatile timehands = &th0;
+struct timecounter *timecounter = &dummy_timecounter;
+static struct timecounter *timecounters = &dummy_timecounter;
time_t time_second;
@@ -52,49 +95,24 @@ TC_STATS(ngetbintime); TC_STATS(ngetnanotime); TC_STATS(ngetmicrotime);
static void tc_windup(void);
-/*
- * Implement a dummy timecounter which we can use until we get a real one
- * in the air. This allows the console and other early stuff to use
- * timeservices.
- */
-
-static unsigned
-dummy_get_timecount(struct timecounter *tc)
-{
- static unsigned now;
-
- if (tc->tc_generation == 0)
- tc->tc_generation = 1;
- return (++now);
-}
-
-static struct timecounter dummy_timecounter = {
- dummy_get_timecount,
- 0,
- ~0u,
- 1000000,
- "dummy"
-};
-
-struct timecounter *volatile timecounter = &dummy_timecounter;
static __inline unsigned
-tc_delta(struct timecounter *tc)
+tc_delta(struct timehands *tc)
{
- return ((tc->tc_get_timecount(tc) - tc->tc_offset_count) &
- tc->tc_counter_mask);
+ return ((tc->tc_counter->tc_get_timecount(tc->tc_counter) -
+ tc->tc_offset_count) & tc->tc_counter->tc_counter_mask);
}
void
binuptime(struct bintime *bt)
{
- struct timecounter *tc;
+ struct timehands *tc;
unsigned gen;
nbinuptime++;
do {
- tc = timecounter;
+ tc = timehands;
gen = tc->tc_generation;
*bt = tc->tc_offset;
bintime_addx(bt, tc->tc_scale * tc_delta(tc));
@@ -153,12 +171,12 @@ microtime(struct timeval *tv)
void
getbinuptime(struct bintime *bt)
{
- struct timecounter *tc;
+ struct timehands *tc;
unsigned gen;
ngetbinuptime++;
do {
- tc = timecounter;
+ tc = timehands;
gen = tc->tc_generation;
*bt = tc->tc_offset;
} while (gen == 0 || gen != tc->tc_generation);
@@ -167,12 +185,12 @@ getbinuptime(struct bintime *bt)
void
getnanouptime(struct timespec *tsp)
{
- struct timecounter *tc;
+ struct timehands *tc;
unsigned gen;
ngetnanouptime++;
do {
- tc = timecounter;
+ tc = timehands;
gen = tc->tc_generation;
bintime2timespec(&tc->tc_offset, tsp);
} while (gen == 0 || gen != tc->tc_generation);
@@ -181,12 +199,12 @@ getnanouptime(struct timespec *tsp)
void
getmicrouptime(struct timeval *tvp)
{
- struct timecounter *tc;
+ struct timehands *tc;
unsigned gen;
ngetmicrouptime++;
do {
- tc = timecounter;
+ tc = timehands;
gen = tc->tc_generation;
bintime2timeval(&tc->tc_offset, tvp);
} while (gen == 0 || gen != tc->tc_generation);
@@ -195,12 +213,12 @@ getmicrouptime(struct timeval *tvp)
void
getbintime(struct bintime *bt)
{
- struct timecounter *tc;
+ struct timehands *tc;
unsigned gen;
ngetbintime++;
do {
- tc = timecounter;
+ tc = timehands;
gen = tc->tc_generation;
*bt = tc->tc_offset;
} while (gen == 0 || gen != tc->tc_generation);
@@ -210,12 +228,12 @@ getbintime(struct bintime *bt)
void
getnanotime(struct timespec *tsp)
{
- struct timecounter *tc;
+ struct timehands *tc;
unsigned gen;
ngetnanotime++;
do {
- tc = timecounter;
+ tc = timehands;
gen = tc->tc_generation;
*tsp = tc->tc_nanotime;
} while (gen == 0 || gen != tc->tc_generation);
@@ -224,19 +242,19 @@ getnanotime(struct timespec *tsp)
void
getmicrotime(struct timeval *tvp)
{
- struct timecounter *tc;
+ struct timehands *tc;
unsigned gen;
ngetmicrotime++;
do {
- tc = timecounter;
+ tc = timehands;
gen = tc->tc_generation;
*tvp = tc->tc_microtime;
} while (gen == 0 || gen != tc->tc_generation);
}
static void
-tc_setscales(struct timecounter *tc)
+tc_setscales(struct timehands *tc)
{
u_int64_t scale;
@@ -250,49 +268,26 @@ tc_setscales(struct timecounter *tc)
* Divide by 2 times 512 to match the temporary lower precision.
*/
scale += (tc->tc_adjustment / 1024) * 2199;
- scale /= tc->tc_tweak->tc_frequency;
+ scale /= tc->tc_counter->tc_frequency;
tc->tc_scale = scale * 2;
}
void
tc_init(struct timecounter *tc)
{
- struct timecounter *t1, *t2, *t3;
- int i;
-
- tc->tc_adjustment = 0;
- tc->tc_tweak = tc;
- tc_setscales(tc);
- tc->tc_offset_count = tc->tc_get_timecount(tc);
- if (timecounter == &dummy_timecounter)
- tc->tc_avail = tc;
- else {
- tc->tc_avail = timecounter->tc_tweak->tc_avail;
- timecounter->tc_tweak->tc_avail = tc;
- }
- MALLOC(t1, struct timecounter *, sizeof *t1, M_TIMECOUNTER, M_WAITOK | M_ZERO);
- tc->tc_next = t1;
- *t1 = *tc;
- t2 = t1;
- t3 = NULL;
- for (i = 1; i < NTIMECOUNTER; i++) {
- MALLOC(t3, struct timecounter *, sizeof *t3,
- M_TIMECOUNTER, M_WAITOK | M_ZERO);
- *t3 = *tc;
- t3->tc_next = t2;
- t2 = t3;
- }
- t1->tc_next = t3;
- tc = t1;
+ tc->tc_next = timecounters;
+ timecounters = tc;
printf("Timecounter \"%s\" frequency %lu Hz\n",
tc->tc_name, (u_long)tc->tc_frequency);
-
- /* XXX: For now always start using the counter. */
- tc->tc_offset_count = tc->tc_get_timecount(tc);
- binuptime(&tc->tc_offset);
timecounter = tc;
- tc_windup();
+}
+
+u_int32_t
+tc_getfrequency(void)
+{
+
+ return (timehands->tc_counter->tc_frequency);
}
void
@@ -312,51 +307,25 @@ tc_setclock(struct timespec *ts)
tc_windup();
}
-u_int32_t
-tc_getfrequency(void)
-{
-
- return (timecounter->tc_frequency);
-}
-
-static void
-switch_timecounter(struct timecounter *newtc)
-{
- int s;
- struct timecounter *tc;
-
- s = splclock();
- tc = timecounter;
- if (newtc->tc_tweak == tc->tc_tweak) {
- splx(s);
- return;
- }
- newtc = newtc->tc_tweak->tc_next;
- binuptime(&newtc->tc_offset);
- newtc->tc_offset_count = newtc->tc_get_timecount(newtc);
- tc_setscales(newtc);
- newtc->tc_generation = 0;
- timecounter = newtc;
- tc_windup();
- splx(s);
-}
-
static void
tc_windup(void)
{
- struct timecounter *tc, *tco;
+ struct timehands *tc, *tco;
struct bintime bt;
- unsigned ogen, delta;
+ unsigned ogen, delta, ncount;
int i;
- tco = timecounter;
+ ncount = 0; /* GCC is lame */
+ tco = timehands;
tc = tco->tc_next;
ogen = tc->tc_generation;
tc->tc_generation = 0;
- bcopy(tco, tc, __offsetof(struct timecounter, tc_generation));
+ bcopy(tco, tc, __offsetof(struct timehands, tc_generation));
delta = tc_delta(tc);
+ if (tc->tc_counter != timecounter)
+ ncount = timecounter->tc_get_timecount(timecounter);
tc->tc_offset_count += delta;
- tc->tc_offset_count &= tc->tc_counter_mask;
+ tc->tc_offset_count &= tc->tc_counter->tc_counter_mask;
bintime_addx(&tc->tc_offset, tc->tc_scale * delta);
/*
* We may be inducing a tiny error here, the tc_poll_pps() may
@@ -367,8 +336,8 @@ tc_windup(void)
* going to be only a few weenieseconds (as Dave Mills would
* say), so lets just not talk more about it, OK ?
*/
- if (tco->tc_poll_pps)
- tco->tc_poll_pps(tco);
+ if (tco->tc_counter->tc_poll_pps)
+ tco->tc_counter->tc_poll_pps(tco->tc_counter);
for (i = tc->tc_offset.sec - tco->tc_offset.sec; i > 0; i--)
ntp_update_second(&tc->tc_adjustment, &tc->tc_offset.sec);
tc_setscales(tc);
@@ -382,7 +351,7 @@ tc_windup(void)
ogen++;
tc->tc_generation = ogen;
time_second = tc->tc_microtime.tv_sec;
- timecounter = tc;
+ timehands = tc;
}
static int
@@ -392,24 +361,21 @@ sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS)
struct timecounter *newtc, *tc;
int error;
- tc = timecounter->tc_tweak;
+ tc = timecounter;
strncpy(newname, tc->tc_name, sizeof(newname));
error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req);
- if (error == 0 && req->newptr != NULL &&
- strcmp(newname, tc->tc_name) != 0) {
- for (newtc = tc->tc_avail; newtc != tc;
- newtc = newtc->tc_avail) {
- if (strcmp(newname, newtc->tc_name) == 0) {
- /* Warm up new timecounter. */
- (void)newtc->tc_get_timecount(newtc);
-
- switch_timecounter(newtc);
- return (0);
- }
- }
- return (EINVAL);
+ if (error != 0 && req->newptr == NULL && !strcmp(newname, tc->tc_name))
+ return(error);
+ for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) {
+ if (strcmp(newname, newtc->tc_name))
+ continue;
+ /* Warm up new timecounter. */
+ (void)newtc->tc_get_timecount(newtc);
+ (void)newtc->tc_get_timecount(newtc);
+ timecounter = newtc;
+ return (0);
}
- return (error);
+ return (EINVAL);
}
SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW,
@@ -486,12 +452,12 @@ pps_init(struct pps_state *pps)
void
pps_capture(struct pps_state *pps)
{
- struct timecounter *tc;
+ struct timehands *tc;
- tc = timecounter;
+ tc = timehands;
pps->captc = tc;
pps->capgen = tc->tc_generation;
- pps->capcount = tc->tc_get_timecount(tc);
+ pps->capcount = tc->tc_counter->tc_get_timecount(tc->tc_counter);
}
void
@@ -526,9 +492,9 @@ pps_event(struct pps_state *pps, int event)
/* The timecounter changed: bail */
if (!pps->ppstc ||
- pps->ppstc->tc_name != pps->captc->tc_name ||
- pps->captc->tc_name != timecounter->tc_name) {
- pps->ppstc = pps->captc;
+ pps->ppstc != pps->captc->tc_counter ||
+ pps->captc->tc_counter != timehands->tc_counter) {
+ pps->ppstc = pps->captc->tc_counter;
*pcount = pps->capcount;
#ifdef PPS_SYNC
pps->ppscount[2] = pps->capcount;
@@ -542,7 +508,7 @@ pps_event(struct pps_state *pps, int event)
/* Convert the count to timespec */
tcount = pps->capcount - pps->captc->tc_offset_count;
- tcount &= pps->captc->tc_counter_mask;
+ tcount &= pps->captc->tc_counter->tc_counter_mask;
bt = pps->captc->tc_offset;
bintime_addx(&bt, pps->captc->tc_scale * tcount);
bintime2timespec(&bt, &ts);
@@ -567,7 +533,7 @@ pps_event(struct pps_state *pps, int event)
/* magic, at its best... */
tcount = pps->capcount - pps->ppscount[2];
pps->ppscount[2] = pps->capcount;
- tcount &= pps->captc->tc_counter_mask;
+ tcount &= pps->captc->tc_counter->tc_counter_mask;
bt.sec = 0;
bt.frac = 0;
bintime_addx(&bt, pps->captc->tc_scale * tcount);
OpenPOWER on IntegriCloud