summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2003-08-16 08:23:53 +0000
committerphk <phk@FreeBSD.org>2003-08-16 08:23:53 +0000
commit34014d52616ca61b0b5cf0a932b010bfadd29dba (patch)
tree1ba852aeb06396d333d240e0c07a660ad77cea18 /sys
parente40caa9ae772a64d31f35f65258dec9f48d8a539 (diff)
downloadFreeBSD-src-34014d52616ca61b0b5cf0a932b010bfadd29dba.zip
FreeBSD-src-34014d52616ca61b0b5cf0a932b010bfadd29dba.tar.gz
Give timecounters a numeric quality field.
A timecounter will be selected when registered if its quality is not negative and no less than the current timecounters. Add a sysctl to report all available timecounters and their qualities. Give the dummy timecounter a solid negative quality of minus a million. Give the i8254 zero and the ACPI 1000. The TSC gets 800, unless APM or SMP forces it negative. Other timecounters default to zero quality and thereby retain current selection behaviour.
Diffstat (limited to 'sys')
-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