aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-07-14 00:12:16 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-07-14 00:13:18 -0400
commit34d97e07cc81ab6f1e63696127cc7a5d2c4fce4b (patch)
treec406c3e1b964c4ec8bcd5650d6a339115b4ef6d3
parent850f22d5688941ea51628f3f8f8dcf3baff409ff (diff)
powerpc/book3e: Add generic 64-bit idle powersave support
We use a similar technique to ppc32: We set a thread local flag to indicate that we are about to enter or have entered the stop state, and have fixup code in the async interrupt entry code that reacts to this flag to make us return to a different location (sets NIP to LINK in our case). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> -- v2. Fix lockdep bug Re-mask interrupts when coming back from idle
-rw-r--r--arch/powerpc/include/asm/machdep.h1
-rw-r--r--arch/powerpc/kernel/Makefile2
-rw-r--r--arch/powerpc/kernel/exceptions-64e.S23
-rw-r--r--arch/powerpc/kernel/idle_book3e.S86
4 files changed, 111 insertions, 1 deletions
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 2bad6e5855ad..adc8e6cdf339 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -278,6 +278,7 @@ extern void e500_idle(void);
278extern void power4_idle(void); 278extern void power4_idle(void);
279extern void power4_cpu_offline_powersave(void); 279extern void power4_cpu_offline_powersave(void);
280extern void ppc6xx_idle(void); 280extern void ppc6xx_idle(void);
281extern void book3e_idle(void);
281 282
282/* 283/*
283 * ppc_md contains a copy of the machine description structure for the 284 * ppc_md contains a copy of the machine description structure for the
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 8a33318fa46b..77d831a1cc32 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -37,7 +37,7 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
37obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o 37obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
38obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o 38obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o
39obj64-$(CONFIG_RELOCATABLE) += reloc_64.o 39obj64-$(CONFIG_RELOCATABLE) += reloc_64.o
40obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o 40obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o
41obj-$(CONFIG_PPC64) += vdso64/ 41obj-$(CONFIG_PPC64) += vdso64/
42obj-$(CONFIG_ALTIVEC) += vecemu.o 42obj-$(CONFIG_ALTIVEC) += vecemu.o
43obj-$(CONFIG_PPC_970_NAP) += idle_power4.o 43obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index a42637c3a72d..316465a32a9c 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -204,11 +204,30 @@ exc_##n##_bad_stack: \
204 lis r,TSR_FIS@h; \ 204 lis r,TSR_FIS@h; \
205 mtspr SPRN_TSR,r 205 mtspr SPRN_TSR,r
206 206
207/* Used by asynchronous interrupt that may happen in the idle loop.
208 *
209 * This check if the thread was in the idle loop, and if yes, returns
210 * to the caller rather than the PC. This is to avoid a race if
211 * interrupts happen before the wait instruction.
212 */
213#define CHECK_NAPPING() \
214 clrrdi r11,r1,THREAD_SHIFT; \
215 ld r10,TI_LOCAL_FLAGS(r11); \
216 andi. r9,r10,_TLF_NAPPING; \
217 beq+ 1f; \
218 ld r8,_LINK(r1); \
219 rlwinm r7,r10,0,~_TLF_NAPPING; \
220 std r8,_NIP(r1); \
221 std r7,TI_LOCAL_FLAGS(r11); \
2221:
223
224
207#define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \ 225#define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \
208 START_EXCEPTION(label); \ 226 START_EXCEPTION(label); \
209 NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \ 227 NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \
210 EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL) \ 228 EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL) \
211 ack(r8); \ 229 ack(r8); \
230 CHECK_NAPPING(); \
212 addi r3,r1,STACK_FRAME_OVERHEAD; \ 231 addi r3,r1,STACK_FRAME_OVERHEAD; \
213 bl hdlr; \ 232 bl hdlr; \
214 b .ret_from_except_lite; 233 b .ret_from_except_lite;
@@ -257,6 +276,7 @@ interrupt_end_book3e:
257 CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE) 276 CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE)
258// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL) 277// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL)
259// bl special_reg_save_crit 278// bl special_reg_save_crit
279// CHECK_NAPPING();
260// addi r3,r1,STACK_FRAME_OVERHEAD 280// addi r3,r1,STACK_FRAME_OVERHEAD
261// bl .critical_exception 281// bl .critical_exception
262// b ret_from_crit_except 282// b ret_from_crit_except
@@ -268,6 +288,7 @@ interrupt_end_book3e:
268// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL) 288// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL)
269// bl special_reg_save_mc 289// bl special_reg_save_mc
270// addi r3,r1,STACK_FRAME_OVERHEAD 290// addi r3,r1,STACK_FRAME_OVERHEAD
291// CHECK_NAPPING();
271// bl .machine_check_exception 292// bl .machine_check_exception
272// b ret_from_mc_except 293// b ret_from_mc_except
273 b . 294 b .
@@ -338,6 +359,7 @@ interrupt_end_book3e:
338 CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE) 359 CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE)
339// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL) 360// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL)
340// bl special_reg_save_crit 361// bl special_reg_save_crit
362// CHECK_NAPPING();
341// addi r3,r1,STACK_FRAME_OVERHEAD 363// addi r3,r1,STACK_FRAME_OVERHEAD
342// bl .unknown_exception 364// bl .unknown_exception
343// b ret_from_crit_except 365// b ret_from_crit_except
@@ -434,6 +456,7 @@ kernel_dbg_exc:
434 CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE) 456 CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE)
435// EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL) 457// EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL)
436// bl special_reg_save_crit 458// bl special_reg_save_crit
459// CHECK_NAPPING();
437// addi r3,r1,STACK_FRAME_OVERHEAD 460// addi r3,r1,STACK_FRAME_OVERHEAD
438// bl .doorbell_critical_exception 461// bl .doorbell_critical_exception
439// b ret_from_crit_except 462// b ret_from_crit_except
diff --git a/arch/powerpc/kernel/idle_book3e.S b/arch/powerpc/kernel/idle_book3e.S
new file mode 100644
index 000000000000..16c002d6bdf1
--- /dev/null
+++ b/arch/powerpc/kernel/idle_book3e.S
@@ -0,0 +1,86 @@
1/*
2 * Copyright 2010 IBM Corp, Benjamin Herrenschmidt <benh@kernel.crashing.org>
3 *
4 * Generic idle routine for Book3E processors
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/threads.h>
13#include <asm/reg.h>
14#include <asm/ppc_asm.h>
15#include <asm/asm-offsets.h>
16#include <asm/ppc-opcode.h>
17#include <asm/processor.h>
18#include <asm/thread_info.h>
19
20/* 64-bit version only for now */
21#ifdef CONFIG_PPC64
22
23_GLOBAL(book3e_idle)
24 /* Save LR for later */
25 mflr r0
26 std r0,16(r1)
27
28 /* Hard disable interrupts */
29 wrteei 0
30
31 /* Now check if an interrupt came in while we were soft disabled
32 * since we may otherwise lose it (doorbells etc...). We know
33 * that since PACAHARDIRQEN will have been cleared in that case.
34 */
35 lbz r3,PACAHARDIRQEN(r13)
36 cmpwi cr0,r3,0
37 beqlr
38
39 /* Now we are going to mark ourselves as soft and hard enables in
40 * order to be able to take interrupts while asleep. We inform lockdep
41 * of that. We don't actually turn interrupts on just yet tho.
42 */
43#ifdef CONFIG_TRACE_IRQFLAGS
44 stdu r1,-128(r1)
45 bl .trace_hardirqs_on
46#endif
47 li r0,1
48 stb r0,PACASOFTIRQEN(r13)
49 stb r0,PACAHARDIRQEN(r13)
50
51 /* Interrupts will make use return to LR, so get something we want
52 * in there
53 */
54 bl 1f
55
56 /* Hard disable interrupts again */
57 wrteei 0
58
59 /* Mark them off again in the PACA as well */
60 li r0,0
61 stb r0,PACASOFTIRQEN(r13)
62 stb r0,PACAHARDIRQEN(r13)
63
64 /* Tell lockdep about it */
65#ifdef CONFIG_TRACE_IRQFLAGS
66 bl .trace_hardirqs_off
67 addi r1,r1,128
68#endif
69 ld r0,16(r1)
70 mtlr r0
71 blr
72
731: /* Let's set the _TLF_NAPPING flag so interrupts make us return
74 * to the right spot
75 */
76 clrrdi r11,r1,THREAD_SHIFT
77 ld r10,TI_LOCAL_FLAGS(r11)
78 ori r10,r10,_TLF_NAPPING
79 std r10,TI_LOCAL_FLAGS(r11)
80
81 /* We can now re-enable hard interrupts and go to sleep */
82 wrteei 1
831: PPC_WAIT(0)
84 b 1b
85
86#endif /* CONFIG_PPC64 */