changeset 13533:6c1a51927cbd

1333 High kernel cpu usage & dtrace hang on idle system Reviewed by: Richard Lowe <richlowe@richlowe.net> Reviewed by: Aubrey Li <aubreylee@gmail.com> Reviewed by: Albert Lee <trisk@nexenta.com> Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Robert Mustacchi <rm@joyent.com> Approved by: Gordon Ross <gwr@nexenta.com>
author Garrett D'Amore <garrett@nexenta.com>
date Mon, 28 Nov 2011 20:07:13 -0800
parents 365e6faae95f
children f1634d5c7d82
files usr/src/uts/i86pc/io/pcplusmp/apic_timer.c
diffstat 1 files changed, 34 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/i86pc/io/pcplusmp/apic_timer.c	Wed Jun 22 16:58:54 2011 -0700
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic_timer.c	Mon Nov 28 20:07:13 2011 -0800
@@ -25,6 +25,9 @@
  * Copyright (c) 2010, Intel Corporation.
  * All rights reserved.
  */
+/*
+ * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ */
 
 #include <sys/time.h>
 #include <sys/psm.h>
@@ -286,8 +289,28 @@
 static void
 deadline_timer_enable(void)
 {
+	uint64_t ticks;
+
 	apic_reg_ops->apic_write(APIC_LOCAL_TIMER,
 	    (apic_clkvect + APIC_BASE_VECT) | AV_DEADLINE);
+	/*
+	 * Now we have to serialize this per the SDM.  That is to
+	 * say, the above enabling can race in the pipeline with
+	 * changes to the MSR.  We need to make sure the above
+	 * operation is complete before we proceed to reprogram
+	 * the deadline value in reprogram().  The algorithm
+	 * recommended by the Intel SDM 3A in 10.5.1.4 is:
+	 *
+	 * a) write a big value to the deadline register
+	 * b) read the register back
+	 * c) if it reads zero, go back to a and try again
+	 */
+
+	do {
+		/* write a really big value */
+		wrmsr(IA32_DEADLINE_TSC_MSR, 1ULL << 63);
+		ticks = rdmsr(IA32_DEADLINE_TSC_MSR);
+	} while (ticks == 0);
 }
 
 /* deadline timer disable */
@@ -302,17 +325,20 @@
 static void
 deadline_timer_reprogram(hrtime_t time)
 {
+	int64_t		delta;
 	uint64_t	ticks;
 
-	if (time <= 0) {
-		/*
-		 * generate an immediate interrupt
-		 */
-		ticks = (uint64_t)tsc_read();
-	} else {
-		ticks = unscalehrtime(time);
-	}
+	/*
+	 * Note that this entire routine is called with
+	 * CBE_HIGH_PIL, so we needn't worry about preemption.
+	 */
+	delta = time - gethrtime();
 
+	/* The unscalehrtime wants unsigned values. */
+	delta = max(delta, 0);
+
+	/* Now we shouldn't be interrupted, we can set the deadline */
+	ticks = (uint64_t)tsc_read() + unscalehrtime(delta);
 	wrmsr(IA32_DEADLINE_TSC_MSR, ticks);
 }