linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: jbohac@suse.cz
To: Andi Kleen <ak@suse.de>
Cc: linux-kernel@vger.kernel.org, Jiri Bohac <jbohac@suse.cz>,
	Vojtech Pavlik <vojtech@suse.cz>,
	ssouhlal@freebsd.org, arjan@infradead.org, tglx@linutronix.de,
	johnstul@us.ibm.com, zippel@linux-m68k.org, andrea@suse.de
Subject: [patch 7/9] Adapt the time initialization code
Date: Thu, 01 Feb 2007 10:59:59 +0100	[thread overview]
Message-ID: <20070201103754.041245000@jet.suse.cz> (raw)
In-Reply-To: 20070201095952.589234000@jet.suse.cz

[-- Attachment #1: time_init --]
[-- Type: text/plain, Size: 8230 bytes --]

We need to:
 - initialize the RDTSCP instruction if available
 - decide which hardware timer to use as MT (PM or HPET)
 - decide what level of TSC->MT approximation to use
   - none (as slow as the hardware MT can get) -- "notsc" option
   - strictly monotonic (can't be done in a vsyscall) -- default
   - unguaranteed monotonicity (very fast, vsyscall) -- "nomonotonic" option

Signed-off-by: Jiri Bohac <jbohac@suse.cz>

Index: linux-2.6.20-rc5/arch/x86_64/kernel/smpboot.c
===================================================================
--- linux-2.6.20-rc5.orig/arch/x86_64/kernel/smpboot.c
+++ linux-2.6.20-rc5/arch/x86_64/kernel/smpboot.c
@@ -318,6 +318,8 @@ static inline void set_cpu_sibling_map(i
 	}
 }
 
+extern void time_initialize_cpu(void);
+
 /*
  * Setup code on secondary processor (after comming out of the trampoline)
  */
@@ -345,6 +347,7 @@ void __cpuinit start_secondary(void)
 		enable_NMI_through_LVT0(NULL);
 		enable_8259A_irq(0);
 	}
+	time_initialize_cpu();
 
 	enable_APIC_timer();
 
@@ -963,6 +966,8 @@ int __cpuinit __cpu_up(unsigned int cpu)
 	return err;
 }
 
+extern void time_init_gtod(void);
+
 /*
  * Finish the SMP boot.
  */
Index: linux-2.6.20-rc5/arch/x86_64/kernel/time.c
===================================================================
--- linux-2.6.20-rc5.orig/arch/x86_64/kernel/time.c
+++ linux-2.6.20-rc5/arch/x86_64/kernel/time.c
@@ -968,6 +968,16 @@ static struct irqaction irq0 = {
 	timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL
 };
 
