Module Name:    src
Committed By:   thorpej
Date:           Tue Sep 29 01:33:01 UTC 2020

Modified Files:
        src/sys/arch/alpha/alpha: clock.c cpu.c qemu.c
        src/sys/arch/alpha/include: cpu.h

Log Message:
Improve time keeping and host CPU usage when running in Qemu:
- clockattach(): Allow multiple calls when running in Qemu. Anything
  after this first one is ignored, but this gives us a change to use
  a clock source provided by the VM directly, rather than relying on
  a more expensive hardware emulation.
- Add cpu_initclocks_secondary(), to handle clock setup on secondary
  CPUs, if needed.
- Allow us to use the WTINT PALcode call in cpu_idle() to idle in a lower
  power state (Qemu's PALcode supports this).
- Use the Qemu per-cpu set-alarm-rel call as the hardclock interrupt
  source.  In Qemu environments, reduce hz to 50 (rather than the
  default 1024) to give the clock a snowball's chance when running on
  a host system with hz=100.  XXX We have to manually re-calculate
  tick and tickadj.  There should be MI code to do this for us.  Also
  in Qemu environments, let hardclock() drive the sched clock by setting
  schedhz=0.


To generate a diff of this commit:
cvs rdiff -u -r1.44 -r1.45 src/sys/arch/alpha/alpha/clock.c
cvs rdiff -u -r1.100 -r1.101 src/sys/arch/alpha/alpha/cpu.c
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/alpha/alpha/qemu.c
cvs rdiff -u -r1.97 -r1.98 src/sys/arch/alpha/include/cpu.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/alpha/alpha/clock.c
diff -u src/sys/arch/alpha/alpha/clock.c:1.44 src/sys/arch/alpha/alpha/clock.c:1.45
--- src/sys/arch/alpha/alpha/clock.c:1.44	Sun Sep 27 23:17:36 2020
+++ src/sys/arch/alpha/alpha/clock.c	Tue Sep 29 01:33:00 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: clock.c,v 1.44 2020/09/27 23:17:36 thorpej Exp $ */
+/* $NetBSD: clock.c,v 1.45 2020/09/29 01:33:00 thorpej Exp $ */
 
 /*
  * Copyright (c) 1988 University of Utah.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.44 2020/09/27 23:17:36 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.45 2020/09/29 01:33:00 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -64,10 +64,16 @@ clockattach(void (*fns)(void *), void *d
 {
 
 	/*
-	 * Just bookkeeping.
+	 * Just bookkeeping.  We only allow one system clock.  If
+	 * we're running on real hardware, enforce this.  If we're
+	 * running under Qemu, anything after the first one.
 	 */
-	if (clock_init != NULL)
+	if (clock_init != NULL) {
+		if (alpha_is_qemu) {
+			return;
+		}
 		panic("clockattach: multiple clocks");
+	}
 	clock_init = fns;
 	clockdev = dev;
 }
@@ -114,6 +120,16 @@ cpu_initclocks(void)
 }
 
 /*
+ * Some platforms might have other per-cpu clock initialization.  This
+ * is handled here.
+ */
+void
+cpu_initclocks_secondary(void)
+{
+	(*clock_init)(clockdev);
+}
+
+/*
  * We assume newhz is either stathz or profhz, and that neither will
  * change after being set up above.  Could recalculate intervals here
  * but that would be a drag.

Index: src/sys/arch/alpha/alpha/cpu.c
diff -u src/sys/arch/alpha/alpha/cpu.c:1.100 src/sys/arch/alpha/alpha/cpu.c:1.101
--- src/sys/arch/alpha/alpha/cpu.c:1.100	Fri Sep  4 01:56:29 2020
+++ src/sys/arch/alpha/alpha/cpu.c	Tue Sep 29 01:33:00 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.c,v 1.100 2020/09/04 01:56:29 thorpej Exp $ */
+/* $NetBSD: cpu.c,v 1.101 2020/09/29 01:33:00 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.100 2020/09/04 01:56:29 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.101 2020/09/29 01:33:00 thorpej Exp $");
 
 #include "opt_ddb.h"
 #include "opt_multiprocessor.h"
@@ -100,6 +100,27 @@ volatile u_long cpus_paused __read_mostl
 void	cpu_boot_secondary(struct cpu_info *);
 #endif /* MULTIPROCESSOR */
 
