diff options
Diffstat (limited to 'arch/powerpc/platforms/cell/pervasive.c')
-rw-r--r-- | arch/powerpc/platforms/cell/pervasive.c | 96 |
1 files changed, 27 insertions, 69 deletions
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index 9f2e4ed20a57..c68fabdc7874 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c | |||
@@ -38,32 +38,16 @@ | |||
38 | #include "pervasive.h" | 38 | #include "pervasive.h" |
39 | #include "cbe_regs.h" | 39 | #include "cbe_regs.h" |
40 | 40 | ||
41 | static DEFINE_SPINLOCK(cbe_pervasive_lock); | 41 | static void cbe_power_save(void) |
42 | |||
43 | static void __init cbe_enable_pause_zero(void) | ||
44 | { | 42 | { |
45 | unsigned long thread_switch_control; | 43 | unsigned long ctrl, thread_switch_control; |
46 | unsigned long temp_register; | 44 | ctrl = mfspr(SPRN_CTRLF); |
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->pm_control); | ||
58 | |||
59 | out_be64(&pregs->pm_control, | ||
60 | temp_register | CBE_PMD_PAUSE_ZERO_CONTROL); | ||
61 | 45 | ||
62 | /* Enable DEC and EE interrupt request */ | 46 | /* Enable DEC and EE interrupt request */ |
63 | thread_switch_control = mfspr(SPRN_TSC_CELL); | 47 | thread_switch_control = mfspr(SPRN_TSC_CELL); |
64 | thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST; | 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 | case CTRL_CT0: | 51 | case CTRL_CT0: |
68 | thread_switch_control |= TSC_CELL_DEC_ENABLE_0; | 52 | thread_switch_control |= TSC_CELL_DEC_ENABLE_0; |
69 | break; | 53 | break; |
@@ -75,58 +59,21 @@ static void __init cbe_enable_pause_zero(void) | |||
75 | __FUNCTION__); | 59 | __FUNCTION__); |
76 | break; | 60 | break; |
77 | } | 61 | } |
78 | |||
79 | mtspr(SPRN_TSC_CELL, thread_switch_control); | 62 | mtspr(SPRN_TSC_CELL, thread_switch_control); |
80 | 63 | ||
81 | out: | 64 | /* |
82 | spin_unlock_irq(&cbe_pervasive_lock); | 65 | * go into low thread priority, medium priority will be |
83 | } | 66 | * restored for us after wake-up. |
84 | |||
85 | static void cbe_idle(void) | ||
86 | { | ||
87 | unsigned long ctrl; | ||
88 | |||
89 | /* Why do we do that on every idle ? Couldn't that be done once for | ||
90 | * all or do we lose the state some way ? Also, the pm_control | ||
91 | * register setting, that can't be set once at boot ? We really want | ||
92 | * to move that away in order to implement a simple powersave | ||
93 | */ | 67 | */ |
94 | cbe_enable_pause_zero(); | 68 | HMT_low(); |
95 | |||
96 | while (1) { | ||
97 | if (!need_resched()) { | ||
98 | local_irq_disable(); | ||
99 | while (!need_resched()) { | ||
100 | /* go into low thread priority */ | ||
101 | HMT_low(); | ||
102 | |||
103 | /* | ||
104 | * atomically disable thread execution | ||
105 | * and runlatch. | ||
106 | * External and Decrementer exceptions | ||
107 | * are still handled when the thread | ||
108 | * is disabled but now enter in | ||
109 | * cbe_system_reset_exception() | ||
110 | */ | ||
111 | ctrl = mfspr(SPRN_CTRLF); | ||
112 | ctrl &= ~(CTRL_RUNLATCH | CTRL_TE); | ||
113 | mtspr(SPRN_CTRLT, ctrl); | ||
114 | } | ||
115 | /* restore thread prio */ | ||
116 | HMT_medium(); | ||
117 | local_irq_enable(); | ||
118 | } | ||
119 | 69 | ||
120 | /* | 70 | /* |
121 | * turn runlatch on again before scheduling the | 71 | * atomically disable thread execution and runlatch. |
122 | * process we just woke up | 72 | * External and Decrementer exceptions are still handled when the |
123 | */ | 73 | * thread is disabled but now enter in cbe_system_reset_exception() |
124 | ppc64_runlatch_on(); | 74 | */ |
125 | 75 | ctrl &= ~(CTRL_RUNLATCH | CTRL_TE); | |
126 | preempt_enable_no_resched(); | 76 | mtspr(SPRN_CTRLT, ctrl); |
127 | schedule(); | ||
128 | preempt_disable(); | ||
129 | } | ||
130 | } | 77 | } |
131 | 78 | ||
132 | static int cbe_system_reset_exception(struct pt_regs *regs) | 79 | static int cbe_system_reset_exception(struct pt_regs *regs) |
@@ -158,9 +105,20 @@ static int cbe_system_reset_exception(struct pt_regs *regs) | |||
158 | 105 | ||
159 | void __init cbe_pervasive_init(void) | 106 | void __init cbe_pervasive_init(void) |
160 | { | 107 | { |
108 | int cpu; | ||
161 | if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) | 109 | if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) |
162 | return; | 110 | return; |
163 | 111 | ||
164 | ppc_md.idle_loop = cbe_idle; | 112 | for_each_possible_cpu(cpu) { |
113 | struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu); | ||
114 | if (!regs) | ||
115 | continue; | ||
116 | |||
117 | /* Enable Pause(0) control bit */ | ||
118 | out_be64(®s->pmcr, in_be64(®s->pmcr) | | ||
119 | CBE_PMD_PAUSE_ZERO_CONTROL); | ||
120 | } | ||
121 | |||
122 | ppc_md.power_save = cbe_power_save; | ||
165 | ppc_md.system_reset_exception = cbe_system_reset_exception; | 123 | ppc_md.system_reset_exception = cbe_system_reset_exception; |
166 | } | 124 | } |