aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-04-02 16:47:29 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-02 16:47:29 -0400
commite6d9bfc63813882c896bf7ea6f6b14ca7b50b755 (patch)
tree68decf00726f6f415cee04a62e68cc60b37f380b /arch
parent235c7b9feb8779c7c289ed614324baebf3651bf9 (diff)
parent0888839c5b62c44a55ac9d28acc273ba663c65ea (diff)
Merge branch 'powernv-cpuidle' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
Pull powerpc non-virtualized cpuidle from Ben Herrenschmidt: "This is the branch I mentioned in my other pull request which contains our improved cpuidle support for the "powernv" platform (non-virtualized). It adds support for the "fast sleep" feature of the processor which provides higher power savings than our usual "nap" mode but at the cost of losing the timers while asleep, and thus exploits the new timer broadcast framework to work around that limitation. It's based on a tip timer tree that you seem to have already merged" * 'powernv-cpuidle' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: cpuidle/powernv: Parse device tree to setup idle states cpuidle/powernv: Add "Fast-Sleep" CPU idle state powerpc/powernv: Add OPAL call to resync timebase on wakeup powerpc/powernv: Add context management for Fast Sleep powerpc: Split timer_interrupt() into timer handling and interrupt handling routines powerpc: Implement tick broadcast IPI as a fixed IPI message powerpc: Free up the slot of PPC_MSG_CALL_FUNC_SINGLE IPI message
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/powerpc/include/asm/opal.h2
-rw-r--r--arch/powerpc/include/asm/processor.h1
-rw-r--r--arch/powerpc/include/asm/smp.h2
-rw-r--r--arch/powerpc/include/asm/time.h1
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S10
-rw-r--r--arch/powerpc/kernel/idle_power7.S90
-rw-r--r--arch/powerpc/kernel/smp.c25
-rw-r--r--arch/powerpc/kernel/time.c90
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c2
-rw-r--r--arch/powerpc/platforms/powernv/opal-wrappers.S1
-rw-r--r--arch/powerpc/platforms/ps3/smp.c2
12 files changed, 161 insertions, 67 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 05e532984c13..f3d7846bc9b2 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -130,6 +130,8 @@ config PPC
130 select GENERIC_CMOS_UPDATE 130 select GENERIC_CMOS_UPDATE
131 select GENERIC_TIME_VSYSCALL_OLD 131 select GENERIC_TIME_VSYSCALL_OLD
132 select GENERIC_CLOCKEVENTS 132 select GENERIC_CLOCKEVENTS
133 select GENERIC_CLOCKEVENTS_BROADCAST if SMP
134 select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
133 select GENERIC_STRNCPY_FROM_USER 135 select GENERIC_STRNCPY_FROM_USER
134 select GENERIC_STRNLEN_USER 136 select GENERIC_STRNLEN_USER
135 select HAVE_MOD_ARCH_SPECIFIC 137 select HAVE_MOD_ARCH_SPECIFIC
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index ffafab037ba8..fe2aa0b48d2b 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -161,6 +161,7 @@ extern int opal_enter_rtas(struct rtas_args *args,
161#define OPAL_FLASH_VALIDATE 76 161#define OPAL_FLASH_VALIDATE 76
162#define OPAL_FLASH_MANAGE 77 162#define OPAL_FLASH_MANAGE 77
163#define OPAL_FLASH_UPDATE 78 163#define OPAL_FLASH_UPDATE 78
164#define OPAL_RESYNC_TIMEBASE 79
164#define OPAL_DUMP_INIT 81 165#define OPAL_DUMP_INIT 81
165#define OPAL_DUMP_INFO 82 166#define OPAL_DUMP_INFO 82
166#define OPAL_DUMP_READ 83 167#define OPAL_DUMP_READ 83
@@ -923,6 +924,7 @@ extern int opal_machine_check(struct pt_regs *regs);
923extern bool opal_mce_check_early_recovery(struct pt_regs *regs); 924extern bool opal_mce_check_early_recovery(struct pt_regs *regs);
924 925
925extern void opal_shutdown(void); 926extern void opal_shutdown(void);
927extern int opal_resync_timebase(void);
926 928
927extern void opal_lpc_init(void); 929extern void opal_lpc_init(void);
928 930
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index b62de43ae5f3..d660dc36831a 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -450,6 +450,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
450 450
451extern int powersave_nap; /* set if nap mode can be used in idle loop */ 451extern int powersave_nap; /* set if nap mode can be used in idle loop */
452extern void power7_nap(void); 452extern void power7_nap(void);
453extern void power7_sleep(void);
453extern void flush_instruction_cache(void); 454extern void flush_instruction_cache(void);
454extern void hard_reset_now(void); 455extern void hard_reset_now(void);
455extern void poweroff_now(void); 456extern void poweroff_now(void);
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 084e0807db98..ff51046b6466 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -120,7 +120,7 @@ extern int cpu_to_core_id(int cpu);
120 * in /proc/interrupts will be wrong!!! --Troy */ 120 * in /proc/interrupts will be wrong!!! --Troy */
121#define PPC_MSG_CALL_FUNCTION 0 121#define PPC_MSG_CALL_FUNCTION 0
122#define PPC_MSG_RESCHEDULE 1 122#define PPC_MSG_RESCHEDULE 1
123#define PPC_MSG_CALL_FUNC_SINGLE 2 123#define PPC_MSG_TICK_BROADCAST 2
124#define PPC_MSG_DEBUGGER_BREAK 3 124#define PPC_MSG_DEBUGGER_BREAK 3
125 125
126/* for irq controllers that have dedicated ipis per message (4) */ 126/* for irq controllers that have dedicated ipis per message (4) */
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index c1f267694acb..1d428e6007ca 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -28,6 +28,7 @@ extern struct clock_event_device decrementer_clockevent;
28struct rtc_time; 28struct rtc_time;
29extern void to_tm(int tim, struct rtc_time * tm); 29extern void to_tm(int tim, struct rtc_time * tm);
30extern void GregorianDay(struct rtc_time *tm); 30extern void GregorianDay(struct rtc_time *tm);
31extern void tick_broadcast_ipi_handler(void);
31 32
32extern void generic_calibrate_decr(void); 33extern void generic_calibrate_decr(void);
33 34
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 4c34c3c827ad..d9c650ec7dac 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -121,9 +121,10 @@ BEGIN_FTR_SECTION
121 cmpwi cr1,r13,2 121 cmpwi cr1,r13,2
122 /* Total loss of HV state is fatal, we could try to use the 122 /* Total loss of HV state is fatal, we could try to use the
123 * PIR to locate a PACA, then use an emergency stack etc... 123 * PIR to locate a PACA, then use an emergency stack etc...
124 * but for now, let's just stay stuck here 124 * OPAL v3 based powernv platforms have new idle states
125 * which fall in this catagory.
125 */ 126 */
126 bgt cr1,. 127 bgt cr1,8f
127 GET_PACA(r13) 128 GET_PACA(r13)
128 129
129#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 130#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
@@ -141,6 +142,11 @@ BEGIN_FTR_SECTION
141 beq cr1,2f 142 beq cr1,2f
142 b .power7_wakeup_noloss 143 b .power7_wakeup_noloss
1432: b .power7_wakeup_loss 1442: b .power7_wakeup_loss
145
146 /* Fast Sleep wakeup on PowerNV */
1478: GET_PACA(r13)
148 b .power7_wakeup_tb_loss
149
1449: 1509:
145END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) 151END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
146#endif /* CONFIG_PPC_P7_NAP */ 152#endif /* CONFIG_PPC_P7_NAP */
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index 3fdef0f0c67f..c3ab86975614 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -17,20 +17,31 @@
17#include <asm/ppc-opcode.h> 17#include <asm/ppc-opcode.h>
18#include <asm/hw_irq.h> 18#include <asm/hw_irq.h>
19#include <asm/kvm_book3s_asm.h> 19#include <asm/kvm_book3s_asm.h>
20#include <asm/opal.h>
20 21
21#undef DEBUG 22#undef DEBUG
22 23
23 .text 24/* Idle state entry routines */
24 25
25_GLOBAL(power7_idle) 26#define IDLE_STATE_ENTER_SEQ(IDLE_INST) \
26 /* Now check if user or arch enabled NAP mode */ 27 /* Magic NAP/SLEEP/WINKLE mode enter sequence */ \
27 LOAD_REG_ADDRBASE(r3,powersave_nap) 28 std r0,0(r1); \
28 lwz r4,ADDROFF(powersave_nap)(r3) 29 ptesync; \
29 cmpwi 0,r4,0 30 ld r0,0(r1); \
30 beqlr 311: cmp cr0,r0,r0; \
31 /* fall through */ 32 bne 1b; \
33 IDLE_INST; \
34 b .
32 35
33_GLOBAL(power7_nap) 36 .text
37
38/*
39 * Pass requested state in r3:
40 * 0 - nap
41 * 1 - sleep
42 */
43_GLOBAL(power7_powersave_common)
44 /* Use r3 to pass state nap/sleep/winkle */
34 /* NAP is a state loss, we create a regs frame on the 45 /* NAP is a state loss, we create a regs frame on the
35 * stack, fill it up with the state we care about and 46 * stack, fill it up with the state we care about and
36 * stick a pointer to it in PACAR1. We really only 47 * stick a pointer to it in PACAR1. We really only
@@ -79,8 +90,8 @@ _GLOBAL(power7_nap)
79 /* Continue saving state */ 90 /* Continue saving state */
80 SAVE_GPR(2, r1) 91 SAVE_GPR(2, r1)
81 SAVE_NVGPRS(r1) 92 SAVE_NVGPRS(r1)
82 mfcr r3 93 mfcr r4
83 std r3,_CCR(r1) 94 std r4,_CCR(r1)
84 std r9,_MSR(r1) 95 std r9,_MSR(r1)
85 std r1,PACAR1(r13) 96 std r1,PACAR1(r13)
86 97
@@ -90,15 +101,56 @@ _GLOBAL(power7_enter_nap_mode)
90 li r4,KVM_HWTHREAD_IN_NAP 101 li r4,KVM_HWTHREAD_IN_NAP
91 stb r4,HSTATE_HWTHREAD_STATE(r13) 102 stb r4,HSTATE_HWTHREAD_STATE(r13)
92#endif 103#endif
104 cmpwi cr0,r3,1
105 beq 2f
106 IDLE_STATE_ENTER_SEQ(PPC_NAP)
107 /* No return */
1082: IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
109 /* No return */
93 110
94 /* Magic NAP mode enter sequence */ 111_GLOBAL(power7_idle)
95 std r0,0(r1) 112 /* Now check if user or arch enabled NAP mode */
96 ptesync 113 LOAD_REG_ADDRBASE(r3,powersave_nap)
97 ld r0,0(r1) 114 lwz r4,ADDROFF(powersave_nap)(r3)
981: cmp cr0,r0,r0 115 cmpwi 0,r4,0
99 bne 1b 116 beqlr
100 PPC_NAP 117 /* fall through */
101 b . 118
119_GLOBAL(power7_nap)
120 li r3,0
121 b power7_powersave_common
122 /* No return */
123
124_GLOBAL(power7_sleep)
125 li r3,1
126 b power7_powersave_common
127 /* No return */
128
129_GLOBAL(power7_wakeup_tb_loss)
130 ld r2,PACATOC(r13);
131 ld r1,PACAR1(r13)
132
133 /* Time base re-sync */
134 li r0,OPAL_RESYNC_TIMEBASE
135 LOAD_REG_ADDR(r11,opal);
136 ld r12,8(r11);
137 ld r2,0(r11);
138 mtctr r12
139 bctrl
140
141 /* TODO: Check r3 for failure */
142
143 REST_NVGPRS(r1)
144 REST_GPR(2, r1)
145 ld r3,_CCR(r1)
146 ld r4,_MSR(r1)
147 ld r5,_NIP(r1)
148 addi r1,r1,INT_FRAME_SIZE
149 mtcr r3
150 mfspr r3,SPRN_SRR1 /* Return SRR1 */
151 mtspr SPRN_SRR1,r4
152 mtspr SPRN_SRR0,r5
153 rfid
102 154
103_GLOBAL(power7_wakeup_loss) 155_GLOBAL(power7_wakeup_loss)
104 ld r1,PACAR1(r13) 156 ld r1,PACAR1(r13)
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index ac2621af3154..e2a4232c5871 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -35,6 +35,7 @@
35#include <asm/ptrace.h> 35#include <asm/ptrace.h>
36#include <linux/atomic.h> 36#include <linux/atomic.h>
37#include <asm/irq.h> 37#include <asm/irq.h>
38#include <asm/hw_irq.h>
38#include <asm/page.h> 39#include <asm/page.h>
39#include <asm/pgtable.h> 40#include <asm/pgtable.h>
40#include <asm/prom.h> 41#include <asm/prom.h>
@@ -145,9 +146,9 @@ static irqreturn_t reschedule_action(int irq, void *data)
145 return IRQ_HANDLED; 146 return IRQ_HANDLED;
146} 147}
147 148
148static irqreturn_t call_function_single_action(int irq, void *data) 149static irqreturn_t tick_broadcast_ipi_action(int irq, void *data)
149{ 150{
150 generic_smp_call_function_single_interrupt(); 151 tick_broadcast_ipi_handler();
151 return IRQ_HANDLED; 152 return IRQ_HANDLED;
152} 153}
153 154
@@ -168,14 +169,14 @@ static irqreturn_t debug_ipi_action(int irq, void *data)
168static irq_handler_t smp_ipi_action[] = { 169static irq_handler_t smp_ipi_action[] = {
169 [PPC_MSG_CALL_FUNCTION] = call_function_action, 170 [PPC_MSG_CALL_FUNCTION] = call_function_action,
170 [PPC_MSG_RESCHEDULE] = reschedule_action, 171 [PPC_MSG_RESCHEDULE] = reschedule_action,
171 [PPC_MSG_CALL_FUNC_SINGLE] = call_function_single_action, 172 [PPC_MSG_TICK_BROADCAST] = tick_broadcast_ipi_action,
172 [PPC_MSG_DEBUGGER_BREAK] = debug_ipi_action, 173 [PPC_MSG_DEBUGGER_BREAK] = debug_ipi_action,
173}; 174};
174 175
175const char *smp_ipi_name[] = { 176const char *smp_ipi_name[] = {
176 [PPC_MSG_CALL_FUNCTION] = "ipi call function", 177 [PPC_MSG_CALL_FUNCTION] = "ipi call function",
177 [PPC_MSG_RESCHEDULE] = "ipi reschedule", 178 [PPC_MSG_RESCHEDULE] = "ipi reschedule",
178 [PPC_MSG_CALL_FUNC_SINGLE] = "ipi call function single", 179 [PPC_MSG_TICK_BROADCAST] = "ipi tick-broadcast",
179 [PPC_MSG_DEBUGGER_BREAK] = "ipi debugger", 180 [PPC_MSG_DEBUGGER_BREAK] = "ipi debugger",
180}; 181};
181 182
@@ -251,8 +252,8 @@ irqreturn_t smp_ipi_demux(void)
251 generic_smp_call_function_interrupt(); 252 generic_smp_call_function_interrupt();
252 if (all & IPI_MESSAGE(PPC_MSG_RESCHEDULE)) 253 if (all & IPI_MESSAGE(PPC_MSG_RESCHEDULE))
253 scheduler_ipi(); 254 scheduler_ipi();
254 if (all & IPI_MESSAGE(PPC_MSG_CALL_FUNC_SINGLE)) 255 if (all & IPI_MESSAGE(PPC_MSG_TICK_BROADCAST))
255 generic_smp_call_function_single_interrupt(); 256 tick_broadcast_ipi_handler();
256 if (all & IPI_MESSAGE(PPC_MSG_DEBUGGER_BREAK)) 257 if (all & IPI_MESSAGE(PPC_MSG_DEBUGGER_BREAK))
257 debug_ipi_action(0, NULL); 258 debug_ipi_action(0, NULL);
258 } while (info->messages); 259 } while (info->messages);
@@ -280,7 +281,7 @@ EXPORT_SYMBOL_GPL(smp_send_reschedule);
280 281
281void arch_send_call_function_single_ipi(int cpu) 282void arch_send_call_function_single_ipi(int cpu)
282{ 283{
283 do_message_pass(cpu, PPC_MSG_CALL_FUNC_SINGLE); 284 do_message_pass(cpu, PPC_MSG_CALL_FUNCTION);
284} 285}
285 286
286void arch_send_call_function_ipi_mask(const struct cpumask *mask) 287void arch_send_call_function_ipi_mask(const struct cpumask *mask)
@@ -291,6 +292,16 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
291 do_message_pass(cpu, PPC_MSG_CALL_FUNCTION); 292 do_message_pass(cpu, PPC_MSG_CALL_FUNCTION);
292} 293}
293 294
295#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
296void tick_broadcast(const struct cpumask *mask)
297{
298 unsigned int cpu;
299
300 for_each_cpu(cpu, mask)
301 do_message_pass(cpu, PPC_MSG_TICK_BROADCAST);
302}
303#endif
304
294#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) 305#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
295void smp_send_debugger_break(void) 306void smp_send_debugger_break(void)
296{ 307{
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index b3dab20acf34..122a580f7322 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -42,6 +42,7 @@
42#include <linux/timex.h> 42#include <linux/timex.h>
43#include <linux/kernel_stat.h> 43#include <linux/kernel_stat.h>
44#include <linux/time.h> 44#include <linux/time.h>
45#include <linux/clockchips.h>
45#include <linux/init.h> 46#include <linux/init.h>
46#include <linux/profile.h> 47#include <linux/profile.h>
47#include <linux/cpu.h> 48#include <linux/cpu.h>
@@ -106,7 +107,7 @@ struct clock_event_device decrementer_clockevent = {
106 .irq = 0, 107 .irq = 0,
107 .set_next_event = decrementer_set_next_event, 108 .set_next_event = decrementer_set_next_event,
108 .set_mode = decrementer_set_mode, 109 .set_mode = decrementer_set_mode,
109 .features = CLOCK_EVT_FEAT_ONESHOT, 110 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP,
110}; 111};
111EXPORT_SYMBOL(decrementer_clockevent); 112EXPORT_SYMBOL(decrementer_clockevent);
112 113
@@ -478,6 +479,47 @@ void arch_irq_work_raise(void)
478 479
479#endif /* CONFIG_IRQ_WORK */ 480#endif /* CONFIG_IRQ_WORK */
480 481
482void __timer_interrupt(void)
483{
484 struct pt_regs *regs = get_irq_regs();
485 u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
486 struct clock_event_device *evt = &__get_cpu_var(decrementers);
487 u64 now;
488
489 trace_timer_interrupt_entry(regs);
490
491 if (test_irq_work_pending()) {
492 clear_irq_work_pending();
493 irq_work_run();
494 }
495
496 now = get_tb_or_rtc();
497 if (now >= *next_tb) {
498 *next_tb = ~(u64)0;
499 if (evt->event_handler)
500 evt->event_handler(evt);
501 __get_cpu_var(irq_stat).timer_irqs_event++;
502 } else {
503 now = *next_tb - now;
504 if (now <= DECREMENTER_MAX)
505 set_dec((int)now);
506 /* We may have raced with new irq work */
507 if (test_irq_work_pending())
508 set_dec(1);
509 __get_cpu_var(irq_stat).timer_irqs_others++;
510 }
511
512#ifdef CONFIG_PPC64
513 /* collect purr register values often, for accurate calculations */
514 if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
515 struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
516 cu->current_tb = mfspr(SPRN_PURR);
517 }
518#endif
519
520 trace_timer_interrupt_exit(regs);
521}
522
481/* 523/*
482 * timer_interrupt - gets called when the decrementer overflows, 524 * timer_interrupt - gets called when the decrementer overflows,
483 * with interrupts disabled. 525 * with interrupts disabled.
@@ -486,8 +528,6 @@ void timer_interrupt(struct pt_regs * regs)
486{ 528{
487 struct pt_regs *old_regs; 529 struct pt_regs *old_regs;
488 u64 *next_tb = &__get_cpu_var(decrementers_next_tb); 530 u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
489 struct clock_event_device *evt = &__get_cpu_var(decrementers);
490 u64 now;
491 531
492 /* Ensure a positive value is written to the decrementer, or else 532 /* Ensure a positive value is written to the decrementer, or else
493 * some CPUs will continue to take decrementer exceptions. 533 * some CPUs will continue to take decrementer exceptions.
@@ -519,39 +559,7 @@ void timer_interrupt(struct pt_regs * regs)
519 old_regs = set_irq_regs(regs); 559 old_regs = set_irq_regs(regs);
520 irq_enter(); 560 irq_enter();
521 561
522 trace_timer_interrupt_entry(regs); 562 __timer_interrupt();
523
524 if (test_irq_work_pending()) {
525 clear_irq_work_pending();
526 irq_work_run();
527 }
528
529 now = get_tb_or_rtc();
530 if (now >= *next_tb) {
531 *next_tb = ~(u64)0;
532 if (evt->event_handler)
533 evt->event_handler(evt);
534 __get_cpu_var(irq_stat).timer_irqs_event++;
535 } else {
536 now = *next_tb - now;
537 if (now <= DECREMENTER_MAX)
538 set_dec((int)now);
539 /* We may have raced with new irq work */
540 if (test_irq_work_pending())
541 set_dec(1);
542 __get_cpu_var(irq_stat).timer_irqs_others++;
543 }
544
545#ifdef CONFIG_PPC64
546 /* collect purr register values often, for accurate calculations */
547 if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
548 struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
549 cu->current_tb = mfspr(SPRN_PURR);
550 }
551#endif
552
553 trace_timer_interrupt_exit(regs);
554
555 irq_exit(); 563 irq_exit();
556 set_irq_regs(old_regs); 564 set_irq_regs(old_regs);
557} 565}
@@ -825,6 +833,15 @@ static void decrementer_set_mode(enum clock_event_mode mode,
825 decrementer_set_next_event(DECREMENTER_MAX, dev); 833 decrementer_set_next_event(DECREMENTER_MAX, dev);
826} 834}
827 835
836/* Interrupt handler for the timer broadcast IPI */
837void tick_broadcast_ipi_handler(void)
838{
839 u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
840
841 *next_tb = get_tb_or_rtc();
842 __timer_interrupt();
843}
844
828static void register_decrementer_clockevent(int cpu) 845static void register_decrementer_clockevent(int cpu)
829{ 846{
830 struct clock_event_device *dec = &per_cpu(decrementers, cpu); 847 struct clock_event_device *dec = &per_cpu(decrementers, cpu);
@@ -928,6 +945,7 @@ void __init time_init(void)
928 clocksource_init(); 945 clocksource_init();
929 946
930 init_decrementer_clockevent(); 947 init_decrementer_clockevent();
948 tick_setup_hrtimer_broadcast();
931} 949}
932 950
933 951
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 2d42f3bb66d6..8a106b4172e0 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -215,7 +215,7 @@ void iic_request_IPIs(void)
215{ 215{
216 iic_request_ipi(PPC_MSG_CALL_FUNCTION); 216 iic_request_ipi(PPC_MSG_CALL_FUNCTION);
217 iic_request_ipi(PPC_MSG_RESCHEDULE); 217 iic_request_ipi(PPC_MSG_RESCHEDULE);
218 iic_request_ipi(PPC_MSG_CALL_FUNC_SINGLE); 218 iic_request_ipi(PPC_MSG_TICK_BROADCAST);
219 iic_request_ipi(PPC_MSG_DEBUGGER_BREAK); 219 iic_request_ipi(PPC_MSG_DEBUGGER_BREAK);
220} 220}
221 221
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 75c89df8d71e..bb90f9a4e027 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -131,6 +131,7 @@ OPAL_CALL(opal_write_elog, OPAL_ELOG_WRITE);
131OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE); 131OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE);
132OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE); 132OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE);
133OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE); 133OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE);
134OPAL_CALL(opal_resync_timebase, OPAL_RESYNC_TIMEBASE);
134OPAL_CALL(opal_dump_init, OPAL_DUMP_INIT); 135OPAL_CALL(opal_dump_init, OPAL_DUMP_INIT);
135OPAL_CALL(opal_dump_info, OPAL_DUMP_INFO); 136OPAL_CALL(opal_dump_info, OPAL_DUMP_INFO);
136OPAL_CALL(opal_dump_info2, OPAL_DUMP_INFO2); 137OPAL_CALL(opal_dump_info2, OPAL_DUMP_INFO2);
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 4b35166229fe..b358bec6c8cb 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -76,7 +76,7 @@ static int __init ps3_smp_probe(void)
76 76
77 BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION != 0); 77 BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION != 0);
78 BUILD_BUG_ON(PPC_MSG_RESCHEDULE != 1); 78 BUILD_BUG_ON(PPC_MSG_RESCHEDULE != 1);
79 BUILD_BUG_ON(PPC_MSG_CALL_FUNC_SINGLE != 2); 79 BUILD_BUG_ON(PPC_MSG_TICK_BROADCAST != 2);
80 BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3); 80 BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
81 81
82 for (i = 0; i < MSG_COUNT; i++) { 82 for (i = 0; i < MSG_COUNT; i++) {