[SPARC64]: Use sun4v_cpu_idle() in cpu_idle() on SUN4V.
David S. Miller [Wed, 22 Feb 2006 00:55:23 +0000 (16:55 -0800)]
We have to turn off the "polling nrflag" bit when we sleep
the cpu like this, so that we'll get a cross-cpu interrupt
to wake the processor up from the yield.

We also have to disable PSTATE_IE in %pstate around the yield
call and recheck need_resched() in order to avoid any races.

Signed-off-by: David S. Miller <davem@davemloft.net>

arch/sparc64/kernel/process.c

index 1ab8283..1c7ca2f 100644 (file)
 #include <asm/cpudata.h>
 #include <asm/mmu_context.h>
 #include <asm/unistd.h>
+#include <asm/hypervisor.h>
 
 /* #define VERBOSE_SHOWREGS */
 
-/*
- * Nothing special yet...
- */
-void default_idle(void)
-{
-}
-
-
-
-#ifndef CONFIG_SMP
-
-/*
- * the idle loop on a Sparc... ;)
- */
-void cpu_idle(void)
+static void sparc64_yield(void)
 {
-       /* endless idle loop with no priority at all */
-       for (;;) {
-               /* If current->work.need_resched is zero we should really
-                * setup for a system wakup event and execute a shutdown
-                * instruction.
-                *
-                * But this requires writing back the contents of the
-                * L2 cache etc. so implement this later. -DaveM
-                */
-               while (!need_resched())
-                       barrier();
+       if (tlb_type != hypervisor)
+               return;
 
-               preempt_enable_no_resched();
-               schedule();
-               preempt_disable();
-               check_pgt_cache();
+       clear_thread_flag(TIF_POLLING_NRFLAG);
+       smp_mb__after_clear_bit();
+
+       while (!need_resched()) {
+               unsigned long pstate;
+
+               /* Disable interrupts. */
+               __asm__ __volatile__(
+                       "rdpr %%pstate, %0\n\t"
+                       "andn %0, %1, %0\n\t"
+                       "wrpr %0, %%g0, %%pstate"
+                       : "=&r" (pstate)
+                       : "i" (PSTATE_IE));
+
+               if (!need_resched())
+                       sun4v_cpu_yield();
+
+               /* Re-enable interrupts. */
+               __asm__ __volatile__(
+                       "rdpr %%pstate, %0\n\t"
+                       "or %0, %1, %0\n\t"
+                       "wrpr %0, %%g0, %%pstate"
+                       : "=&r" (pstate)
+                       : "i" (PSTATE_IE));
        }
-}
 
-#else
+       set_thread_flag(TIF_POLLING_NRFLAG);
+}
 
-/*
- * the idle loop on a UltraMultiPenguin...
- *
- * TIF_POLLING_NRFLAG is set because we do not sleep the cpu
- * inside of the idler task, so an interrupt is not needed
- * to get a clean fast response.
- *
- * XXX Reverify this assumption... -DaveM
- *
- * Addendum: We do want it to do something for the signal
- *           delivery case, we detect that by just seeing
- *           if we are trying to send this to an idler or not.
- */
+/* The idle loop on sparc64. */
 void cpu_idle(void)
 {
-       cpuinfo_sparc *cpuinfo = &local_cpu_data();
        set_thread_flag(TIF_POLLING_NRFLAG);
 
        while(1) {
@@ -109,13 +94,11 @@ void cpu_idle(void)
                        preempt_enable_no_resched();
                        schedule();
                        preempt_disable();
-                       check_pgt_cache();
                }
+               sparc64_yield();
        }
 }
 
-#endif
-
 extern char reboot_command [];
 
 extern void (*prom_palette)(int);