Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[POWERPC] cell: use ppc_md->power_save instead of cbe_idle_loop

This moves the cell idle function to use the default cpu_idle
with a special power_save callback, like all other platforms
except iSeries already do.

It also makes it possible to disable this power_save function
with a new powerpc-specific boot option "powersave=off".

Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

arnd@arndb.de and committed by
Paul Mackerras
302eca18 b3d7dc19

+34 -69
+7
arch/powerpc/kernel/idle.c
··· 39 39 #define cpu_should_die() 0 40 40 #endif 41 41 42 + static int __init powersave_off(char *arg) 43 + { 44 + ppc_md.power_save = NULL; 45 + return 0; 46 + } 47 + __setup("powersave=off", powersave_off); 48 + 42 49 /* 43 50 * The body of the idle task. 44 51 */
+27 -69
arch/powerpc/platforms/cell/pervasive.c
··· 38 38 #include "pervasive.h" 39 39 #include "cbe_regs.h" 40 40 41 - static DEFINE_SPINLOCK(cbe_pervasive_lock); 42 - 43 - static void __init cbe_enable_pause_zero(void) 41 + static void cbe_power_save(void) 44 42 { 45 - unsigned long thread_switch_control; 46 - unsigned long temp_register; 47 - struct cbe_pmd_regs __iomem *pregs; 48 - 49 - spin_lock_irq(&cbe_pervasive_lock); 50 - pregs = cbe_get_cpu_pmd_regs(smp_processor_id()); 51 - if (pregs == NULL) 52 - goto out; 53 - 54 - pr_debug("Power Management: CPU %d\n", smp_processor_id()); 55 - 56 - /* Enable Pause(0) control bit */ 57 - temp_register = in_be64(&pregs->pmcr); 58 - 59 - out_be64(&pregs->pmcr, 60 - temp_register | CBE_PMD_PAUSE_ZERO_CONTROL); 43 + unsigned long ctrl, thread_switch_control; 44 + ctrl = mfspr(SPRN_CTRLF); 61 45 62 46 /* Enable DEC and EE interrupt request */ 63 47 thread_switch_control = mfspr(SPRN_TSC_CELL); 64 48 thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST; 65 49 66 - switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) { 50 + switch (ctrl & CTRL_CT) { 67 51 case CTRL_CT0: 68 52 thread_switch_control |= TSC_CELL_DEC_ENABLE_0; 69 53 break; ··· 59 75 __FUNCTION__); 60 76 break; 61 77 } 62 - 63 78 mtspr(SPRN_TSC_CELL, thread_switch_control); 64 79 65 - out: 66 - spin_unlock_irq(&cbe_pervasive_lock); 67 - } 68 - 69 - static void cbe_idle(void) 70 - { 71 - unsigned long ctrl; 72 - 73 - /* Why do we do that on every idle ? Couldn't that be done once for 74 - * all or do we lose the state some way ? Also, the pmcr 75 - * register setting, that can't be set once at boot ? We really want 76 - * to move that away in order to implement a simple powersave 80 + /* 81 + * go into low thread priority, medium priority will be 82 + * restored for us after wake-up. 77 83 */ 78 - cbe_enable_pause_zero(); 84 + HMT_low(); 79 85 80 - while (1) { 81 - if (!need_resched()) { 82 - local_irq_disable(); 83 - while (!need_resched()) { 84 - /* go into low thread priority */ 85 - HMT_low(); 86 - 87 - /* 88 - * atomically disable thread execution 89 - * and runlatch. 90 - * External and Decrementer exceptions 91 - * are still handled when the thread 92 - * is disabled but now enter in 93 - * cbe_system_reset_exception() 94 - */ 95 - ctrl = mfspr(SPRN_CTRLF); 96 - ctrl &= ~(CTRL_RUNLATCH | CTRL_TE); 97 - mtspr(SPRN_CTRLT, ctrl); 98 - } 99 - /* restore thread prio */ 100 - HMT_medium(); 101 - local_irq_enable(); 102 - } 103 - 104 - /* 105 - * turn runlatch on again before scheduling the 106 - * process we just woke up 107 - */ 108 - ppc64_runlatch_on(); 109 - 110 - preempt_enable_no_resched(); 111 - schedule(); 112 - preempt_disable(); 113 - } 86 + /* 87 + * atomically disable thread execution and runlatch. 88 + * External and Decrementer exceptions are still handled when the 89 + * thread is disabled but now enter in cbe_system_reset_exception() 90 + */ 91 + ctrl &= ~(CTRL_RUNLATCH | CTRL_TE); 92 + mtspr(SPRN_CTRLT, ctrl); 114 93 } 115 94 116 95 static int cbe_system_reset_exception(struct pt_regs *regs) ··· 105 158 106 159 void __init cbe_pervasive_init(void) 107 160 { 161 + int cpu; 108 162 if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) 109 163 return; 110 164 111 - ppc_md.idle_loop = cbe_idle; 165 + for_each_possible_cpu(cpu) { 166 + struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu); 167 + if (!regs) 168 + continue; 169 + 170 + /* Enable Pause(0) control bit */ 171 + out_be64(&regs->pmcr, in_be64(&regs->pmcr) | 172 + CBE_PMD_PAUSE_ZERO_CONTROL); 173 + } 174 + 175 + ppc_md.power_save = cbe_power_save; 112 176 ppc_md.system_reset_exception = cbe_system_reset_exception; 113 177 }