diff options
-rw-r--r-- | sys/dev/acpica/acpi_timer.c | 11 | ||||
-rw-r--r-- | sys/i386/i386/tsc.c | 34 | ||||
-rw-r--r-- | sys/i386/isa/clock.c | 3 | ||||
-rw-r--r-- | sys/isa/atrtc.c | 3 | ||||
-rw-r--r-- | sys/kern/kern_tc.c | 43 | ||||
-rw-r--r-- | sys/sys/timetc.h | 7 |
6 files changed, 68 insertions, 33 deletions
diff --git a/sys/dev/acpica/acpi_timer.c b/sys/dev/acpica/acpi_timer.c index 67e308a..576ce59 100644 --- a/sys/dev/acpica/acpi_timer.c +++ b/sys/dev/acpica/acpi_timer.c @@ -98,11 +98,12 @@ DRIVER_MODULE(acpi_timer, acpi, acpi_timer_driver, acpi_timer_devclass, 0, 0); * Timecounter. */ static struct timecounter acpi_timer_timecounter = { - acpi_timer_get_timecount_safe, - 0, - 0xffffff, - 0, - "ACPI" + acpi_timer_get_timecount_safe, + 0, + 0xffffff, + 0, + "ACPI", + 1000 }; diff --git a/sys/i386/i386/tsc.c b/sys/i386/i386/tsc.c index 4dc1861..7b46dd4 100644 --- a/sys/i386/i386/tsc.c +++ b/sys/i386/i386/tsc.c @@ -60,7 +60,8 @@ static struct timecounter tsc_timecounter = { 0, /* no poll_pps */ ~0u, /* counter_mask */ 0, /* frequency */ - "TSC" /* name */ + "TSC", /* name */ + 800, /* quality (adjusted in code) */ }; void @@ -86,20 +87,6 @@ init_TSC(void) tsc_freq = tscval[1] - tscval[0]; if (bootverbose) printf("TSC clock: %ju Hz\n", (intmax_t)tsc_freq); - -#ifdef SMP - /* - * We can not use the TSC in SMP mode unless the TSCs on all CPUs - * are somehow synchronized. Some hardware configurations do - * this, but we have no way of determining whether this is the - * case, so we do not use the TSC in multi-processor systems - * unless the user indicated (by setting kern.timecounter.smp_tsc - * to 1) that he believes that his TSCs are synchronized. - */ - if (mp_ncpus > 1 && !smp_tsc) - return; -#endif - return; } @@ -117,17 +104,28 @@ init_TSC_tc(void) * or not, nor when it might be activated. Play it safe. */ if (power_pm_get_type() == POWER_PM_TYPE_APM) { + tsc_timecounter.tc_quality = -1000; if (bootverbose) printf("TSC timecounter disabled: APM enabled.\n"); - return; } +#ifdef SMP + /* + * We can not use the TSC in SMP mode unless the TSCs on all CPUs + * are somehow synchronized. Some hardware configurations do + * this, but we have no way of determining whether this is the + * case, so we do not use the TSC in multi-processor systems + * unless the user indicated (by setting kern.timecounter.smp_tsc + * to 1) that he believes that his TSCs are synchronized. + */ + if (mp_ncpus > 1 && !smp_tsc) + tsc_timecounter.tc_quality = -100; +#endif + if (tsc_present && tsc_freq != 0 && !tsc_is_broken) { tsc_timecounter.tc_frequency = tsc_freq; tc_init(&tsc_timecounter); } - - return; } static int diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c index 3c9c915..3d7d8c1 100644 --- a/sys/i386/isa/clock.c +++ b/sys/i386/isa/clock.c @@ -155,7 +155,8 @@ static struct timecounter i8254_timecounter = { 0, /* no poll_pps */ ~0u, /* counter_mask */ 0, /* frequency */ - "i8254" /* name */ + "i8254", /* name */ + 0 /* quality */ }; static void diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c index 3c9c915..3d7d8c1 100644 --- a/sys/isa/atrtc.c +++ b/sys/isa/atrtc.c @@ -155,7 +155,8 @@ static struct timecounter i8254_timecounter = { 0, /* no poll_pps */ ~0u, /* counter_mask */ 0, /* frequency */ - "i8254" /* name */ + "i8254", /* name */ + 0 /* quality */ }; static void diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 379a64a..a3cef31 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -43,7 +43,7 @@ dummy_get_timecount(struct timecounter *tc) } static struct timecounter dummy_timecounter = { - dummy_get_timecount, 0, ~0u, 1000000, "dummy", + dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000 }; struct timehands { @@ -281,29 +281,33 @@ getmicrotime(struct timeval *tvp) } /* - * Initialize a new timecounter. - * We should really try to rank the timecounters and intelligently determine - * if the new timecounter is better than the current one. This is subject - * to further study. For now always use the new timecounter. + * Initialize a new timecounter and possibly use it. */ void tc_init(struct timecounter *tc) { unsigned u; - printf("Timecounter \"%s\" frequency %ju Hz", - tc->tc_name, (intmax_t)tc->tc_frequency); + if (tc->tc_quality >= 0 || bootverbose) + printf("Timecounter \"%s\" frequency %ju Hz quality %d", + tc->tc_name, (intmax_t)tc->tc_frequency, + tc->tc_quality); u = tc->tc_frequency / tc->tc_counter_mask; if (u > hz) { printf(" -- Insufficient hz, needs at least %u\n", u); return; } + printf("\n"); tc->tc_next = timecounters; timecounters = tc; - printf("\n"); (void)tc->tc_get_timecount(tc); (void)tc->tc_get_timecount(tc); + /* Never automatically use a timecounter with negative quality */ + if (tc->tc_quality < 0) + return; + if (tc->tc_quality < timecounter->tc_quality) + return; timecounter = tc; } @@ -496,6 +500,29 @@ sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW, 0, 0, sysctl_kern_timecounter_hardware, "A", ""); + +/* Report or change the active timecounter hardware. */ +static int +sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS) +{ + char buf[32], *spc; + struct timecounter *tc; + int error; + + spc = ""; + error = 0; + for (tc = timecounters; error == 0 && tc != NULL; tc = tc->tc_next) { + sprintf(buf, "%s%s(%d)", + spc, tc->tc_name, tc->tc_quality); + error = SYSCTL_OUT(req, buf, strlen(buf)); + spc = " "; + } + return (error); +} + +SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD, + 0, 0, sysctl_kern_timecounter_choice, "A", ""); + /* * RFC 2783 PPS-API implementation. */ diff --git a/sys/sys/timetc.h b/sys/sys/timetc.h index 81bad80..d5a818b 100644 --- a/sys/sys/timetc.h +++ b/sys/sys/timetc.h @@ -51,6 +51,13 @@ struct timecounter { /* Frequency of the counter in Hz. */ char *tc_name; /* Name of the timecounter. */ + int tc_quality; + /* + * Used to determine if this timecounter is better than + * another timecounter higher means better. Negative + * means "only use at explicit request". + */ + void *tc_priv; /* Pointer to the timecounter's private parts. */ struct timecounter *tc_next; |