svn commit: r191720 - in head/sys: amd64/amd64 i386/i386

Alexander Motin mav at FreeBSD.org
Fri May 1 17:05:50 UTC 2009


Author: mav
Date: Fri May  1 17:05:49 2009
New Revision: 191720
URL: http://svn.freebsd.org/changeset/base/191720

Log:
  Use value -1 instead of 0 for marking unused APIC vectors. This fixes
  IRQ0 routing on LAPIC-enabled systems.
  
  Add hint.apic.0.clock tunable. Setting it 0 disables using LAPIC timers
  as hard-/stat-/profclock sources falling back to using i8254 and rtc timers.
  
  On modern CPUs LAPIC is a part of CPU core which is shutting down when CPU
  enters C3 or deeper power state. It makes no problems for interrupt
  processing, as chipset wakes up CPU on interrupt triggering. But entering
  C3 state kills LAPIC timer and freezes system time, making C3 and deeper
  states practically unusable. Using i8254 timer allows to avoid this
  problem.
  
  By using i8254 timer my T7700 C2D CPU with UP kernel successfully enters
  C3 state, saving more then a Watt of total idle power (>10%) in addition to
  all other power-saving techniques.
  
  This technique is not working for SMP yet, as only one CPU receives
  timer interrupts. But I think that problem could be fixed by forwarding
  interrupts to other CPUs with IPI.

Modified:
  head/sys/amd64/amd64/local_apic.c
  head/sys/i386/i386/local_apic.c

Modified: head/sys/amd64/amd64/local_apic.c
==============================================================================
--- head/sys/amd64/amd64/local_apic.c	Fri May  1 15:36:02 2009	(r191719)
+++ head/sys/amd64/amd64/local_apic.c	Fri May  1 17:05:49 2009	(r191720)
@@ -112,7 +112,7 @@ struct lapic {
 	u_long la_stat_ticks;
 	u_long la_prof_ticks;
 	/* Include IDT_SYSCALL to make indexing easier. */
-	u_int la_ioint_irqs[APIC_NUM_IOINTS + 1];
+	int la_ioint_irqs[APIC_NUM_IOINTS + 1];
 } static lapics[MAX_APIC_ID + 1];
 
 /* XXX: should thermal be an NMI? */
@@ -254,6 +254,8 @@ lapic_create(u_int apic_id, int boot_cpu
 		lapics[apic_id].la_lvts[i] = lvts[i];
 		lapics[apic_id].la_lvts[i].lvt_active = 0;
 	}
+	for (i = 0; i <= APIC_NUM_IOINTS; i++)
+	    lapics[apic_id].la_ioint_irqs[i] = -1;
 	lapics[apic_id].la_ioint_irqs[IDT_SYSCALL - APIC_IO_INTS] = IRQ_SYSCALL;
 	lapics[apic_id].la_ioint_irqs[APIC_TIMER_INT - APIC_IO_INTS] =
 	    IRQ_TIMER;
