svn commit: r263008 - in head/sys: amd64/amd64 amd64/include conf dev/xen/timer i386/i386 i386/include i386/xen pc98/pc98 x86/include x86/isa x86/x86 x86/xen

Roger Pau Monné royger at FreeBSD.org
Tue Mar 11 10:20:45 UTC 2014


Author: royger
Date: Tue Mar 11 10:20:42 2014
New Revision: 263008
URL: http://svnweb.freebsd.org/changeset/base/263008

Log:
  xen: implement an early timer for Xen PVH
  
  When running as a PVH guest, there's no emulated i8254, so we need to
  use the Xen PV timer as the early source for DELAY. This change allows
  for different implementations of the early DELAY function and
  implements a Xen variant for it.
  
  Approved by: gibbs
  Sponsored by: Citrix Systems R&D
  
  dev/xen/timer/timer.c:
  dev/xen/timer/timer.h:
   - Implement Xen early delay functions using the PV timer and declare
     them.
  
  x86/include/init.h:
   - Add hooks for early clock source initialization and early delay
     functions.
  
  i386/i386/machdep.c:
  pc98/pc98/machdep.c:
  amd64/amd64/machdep.c:
   - Set early delay hooks to use the i8254 on bare metal.
   - Use clock_init (that will in turn make use of init_ops) to
     initialize the early clock source.
  
  amd64/include/clock.h:
  i386/include/clock.h:
   - Declare i8254_delay and clock_init.
  
  i386/xen/clock.c:
   - Rename DELAY to i8254_delay.
  
  x86/isa/clock.c:
   - Introduce clock_init that will take care of initializing the early
     clock by making use of the init_ops hooks.
   - Move non ISA related delay functions to the newly introduced delay
     file.
  
  x86/x86/delay.c:
   - Add moved delay related functions.
   - Implement generic DELAY function that will use the init_ops hooks.
  
  x86/xen/pv.c:
   - Set PVH hooks for the early delay related functions in init_ops.
  
  conf/files.amd64:
  conf/files.i386:
  conf/files.pc98:
   - Add delay.c to the kernel build.

Added:
  head/sys/dev/xen/timer/timer.h   (contents, props changed)
  head/sys/x86/x86/delay.c   (contents, props changed)
Modified:
  head/sys/amd64/amd64/machdep.c
  head/sys/amd64/include/clock.h
  head/sys/conf/files.amd64
  head/sys/conf/files.i386
  head/sys/conf/files.pc98
  head/sys/dev/xen/timer/timer.c
  head/sys/i386/i386/machdep.c
  head/sys/i386/include/clock.h
  head/sys/i386/xen/clock.c
  head/sys/pc98/pc98/machdep.c
  head/sys/x86/include/init.h
  head/sys/x86/isa/clock.c
  head/sys/x86/xen/pv.c

Modified: head/sys/amd64/amd64/machdep.c
==============================================================================
--- head/sys/amd64/amd64/machdep.c	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/amd64/amd64/machdep.c	Tue Mar 11 10:20:42 2014	(r263008)
@@ -172,6 +172,8 @@ static caddr_t native_parse_preload_data
 /* Default init_ops implementation. */
 struct init_ops init_ops = {
 	.parse_preload_data =	native_parse_preload_data,
+	.early_clock_source_init =	i8254_init,
+	.early_delay =			i8254_delay,
 };
 
 /*
@@ -1822,10 +1824,10 @@ hammer_time(u_int64_t modulep, u_int64_t
 	lidt(&r_idt);
 
 	/*
-	 * Initialize the i8254 before the console so that console
+	 * Initialize the clock before the console so that console
 	 * initialization can use DELAY().
 	 */
