[PATCH] [ppc64] Clean up idle loop code

Anton Blanchard anton at samba.org
Fri Sep 10 22:36:49 EST 2004


 
Clean up our idle loop code:

- Remove a bunch of useless includes and make most functions static
- There were places where we werent disabling interrupts before checking
  need_resched then calling the hypervisor to sleep our thread. We might
  race with an IPI and end up missing a reschedule. Disable interrupts
  around these regions to make them safe.
- We forgot to turn off the polling flag when exiting the dedicated_idle
  idle loop. This could have resulted in all manner problems as other
  cpus would avoid sending IPIs to force reschedules.
- Add a missing check for cpu_is_offline in the shared cpu idle loop.

Signed-off-by: Anton Blanchard <anton at samba.org>

diff -puN arch/ppc64/kernel/idle.c~cleanup_idle arch/ppc64/kernel/idle.c
--- foobar2/arch/ppc64/kernel/idle.c~cleanup_idle	2004-09-10 21:56:13.748876543 +1000
+++ foobar2-anton/arch/ppc64/kernel/idle.c	2004-09-10 22:02:54.115249090 +1000
@@ -16,28 +16,16 @@
  */
 
 #include <linux/config.h>
-#include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
-#include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
 #include <linux/cpu.h>
 
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/mmu.h>
-#include <asm/cache.h>
 #include <asm/cputable.h>
 #include <asm/time.h>
-#include <asm/iSeries/LparData.h>
 #include <asm/iSeries/HvCall.h>
 #include <asm/iSeries/ItLpQueue.h>
 
@@ -45,11 +33,11 @@ extern long cede_processor(void);
 extern long poll_pending(void);
 extern void power4_idle(void);
 
-int (*idle_loop)(void);
+static int (*idle_loop)(void);
 
 #ifdef CONFIG_PPC_ISERIES
-unsigned long maxYieldTime = 0;
-unsigned long minYieldTime = 0xffffffffffffffffUL;
+static unsigned long maxYieldTime = 0;
+static unsigned long minYieldTime = 0xffffffffffffffffUL;
 
 static void yield_shared_processor(void)
 {
@@ -80,7 +68,7 @@ static void yield_shared_processor(void)
 	process_iSeries_events();
 }
 
-int iSeries_idle(void)
+static int iSeries_idle(void)
 {
 	struct paca_struct *lpaca;
 	long oldval;
@@ -91,13 +79,10 @@ int iSeries_idle(void)
 	CTRL = mfspr(CTRLF);
 	CTRL &= ~RUNLATCH;
 	mtspr(CTRLT, CTRL);
-#if 0
-	init_idle();	
-#endif
 
 	lpaca = get_paca();
 
-	for (;;) {
+	while (1) {
 		if (lpaca->lppaca.xSharedProc) {
 			if (ItLpQueue_isLpIntPending(lpaca->lpqueue_ptr))
 				process_iSeries_events();
@@ -125,11 +110,13 @@ int iSeries_idle(void)
 
 		schedule();
 	}
+
 	return 0;
 }
-#endif
 
-int default_idle(void)
+#else
+
+static int default_idle(void)
 {
 	long oldval;
 	unsigned int cpu = smp_processor_id();
@@ -164,8 +151,6 @@ int default_idle(void)
 	return 0;
 }
 
-#ifdef CONFIG_PPC_PSERIES
-
 DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
 
 int dedicated_idle(void)
@@ -179,8 +164,10 @@ int dedicated_idle(void)
 	ppaca = &paca[cpu ^ 1];
 
 	while (1) {
-		/* Indicate to the HV that we are idle.  Now would be
-		 * a good time to find other work to dispatch. */
+		/*
+		 * Indicate to the HV that we are idle. Now would be
+		 * a good time to find other work to dispatch.
+		 */
 		lpaca->lppaca.xIdle = 1;
 
 		oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
@@ -203,21 +190,17 @@ int dedicated_idle(void)
 				HMT_medium();
 
 				if (!(ppaca->lppaca.xIdle)) {
-					/* Indicate we are no longer polling for
-					 * work, and then clear need_resched.  If
-					 * need_resched was 1, set it back to 1
-					 * and schedule work
+					local_irq_disable();
+
+					/*
+					 * We are about to sleep the thread
+					 * and so wont be polling any
+					 * more.
 					 */
 					clear_thread_flag(TIF_POLLING_NRFLAG);
-					oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-					if(oldval == 1) {
-						set_need_resched();
-						break;
-					}
-
-					local_irq_disable(); 
 
-					/* SMT dynamic mode.  Cede will result 
+					/*
+					 * SMT dynamic mode. Cede will result
 					 * in this thread going dormant, if the
 					 * partner thread is still doing work.
 					 * Thread wakes up if partner goes idle,
@@ -225,15 +208,21 @@ int dedicated_idle(void)
 					 * occurs.  Returning from the cede
 					 * enables external interrupts.
 					 */
-					cede_processor();
+					if (!need_resched())
+						cede_processor();
+					else
+						local_irq_enable();
 				} else {
-					/* Give the HV an opportunity at the
+					/*
+					 * Give the HV an opportunity at the
 					 * processor, since we are not doing
 					 * any work.
 					 */
 					poll_pending();
 				}
 			}
+
+			clear_thread_flag(TIF_POLLING_NRFLAG);
 		} else {
 			set_need_resched();
 		}
@@ -247,48 +236,49 @@ int dedicated_idle(void)
 	return 0;
 }
 
