summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/acpica/acpi_timer.c11
-rw-r--r--sys/i386/i386/tsc.c34
-rw-r--r--sys/i386/isa/clock.c3
-rw-r--r--sys/isa/atrtc.c3
-rw-r--r--sys/kern/kern_tc.c43
-rw-r--r--sys/sys/timetc.h7
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;
OpenPOWER on IntegriCloud