summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/hw_irq.h6
-rw-r--r--arch/powerpc/kernel/irq.c48
-rw-r--r--arch/powerpc/mm/numa.c2
-rw-r--r--arch/powerpc/platforms/cell/pervasive.c11
-rw-r--r--arch/powerpc/platforms/pseries/processor_idle.c17
-rw-r--r--drivers/tty/hvc/hvc_opal.c2
6 files changed, 69 insertions, 17 deletions
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h
index 6eb75b80488c..0554ab062bdc 100644
--- a/arch/powerpc/include/asm/hw_irq.h
+++ b/arch/powerpc/include/asm/hw_irq.h
@@ -86,8 +86,8 @@ static inline bool arch_irqs_disabled(void)
86} 86}
87 87
88#ifdef CONFIG_PPC_BOOK3E 88#ifdef CONFIG_PPC_BOOK3E
89#define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory"); 89#define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory")
90#define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory"); 90#define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory")
91#else 91#else
92#define __hard_irq_enable() __mtmsrd(local_paca->kernel_msr | MSR_EE, 1) 92#define __hard_irq_enable() __mtmsrd(local_paca->kernel_msr | MSR_EE, 1)
93#define __hard_irq_disable() __mtmsrd(local_paca->kernel_msr, 1) 93#define __hard_irq_disable() __mtmsrd(local_paca->kernel_msr, 1)
@@ -125,6 +125,8 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
125 return !regs->softe; 125 return !regs->softe;
126} 126}
127 127
128extern bool prep_irq_for_idle(void);
129
128#else /* CONFIG_PPC64 */ 130#else /* CONFIG_PPC64 */
129 131
130#define SET_MSR_EE(x) mtmsr(x) 132#define SET_MSR_EE(x) mtmsr(x)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 1b415027ec0e..1f017bb7a7ce 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -229,7 +229,7 @@ notrace void arch_local_irq_restore(unsigned long en)
229 */ 229 */
230 if (unlikely(irq_happened != PACA_IRQ_HARD_DIS)) 230 if (unlikely(irq_happened != PACA_IRQ_HARD_DIS))
231 __hard_irq_disable(); 231 __hard_irq_disable();
232#ifdef CONFIG_TRACE_IRQFLAG 232#ifdef CONFIG_TRACE_IRQFLAGS
233 else { 233 else {
234 /* 234 /*
235 * We should already be hard disabled here. We had bugs 235 * We should already be hard disabled here. We had bugs
@@ -286,6 +286,52 @@ void notrace restore_interrupts(void)
286 __hard_irq_enable(); 286 __hard_irq_enable();
287} 287}
288 288
289/*
290 * This is a helper to use when about to go into idle low-power
291 * when the latter has the side effect of re-enabling interrupts
292 * (such as calling H_CEDE under pHyp).
293 *
294 * You call this function with interrupts soft-disabled (this is
295 * already the case when ppc_md.power_save is called). The function
296 * will return whether to enter power save or just return.
297 *
298 * In the former case, it will have notified lockdep of interrupts
299 * being re-enabled and generally sanitized the lazy irq state,
300 * and in the latter case it will leave with interrupts hard
301 * disabled and marked as such, so the local_irq_enable() call
302 * in cpu_idle() will properly re-enable everything.
303 */
304bool prep_irq_for_idle(void)
305{
306 /*
307 * First we need to hard disable to ensure no interrupt
308 * occurs before we effectively enter the low power state
309 */
310 hard_irq_disable();
311
312 /*
313 * If anything happened while we were soft-disabled,
314 * we return now and do not enter the low power state.
315 */
316 if (lazy_irq_pending())
317 return false;
318
319 /* Tell lockdep we are about to re-enable */
320 trace_hardirqs_on();
321
322 /*
323 * Mark interrupts as soft-enabled and clear the
324 * PACA_IRQ_HARD_DIS from the pending mask since we
325 * are about to hard enable as well as a side effect
326 * of entering the low power state.
327 */
328 local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
329 local_paca->soft_enabled = 1;
330
331 /* Tell the caller to enter the low power state */
332 return true;
333}
334
289#endif /* CONFIG_PPC64 */ 335#endif /* CONFIG_PPC64 */
290 336
291int arch_show_interrupts(struct seq_file *p, int prec) 337int arch_show_interrupts(struct seq_file *p, int prec)
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 6e8f677f5646..1e95556dc692 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -639,7 +639,7 @@ static void __init parse_drconf_memory(struct device_node *memory)
639 unsigned int n, rc, ranges, is_kexec_kdump = 0; 639 unsigned int n, rc, ranges, is_kexec_kdump = 0;
640 unsigned long lmb_size, base, size, sz; 640 unsigned long lmb_size, base, size, sz;
641 int nid; 641 int nid;
642 struct assoc_arrays aa; 642 struct assoc_arrays aa = { .arrays = NULL };
643 643
644 n = of_get_drconf_memory(memory, &dm); 644 n = of_get_drconf_memory(memory, &dm);
645 if (!n) 645 if (!n)
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
index efdacc829576..d17e98bc0c10 100644
--- a/arch/powerpc/platforms/cell/pervasive.c
+++ b/arch/powerpc/platforms/cell/pervasive.c
@@ -42,11 +42,9 @@ static void cbe_power_save(void)
42{ 42{
43 unsigned long ctrl, thread_switch_control; 43 unsigned long ctrl, thread_switch_control;
44 44
45 /* 45 /* Ensure our interrupt state is properly tracked */
46 * We need to hard disable interrupts, the local_irq_enable() done by 46 if (!prep_irq_for_idle())
47 * our caller upon return will hard re-enable. 47 return;
48 */
49 hard_irq_disable();
50 48
51 ctrl = mfspr(SPRN_CTRLF); 49 ctrl = mfspr(SPRN_CTRLF);
52 50
@@ -81,6 +79,9 @@ static void cbe_power_save(void)
81 */ 79 */
82 ctrl &= ~(CTRL_RUNLATCH | CTRL_TE); 80 ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
83 mtspr(SPRN_CTRLT, ctrl); 81 mtspr(SPRN_CTRLT, ctrl);
82
83 /* Re-enable interrupts in MSR */
84 __hard_irq_enable();
84} 85}
85 86
86static int cbe_system_reset_exception(struct pt_regs *regs) 87static int cbe_system_reset_exception(struct pt_regs *regs)
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
index e61483e8e960..c71be66bd5dc 100644
--- a/arch/powerpc/platforms/pseries/processor_idle.c
+++ b/arch/powerpc/platforms/pseries/processor_idle.c
@@ -99,15 +99,18 @@ out:
99static void check_and_cede_processor(void) 99static void check_and_cede_processor(void)
100{ 100{
101 /* 101 /*
102 * Interrupts are soft-disabled at this point, 102 * Ensure our interrupt state is properly tracked,
103 * but not hard disabled. So an interrupt might have 103 * also checks if no interrupt has occurred while we
104 * occurred before entering NAP, and would be potentially 104 * were soft-disabled
105 * lost (edge events, decrementer events, etc...) unless
106 * we first hard disable then check.
107 */ 105 */
108 hard_irq_disable(); 106 if (prep_irq_for_idle()) {
109 if (!lazy_irq_pending())
110 cede_processor(); 107 cede_processor();
108#ifdef CONFIG_TRACE_IRQFLAGS
109 /* Ensure that H_CEDE returns with IRQs on */
110 if (WARN_ON(!(mfmsr() & MSR_EE)))
111 __hard_irq_enable();
112#endif
113 }
111} 114}
112 115
113static int dedicated_cede_loop(struct cpuidle_device *dev, 116static int dedicated_cede_loop(struct cpuidle_device *dev,
diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c
index ced26c8ccd57..0d2ea0c224c3 100644
--- a/drivers/tty/hvc/hvc_opal.c
+++ b/drivers/tty/hvc/hvc_opal.c
@@ -401,7 +401,7 @@ out:
401} 401}
402 402
403#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_RAW 403#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_RAW
404void __init udbg_init_debug_opal(void) 404void __init udbg_init_debug_opal_raw(void)
405{ 405{
406 u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO; 406 u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO;
407 hvc_opal_privs[index] = &hvc_opal_boot_priv; 407 hvc_opal_privs[index] = &hvc_opal_boot_priv;