-int shared_idle(void)
+static int shared_idle(void)
 {
 	struct paca_struct *lpaca = get_paca();
+	unsigned int cpu = smp_processor_id();
 
 	while (1) {
-		if (cpu_is_offline(smp_processor_id()) &&
-				system_state == SYSTEM_RUNNING)
-			cpu_die();
-
-		/* Indicate to the HV that we are idle.  Now would be
-		 * a good time to find other work to dispatch. */
+		/*
+		 * Indicate to the HV that we are idle. Now would be
+		 * a good time to find other work to dispatch.
+		 */
 		lpaca->lppaca.xIdle = 1;
 
-		if (!need_resched()) {
-			local_irq_disable(); 
-			
-			/* 
+		while (!need_resched() && !cpu_is_offline(cpu)) {
+			local_irq_disable();
+
+			/*
 			 * Yield the processor to the hypervisor.  We return if
 			 * an external interrupt occurs (which are driven prior
 			 * to returning here) or if a prod occurs from another 
-			 * processor.  When returning here, external interrupts 
+			 * processor. When returning here, external interrupts
 			 * are enabled.
+			 *
+			 * Check need_resched() again with interrupts disabled
+			 * to avoid a race.
 			 */
-			cede_processor();
+			if (!need_resched())
+				cede_processor();
+			else
+				local_irq_enable();
 		}
 
 		HMT_medium();
 		lpaca->lppaca.xIdle = 0;
 		schedule();
+		if (cpu_is_offline(smp_processor_id()) &&
+		    system_state == SYSTEM_RUNNING)
+			cpu_die();
 	}
 
 	return 0;
 }
-#endif
-
-int cpu_idle(void)
-{
-	idle_loop();
-	return 0; 
-}
 
-int native_idle(void)
+static int powermac_idle(void)
 {
 	while(1) {
 		if (!need_resched())
@@ -298,6 +288,13 @@ int native_idle(void)
 	}
 	return 0;
 }
+#endif
+
+int cpu_idle(void)
+{
+	idle_loop();
+	return 0;
+}
 
 int idle_setup(void)
 {
@@ -318,8 +315,8 @@ int idle_setup(void)
 			idle_loop = default_idle;
 		}
 	} else if (systemcfg->platform == PLATFORM_POWERMAC) {
-		printk("idle = native_idle\n");
-		idle_loop = native_idle;
+		printk("idle = powermac_idle\n");
+		idle_loop = powermac_idle;
 	} else {
 		printk("idle_setup: unknown platform, use default_idle\n");
 		idle_loop = default_idle;
@@ -328,4 +325,3 @@ int idle_setup(void)
 
 	return 1;
 }
-
_



More information about the Linuxppc64-dev mailing list