http://defect.opensolaris.org/bz/show_bug.cgi?id=3291


Bill Holler <bill.holler at sun.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|ACCEPTED                    |FIXUNDERSTOOD




--- Comment #1 from Bill Holler <bill.holler at sun.com>  2008-10-07 19:20:27 
---
Idle threads can check if the LAPIC timer would have expired when
waking up from deep C-State.  If so, the idle thread can raise ipl
to CBE_HIGH_PIL, sti, and directly call cyclic_fire().  cyclic_fire()
is a high level interrupt handler which cannot block, so it *should*
be safe to call from the idle thread at CBE_HIGH_PIL (the idle thread
cannot block).

libmicro benchmark showed almost no difference with this fix compared
with the older mechanism that reprograms the LAPIC Timer to cause
the cyclic_fire() interrupt ASAP.  The CPU is idle in this case
this bug is attempting to improve.
There were roughly 100 less interrupts per second on a 2-socket 
system with this fix.  Perhaps it will help power.


bash-3.2$ hg pdiff
Enter passphrase for key '/home/bholler/.ssh/id_dsa': 
Enter passphrase for key '/home/bholler/.ssh/id_dsa': 
diff -r a342f0f30ded usr/src/uts/i86pc/io/hpet_acpi.c
--- a/usr/src/uts/i86pc/io/hpet_acpi.c  Wed Oct 01 18:28:42 2008 -0700
+++ b/usr/src/uts/i86pc/io/hpet_acpi.c  Tue Oct 07 19:07:01 2008 -0700
@@ -45,6 +45,9 @@
 #include <sys/ksynch.h>

 #include <sys/apic.h>
+#include <sys/systm.h>
+#include <sys/spl.h>
+#include <sys/archsystm.h>

@@ -1066,6 +1063,11 @@
  * Returns B_TRUE if the HPET was programmed to interrupt by
  * required_wakeup_time.  B_FLASE is returned if the HPET could not be
  * programmed to interrupt before the required time.
+ *
+ * We can use poke_cpu() to wake CPUs at XC_CPUPOKE_PIL instead of
CBE_HIGH_PIL.
+ * The idle CPU wakes up from the poke with interrupts blocked.  The poked CPU
+ * raises IPL to CBE_HIGH_PIL before enabling interrupts, and cyclic_fire() is
+ * properly run at CBE_HIGH_PIL before any lower priority interrupts can run.
  */
 static boolean_t
 hpet_guaranteed_schedule(hrtime_t required_wakeup_time)
@@ -1280,35 +1282,63 @@
 }

 /*
- * Remove self from list of CPUs using HPET as a proxy local APIC timer.
- * Called by the idle thread with interrupts disabled.
+ * This function is called by the idle loop when returning from deep c-state
+ * before enabling interrupts.
  *
- * The ISR cannot be running on a CPU who's idle thread is in this function
- * because this is always called with interrupts disabled.
- * When returning from deep c-state the idle loop calls this before enabling
- * interrupts (before the ISR can run on this CPU).
+ * Remove self from list of CPUs using HPET as a proxy Local APIC timer.
+ * This thread has work to do now; do not reprogram the HPET timer here.
+ * We use a HPET reprogramming lazy policy: let idle CPUs and the ISR
reprogram
+ * the HPET.  Chances are another CPU will go idle before the ISR fires.
  *
- * Always remove ourself from the list of CPUs using the HPET for proxy intr.
+ * Perform Local APIC fixup if it is not time to 
  */
 static void
 hpet_lapic_deschedule(hrtime_t expire)
 {
+       extern void     cyclic_fire(cpu_t *cpu);
        extern void     apic_timer_restart(hrtime_t);
        processorid_t   cpu_id = CPU->cpu_id;
+       int             idle_spl;

        hpet_info.lapic_deschedule++;

-       /* ASSERT(interrupts disabled); */
+       ASSERT(!interrupts_enabled());

        hpet_proxy_users[cpu_id] = CY_INFINITY;

-       /*
-        * Do not enable a LAPIC Timer than was initially disabled.
-        */
-       if (expire != CY_INFINITY)
-               apic_timer_restart(expire);
+       if (expire != CY_INFINITY) {
+               if (gethrtime() >= expire) {
+                       /*
+                        * Execute cyclic_fire() inline here.  Raise IPL to
+                        * CBE_HIGH_PIL before enabling interrupts to allow
+                        * cyclic_fire() to run at proper priority.
+                        *
+                        * apic_timer_restart() does not need to be run because
+                        * cyclic_fire() will properly reprogram the LAPIC
+                        * counter for the next cyclic.
+                        */

-       sti();
+                       idle_spl = getpil();
+                       splx(ipltospl(hpet_proxy_ipl()));
+                       sti();
+                       cyclic_fire(CPU);
+                       splx(idle_spl);
+               } else {
+                       /*
+                        * The LAPIC Timer would not yet have expire if it
+                        * had kept running in Deep C-State.  Reprogram
+                        * the LAPIC Timer and be on our way.
+                        */
+                       apic_timer_restart(expire);
+                       sti();
+               }
+       } else {
+               /*
+                * Do not enable a LAPIC Timer than was initially disabled.
+                */
+               sti();
+       }
 }

-- 
Configure bugmail: http://defect.opensolaris.org/bz/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.

Reply via email to