@@ -363,11 +365,15 @@ int
 lapic_setup_clock(void)
 {
 	u_long value;
+	int i;
 
 	/* Can't drive the timer without a local APIC. */
 	if (lapic == NULL)
 		return (0);
 
+	if (resource_int_value("apic", 0, "clock", &i) == 0 && i == 0)
+		return (0);
+
 	/* Start off with a divisor of 2 (power on reset default). */
 	lapic_timer_divisor = 2;
 
@@ -807,7 +813,7 @@ apic_alloc_vector(u_int apic_id, u_int i
 	 */
 	mtx_lock_spin(&icu_lock);
 	for (vector = 0; vector < APIC_NUM_IOINTS; vector++) {
-		if (lapics[apic_id].la_ioint_irqs[vector] != 0)
+		if (lapics[apic_id].la_ioint_irqs[vector] != -1)
 			continue;
 		lapics[apic_id].la_ioint_irqs[vector] = irq;
 		mtx_unlock_spin(&icu_lock);
@@ -847,7 +853,7 @@ apic_alloc_vectors(u_int apic_id, u_int 
 	for (vector = 0; vector < APIC_NUM_IOINTS; vector++) {
 
 		/* Vector is in use, end run. */
-		if (lapics[apic_id].la_ioint_irqs[vector] != 0) {
+		if (lapics[apic_id].la_ioint_irqs[vector] != -1) {
 			run = 0;
 			first = 0;
 			continue;
@@ -932,7 +938,7 @@ apic_free_vector(u_int apic_id, u_int ve
 	sched_bind(td, apic_cpuid(apic_id));
 	thread_unlock(td);
 	mtx_lock_spin(&icu_lock);
-	lapics[apic_id].la_ioint_irqs[vector - APIC_IO_INTS] = 0;
+	lapics[apic_id].la_ioint_irqs[vector - APIC_IO_INTS] = -1;
 	mtx_unlock_spin(&icu_lock);
 	thread_lock(td);
 	sched_unbind(td);
@@ -974,7 +980,7 @@ DB_SHOW_COMMAND(apic, db_show_apic)
 		db_printf("Interrupts bound to lapic %u\n", apic_id);
 		for (i = 0; i < APIC_NUM_IOINTS + 1 && !db_pager_quit; i++) {
 			irq = lapics[apic_id].la_ioint_irqs[i];
-			if (irq == 0 || irq == IRQ_SYSCALL)
+			if (irq == -1 || irq == IRQ_SYSCALL)
 				continue;
 			db_printf("vec 0x%2x -> ", i + APIC_IO_INTS);
 			if (irq == IRQ_TIMER)

Modified: head/sys/i386/i386/local_apic.c
==============================================================================
--- head/sys/i386/i386/local_apic.c	Fri May  1 15:36:02 2009	(r191719)
+++ head/sys/i386/i386/local_apic.c	Fri May  1 17:05:49 2009	(r191720)
@@ -112,7 +112,7 @@ struct lapic {
 	u_long la_stat_ticks;
 	u_long la_prof_ticks;
 	/* Include IDT_SYSCALL to make indexing easier. */
-	u_int la_ioint_irqs[APIC_NUM_IOINTS + 1];
+	int la_ioint_irqs[APIC_NUM_IOINTS + 1];
 } static lapics[MAX_APIC_ID + 1];
 
 /* XXX: should thermal be an NMI? */
@@ -256,6 +256,8 @@ lapic_create(u_int apic_id, int boot_cpu
 		lapics[apic_id].la_lvts[i] = lvts[i];
 		lapics[apic_id].la_lvts[i].lvt_active = 0;
 	}
+	for (i = 0; i <= APIC_NUM_IOINTS; i++)
+	    lapics[apic_id].la_ioint_irqs[i] = -1;
 	lapics[apic_id].la_ioint_irqs[IDT_SYSCALL - APIC_IO_INTS] = IRQ_SYSCALL;
 	lapics[apic_id].la_ioint_irqs[APIC_TIMER_INT - APIC_IO_INTS] =
 	    IRQ_TIMER;
@@ -365,11 +367,15 @@ int
 lapic_setup_clock(void)
 {
 	u_long value;
+	int i;
 
 	/* Can't drive the timer without a local APIC. */
 	if (lapic == NULL)
 		return (0);
 
+	if (resource_int_value("apic", 0, "clock", &i) == 0 && i == 0)
+		return (0);
+
 	/* Start off with a divisor of 2 (power on reset default). */
 	lapic_timer_divisor = 2;
 
@@ -809,7 +815,7 @@ apic_alloc_vector(u_int apic_id, u_int i
 	 */
 	mtx_lock_spin(&icu_lock);
 	for (vector = 0; vector < APIC_NUM_IOINTS; vector++) {
-		if (lapics[apic_id].la_ioint_irqs[vector] != 0)
+		if (lapics[apic_id].la_ioint_irqs[vector] != -1)
 			continue;
 		lapics[apic_id].la_ioint_irqs[vector] = irq;
 		mtx_unlock_spin(&icu_lock);
@@ -849,7 +855,7 @@ apic_alloc_vectors(u_int apic_id, u_int 
 	for (vector = 0; vector < APIC_NUM_IOINTS; vector++) {
 
 		/* Vector is in use, end run. */
-		if (lapics[apic_id].la_ioint_irqs[vector] != 0) {
+		if (lapics[apic_id].la_ioint_irqs[vector] != -1) {
 			run = 0;
 			first = 0;
 			continue;
@@ -936,7 +942,7 @@ apic_free_vector(u_int apic_id, u_int ve
 	sched_bind(td, apic_cpuid(apic_id));
 	thread_unlock(td);
 	mtx_lock_spin(&icu_lock);
-	lapics[apic_id].la_ioint_irqs[vector - APIC_IO_INTS] = 0;
+	lapics[apic_id].la_ioint_irqs[vector - APIC_IO_INTS] = -1;
 	mtx_unlock_spin(&icu_lock);
 	thread_lock(td);
 	sched_unbind(td);
@@ -978,7 +984,7 @@ DB_SHOW_COMMAND(apic, db_show_apic)
 		db_printf("Interrupts bound to lapic %u\n", apic_id);
 		for (i = 0; i < APIC_NUM_IOINTS + 1 && !db_pager_quit; i++) {
 			irq = lapics[apic_id].la_ioint_irqs[i];
-			if (irq == 0 || irq == IRQ_SYSCALL)
+			if (irq == -1 || irq == IRQ_SYSCALL)
 				continue;
 			db_printf("vec 0x%2x -> ", i + APIC_IO_INTS);
 			if (irq == IRQ_TIMER)


More information about the svn-src-head mailing list