Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/x86/x86 - Install HPET based DELAY() before going m...
details: https://anonhg.NetBSD.org/src/rev/e8e93505677d
branches: trunk
changeset: 971428:e8e93505677d
user: ad <ad%NetBSD.org@localhost>
date: Thu Apr 23 21:35:18 2020 +0000
description:
- Install HPET based DELAY() before going multiuser then recalibrate the TSC.
Idea from joerg@.
- Take overhead into account when computing CPU frequency.
- Don't flush cache before computing TSC skew.
diffstat:
sys/arch/x86/x86/cpu.c | 60 +++++++++++++++++++++++++++++++++++++------------
1 files changed, 45 insertions(+), 15 deletions(-)
diffs (162 lines):
diff -r ca7022ac3533 -r e8e93505677d sys/arch/x86/x86/cpu.c
--- a/sys/arch/x86/x86/cpu.c Thu Apr 23 21:12:06 2020 +0000
+++ b/sys/arch/x86/x86/cpu.c Thu Apr 23 21:35:18 2020 +0000
@@ -1,7 +1,7 @@
-/* $NetBSD: cpu.c,v 1.185 2020/04/21 02:56:37 msaitoh Exp $ */
+/* $NetBSD: cpu.c,v 1.186 2020/04/23 21:35:18 ad Exp $ */
/*
- * Copyright (c) 2000-2012 NetBSD Foundation, Inc.
+ * Copyright (c) 2000-2020 NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.185 2020/04/21 02:56:37 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.186 2020/04/23 21:35:18 ad Exp $");
#include "opt_ddb.h"
#include "opt_mpbios.h" /* for MPDEBUG */
@@ -73,6 +73,7 @@
#include "lapic.h"
#include "ioapic.h"
#include "acpica.h"
+#include "hpet.h"
#include <sys/param.h>
#include <sys/proc.h>
@@ -118,6 +119,7 @@
#endif
#include <dev/ic/mc146818reg.h>
+#include <dev/ic/hpetvar.h>
#include <i386/isa/nvram.h>
#include <dev/isa/isareg.h>
@@ -197,6 +199,8 @@
#endif
struct cpu_info *cpu_starting;
+int (*cpu_nullop_ptr)(void *) = nullop;
+
#ifdef MULTIPROCESSOR
void cpu_hatch(void *);
static void cpu_boot_secondary(struct cpu_info *ci);
@@ -428,8 +432,11 @@
* must be done to allow booting other processors.
*/
if (!again) {
+ /* Make sure DELAY() (likely i8254_delay()) is initialized. */
+ DELAY(1);
+
+ /* Basic init. */
atomic_or_32(&ci->ci_flags, CPUF_PRESENT | CPUF_PRIMARY);
- /* Basic init. */
cpu_intr_init(ci);
cpu_get_tsc_freq(ci);
cpu_init(ci);
@@ -445,8 +452,6 @@
lapic_calibrate_timer(ci);
}
#endif
- /* Make sure DELAY() is initialized. */
- DELAY(1);
kcsan_cpu_init(ci);
again = true;
}
@@ -704,7 +709,6 @@
if (ci != &cpu_info_primary) {
/* Synchronize TSC */
- wbinvd();
atomic_or_32(&ci->ci_flags, CPUF_RUNNING);
tsc_sync_ap(ci);
} else {
@@ -720,6 +724,14 @@
kcpuset_t *cpus;
u_long i;
+#if NHPET > 0
+ /* Use HPET delay, and re-calibrate TSC on boot CPU using HPET. */
+ if (hpet_delay_p() && x86_delay == i8254_delay) {
+ delay_func = x86_delay = hpet_delay;
+ cpu_get_tsc_freq(curcpu());
+ }
+#endif
+
#ifndef XEN
/* Now that we know the number of CPUs, patch the text segment. */
x86_patch(false);
@@ -830,7 +842,6 @@
*/
psl = x86_read_psl();
x86_disable_intr();
- wbinvd();
tsc_sync_bp(ci);
x86_write_psl(psl);
}
@@ -861,7 +872,6 @@
drift = ci->ci_data.cpu_cc_skew;
psl = x86_read_psl();
x86_disable_intr();
- wbinvd();
tsc_sync_bp(ci);
x86_write_psl(psl);
drift -= ci->ci_data.cpu_cc_skew;
@@ -907,7 +917,6 @@
* Synchronize the TSC for the first time. Note that interrupts are
* off at this point.
*/
- wbinvd();
atomic_or_32(&ci->ci_flags, CPUF_PRESENT);
tsc_sync_ap(ci);
@@ -1295,7 +1304,8 @@
void
cpu_get_tsc_freq(struct cpu_info *ci)
{
- uint64_t freq = 0, last_tsc;
+ uint64_t freq = 0, t0, t1;
+ int64_t overhead;
if (cpu_hascounter())
freq = cpu_tsc_freq_cpuid(ci);
@@ -1304,11 +1314,31 @@
/* Use TSC frequency taken from CPUID. */
ci->ci_data.cpu_cc_freq = freq;
} else {
- /* Calibrate TSC frequency. */
- last_tsc = cpu_counter_serializing();
+ /*
+ * Work out the approximate overhead involved below.
+ * Discard the result of the first go around the loop.
+ */
+ overhead = 0;
+ for (int i = 0; i <= 8; i++) {
+ __insn_barrier();
+ t0 = cpu_counter_serializing();
+ (*cpu_nullop_ptr)(NULL);
+ t1 = cpu_counter_serializing();
+ __insn_barrier();
+ if (i > 0) {
+ overhead += (t1 - t0);
+ }
+ }
+ overhead >>= 3;
+
+ /* Now warm up x86_delay() and do the calibration. */
+ x86_delay(1);
+ __insn_barrier();
+ t0 = cpu_counter_serializing();
x86_delay(100000);
- ci->ci_data.cpu_cc_freq =
- (cpu_counter_serializing() - last_tsc) * 10;
+ t1 = cpu_counter_serializing();
+ __insn_barrier();
+ ci->ci_data.cpu_cc_freq = (t1 - t0 - overhead) * 10;
}
}
Home |
Main Index |
Thread Index |
Old Index