diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-05 21:41:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-05 21:41:32 -0400 |
commit | cb4f9a296472ebd1cde88970194888e962150875 (patch) | |
tree | 257cf69e93eb1773e0c9c3905a84b4d476267b41 /arch/powerpc/kernel | |
parent | 813e64382a8a4afcbfd7caeba40292a8ea6d5cc3 (diff) | |
parent | 636802ef96eebe279b22ad9f9dacfe29291e45c7 (diff) |
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
Pull powerpc fixes from Benjamin Herrenschmidt:
"Here are a few fixes for 3.6 that were piling up while I was away or
busy (I was mostly MIA a week or two before San Diego).
Some fixes from Anton fixing up issues with our relatively new DSCR
control feature, and a few other fixes that are either regressions or
bugs nasty enough to warrant not waiting."
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
powerpc: Don't use __put_user() in patch_instruction
powerpc: Make sure IPI handlers see data written by IPI senders
powerpc: Restore correct DSCR in context switch
powerpc: Fix DSCR inheritance in copy_thread()
powerpc: Keep thread.dscr and thread.dscr_inherit in sync
powerpc: Update DSCR on all CPUs when writing sysfs dscr_default
powerpc/powernv: Always go into nap mode when CPU is offline
powerpc: Give hypervisor decrementer interrupts their own handler
powerpc/vphn: Fix arch_update_cpu_topology() return value
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/dbell.c | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_64.S | 23 | ||||
-rw-r--r-- | arch/powerpc/kernel/exceptions-64s.S | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/idle_power7.S | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/process.c | 12 | ||||
-rw-r--r-- | arch/powerpc/kernel/smp.c | 11 | ||||
-rw-r--r-- | arch/powerpc/kernel/sysfs.c | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/time.c | 9 | ||||
-rw-r--r-- | arch/powerpc/kernel/traps.c | 3 |
10 files changed, 56 insertions, 20 deletions
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 85b05c463fa..e8995727b1c 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -76,6 +76,7 @@ int main(void) | |||
76 | DEFINE(SIGSEGV, SIGSEGV); | 76 | DEFINE(SIGSEGV, SIGSEGV); |
77 | DEFINE(NMI_MASK, NMI_MASK); | 77 | DEFINE(NMI_MASK, NMI_MASK); |
78 | DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr)); | 78 | DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr)); |
79 | DEFINE(THREAD_DSCR_INHERIT, offsetof(struct thread_struct, dscr_inherit)); | ||
79 | #else | 80 | #else |
80 | DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); | 81 | DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); |
81 | #endif /* CONFIG_PPC64 */ | 82 | #endif /* CONFIG_PPC64 */ |
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index 5b25c8060fd..a892680668d 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c | |||
@@ -28,6 +28,8 @@ void doorbell_setup_this_cpu(void) | |||
28 | 28 | ||
29 | void doorbell_cause_ipi(int cpu, unsigned long data) | 29 | void doorbell_cause_ipi(int cpu, unsigned long data) |
30 | { | 30 | { |
31 | /* Order previous accesses vs. msgsnd, which is treated as a store */ | ||
32 | mb(); | ||
31 | ppc_msgsnd(PPC_DBELL, 0, data); | 33 | ppc_msgsnd(PPC_DBELL, 0, data); |
32 | } | 34 | } |
33 | 35 | ||
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 4b01a25e29e..b40e0b4815b 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -370,6 +370,12 @@ _GLOBAL(ret_from_fork) | |||
370 | li r3,0 | 370 | li r3,0 |
371 | b syscall_exit | 371 | b syscall_exit |
372 | 372 | ||
373 | .section ".toc","aw" | ||
374 | DSCR_DEFAULT: | ||
375 | .tc dscr_default[TC],dscr_default | ||
376 | |||
377 | .section ".text" | ||
378 | |||
373 | /* | 379 | /* |
374 | * This routine switches between two different tasks. The process | 380 | * This routine switches between two different tasks. The process |
375 | * state of one is saved on its kernel stack. Then the state | 381 | * state of one is saved on its kernel stack. Then the state |
@@ -509,9 +515,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) | |||
509 | mr r1,r8 /* start using new stack pointer */ | 515 | mr r1,r8 /* start using new stack pointer */ |
510 | std r7,PACAKSAVE(r13) | 516 | std r7,PACAKSAVE(r13) |
511 | 517 | ||
512 | ld r6,_CCR(r1) | ||
513 | mtcrf 0xFF,r6 | ||
514 | |||
515 | #ifdef CONFIG_ALTIVEC | 518 | #ifdef CONFIG_ALTIVEC |
516 | BEGIN_FTR_SECTION | 519 | BEGIN_FTR_SECTION |
517 | ld r0,THREAD_VRSAVE(r4) | 520 | ld r0,THREAD_VRSAVE(r4) |
@@ -520,14 +523,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | |||
520 | #endif /* CONFIG_ALTIVEC */ | 523 | #endif /* CONFIG_ALTIVEC */ |
521 | #ifdef CONFIG_PPC64 | 524 | #ifdef CONFIG_PPC64 |
522 | BEGIN_FTR_SECTION | 525 | BEGIN_FTR_SECTION |
526 | lwz r6,THREAD_DSCR_INHERIT(r4) | ||
527 | ld r7,DSCR_DEFAULT@toc(2) | ||
523 | ld r0,THREAD_DSCR(r4) | 528 | ld r0,THREAD_DSCR(r4) |
524 | cmpd r0,r25 | 529 | cmpwi r6,0 |
525 | beq 1f | 530 | bne 1f |
531 | ld r0,0(r7) | ||
532 | 1: cmpd r0,r25 | ||
533 | beq 2f | ||
526 | mtspr SPRN_DSCR,r0 | 534 | mtspr SPRN_DSCR,r0 |
527 | 1: | 535 | 2: |
528 | END_FTR_SECTION_IFSET(CPU_FTR_DSCR) | 536 | END_FTR_SECTION_IFSET(CPU_FTR_DSCR) |
529 | #endif | 537 | #endif |
530 | 538 | ||
539 | ld r6,_CCR(r1) | ||
540 | mtcrf 0xFF,r6 | ||
541 | |||
531 | /* r3-r13 are destroyed -- Cort */ | 542 | /* r3-r13 are destroyed -- Cort */ |
532 | REST_8GPRS(14, r1) | 543 | REST_8GPRS(14, r1) |
533 | REST_10GPRS(22, r1) | 544 | REST_10GPRS(22, r1) |
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index e894515e77b..39aa97d3ff8 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S | |||
@@ -186,7 +186,7 @@ hardware_interrupt_hv: | |||
186 | KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x800) | 186 | KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x800) |
187 | 187 | ||
188 | MASKABLE_EXCEPTION_PSERIES(0x900, 0x900, decrementer) | 188 | MASKABLE_EXCEPTION_PSERIES(0x900, 0x900, decrementer) |
189 | MASKABLE_EXCEPTION_HV(0x980, 0x982, decrementer) | 189 | STD_EXCEPTION_HV(0x980, 0x982, hdecrementer) |
190 | 190 | ||
191 | STD_EXCEPTION_PSERIES(0xa00, 0xa00, trap_0a) | 191 | STD_EXCEPTION_PSERIES(0xa00, 0xa00, trap_0a) |
192 | KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xa00) | 192 | KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xa00) |
@@ -486,6 +486,7 @@ machine_check_common: | |||
486 | 486 | ||
487 | STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) | 487 | STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) |
488 | STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt) | 488 | STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt) |
489 | STD_EXCEPTION_COMMON(0x980, hdecrementer, .hdec_interrupt) | ||
489 | STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception) | 490 | STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception) |
490 | STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) | 491 | STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) |
491 | STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) | 492 | STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) |
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S index 7140d838339..e11863f4e59 100644 --- a/arch/powerpc/kernel/idle_power7.S +++ b/arch/powerpc/kernel/idle_power7.S | |||
@@ -28,7 +28,9 @@ _GLOBAL(power7_idle) | |||
28 | lwz r4,ADDROFF(powersave_nap)(r3) | 28 | lwz r4,ADDROFF(powersave_nap)(r3) |
29 | cmpwi 0,r4,0 | 29 | cmpwi 0,r4,0 |
30 | beqlr | 30 | beqlr |
31 | /* fall through */ | ||
31 | 32 | ||
33 | _GLOBAL(power7_nap) | ||
32 | /* NAP is a state loss, we create a regs frame on the | 34 | /* NAP is a state loss, we create a regs frame on the |
33 | * stack, fill it up with the state we care about and | 35 | * stack, fill it up with the state we care about and |
34 | * stick a pointer to it in PACAR1. We really only | 36 | * stick a pointer to it in PACAR1. We really only |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 710f400476d..1a1f2ddfb58 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -802,16 +802,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
802 | #endif /* CONFIG_PPC_STD_MMU_64 */ | 802 | #endif /* CONFIG_PPC_STD_MMU_64 */ |
803 | #ifdef CONFIG_PPC64 | 803 | #ifdef CONFIG_PPC64 |
804 | if (cpu_has_feature(CPU_FTR_DSCR)) { | 804 | if (cpu_has_feature(CPU_FTR_DSCR)) { |
805 | if (current->thread.dscr_inherit) { | 805 | p->thread.dscr_inherit = current->thread.dscr_inherit; |
806 | p->thread.dscr_inherit = 1; | 806 | p->thread.dscr = current->thread.dscr; |
807 | p->thread.dscr = current->thread.dscr; | ||
808 | } else if (0 != dscr_default) { | ||
809 | p->thread.dscr_inherit = 1; | ||
810 | p->thread.dscr = dscr_default; | ||
811 | } else { | ||
812 | p->thread.dscr_inherit = 0; | ||
813 | p->thread.dscr = 0; | ||
814 | } | ||
815 | } | 807 | } |
816 | #endif | 808 | #endif |
817 | 809 | ||
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 0321007086f..8d4214afc21 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -198,8 +198,15 @@ void smp_muxed_ipi_message_pass(int cpu, int msg) | |||
198 | struct cpu_messages *info = &per_cpu(ipi_message, cpu); | 198 | struct cpu_messages *info = &per_cpu(ipi_message, cpu); |
199 | char *message = (char *)&info->messages; | 199 | char *message = (char *)&info->messages; |
200 | 200 | ||
201 | /* | ||
202 | * Order previous accesses before accesses in the IPI handler. | ||
203 | */ | ||
204 | smp_mb(); | ||
201 | message[msg] = 1; | 205 | message[msg] = 1; |
202 | mb(); | 206 | /* |
207 | * cause_ipi functions are required to include a full barrier | ||
208 | * before doing whatever causes the IPI. | ||
209 | */ | ||
203 | smp_ops->cause_ipi(cpu, info->data); | 210 | smp_ops->cause_ipi(cpu, info->data); |
204 | } | 211 | } |
205 | 212 | ||
@@ -211,7 +218,7 @@ irqreturn_t smp_ipi_demux(void) | |||
211 | mb(); /* order any irq clear */ | 218 | mb(); /* order any irq clear */ |
212 | 219 | ||
213 | do { | 220 | do { |
214 | all = xchg_local(&info->messages, 0); | 221 | all = xchg(&info->messages, 0); |
215 | 222 | ||
216 | #ifdef __BIG_ENDIAN | 223 | #ifdef __BIG_ENDIAN |
217 | if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNCTION))) | 224 | if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNCTION))) |
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 3529446c2ab..8302af64921 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c | |||
@@ -194,6 +194,14 @@ static ssize_t show_dscr_default(struct device *dev, | |||
194 | return sprintf(buf, "%lx\n", dscr_default); | 194 | return sprintf(buf, "%lx\n", dscr_default); |
195 | } | 195 | } |
196 | 196 | ||
197 | static void update_dscr(void *dummy) | ||
198 | { | ||
199 | if (!current->thread.dscr_inherit) { | ||
200 | current->thread.dscr = dscr_default; | ||
201 | mtspr(SPRN_DSCR, dscr_default); | ||
202 | } | ||
203 | } | ||
204 | |||
197 | static ssize_t __used store_dscr_default(struct device *dev, | 205 | static ssize_t __used store_dscr_default(struct device *dev, |
198 | struct device_attribute *attr, const char *buf, | 206 | struct device_attribute *attr, const char *buf, |
199 | size_t count) | 207 | size_t count) |
@@ -206,6 +214,8 @@ static ssize_t __used store_dscr_default(struct device *dev, | |||
206 | return -EINVAL; | 214 | return -EINVAL; |
207 | dscr_default = val; | 215 | dscr_default = val; |
208 | 216 | ||
217 | on_each_cpu(update_dscr, NULL, 1); | ||
218 | |||
209 | return count; | 219 | return count; |
210 | } | 220 | } |
211 | 221 | ||
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index be171ee73bf..e49e93191b6 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -535,6 +535,15 @@ void timer_interrupt(struct pt_regs * regs) | |||
535 | trace_timer_interrupt_exit(regs); | 535 | trace_timer_interrupt_exit(regs); |
536 | } | 536 | } |
537 | 537 | ||
538 | /* | ||
539 | * Hypervisor decrementer interrupts shouldn't occur but are sometimes | ||
540 | * left pending on exit from a KVM guest. We don't need to do anything | ||
541 | * to clear them, as they are edge-triggered. | ||
542 | */ | ||
543 | void hdec_interrupt(struct pt_regs *regs) | ||
544 | { | ||
545 | } | ||
546 | |||
538 | #ifdef CONFIG_SUSPEND | 547 | #ifdef CONFIG_SUSPEND |
539 | static void generic_suspend_disable_irqs(void) | 548 | static void generic_suspend_disable_irqs(void) |
540 | { | 549 | { |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 158972341a2..ae0843fa7a6 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -972,8 +972,9 @@ static int emulate_instruction(struct pt_regs *regs) | |||
972 | cpu_has_feature(CPU_FTR_DSCR)) { | 972 | cpu_has_feature(CPU_FTR_DSCR)) { |
973 | PPC_WARN_EMULATED(mtdscr, regs); | 973 | PPC_WARN_EMULATED(mtdscr, regs); |
974 | rd = (instword >> 21) & 0x1f; | 974 | rd = (instword >> 21) & 0x1f; |
975 | mtspr(SPRN_DSCR, regs->gpr[rd]); | 975 | current->thread.dscr = regs->gpr[rd]; |
976 | current->thread.dscr_inherit = 1; | 976 | current->thread.dscr_inherit = 1; |
977 | mtspr(SPRN_DSCR, current->thread.dscr); | ||
977 | return 0; | 978 | return 0; |
978 | } | 979 | } |
979 | #endif | 980 | #endif |