+static void time_init_rdtsc(void)
+{
+	if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP)) {
+		int p;
+		p = smp_processor_id();
+		printk(KERN_INFO "Initializing RDTSCP feature on cpu %d.\n", p);
+		write_rdtscp_aux(p);
+	}
+}
+
 void __init time_init(void)
 {
 	if (nohpet)
@@ -979,27 +989,40 @@ void __init time_init(void)
 	set_normalized_timespec(&wall_to_monotonic,
 	                        -xtime.tv_sec, -xtime.tv_nsec);
 
-	if (!hpet_init())
-                vxtime_hz = (FSEC_PER_SEC + hpet_period / 2) / hpet_period;
-	else
-		vxtime.hpet_address = 0;
+	/* decide what to use as Master Timer: HPET or PM? */
+	if (!hpet_init()) {
+		vxtime.mt_q = (hpet_period << 32) / FSEC_PER_NSEC;
+		mt_per_tick = hpet_use_timer ?
+			hpet_tick : LATCH * 12;
+		read_master_timer = read_master_timer_hpet;
+		timename = "HPET";
+	} else
+	if (pmtmr_ioport) {
+		vxtime.mt_q = (NSEC_PER_SEC << 32) / 916363636UL;
+		mt_per_tick = (LATCH * 3) << 8;
+		read_master_timer = read_master_timer_pm;
+		timename = "PM timer";
+	} else
+		panic("No suitable Master Timer found.\n");
 
-	if (hpet_use_timer) {
-		/* set tick_nsec to use the proper rate for HPET */
-	  	tick_nsec = TICK_NSEC_HPET;
+	/* use PIT as main timer interrupt source if we can't use HPET */
+	if (hpet_use_timer)
 		cpu_khz = hpet_calibrate_tsc();
-		timename = "HPET";
-	} else {
+	else {
 		pit_init();
 		cpu_khz = pit_calibrate_tsc();
-		timename = "PIT";
 	}
 
-	vxtime.mode = VXTIME_TSC;
-	vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz;
-	vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz;
-	vxtime.last_tsc = get_cycles_sync();
-	set_cyc2ns_scale(cpu_khz);
+	/* initialize the master timer */
+	set_master_timer64(0);
+
+	/* initialize the timekeeping variables of the boot CPU */
+	vxtime.cpu[0].tsc_last = get_cycles_sync();
+	vxtime.cpu[0].mt_last = vxtime.cpu[0].mt_base = 0;
+	vxtime.cpu[0].tsc_slope = vxtime.cpu[0].tsc_slope_avg = (((USEC_PER_SEC << 32) / vxtime.mt_q) << TSC_SLOPE_SCALE) / cpu_khz;
+	time_init_rdtsc();
+
+	vxtime.mode = VXTIME_TSCS; /* not sure yet if CPUs have synced TSCs */
 	setup_irq(0, &irq0);
 
 #ifndef CONFIG_SMP
@@ -1037,28 +1060,71 @@ __cpuinit int unsynchronized_tsc(void)
  */
 void time_init_gtod(void)
 {
-	char *timetype;
-
-	if (unsynchronized_tsc())
-		notsc = 1;
+	char *tsc_method;
 
  	if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
 		vgetcpu_mode = VGETCPU_RDTSCP;
 	else
 		vgetcpu_mode = VGETCPU_LSL;
 
-		timetype = hpet_use_timer ? "HPET/TSC" : "PIT/TSC";
+	if (notsc) {
+		tsc_method = "nothing";
+		vxtime.mode = VXTIME_MT;
+	}
+	else if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP)) {
+		if (nomonotonic) {
+			tsc_method = "RDTSCP";
+			vxtime.mode = VXTIME_TSCP;
+		}
+		else {
+			tsc_method = "RDTSCM (syscall)";
+			vxtime.mode = VXTIME_TSCM;
+		}
+	}
+	else {
+		tsc_method = "RDTSC";
 		vxtime.mode = VXTIME_TSC;
+#ifdef CONFIG_SMP
+		if (unsynchronized_tsc()) {
+			if (nomonotonic) {
+				tsc_method = "RDTSC (syscall)";
+				vxtime.mode = VXTIME_TSCS;
+			}
+			else {
+				tsc_method = "RDTSCM (syscall)";
+				vxtime.mode = VXTIME_TSCM;
+			}
+		}
+#endif
+ 	}
+
 
-	printk(KERN_INFO "time.c: Using %ld.%06ld MHz WALL %s GTOD %s timer.\n",
-	       vxtime_hz / 1000000, vxtime_hz % 1000000, timename, timetype);
+	printk(KERN_INFO "time.c: Using %s as master timer, %s for time caching; vsyscall %s.\n",
+	       timename, tsc_method, sysctl_vsyscall ? "enabled" : "disabled");
+	printk(KERN_INFO "time.c: Using %s as interrupt source.\n",
+	       hpet_use_timer ? "HPET" : "PIT");
 	printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
 		cpu_khz / 1000, cpu_khz % 1000);
-	vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz;
-	vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz;
-	vxtime.last_tsc = get_cycles_sync();
+}
 
-	set_cyc2ns_scale(cpu_khz);
+/*
+ * initialize the per_cpu timekeeping variables
+ * for non-boot CPUs
+ */
+void time_initialize_cpu(void *info)
+{
+	unsigned long flags;
+	int cpu = smp_processor_id();
+	u64 mt_now;
+	write_seqlock_irqsave(&xtime_lock, flags);
+	mt_now = get_master_timer64();
+	vxtime.cpu[cpu].tsc_last = get_cycles_sync();
+	vxtime.cpu[cpu].mt_last = mt_now;
+	vxtime.cpu[cpu].mt_base = mt_now;
+	vxtime.cpu[cpu].tsc_slope = vxtime.cpu[0].tsc_slope;
+	vxtime.cpu[cpu].tsc_slope_avg = vxtime.cpu[0].tsc_slope_avg;
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+	time_init_rdtsc();
 }
 
 __setup("report_lost_ticks", time_setup);
