diff options
Diffstat (limited to 'arch/powerpc/platforms/cell/pervasive.c')
-rw-r--r-- | arch/powerpc/platforms/cell/pervasive.c | 101 |
1 files changed, 34 insertions, 67 deletions
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index 9f2e4ed20a57..8c20f0fb8651 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c | |||
@@ -38,32 +38,25 @@ | |||
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; | ||
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 | 44 | ||
54 | pr_debug("Power Management: CPU %d\n", smp_processor_id()); | 45 | /* |
55 | 46 | * We need to hard disable interrupts, but we also need to mark them | |
56 | /* Enable Pause(0) control bit */ | 47 | * hard disabled in the PACA so that the local_irq_enable() done by |
57 | temp_register = in_be64(&pregs->pm_control); | 48 | * our caller upon return propertly hard enables. |
49 | */ | ||
50 | hard_irq_disable(); | ||
51 | get_paca()->hard_enabled = 0; | ||
58 | 52 | ||
59 | out_be64(&pregs->pm_control, | 53 | ctrl = mfspr(SPRN_CTRLF); |
60 | temp_register | CBE_PMD_PAUSE_ZERO_CONTROL); | ||
61 | 54 | ||
62 | /* Enable DEC and EE interrupt request */ | 55 | /* Enable DEC and EE interrupt request */ |
63 | thread_switch_control = mfspr(SPRN_TSC_CELL); | 56 | thread_switch_control = mfspr(SPRN_TSC_CELL); |
64 | thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST; | 57 | thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST; |
65 | 58 | ||
66 | switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) { | 59 | switch (ctrl & CTRL_CT) { |
67 | case CTRL_CT0: | 60 | case CTRL_CT0: |
68 | thread_switch_control |= TSC_CELL_DEC_ENABLE_0; | 61 | thread_switch_control |= TSC_CELL_DEC_ENABLE_0; |
69 | break; | 62 | break; |
@@ -75,58 +68,21 @@ static void __init cbe_enable_pause_zero(void) | |||
75 | __FUNCTION__); | 68 | __FUNCTION__); |
76 | break; | 69 | break; |
77 | } | 70 | } |
78 | |||
79 | mtspr(SPRN_TSC_CELL, thread_switch_control); | 71 | mtspr(SPRN_TSC_CELL, thread_switch_control); |
80 | 72 | ||
81 | out: | 73 | /* |
82 | spin_unlock_irq(&cbe_pervasive_lock); | 74 | * go into low thread priority, medium priority will be |
83 | } | 75 | * restored for us after wake-up. |
84 | 76 | */ | |
85 | static void cbe_idle(void) | 77 | HMT_low(); |
86 | { | ||
87 | unsigned long ctrl; | ||
88 | 78 | ||
89 | /* Why do we do that on every idle ? Couldn't that be done once for | 79 | /* |
90 | * all or do we lose the state some way ? Also, the pm_control | 80 | * atomically disable thread execution and runlatch. |
91 | * register setting, that can't be set once at boot ? We really want | 81 | * External and Decrementer exceptions are still handled when the |
92 | * to move that away in order to implement a simple powersave | 82 | * thread is disabled but now enter in cbe_system_reset_exception() |
93 | */ | 83 | */ |
94 | cbe_enable_pause_zero(); | 84 | ctrl &= ~(CTRL_RUNLATCH | CTRL_TE); |
95 | 85 | mtspr(SPRN_CTRLT, ctrl); | |
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 | |||
120 | /* | ||
121 | * turn runlatch on again before scheduling the | ||
122 | * process we just woke up | ||
123 | */ | ||
124 | ppc64_runlatch_on(); | ||
125 | |||
126 | preempt_enable_no_resched(); | ||
127 | schedule(); | ||
128 | preempt_disable(); | ||
129 | } | ||
130 | } | 86 | } |
131 | 87 | ||
132 | static int cbe_system_reset_exception(struct pt_regs *regs) | 88 | static int cbe_system_reset_exception(struct pt_regs *regs) |
@@ -158,9 +114,20 @@ static int cbe_system_reset_exception(struct pt_regs *regs) | |||
158 | 114 | ||
159 | void __init cbe_pervasive_init(void) | 115 | void __init cbe_pervasive_init(void) |
160 | { | 116 | { |
117 | int cpu; | ||
161 | if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) | 118 | if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) |
162 | return; | 119 | return; |
163 | 120 | ||
164 | ppc_md.idle_loop = cbe_idle; | 121 | for_each_possible_cpu(cpu) { |
122 | struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu); | ||
123 | if (!regs) | ||
124 | continue; | ||
125 | |||
126 | /* Enable Pause(0) control bit */ | ||
127 | out_be64(®s->pmcr, in_be64(®s->pmcr) | | ||
128 | CBE_PMD_PAUSE_ZERO_CONTROL); | ||
129 | } | ||
130 | |||
131 | ppc_md.power_save = cbe_power_save; | ||
165 | ppc_md.system_reset_exception = cbe_system_reset_exception; | 132 | ppc_md.system_reset_exception = cbe_system_reset_exception; |
166 | } | 133 | } |