-	i8254_init();
+	clock_init();
 
 	/*
 	 * Initialize the console before we print anything out.

Modified: head/sys/amd64/include/clock.h
==============================================================================
--- head/sys/amd64/include/clock.h	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/amd64/include/clock.h	Tue Mar 11 10:20:42 2014	(r263008)
@@ -25,6 +25,8 @@ extern int	smp_tsc;
 #endif
 
 void	i8254_init(void);
+void	i8254_delay(int);
+void	clock_init(void);
 
 /*
  * Driver to clock driver interface.

Modified: head/sys/conf/files.amd64
==============================================================================
--- head/sys/conf/files.amd64	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/conf/files.amd64	Tue Mar 11 10:20:42 2014	(r263008)
@@ -554,6 +554,7 @@ x86/x86/mptable_pci.c		optional	mptable 
 x86/x86/msi.c			optional	pci
 x86/x86/nexus.c			standard
 x86/x86/tsc.c			standard
+x86/x86/delay.c			standard
 x86/xen/hvm.c			optional	xenhvm
 x86/xen/xen_intr.c		optional	xen | xenhvm
 x86/xen/pv.c			optional	xenhvm

Modified: head/sys/conf/files.i386
==============================================================================
--- head/sys/conf/files.i386	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/conf/files.i386	Tue Mar 11 10:20:42 2014	(r263008)
@@ -593,5 +593,6 @@ x86/x86/mptable_pci.c		optional apic nat
 x86/x86/msi.c			optional apic pci
 x86/x86/nexus.c			standard
 x86/x86/tsc.c			standard
+x86/x86/delay.c			standard
 x86/xen/hvm.c			optional xenhvm
 x86/xen/xen_intr.c		optional xen | xenhvm

Modified: head/sys/conf/files.pc98
==============================================================================
--- head/sys/conf/files.pc98	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/conf/files.pc98	Tue Mar 11 10:20:42 2014	(r263008)
@@ -259,3 +259,5 @@ x86/x86/mptable_pci.c		optional apic pci
 x86/x86/msi.c			optional apic pci
 x86/x86/nexus.c			standard
 x86/x86/tsc.c			standard
+x86/x86/tsc.c			standard
+x86/x86/delay.c			standard

Modified: head/sys/dev/xen/timer/timer.c
==============================================================================
--- head/sys/dev/xen/timer/timer.c	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/dev/xen/timer/timer.c	Tue Mar 11 10:20:42 2014	(r263008)
@@ -60,6 +60,8 @@ __FBSDID("$FreeBSD$");
 #include <machine/_inttypes.h>
 #include <machine/smp.h>
 
+#include <dev/xen/timer/timer.h>
+
 #include "clock_if.h"
 
 static devclass_t xentimer_devclass;
@@ -592,6 +594,38 @@ xentimer_suspend(device_t dev)
 	return (0);
 }
 
+/*
+ * Xen early clock init
+ */
+void
+xen_clock_init(void)
+{
+}
+
+/*
+ * Xen PV DELAY function
+ *
+ * When running on PVH mode we don't have an emulated i8524, so
+ * make use of the Xen time info in order to code a simple DELAY
+ * function that can be used during early boot.
+ */
+void
+xen_delay(int n)
+{
+	struct vcpu_info *vcpu = &HYPERVISOR_shared_info->vcpu_info[0];
+	uint64_t end_ns;
+	uint64_t current;
+
+	end_ns = xen_fetch_vcpu_time(vcpu);
+	end_ns += n * NSEC_IN_USEC;
+
+	for (;;) {
+		current = xen_fetch_vcpu_time(vcpu);
+		if (current >= end_ns)
+			break;
+	}
+}
+
 static device_method_t xentimer_methods[] = {
 	DEVMETHOD(device_identify, xentimer_identify),
 	DEVMETHOD(device_probe, xentimer_probe),

Added: head/sys/dev/xen/timer/timer.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/xen/timer/timer.h	Tue Mar 11 10:20:42 2014	(r263008)
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2013 Roger Pau Monné <roger.pau at citrix.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _XEN_TIMER_H_
+#define _XEN_TIMER_H_
+
+void xen_clock_init(void);
+void xen_delay(int);
+
+#endif /* _XEN_TIMER_H_ */

Modified: head/sys/i386/i386/machdep.c
==============================================================================
--- head/sys/i386/i386/machdep.c	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/i386/i386/machdep.c	Tue Mar 11 10:20:42 2014	(r263008)
@@ -132,6 +132,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/sigframe.h>
 #include <machine/specialreg.h>
 #include <machine/vm86.h>
+#include <x86/init.h>
 #ifdef PERFMON
 #include <machine/perfmon.h>
 #endif
@@ -253,6 +254,12 @@ struct mtx icu_lock;
 
 struct mem_range_softc mem_range_softc;
 
+ /* Default init_ops implementation. */
+ struct init_ops init_ops = {
+	.early_clock_source_init =	i8254_init,
+	.early_delay =			i8254_delay,
+ };
+
 static void
 cpu_startup(dummy)
 	void *dummy;
@@ -2977,10 +2984,10 @@ init386(first)
 #endif /* XBOX */
 
 	/*
-	 * Initialize the i8254 before the console so that console
+	 * Initialize the clock before the console so that console
 	 * initialization can use DELAY().
 	 */
-	i8254_init();
+	clock_init();
 
 	/*
 	 * Initialize the console before we print anything out.

Modified: head/sys/i386/include/clock.h
==============================================================================
--- head/sys/i386/include/clock.h	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/i386/include/clock.h	Tue Mar 11 10:20:42 2014	(r263008)
@@ -22,6 +22,8 @@ extern int	tsc_is_invariant;
 extern int	tsc_perf_stat;
 
 void	i8254_init(void);
+void	i8254_delay(int);
+void	clock_init(void);
 
 /*
  * Driver to clock driver interface.

Modified: head/sys/i386/xen/clock.c
==============================================================================
--- head/sys/i386/xen/clock.c	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/i386/xen/clock.c	Tue Mar 11 10:20:42 2014	(r263008)
@@ -192,7 +192,7 @@ i8254_init(void)
  * Note: timer had better have been programmed before this is first used!
  */
 void
-DELAY(int n)
+i8254_delay(int n)
 {
 	int delta, ticks_left;
 	uint32_t tick, prev_tick;

Modified: head/sys/pc98/pc98/machdep.c
==============================================================================
--- head/sys/pc98/pc98/machdep.c	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/pc98/pc98/machdep.c	Tue Mar 11 10:20:42 2014	(r263008)
@@ -129,6 +129,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/sigframe.h>
 #include <machine/specialreg.h>
 #include <machine/vm86.h>
+#include <x86/init.h>
 #ifdef PERFMON
 #include <machine/perfmon.h>
 #endif
@@ -220,6 +221,12 @@ struct mtx icu_lock;
 
 struct mem_range_softc mem_range_softc;
 
+ /* Default init_ops implementation. */
+ struct init_ops init_ops = {
+	.early_clock_source_init =	i8254_init,
+	.early_delay =			i8254_delay,
+ };
+
 static void
 cpu_startup(dummy)
 	void *dummy;
@@ -2267,7 +2274,7 @@ init386(first)
 	 * Initialize the i8254 before the console so that console
 	 * initialization can use DELAY().
 	 */
-	i8254_init();
+	clock_init();
 
 	/*
 	 * Initialize the console before we print anything out.

Modified: head/sys/x86/include/init.h
==============================================================================
--- head/sys/x86/include/init.h	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/x86/include/init.h	Tue Mar 11 10:20:42 2014	(r263008)
@@ -36,6 +36,8 @@
  */
 struct init_ops {
 	caddr_t	(*parse_preload_data)(u_int64_t);
+	void	(*early_clock_source_init)(void);
+	void	(*early_delay)(int);
 };
 
 extern struct init_ops init_ops;

Modified: head/sys/x86/isa/clock.c
==============================================================================
--- head/sys/x86/isa/clock.c	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/x86/isa/clock.c	Tue Mar 11 10:20:42 2014	(r263008)
@@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/intr_machdep.h>
 #include <machine/ppireg.h>
 #include <machine/timerreg.h>
+#include <x86/init.h>
 
 #ifdef PC98
 #include <pc98/pc98/pc98_machdep.h>
@@ -139,6 +140,15 @@ static	u_char	timer2_state;
 static	unsigned i8254_get_timecount(struct timecounter *tc);
 static	void	set_i8254_freq(int mode, uint32_t period);
 
+void
+clock_init(void)
+{
+	/* Init the clock lock */
+	mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE);
+	/* Init the clock in order to use DELAY */
+	init_ops.early_clock_source_init();
+}
+
 static int
 clkintr(void *arg)
 {
@@ -247,61 +257,13 @@ getit(void)
 	return ((high << 8) | low);
 }
 
-#ifndef DELAYDEBUG
-static u_int
-get_tsc(__unused struct timecounter *tc)
-{
-
-	return (rdtsc32());
-}
-
-static __inline int
-delay_tc(int n)
-{
-	struct timecounter *tc;
-	timecounter_get_t *func;
-	uint64_t end, freq, now;
-	u_int last, mask, u;
-
-	tc = timecounter;
-	freq = atomic_load_acq_64(&tsc_freq);
-	if (tsc_is_invariant && freq != 0) {
-		func = get_tsc;
-		mask = ~0u;
-	} else {
-		if (tc->tc_quality <= 0)
-			return (0);
-		func = tc->tc_get_timecount;
-		mask = tc->tc_counter_mask;
-		freq = tc->tc_frequency;
-	}
-	now = 0;
-	end = freq * n / 1000000;
-	if (func == get_tsc)
-		sched_pin();
-	last = func(tc) & mask;
-	do {
-		cpu_spinwait();
-		u = func(tc) & mask;
-		if (u < last)
-			now += mask - last + u + 1;
-		else
-			now += u - last;
-		last = u;
-	} while (now < end);
-	if (func == get_tsc)
-		sched_unpin();
-	return (1);
-}
-#endif
-
 /*
  * Wait "n" microseconds.
  * Relies on timer 1 counting down from (i8254_freq / hz)
  * Note: timer had better have been programmed before this is first used!
  */
 void
-DELAY(int n)
+i8254_delay(int n)
 {
 	int delta, prev_tick, tick, ticks_left;
 #ifdef DELAYDEBUG
@@ -317,9 +279,6 @@ DELAY(int n)
 	}
 	if (state == 1)
 		printf("DELAY(%d)...", n);
-#else
-	if (delay_tc(n))
-		return;
 #endif
 	/*
 	 * Read the counter first, so that the rest of the setup overhead is
@@ -499,7 +458,6 @@ void
 i8254_init(void)
 {
 
-	mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE);
 #ifdef PC98
 	if (pc98_machine_type & M_8M)
 		i8254_freq = 1996800L; /* 1.9968 MHz */

Added: head/sys/x86/x86/delay.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/x86/x86/delay.c	Tue Mar 11 10:20:42 2014	(r263008)
@@ -0,0 +1,106 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 2010 Alexander Motin <mav at FreeBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	from: @(#)clock.c	7.2 (Berkeley) 5/12/91
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Generic x86 routines to handle delay */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/timetc.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/sched.h>
+
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <x86/init.h>
+
+static u_int
+get_tsc(__unused struct timecounter *tc)
+{
+
+	return (rdtsc32());
+}
+
+static int
+delay_tc(int n)
+{
+	struct timecounter *tc;
+	timecounter_get_t *func;
+	uint64_t end, freq, now;
+	u_int last, mask, u;
+
+	tc = timecounter;
+	freq = atomic_load_acq_64(&tsc_freq);
+	if (tsc_is_invariant && freq != 0) {
+		func = get_tsc;
+		mask = ~0u;
+	} else {
+		if (tc->tc_quality <= 0)
+			return (0);
+		func = tc->tc_get_timecount;
+		mask = tc->tc_counter_mask;
+		freq = tc->tc_frequency;
+	}
+	now = 0;
+	end = freq * n / 1000000;
+	if (func == get_tsc)
+		sched_pin();
+	last = func(tc) & mask;
+	do {
+		cpu_spinwait();
+		u = func(tc) & mask;
+		if (u < last)
+			now += mask - last + u + 1;
+		else
+			now += u - last;
+		last = u;
+	} while (now < end);
+	if (func == get_tsc)
+		sched_unpin();
+	return (1);
+}
+
+void
+DELAY(int n)
+{
+
+	if (delay_tc(n))
+		return;
+
+	init_ops.early_delay(n);
+}

Modified: head/sys/x86/xen/pv.c
==============================================================================
--- head/sys/x86/xen/pv.c	Tue Mar 11 10:16:17 2014	(r263007)
+++ head/sys/x86/xen/pv.c	Tue Mar 11 10:20:42 2014	(r263008)
@@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$");
 #include <xen/xen-os.h>
 #include <xen/hypervisor.h>
 
+#include <dev/xen/timer/timer.h>
+
 /* Native initial function */
 extern u_int64_t hammer_time(u_int64_t, u_int64_t);
 /* Xen initial function */
@@ -65,6 +67,8 @@ static caddr_t xen_pv_parse_preload_data
 /* Xen init_ops implementation. */
 struct init_ops xen_init_ops = {
 	.parse_preload_data =	xen_pv_parse_preload_data,
+	.early_clock_source_init =	xen_clock_init,
+	.early_delay =			xen_delay,
 };
 
 /*-------------------------------- Xen PV init -------------------------------*/


More information about the svn-src-all mailing list