@@ -1098,19 +1164,38 @@ static int timer_resume(struct sys_devic
 		sleep_length = 0;
 		ctime = sleep_start;
 	}
-	if (vxtime.hpet_address)
+
+	write_seqlock_irqsave(&xtime_lock,flags);
+
+	/* reenable the Master Timer */
+	if (read_master_timer == read_master_timer_hpet || hpet_use_timer)
 		hpet_reenable();
+	/* reenable PIT if used as main timer interrupt source */
 	else
 		i8254_timer_resume();
 
 	sec = ctime + clock_cmos_diff;
-	write_seqlock_irqsave(&xtime_lock,flags);
 	xtime.tv_sec = sec;
 	xtime.tv_nsec = 0;
-		vxtime.last_tsc = get_cycles_sync();
-	write_sequnlock_irqrestore(&xtime_lock,flags);
+
+	/* re-initialize the master timer */
+	add_master_timer64(sleep_length * mt_per_tick);
+	vxtime.mt_wall += sleep_length * mt_per_tick;
+
 	jiffies += sleep_length;
-	monotonic_base += sleep_length * (NSEC_PER_SEC/HZ);
+
+	/* re-initialize the timekeeping variables of the boot CPU */
+	vxtime.cpu[0].tsc_last = get_cycles_sync();
+	vxtime.cpu[0].mt_last = vxtime.cpu[0].mt_base = get_master_timer64();
+	/* FIXME: what speed does the cpu really start at; I doubt cpu_khz is right at this point ??!!!
+	   And what speed do the non-boot cpus start at? Their timekeeping variables will probably be set wrong
+	   by copying from CPU 0 in time_initialize_cpu(); Not a great deal, as they will be synced somehow,
+	   but not exactly nice -JB */
+	vxtime.cpu[0].tsc_slope = vxtime.cpu[0].tsc_slope_avg =
+		(((USEC_PER_SEC << 32) / vxtime.mt_q) << TSC_SLOPE_SCALE) / cpu_khz;
+
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+	
 	touch_softlockup_watchdog();
 	return 0;
 }
@@ -1402,3 +1487,11 @@ int __init notsc_setup(char *s)
 }
 
 __setup("notsc", notsc_setup);