+static void
+cpu_idle_default(void)
+{
+	/*
+	 * Default is to do nothing.  Platform code can overwrite
+	 * as needed.
+	 */
+}
+
+void
+cpu_idle_wtint(void)
+{
+	/*
+	 * Some PALcode versions implement the WTINT call to idle
+	 * in a low power mode.
+	 */
+	alpha_pal_wtint(0);
+}
+
+void	(*cpu_idle_fn)(void) __read_mostly = cpu_idle_default;
+
 /*
  * The Implementation Version and the Architecture Mask must be
  * consistent across all CPUs in the system, so we set it for the
@@ -582,6 +603,8 @@ cpu_hatch(struct cpu_info *ci)
 	alpha_pal_imb();
 
 	cc_calibrate_cpu(ci);
+
+	cpu_initclocks_secondary();
 }
 
 int

Index: src/sys/arch/alpha/alpha/qemu.c
diff -u src/sys/arch/alpha/alpha/qemu.c:1.1 src/sys/arch/alpha/alpha/qemu.c:1.2
--- src/sys/arch/alpha/alpha/qemu.c:1.1	Sun Sep 27 23:59:37 2020
+++ src/sys/arch/alpha/alpha/qemu.c	Tue Sep 29 01:33:00 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: qemu.c,v 1.1 2020/09/27 23:59:37 thorpej Exp $ */
+/* $NetBSD: qemu.c,v 1.2 2020/09/29 01:33:00 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -38,12 +38,16 @@ __KERNEL_RCSID(0, "$NetBSD");
 #include <sys/device.h>
 #include <sys/time.h>
 #include <sys/timetc.h>
+#include <sys/kernel.h>
 #include <sys/cpu.h>
 
 #include <machine/autoconf.h>
+#include <machine/cpuconf.h>
 #include <machine/rpb.h>
 #include <machine/alpha.h>
 
+#include <alpha/alpha/clockvar.h>
+
 extern struct cfdriver qemu_cd;
 
 struct qemu_softc {
@@ -57,7 +61,7 @@ qemu_get_timecount(struct timecounter * 
 {
 	register unsigned long v0 __asm("$0");
 	register unsigned long a0 __asm("$16") = 7;	/* Qemu get-time */
-	
+
 	__asm volatile ("call_pal %2"
 		: "=r"(v0), "+r"(a0)
 		: "i"(PAL_cserve)
@@ -66,6 +70,69 @@ qemu_get_timecount(struct timecounter * 
 	return (u_int)v0;
 }
 
+static inline void
+qemu_set_alarm_relative(unsigned long nsec)
+{
+	register unsigned long a0 __asm("$16") = 5;	/* Qemu set-alarm-rel */
+	register unsigned long a1 __asm("$17") = nsec;
+
+	__asm volatile ("call_pal %2"
+		: "+r"(a0), "+r"(a1)
+		: "i"(PAL_cserve)
+		: "$0", "$18", "$19", "$20", "$21");
+}
+
+static unsigned long qemu_nsec_per_tick __read_mostly;
+
+static void
+qemu_hardclock(struct clockframe * const framep)
+{
+	if (__predict_false(qemu_nsec_per_tick == 0)) {
+		/* Spurious; qemu_clock_init() hasn't been called yet. */
+		return;
+	}
+
+	/* Schedule the next tick before we process the current one. */
+	qemu_set_alarm_relative(qemu_nsec_per_tick);
+
+	hardclock(framep);
+}
+
+static void
+qemu_clock_init(void * const v __unused)
+{
+	/* First-time initialization... */
+	if (qemu_nsec_per_tick == 0) {
+		KASSERT(CPU_IS_PRIMARY(curcpu()));
+		qemu_nsec_per_tick = 1000000000UL / hz;
+
+		/*
+		 * Override the clockintr routine; the Qemu alarm is
+		 * one-shot, so we have to restart it for the next one.
+		 */
+		platform.clockintr = qemu_hardclock;
+
+		/*
+		 * hz=1024 is a little bananas for an emulated
+		 * virtual machine.  Reset to something more
+		 * reasonable, and recalculate everything based
+		 * on it.
+		 */
+		hz = 50;
+		tick = 1000000 / hz;
+		tickadj = (240000 / (60 * hz)) ? (240000 / (60 * hz)) : 1;
+		schedhz = 0;
+
+		printf("Using the Qemu CPU alarm for %d Hz hardclock.\n", hz);
+	}
+
+	/*
+	 * Note: We need to do this on each CPU, as the Qemu
+	 * alarm is implemented as a per-CPU register.
+	 */
+	qemu_set_alarm_relative(qemu_nsec_per_tick);
+}
+
 static int
 qemu_match(device_t parent, cfdata_t cfdata, void *aux)
 {
@@ -98,6 +165,16 @@ qemu_attach(device_t parent, device_t se
 	tc->tc_frequency = 1000000000UL;	/* nanosecond granularity */
 	tc->tc_priv = sc;
 	tc_init(tc);
+
+	/*
+	 * Use the Qemu alarm as the system clock.
+	 */
+	clockattach(qemu_clock_init, sc);
+
+	/*
+	 * Qemu's PALcode implements WTINT; use it to save host cycles.
+	 */
+	cpu_idle_fn = cpu_idle_wtint;
 }
 
 CFATTACH_DECL_NEW(qemu, sizeof(struct qemu_softc),

Index: src/sys/arch/alpha/include/cpu.h
diff -u src/sys/arch/alpha/include/cpu.h:1.97 src/sys/arch/alpha/include/cpu.h:1.98
--- src/sys/arch/alpha/include/cpu.h:1.97	Fri Sep 25 03:40:11 2020
+++ src/sys/arch/alpha/include/cpu.h	Tue Sep 29 01:33:00 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.h,v 1.97 2020/09/25 03:40:11 thorpej Exp $ */
+/* $NetBSD: cpu.h,v 1.98 2020/09/29 01:33:00 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -242,7 +242,11 @@ int	badaddr(void *, size_t);
 void *	cpu_uarea_alloc(bool);
 bool	cpu_uarea_free(void *);
 
-#define	cpu_idle()	/* nothing */
+void	cpu_idle_wtint(void);
+extern	void (*cpu_idle_fn)(void);
+#define	cpu_idle()	(*cpu_idle_fn)()
+
+void	cpu_initclocks_secondary(void);
 
 #endif /* _KERNEL */
 #endif /* _ALPHA_CPU_H_ */

Reply via email to