diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/mips/kernel/traps.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r-- | arch/mips/kernel/traps.c | 85 |
1 files changed, 61 insertions, 24 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 03ec0019032b..e9b3af27d844 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <linux/kprobes.h> | 28 | #include <linux/kprobes.h> |
29 | #include <linux/notifier.h> | 29 | #include <linux/notifier.h> |
30 | #include <linux/kdb.h> | 30 | #include <linux/kdb.h> |
31 | #include <linux/irq.h> | ||
32 | #include <linux/perf_event.h> | ||
31 | 33 | ||
32 | #include <asm/bootinfo.h> | 34 | #include <asm/bootinfo.h> |
33 | #include <asm/branch.h> | 35 | #include <asm/branch.h> |
@@ -51,7 +53,6 @@ | |||
51 | #include <asm/mmu_context.h> | 53 | #include <asm/mmu_context.h> |
52 | #include <asm/types.h> | 54 | #include <asm/types.h> |
53 | #include <asm/stacktrace.h> | 55 | #include <asm/stacktrace.h> |
54 | #include <asm/irq.h> | ||
55 | #include <asm/uasm.h> | 56 | #include <asm/uasm.h> |
56 | 57 | ||
57 | extern void check_wait(void); | 58 | extern void check_wait(void); |
@@ -82,7 +83,8 @@ extern asmlinkage void handle_mcheck(void); | |||
82 | extern asmlinkage void handle_reserved(void); | 83 | extern asmlinkage void handle_reserved(void); |
83 | 84 | ||
84 | extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, | 85 | extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, |
85 | struct mips_fpu_struct *ctx, int has_fpu); | 86 | struct mips_fpu_struct *ctx, int has_fpu, |
87 | void *__user *fault_addr); | ||
86 | 88 | ||
87 | void (*board_be_init)(void); | 89 | void (*board_be_init)(void); |
88 | int (*board_be_handler)(struct pt_regs *regs, int is_fixup); | 90 | int (*board_be_handler)(struct pt_regs *regs, int is_fixup); |
@@ -372,7 +374,8 @@ void __noreturn die(const char *str, struct pt_regs *regs) | |||
372 | unsigned long dvpret = dvpe(); | 374 | unsigned long dvpret = dvpe(); |
373 | #endif /* CONFIG_MIPS_MT_SMTC */ | 375 | #endif /* CONFIG_MIPS_MT_SMTC */ |
374 | 376 | ||
375 | notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV); | 377 | if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP) |
378 | sig = 0; | ||
376 | 379 | ||
377 | console_verbose(); | 380 | console_verbose(); |
378 | spin_lock_irq(&die_lock); | 381 | spin_lock_irq(&die_lock); |
@@ -381,9 +384,6 @@ void __noreturn die(const char *str, struct pt_regs *regs) | |||
381 | mips_mt_regdump(dvpret); | 384 | mips_mt_regdump(dvpret); |
382 | #endif /* CONFIG_MIPS_MT_SMTC */ | 385 | #endif /* CONFIG_MIPS_MT_SMTC */ |
383 | 386 | ||
384 | if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP) | ||
385 | sig = 0; | ||
386 | |||
387 | printk("%s[#%d]:\n", str, ++die_counter); | 387 | printk("%s[#%d]:\n", str, ++die_counter); |
388 | show_registers(regs); | 388 | show_registers(regs); |
389 | add_taint(TAINT_DIE); | 389 | add_taint(TAINT_DIE); |
@@ -576,10 +576,16 @@ static inline int simulate_sc(struct pt_regs *regs, unsigned int opcode) | |||
576 | */ | 576 | */ |
577 | static int simulate_llsc(struct pt_regs *regs, unsigned int opcode) | 577 | static int simulate_llsc(struct pt_regs *regs, unsigned int opcode) |
578 | { | 578 | { |
579 | if ((opcode & OPCODE) == LL) | 579 | if ((opcode & OPCODE) == LL) { |
580 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, | ||
581 | 1, 0, regs, 0); | ||
580 | return simulate_ll(regs, opcode); | 582 | return simulate_ll(regs, opcode); |
581 | if ((opcode & OPCODE) == SC) | 583 | } |
584 | if ((opcode & OPCODE) == SC) { | ||
585 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, | ||
586 | 1, 0, regs, 0); | ||
582 | return simulate_sc(regs, opcode); | 587 | return simulate_sc(regs, opcode); |
588 | } | ||
583 | 589 | ||
584 | return -1; /* Must be something else ... */ | 590 | return -1; /* Must be something else ... */ |
585 | } | 591 | } |
@@ -595,6 +601,8 @@ static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode) | |||
595 | if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) { | 601 | if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) { |
596 | int rd = (opcode & RD) >> 11; | 602 | int rd = (opcode & RD) >> 11; |
597 | int rt = (opcode & RT) >> 16; | 603 | int rt = (opcode & RT) >> 16; |
604 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, | ||
605 | 1, 0, regs, 0); | ||
598 | switch (rd) { | 606 | switch (rd) { |
599 | case 0: /* CPU number */ | 607 | case 0: /* CPU number */ |
600 | regs->regs[rt] = smp_processor_id(); | 608 | regs->regs[rt] = smp_processor_id(); |
@@ -630,8 +638,11 @@ static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode) | |||
630 | 638 | ||
631 | static int simulate_sync(struct pt_regs *regs, unsigned int opcode) | 639 | static int simulate_sync(struct pt_regs *regs, unsigned int opcode) |
632 | { | 640 | { |
633 | if ((opcode & OPCODE) == SPEC0 && (opcode & FUNC) == SYNC) | 641 | if ((opcode & OPCODE) == SPEC0 && (opcode & FUNC) == SYNC) { |
642 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, | ||
643 | 1, 0, regs, 0); | ||
634 | return 0; | 644 | return 0; |
645 | } | ||
635 | 646 | ||
636 | return -1; /* Must be something else ... */ | 647 | return -1; /* Must be something else ... */ |
637 | } | 648 | } |
@@ -649,12 +660,36 @@ asmlinkage void do_ov(struct pt_regs *regs) | |||
649 | force_sig_info(SIGFPE, &info, current); | 660 | force_sig_info(SIGFPE, &info, current); |
650 | } | 661 | } |
651 | 662 | ||
663 | static int process_fpemu_return(int sig, void __user *fault_addr) | ||
664 | { | ||
665 | if (sig == SIGSEGV || sig == SIGBUS) { | ||
666 | struct siginfo si = {0}; | ||
667 | si.si_addr = fault_addr; | ||
668 | si.si_signo = sig; | ||
669 | if (sig == SIGSEGV) { | ||
670 | if (find_vma(current->mm, (unsigned long)fault_addr)) | ||
671 | si.si_code = SEGV_ACCERR; | ||
672 | else | ||
673 | si.si_code = SEGV_MAPERR; | ||
674 | } else { | ||
675 | si.si_code = BUS_ADRERR; | ||
676 | } | ||
677 | force_sig_info(sig, &si, current); | ||
678 | return 1; | ||
679 | } else if (sig) { | ||
680 | force_sig(sig, current); | ||
681 | return 1; | ||
682 | } else { | ||
683 | return 0; | ||
684 | } | ||
685 | } | ||
686 | |||
652 | /* | 687 | /* |
653 | * XXX Delayed fp exceptions when doing a lazy ctx switch XXX | 688 | * XXX Delayed fp exceptions when doing a lazy ctx switch XXX |
654 | */ | 689 | */ |
655 | asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | 690 | asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) |
656 | { | 691 | { |
657 | siginfo_t info; | 692 | siginfo_t info = {0}; |
658 | 693 | ||
659 | if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE) | 694 | if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE) |
660 | == NOTIFY_STOP) | 695 | == NOTIFY_STOP) |
@@ -663,6 +698,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
663 | 698 | ||
664 | if (fcr31 & FPU_CSR_UNI_X) { | 699 | if (fcr31 & FPU_CSR_UNI_X) { |
665 | int sig; | 700 | int sig; |
701 | void __user *fault_addr = NULL; | ||
666 | 702 | ||
667 | /* | 703 | /* |
668 | * Unimplemented operation exception. If we've got the full | 704 | * Unimplemented operation exception. If we've got the full |
@@ -678,7 +714,8 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
678 | lose_fpu(1); | 714 | lose_fpu(1); |
679 | 715 | ||
680 | /* Run the emulator */ | 716 | /* Run the emulator */ |
681 | sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1); | 717 | sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, |
718 | &fault_addr); | ||
682 | 719 | ||
683 | /* | 720 | /* |
684 | * We can't allow the emulated instruction to leave any of | 721 | * We can't allow the emulated instruction to leave any of |
@@ -690,8 +727,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
690 | own_fpu(1); /* Using the FPU again. */ | 727 | own_fpu(1); /* Using the FPU again. */ |
691 | 728 | ||
692 | /* If something went wrong, signal */ | 729 | /* If something went wrong, signal */ |
693 | if (sig) | 730 | process_fpemu_return(sig, fault_addr); |
694 | force_sig(sig, current); | ||
695 | 731 | ||
696 | return; | 732 | return; |
697 | } else if (fcr31 & FPU_CSR_INV_X) | 733 | } else if (fcr31 & FPU_CSR_INV_X) |
@@ -984,11 +1020,11 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
984 | 1020 | ||
985 | if (!raw_cpu_has_fpu) { | 1021 | if (!raw_cpu_has_fpu) { |
986 | int sig; | 1022 | int sig; |
1023 | void __user *fault_addr = NULL; | ||
987 | sig = fpu_emulator_cop1Handler(regs, | 1024 | sig = fpu_emulator_cop1Handler(regs, |
988 | ¤t->thread.fpu, 0); | 1025 | ¤t->thread.fpu, |
989 | if (sig) | 1026 | 0, &fault_addr); |
990 | force_sig(sig, current); | 1027 | if (!process_fpemu_return(sig, fault_addr)) |
991 | else | ||
992 | mt_ase_fp_affinity(); | 1028 | mt_ase_fp_affinity(); |
993 | } | 1029 | } |
994 | 1030 | ||
@@ -1469,6 +1505,7 @@ void __cpuinit per_cpu_trap_init(void) | |||
1469 | { | 1505 | { |
1470 | unsigned int cpu = smp_processor_id(); | 1506 | unsigned int cpu = smp_processor_id(); |
1471 | unsigned int status_set = ST0_CU0; | 1507 | unsigned int status_set = ST0_CU0; |
1508 | unsigned int hwrena = cpu_hwrena_impl_bits; | ||
1472 | #ifdef CONFIG_MIPS_MT_SMTC | 1509 | #ifdef CONFIG_MIPS_MT_SMTC |
1473 | int secondaryTC = 0; | 1510 | int secondaryTC = 0; |
1474 | int bootTC = (cpu == 0); | 1511 | int bootTC = (cpu == 0); |
@@ -1501,14 +1538,14 @@ void __cpuinit per_cpu_trap_init(void) | |||
1501 | change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, | 1538 | change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, |
1502 | status_set); | 1539 | status_set); |
1503 | 1540 | ||
1504 | if (cpu_has_mips_r2) { | 1541 | if (cpu_has_mips_r2) |
1505 | unsigned int enable = 0x0000000f | cpu_hwrena_impl_bits; | 1542 | hwrena |= 0x0000000f; |
1506 | 1543 | ||
1507 | if (!noulri && cpu_has_userlocal) | 1544 | if (!noulri && cpu_has_userlocal) |
1508 | enable |= (1 << 29); | 1545 | hwrena |= (1 << 29); |
1509 | 1546 | ||
1510 | write_c0_hwrena(enable); | 1547 | if (hwrena) |
1511 | } | 1548 | write_c0_hwrena(hwrena); |
1512 | 1549 | ||
1513 | #ifdef CONFIG_MIPS_MT_SMTC | 1550 | #ifdef CONFIG_MIPS_MT_SMTC |
1514 | if (!secondaryTC) { | 1551 | if (!secondaryTC) { |
@@ -1553,7 +1590,6 @@ void __cpuinit per_cpu_trap_init(void) | |||
1553 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1590 | #endif /* CONFIG_MIPS_MT_SMTC */ |
1554 | 1591 | ||
1555 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; | 1592 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; |
1556 | TLBMISS_HANDLER_SETUP(); | ||
1557 | 1593 | ||
1558 | atomic_inc(&init_mm.mm_count); | 1594 | atomic_inc(&init_mm.mm_count); |
1559 | current->active_mm = &init_mm; | 1595 | current->active_mm = &init_mm; |
@@ -1575,6 +1611,7 @@ void __cpuinit per_cpu_trap_init(void) | |||
1575 | write_c0_wired(0); | 1611 | write_c0_wired(0); |
1576 | } | 1612 | } |
1577 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1613 | #endif /* CONFIG_MIPS_MT_SMTC */ |
1614 | TLBMISS_HANDLER_SETUP(); | ||
1578 | } | 1615 | } |
1579 | 1616 | ||
1580 | /* Install CPU exception handler */ | 1617 | /* Install CPU exception handler */ |