+
+int __init nomonotonic_setup(char *s)
+{
+	nomonotonic = 1;
+	return 1;
+}
+
+__setup("nomonotonic", nomonotonic_setup);
Index: linux-2.6.20-rc5/include/linux/time.h
===================================================================
--- linux-2.6.20-rc5.orig/include/linux/time.h
+++ linux-2.6.20-rc5/include/linux/time.h
@@ -31,6 +31,7 @@ struct timezone {
 #define MSEC_PER_SEC	1000L
 #define USEC_PER_MSEC	1000L
 #define NSEC_PER_USEC	1000L
+#define FSEC_PER_NSEC 	1000000L
 #define NSEC_PER_MSEC	1000000L
 #define USEC_PER_SEC	1000000L
 #define NSEC_PER_SEC	1000000000L

--

  parent reply	other threads:[~2007-02-01 11:29 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-02-01  9:59 [patch 0/9] x86_64: reliable TSC-based gettimeofday jbohac
2007-02-01  9:59 ` [patch 1/9] Fix HPET init race jbohac
2007-02-02  2:34   ` Andrew Morton
2007-02-06 16:44     ` Jiri Bohac
2007-02-07  0:12       ` Andrew Morton
2007-02-10 12:31         ` Andi Kleen
2007-07-26 20:58           ` Robin Holt
2007-02-01  9:59 ` [patch 2/9] Remove the support for the VXTIME_PMTMR timer mode jbohac
2007-02-01 11:13   ` Andi Kleen
2007-02-01 13:13     ` Jiri Bohac
2007-02-01 13:13       ` Andi Kleen
2007-02-01 13:59         ` Jiri Bohac
2007-02-01 14:18           ` Andi Kleen
2007-02-01  9:59 ` [patch 3/9] Remove the support for the VXTIME_HPET " jbohac
2007-02-01  9:59 ` [patch 4/9] Remove the TSC synchronization on SMP machines jbohac
2007-02-01 11:14   ` Andi Kleen
2007-02-01 13:17     ` Jiri Bohac
2007-02-01 15:16       ` Vojtech Pavlik
2007-02-02  7:14         ` Andi Kleen
2007-02-13  0:34           ` Christoph Lameter
2007-02-13  6:40             ` Arjan van de Ven
2007-02-13  8:28               ` Andi Kleen
2007-02-13  8:41                 ` Arjan van de Ven
2007-02-13 17:09               ` Christoph Lameter
2007-02-13 17:20                 ` Andi Kleen
2007-02-13 22:18                   ` Vojtech Pavlik
2007-02-13 22:38                     ` Andrea Arcangeli
2007-02-14  6:59                       ` Vojtech Pavlik
2007-02-13 23:55                     ` Christoph Lameter
2007-02-14  0:18                   ` Paul Mackerras
2007-02-14  0:25                     ` john stultz
2007-02-02  7:13       ` Andi Kleen
2007-02-01 21:05     ` mbligh
2007-02-03  1:16   ` H. Peter Anvin
2007-02-01  9:59 ` [patch 5/9] Add all the necessary structures to the vsyscall page jbohac
2007-02-01 11:17   ` Andi Kleen
2007-02-01  9:59 ` [patch 6/9] Add the "Master Timer" jbohac
2007-02-01 11:22   ` Andi Kleen
2007-02-01 13:29     ` Jiri Bohac
2007-02-01  9:59 ` jbohac [this message]
2007-02-01 11:26   ` [patch 7/9] Adapt the time initialization code Andi Kleen
2007-02-01 13:41     ` Jiri Bohac
2007-02-01 10:00 ` [patch 8/9] Add time_update_mt_guess() jbohac
2007-02-01 11:28   ` Andi Kleen
2007-02-01 13:54     ` Jiri Bohac
2007-02-01 10:00 ` [patch 9/9] Make use of the Master Timer jbohac
2007-02-01 11:36   ` Andi Kleen
2007-02-01 14:29     ` Jiri Bohac
2007-02-01 15:23       ` Vojtech Pavlik
2007-02-02  7:05         ` Andi Kleen
2007-02-02  7:04       ` Andi Kleen
2007-02-01 11:20 ` [patch 0/9] x86_64: reliable TSC-based gettimeofday Andi Kleen
2007-02-01 11:53   ` Andrea Arcangeli
2007-02-01 12:02     ` Andi Kleen
2007-02-01 12:54       ` Andrea Arcangeli
2007-02-01 12:17   ` Ingo Molnar
2007-02-01 14:52   ` Jiri Bohac
2007-02-01 16:56     ` john stultz
2007-02-01 19:41       ` Vojtech Pavlik
2007-02-01 11:34 ` Ingo Molnar
2007-02-01 11:46 ` [-mm patch] x86_64 GTOD: offer scalable vgettimeofday Ingo Molnar
2007-02-01 12:01   ` Andi Kleen
2007-02-01 12:14     ` Ingo Molnar
2007-02-01 12:17   ` [-mm patch] x86_64 GTOD: offer scalable vgettimeofday II Andi Kleen
2007-02-01 12:24     ` Ingo Molnar
2007-02-01 12:45       ` Andi Kleen
2007-02-02  4:22 ` [patch 0/9] x86_64: reliable TSC-based gettimeofday Andrew Morton
2007-02-02  7:07   ` Andi Kleen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070201103754.041245000@jet.suse.cz \
    --to=jbohac@suse.cz \
    --cc=ak@suse.de \
    --cc=andrea@suse.de \
    --cc=arjan@infradead.org \
    --cc=johnstul@us.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ssouhlal@freebsd.org \
    --cc=tglx@linutronix.de \
    --cc=vojtech@suse.cz \
    --cc=zippel@linux-m68k.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).