diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/Kconfig | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/opal.h | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/processor.h | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/smp.h | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/time.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/exceptions-64s.S | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/idle_power7.S | 90 | ||||
-rw-r--r-- | arch/powerpc/kernel/smp.c | 25 | ||||
-rw-r--r-- | arch/powerpc/kernel/time.c | 90 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/opal-wrappers.S | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/smp.c | 2 |
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); | |||
923 | extern bool opal_mce_check_early_recovery(struct pt_regs *regs); | 924 | extern bool opal_mce_check_early_recovery(struct pt_regs *regs); |
924 | 925 | ||
925 | extern void opal_shutdown(void); | 926 | extern void opal_shutdown(void); |
927 | extern int opal_resync_timebase(void); | ||
926 | 928 | ||
927 | extern void opal_lpc_init(void); | 929 | extern 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 | ||
451 | extern int powersave_nap; /* set if nap mode can be used in idle loop */ | 451 | extern int powersave_nap; /* set if nap mode can be used in idle loop */ |
452 | extern void power7_nap(void); | 452 | extern void power7_nap(void); |
453 | extern void power7_sleep(void); | ||
453 | extern void flush_instruction_cache(void); | 454 | extern void flush_instruction_cache(void); |
454 | extern void hard_reset_now(void); | 455 | extern void hard_reset_now(void); |
455 | extern void poweroff_now(void); | 456 | extern 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; | |||
28 | struct rtc_time; | 28 | struct rtc_time; |
29 | extern void to_tm(int tim, struct rtc_time * tm); | 29 | extern void to_tm(int tim, struct rtc_time * tm); |
30 | extern void GregorianDay(struct rtc_time *tm); | 30 | extern void GregorianDay(struct rtc_time *tm); |
31 | extern void tick_broadcast_ipi_handler(void); | ||
31 | 32 | ||
32 | extern void generic_calibrate_decr(void); | 33 | extern 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 |
143 | 2: b .power7_wakeup_loss | 144 | 2: b .power7_wakeup_loss |
145 | |||
146 | /* Fast Sleep wakeup on PowerNV */ | ||
147 | 8: GET_PACA(r13) | ||
148 | b .power7_wakeup_tb_loss | ||
149 | |||
144 | 9: | 150 | 9: |
145 | END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) | 151 | END_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 | 31 | 1: 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 */ | ||
108 | 2: 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) |
98 | 1: 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 | ||
148 | static irqreturn_t call_function_single_action(int irq, void *data) | 149 | static 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) | |||
168 | static irq_handler_t smp_ipi_action[] = { | 169 | static 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 | ||
175 | const char *smp_ipi_name[] = { | 176 | const 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 | ||
281 | void arch_send_call_function_single_ipi(int cpu) | 282 | void 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 | ||
286 | void arch_send_call_function_ipi_mask(const struct cpumask *mask) | 287 | void 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 | ||
296 | void 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) |
295 | void smp_send_debugger_break(void) | 306 | void 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 | }; |
111 | EXPORT_SYMBOL(decrementer_clockevent); | 112 | EXPORT_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 | ||
482 | void __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 */ | ||
837 | void 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 | |||
828 | static void register_decrementer_clockevent(int cpu) | 845 | static 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); | |||
131 | OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE); | 131 | OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE); |
132 | OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE); | 132 | OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE); |
133 | OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE); | 133 | OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE); |
134 | OPAL_CALL(opal_resync_timebase, OPAL_RESYNC_TIMEBASE); | ||
134 | OPAL_CALL(opal_dump_init, OPAL_DUMP_INIT); | 135 | OPAL_CALL(opal_dump_init, OPAL_DUMP_INIT); |
135 | OPAL_CALL(opal_dump_info, OPAL_DUMP_INFO); | 136 | OPAL_CALL(opal_dump_info, OPAL_DUMP_INFO); |
136 | OPAL_CALL(opal_dump_info2, OPAL_DUMP_INFO2); | 137 | OPAL_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++) { |