diff options
Diffstat (limited to 'arch/powerpc/kernel/process.c')
-rw-r--r-- | arch/powerpc/kernel/process.c | 241 |
1 files changed, 220 insertions, 21 deletions
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 81430674e71c..59dd545fdde1 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <asm/runlatch.h> | 50 | #include <asm/runlatch.h> |
51 | #include <asm/syscalls.h> | 51 | #include <asm/syscalls.h> |
52 | #include <asm/switch_to.h> | 52 | #include <asm/switch_to.h> |
53 | #include <asm/tm.h> | ||
53 | #include <asm/debug.h> | 54 | #include <asm/debug.h> |
54 | #ifdef CONFIG_PPC64 | 55 | #ifdef CONFIG_PPC64 |
55 | #include <asm/firmware.h> | 56 | #include <asm/firmware.h> |
@@ -57,6 +58,13 @@ | |||
57 | #include <linux/kprobes.h> | 58 | #include <linux/kprobes.h> |
58 | #include <linux/kdebug.h> | 59 | #include <linux/kdebug.h> |
59 | 60 | ||
61 | /* Transactional Memory debug */ | ||
62 | #ifdef TM_DEBUG_SW | ||
63 | #define TM_DEBUG(x...) printk(KERN_INFO x) | ||
64 | #else | ||
65 | #define TM_DEBUG(x...) do { } while(0) | ||
66 | #endif | ||
67 | |||
60 | extern unsigned long _get_SP(void); | 68 | extern unsigned long _get_SP(void); |
61 | 69 | ||
62 | #ifndef CONFIG_SMP | 70 | #ifndef CONFIG_SMP |
@@ -271,7 +279,7 @@ void do_send_trap(struct pt_regs *regs, unsigned long address, | |||
271 | force_sig_info(SIGTRAP, &info, current); | 279 | force_sig_info(SIGTRAP, &info, current); |
272 | } | 280 | } |
273 | #else /* !CONFIG_PPC_ADV_DEBUG_REGS */ | 281 | #else /* !CONFIG_PPC_ADV_DEBUG_REGS */ |
274 | void do_dabr(struct pt_regs *regs, unsigned long address, | 282 | void do_break (struct pt_regs *regs, unsigned long address, |
275 | unsigned long error_code) | 283 | unsigned long error_code) |
276 | { | 284 | { |
277 | siginfo_t info; | 285 | siginfo_t info; |
@@ -281,11 +289,11 @@ void do_dabr(struct pt_regs *regs, unsigned long address, | |||
281 | 11, SIGSEGV) == NOTIFY_STOP) | 289 | 11, SIGSEGV) == NOTIFY_STOP) |
282 | return; | 290 | return; |
283 | 291 | ||
284 | if (debugger_dabr_match(regs)) | 292 | if (debugger_break_match(regs)) |
285 | return; | 293 | return; |
286 | 294 | ||
287 | /* Clear the DABR */ | 295 | /* Clear the breakpoint */ |
288 | set_dabr(0, 0); | 296 | hw_breakpoint_disable(); |
289 | 297 | ||
290 | /* Deliver the signal to userspace */ | 298 | /* Deliver the signal to userspace */ |
291 | info.si_signo = SIGTRAP; | 299 | info.si_signo = SIGTRAP; |
@@ -296,7 +304,7 @@ void do_dabr(struct pt_regs *regs, unsigned long address, | |||
296 | } | 304 | } |
297 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ | 305 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ |
298 | 306 | ||
299 | static DEFINE_PER_CPU(unsigned long, current_dabr); | 307 | static DEFINE_PER_CPU(struct arch_hw_breakpoint, current_brk); |
300 | 308 | ||
301 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | 309 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
302 | /* | 310 | /* |
@@ -364,39 +372,214 @@ static void switch_booke_debug_regs(struct thread_struct *new_thread) | |||
364 | #ifndef CONFIG_HAVE_HW_BREAKPOINT | 372 | #ifndef CONFIG_HAVE_HW_BREAKPOINT |
365 | static void set_debug_reg_defaults(struct thread_struct *thread) | 373 | static void set_debug_reg_defaults(struct thread_struct *thread) |
366 | { | 374 | { |
367 | if (thread->dabr) { | 375 | thread->hw_brk.address = 0; |
368 | thread->dabr = 0; | 376 | thread->hw_brk.type = 0; |
369 | thread->dabrx = 0; | 377 | set_breakpoint(&thread->hw_brk); |
370 | set_dabr(0, 0); | ||
371 | } | ||
372 | } | 378 | } |
373 | #endif /* !CONFIG_HAVE_HW_BREAKPOINT */ | 379 | #endif /* !CONFIG_HAVE_HW_BREAKPOINT */ |
374 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ | 380 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ |
375 | 381 | ||
376 | int set_dabr(unsigned long dabr, unsigned long dabrx) | ||
377 | { | ||
378 | __get_cpu_var(current_dabr) = dabr; | ||
379 | |||
380 | if (ppc_md.set_dabr) | ||
381 | return ppc_md.set_dabr(dabr, dabrx); | ||
382 | |||
383 | /* XXX should we have a CPU_FTR_HAS_DABR ? */ | ||
384 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | 382 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
383 | static inline int __set_dabr(unsigned long dabr, unsigned long dabrx) | ||
384 | { | ||
385 | mtspr(SPRN_DAC1, dabr); | 385 | mtspr(SPRN_DAC1, dabr); |
386 | #ifdef CONFIG_PPC_47x | 386 | #ifdef CONFIG_PPC_47x |
387 | isync(); | 387 | isync(); |
388 | #endif | 388 | #endif |
389 | return 0; | ||
390 | } | ||
389 | #elif defined(CONFIG_PPC_BOOK3S) | 391 | #elif defined(CONFIG_PPC_BOOK3S) |
392 | static inline int __set_dabr(unsigned long dabr, unsigned long dabrx) | ||
393 | { | ||
390 | mtspr(SPRN_DABR, dabr); | 394 | mtspr(SPRN_DABR, dabr); |
391 | mtspr(SPRN_DABRX, dabrx); | 395 | mtspr(SPRN_DABRX, dabrx); |
396 | return 0; | ||
397 | } | ||
398 | #else | ||
399 | static inline int __set_dabr(unsigned long dabr, unsigned long dabrx) | ||
400 | { | ||
401 | return -EINVAL; | ||
402 | } | ||
392 | #endif | 403 | #endif |
404 | |||
405 | static inline int set_dabr(struct arch_hw_breakpoint *brk) | ||
406 | { | ||
407 | unsigned long dabr, dabrx; | ||
408 | |||
409 | dabr = brk->address | (brk->type & HW_BRK_TYPE_DABR); | ||
410 | dabrx = ((brk->type >> 3) & 0x7); | ||
411 | |||
412 | if (ppc_md.set_dabr) | ||
413 | return ppc_md.set_dabr(dabr, dabrx); | ||
414 | |||
415 | return __set_dabr(dabr, dabrx); | ||
416 | } | ||
417 | |||
418 | static inline int set_dawr(struct arch_hw_breakpoint *brk) | ||
419 | { | ||
420 | unsigned long dawr, dawrx, mrd; | ||
421 | |||
422 | dawr = brk->address; | ||
423 | |||
424 | dawrx = (brk->type & (HW_BRK_TYPE_READ | HW_BRK_TYPE_WRITE)) \ | ||
425 | << (63 - 58); //* read/write bits */ | ||
426 | dawrx |= ((brk->type & (HW_BRK_TYPE_TRANSLATE)) >> 2) \ | ||
427 | << (63 - 59); //* translate */ | ||
428 | dawrx |= (brk->type & (HW_BRK_TYPE_PRIV_ALL)) \ | ||
429 | >> 3; //* PRIM bits */ | ||
430 | /* dawr length is stored in field MDR bits 48:53. Matches range in | ||
431 | doublewords (64 bits) baised by -1 eg. 0b000000=1DW and | ||
432 | 0b111111=64DW. | ||
433 | brk->len is in bytes. | ||
434 | This aligns up to double word size, shifts and does the bias. | ||
435 | */ | ||
436 | mrd = ((brk->len + 7) >> 3) - 1; | ||
437 | dawrx |= (mrd & 0x3f) << (63 - 53); | ||
438 | |||
439 | if (ppc_md.set_dawr) | ||
440 | return ppc_md.set_dawr(dawr, dawrx); | ||
441 | mtspr(SPRN_DAWR, dawr); | ||
442 | mtspr(SPRN_DAWRX, dawrx); | ||
393 | return 0; | 443 | return 0; |
394 | } | 444 | } |
395 | 445 | ||
446 | int set_breakpoint(struct arch_hw_breakpoint *brk) | ||
447 | { | ||
448 | __get_cpu_var(current_brk) = *brk; | ||
449 | |||
450 | if (cpu_has_feature(CPU_FTR_DAWR)) | ||
451 | return set_dawr(brk); | ||
452 | |||
453 | return set_dabr(brk); | ||
454 | } | ||
455 | |||
396 | #ifdef CONFIG_PPC64 | 456 | #ifdef CONFIG_PPC64 |
397 | DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); | 457 | DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); |
398 | #endif | 458 | #endif |
399 | 459 | ||
460 | static inline bool hw_brk_match(struct arch_hw_breakpoint *a, | ||
461 | struct arch_hw_breakpoint *b) | ||
462 | { | ||
463 | if (a->address != b->address) | ||
464 | return false; | ||
465 | if (a->type != b->type) | ||
466 | return false; | ||
467 | if (a->len != b->len) | ||
468 | return false; | ||
469 | return true; | ||
470 | } | ||
471 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | ||
472 | static inline void tm_reclaim_task(struct task_struct *tsk) | ||
473 | { | ||
474 | /* We have to work out if we're switching from/to a task that's in the | ||
475 | * middle of a transaction. | ||
476 | * | ||
477 | * In switching we need to maintain a 2nd register state as | ||
478 | * oldtask->thread.ckpt_regs. We tm_reclaim(oldproc); this saves the | ||
479 | * checkpointed (tbegin) state in ckpt_regs and saves the transactional | ||
480 | * (current) FPRs into oldtask->thread.transact_fpr[]. | ||
481 | * | ||
482 | * We also context switch (save) TFHAR/TEXASR/TFIAR in here. | ||
483 | */ | ||
484 | struct thread_struct *thr = &tsk->thread; | ||
485 | |||
486 | if (!thr->regs) | ||
487 | return; | ||
488 | |||
489 | if (!MSR_TM_ACTIVE(thr->regs->msr)) | ||
490 | goto out_and_saveregs; | ||
491 | |||
492 | /* Stash the original thread MSR, as giveup_fpu et al will | ||
493 | * modify it. We hold onto it to see whether the task used | ||
494 | * FP & vector regs. | ||
495 | */ | ||
496 | thr->tm_orig_msr = thr->regs->msr; | ||
497 | |||
498 | TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, " | ||
499 | "ccr=%lx, msr=%lx, trap=%lx)\n", | ||
500 | tsk->pid, thr->regs->nip, | ||
501 | thr->regs->ccr, thr->regs->msr, | ||
502 | thr->regs->trap); | ||
503 | |||
504 | tm_reclaim(thr, thr->regs->msr, TM_CAUSE_RESCHED); | ||
505 | |||
506 | TM_DEBUG("--- tm_reclaim on pid %d complete\n", | ||
507 | tsk->pid); | ||
508 | |||
509 | out_and_saveregs: | ||
510 | /* Always save the regs here, even if a transaction's not active. | ||
511 | * This context-switches a thread's TM info SPRs. We do it here to | ||
512 | * be consistent with the restore path (in recheckpoint) which | ||
513 | * cannot happen later in _switch(). | ||
514 | */ | ||
515 | tm_save_sprs(thr); | ||
516 | } | ||
517 | |||
518 | static inline void tm_recheckpoint_new_task(struct task_struct *new) | ||
519 | { | ||
520 | unsigned long msr; | ||
521 | |||
522 | if (!cpu_has_feature(CPU_FTR_TM)) | ||
523 | return; | ||
524 | |||
525 | /* Recheckpoint the registers of the thread we're about to switch to. | ||
526 | * | ||
527 | * If the task was using FP, we non-lazily reload both the original and | ||
528 | * the speculative FP register states. This is because the kernel | ||
529 | * doesn't see if/when a TM rollback occurs, so if we take an FP | ||
530 | * unavoidable later, we are unable to determine which set of FP regs | ||
531 | * need to be restored. | ||
532 | */ | ||
533 | if (!new->thread.regs) | ||
534 | return; | ||
535 | |||
536 | /* The TM SPRs are restored here, so that TEXASR.FS can be set | ||
537 | * before the trecheckpoint and no explosion occurs. | ||
538 | */ | ||
539 | tm_restore_sprs(&new->thread); | ||
540 | |||
541 | if (!MSR_TM_ACTIVE(new->thread.regs->msr)) | ||
542 | return; | ||
543 | msr = new->thread.tm_orig_msr; | ||
544 | /* Recheckpoint to restore original checkpointed register state. */ | ||
545 | TM_DEBUG("*** tm_recheckpoint of pid %d " | ||
546 | "(new->msr 0x%lx, new->origmsr 0x%lx)\n", | ||
547 | new->pid, new->thread.regs->msr, msr); | ||
548 | |||
549 | /* This loads the checkpointed FP/VEC state, if used */ | ||
550 | tm_recheckpoint(&new->thread, msr); | ||
551 | |||
552 | /* This loads the speculative FP/VEC state, if used */ | ||
553 | if (msr & MSR_FP) { | ||
554 | do_load_up_transact_fpu(&new->thread); | ||
555 | new->thread.regs->msr |= | ||
556 | (MSR_FP | new->thread.fpexc_mode); | ||
557 | } | ||
558 | if (msr & MSR_VEC) { | ||
559 | do_load_up_transact_altivec(&new->thread); | ||
560 | new->thread.regs->msr |= MSR_VEC; | ||
561 | } | ||
562 | /* We may as well turn on VSX too since all the state is restored now */ | ||
563 | if (msr & MSR_VSX) | ||
564 | new->thread.regs->msr |= MSR_VSX; | ||
565 | |||
566 | TM_DEBUG("*** tm_recheckpoint of pid %d complete " | ||
567 | "(kernel msr 0x%lx)\n", | ||
568 | new->pid, mfmsr()); | ||
569 | } | ||
570 | |||
571 | static inline void __switch_to_tm(struct task_struct *prev) | ||
572 | { | ||
573 | if (cpu_has_feature(CPU_FTR_TM)) { | ||
574 | tm_enable(); | ||
575 | tm_reclaim_task(prev); | ||
576 | } | ||
577 | } | ||
578 | #else | ||
579 | #define tm_recheckpoint_new_task(new) | ||
580 | #define __switch_to_tm(prev) | ||
581 | #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ | ||
582 | |||
400 | struct task_struct *__switch_to(struct task_struct *prev, | 583 | struct task_struct *__switch_to(struct task_struct *prev, |
401 | struct task_struct *new) | 584 | struct task_struct *new) |
402 | { | 585 | { |
@@ -407,6 +590,8 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
407 | struct ppc64_tlb_batch *batch; | 590 | struct ppc64_tlb_batch *batch; |
408 | #endif | 591 | #endif |
409 | 592 | ||
593 | __switch_to_tm(prev); | ||
594 | |||
410 | #ifdef CONFIG_SMP | 595 | #ifdef CONFIG_SMP |
411 | /* avoid complexity of lazy save/restore of fpu | 596 | /* avoid complexity of lazy save/restore of fpu |
412 | * by just saving it every time we switch out if | 597 | * by just saving it every time we switch out if |
@@ -481,8 +666,8 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
481 | * schedule DABR | 666 | * schedule DABR |
482 | */ | 667 | */ |
483 | #ifndef CONFIG_HAVE_HW_BREAKPOINT | 668 | #ifndef CONFIG_HAVE_HW_BREAKPOINT |
484 | if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) | 669 | if (unlikely(hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk))) |
485 | set_dabr(new->thread.dabr, new->thread.dabrx); | 670 | set_breakpoint(&new->thread.hw_brk); |
486 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | 671 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
487 | #endif | 672 | #endif |
488 | 673 | ||
@@ -522,6 +707,9 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
522 | * of sync. Hard disable here. | 707 | * of sync. Hard disable here. |
523 | */ | 708 | */ |
524 | hard_irq_disable(); | 709 | hard_irq_disable(); |
710 | |||
711 | tm_recheckpoint_new_task(new); | ||
712 | |||
525 | last = _switch(old_thread, new_thread); | 713 | last = _switch(old_thread, new_thread); |
526 | 714 | ||
527 | #ifdef CONFIG_PPC_BOOK3S_64 | 715 | #ifdef CONFIG_PPC_BOOK3S_64 |
@@ -683,6 +871,9 @@ void show_regs(struct pt_regs * regs) | |||
683 | printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip); | 871 | printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip); |
684 | printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link); | 872 | printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link); |
685 | #endif | 873 | #endif |
874 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | ||
875 | printk("PACATMSCRATCH [%llx]\n", get_paca()->tm_scratch); | ||
876 | #endif | ||
686 | show_stack(current, (unsigned long *) regs->gpr[1]); | 877 | show_stack(current, (unsigned long *) regs->gpr[1]); |
687 | if (!user_mode(regs)) | 878 | if (!user_mode(regs)) |
688 | show_instructions(regs); | 879 | show_instructions(regs); |
@@ -813,6 +1004,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
813 | p->thread.dscr_inherit = current->thread.dscr_inherit; | 1004 | p->thread.dscr_inherit = current->thread.dscr_inherit; |
814 | p->thread.dscr = current->thread.dscr; | 1005 | p->thread.dscr = current->thread.dscr; |
815 | } | 1006 | } |
1007 | if (cpu_has_feature(CPU_FTR_HAS_PPR)) | ||
1008 | p->thread.ppr = INIT_PPR; | ||
816 | #endif | 1009 | #endif |
817 | /* | 1010 | /* |
818 | * The PPC64 ABI makes use of a TOC to contain function | 1011 | * The PPC64 ABI makes use of a TOC to contain function |
@@ -892,7 +1085,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) | |||
892 | regs->msr = MSR_USER32; | 1085 | regs->msr = MSR_USER32; |
893 | } | 1086 | } |
894 | #endif | 1087 | #endif |
895 | |||
896 | discard_lazy_cpu_state(); | 1088 | discard_lazy_cpu_state(); |
897 | #ifdef CONFIG_VSX | 1089 | #ifdef CONFIG_VSX |
898 | current->thread.used_vsr = 0; | 1090 | current->thread.used_vsr = 0; |
@@ -912,6 +1104,13 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) | |||
912 | current->thread.spefscr = 0; | 1104 | current->thread.spefscr = 0; |
913 | current->thread.used_spe = 0; | 1105 | current->thread.used_spe = 0; |
914 | #endif /* CONFIG_SPE */ | 1106 | #endif /* CONFIG_SPE */ |
1107 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | ||
1108 | if (cpu_has_feature(CPU_FTR_TM)) | ||
1109 | regs->msr |= MSR_TM; | ||
1110 | current->thread.tm_tfhar = 0; | ||
1111 | current->thread.tm_texasr = 0; | ||
1112 | current->thread.tm_tfiar = 0; | ||
1113 | #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ | ||
915 | } | 1114 | } |
916 | 1115 | ||
917 | #define PR_FP_ALL_EXCEPT (PR_FP_EXC_DIV | PR_FP_EXC_OVF | PR_FP_EXC_UND \ | 1116 | #define PR_FP_ALL_EXCEPT (PR_FP_EXC_DIV | PR_FP_EXC_OVF | PR_FP_EXC_UND \ |