MIPS: Implement HAVE_CONTEXT_TRACKING.
authorRalf Baechle <ralf@linux-mips.org>
Tue, 28 May 2013 23:07:19 +0000 (01:07 +0200)
committerRalf Baechle <ralf@linux-mips.org>
Mon, 10 Jun 2013 16:02:30 +0000 (18:02 +0200)
This enables support for CONFIG_NO_HZ_FULL.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/Kconfig
arch/mips/include/asm/thread_info.h
arch/mips/kernel/cpu-bugs64.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/signal.c
arch/mips/kernel/traps.c
arch/mips/kernel/unaligned.c
arch/mips/mm/fault.c

index ade99730ef3b19f3d602bf8b835ff2eeed231e65..87ddac9477fa18476f92e78cd16aa1948152f5f8 100644 (file)
@@ -1,6 +1,7 @@
 config MIPS
        bool
        default y
+       select HAVE_CONTEXT_TRACKING
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_IDE
        select HAVE_OPROFILE
index cdea4f65b944b6c1a8cff880248c486c4a3dd304..61215a34acc68ff87da07665c65c8dc0f6dbfcc1 100644 (file)
@@ -109,6 +109,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_RESTORE_SIGMASK    9       /* restore signal mask in do_signal() */
 #define TIF_USEDFPU            16      /* FPU was used by this task this quantum (SMP) */
 #define TIF_MEMDIE             18      /* is terminating due to OOM killer */
+#define TIF_NOHZ               19      /* in adaptive nohz mode */
 #define TIF_FIXADE             20      /* Fix address errors in software */
 #define TIF_LOGADE             21      /* Log address errors to syslog */
 #define TIF_32BIT_REGS         22      /* also implies 16/32 fprs */
@@ -124,6 +125,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
 #define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_USEDFPU           (1<<TIF_USEDFPU)
+#define _TIF_NOHZ              (1<<TIF_NOHZ)
 #define _TIF_FIXADE            (1<<TIF_FIXADE)
 #define _TIF_LOGADE            (1<<TIF_LOGADE)
 #define _TIF_32BIT_REGS                (1<<TIF_32BIT_REGS)
@@ -131,16 +133,19 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_FPUBOUND          (1<<TIF_FPUBOUND)
 #define _TIF_LOAD_WATCH                (1<<TIF_LOAD_WATCH)
 
-#define _TIF_WORK_SYSCALL_ENTRY        (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
+#define _TIF_WORK_SYSCALL_ENTRY        (_TIF_NOHZ | _TIF_SYSCALL_TRACE |       \
+                                _TIF_SYSCALL_AUDIT)
 
 /* work to do in syscall_trace_leave() */
-#define _TIF_WORK_SYSCALL_EXIT (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
+#define _TIF_WORK_SYSCALL_EXIT (_TIF_NOHZ | _TIF_SYSCALL_TRACE |       \
+                                _TIF_SYSCALL_AUDIT)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK         \
        (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME)
 /* work to do on any return to u-space */
-#define _TIF_ALLWORK_MASK      (_TIF_WORK_MASK | _TIF_WORK_SYSCALL_EXIT)
+#define _TIF_ALLWORK_MASK      (_TIF_NOHZ | _TIF_WORK_MASK |           \
+                                _TIF_WORK_SYSCALL_EXIT)
 
 #endif /* __KERNEL__ */
 
index de3c25ffd9f91e38487303696402b8c97f46bf45..0c61df281ce6788a299d655df68d874d02c6f71d 100644 (file)
@@ -6,6 +6,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
+#include <linux/context_tracking.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/ptrace.h>
@@ -171,8 +172,12 @@ static volatile int daddi_ov __cpuinitdata;
 
 asmlinkage void __init do_daddi_ov(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
+
+       prev_state = exception_enter();
        daddi_ov = 1;
        regs->cp0_epc += 4;
+       exception_exit(prev_state);
 }
 
 static inline void check_daddi(void)
index 9c6299c733a317ce5c975ce91b054297502ba960..8ae1ebef8b71e67fd5e205646bd10adcdb1b0299 100644 (file)
@@ -15,6 +15,7 @@
  * binaries.
  */
 #include <linux/compiler.h>
+#include <linux/context_tracking.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -534,6 +535,8 @@ static inline int audit_arch(void)
  */
 asmlinkage void syscall_trace_enter(struct pt_regs *regs)
 {
+       user_exit();
+
        /* do the secure computing check first */
        secure_computing_strict(regs->regs[2]);
 
@@ -570,6 +573,13 @@ out:
  */
 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 {
+        /*
+        * We may come here right after calling schedule_user()
+        * or do_notify_resume(), in which case we can be in RCU
+        * user mode.
+        */
+       user_exit();
+
        audit_syscall_exit(regs);
 
        if (!(current->ptrace & PT_PTRACED))
@@ -592,4 +602,6 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs)
                send_sig(current->exit_code, current, 1);
                current->exit_code = 0;
        }
+
+       user_enter();
 }
index fd3ef2c2afbc37732d9bedcb9fff59d1dda935ea..2f285abc76d5b9be1e68920bdbe962b5c6c6d11f 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
 #include <linux/cache.h>
+#include <linux/context_tracking.h>
 #include <linux/irqflags.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -573,6 +574,8 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
 {
        local_irq_enable();
 
+       user_exit();
+
        /* deal with pending signal delivery */
        if (thread_info_flags & _TIF_SIGPENDING)
                do_signal(regs);
@@ -581,6 +584,8 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
        }
+
+       user_enter();
 }
 
 #ifdef CONFIG_SMP
index a75ae40184aa3a5d35e08668e71022230ee087bc..beba1e616b6eec42762b2ee3c5f63e0569def845 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <linux/bug.h>
 #include <linux/compiler.h>
+#include <linux/context_tracking.h>
 #include <linux/kexec.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -423,7 +424,9 @@ asmlinkage void do_be(struct pt_regs *regs)
        const struct exception_table_entry *fixup = NULL;
        int data = regs->cp0_cause & 4;
        int action = MIPS_BE_FATAL;
+       enum ctx_state prev_state;
 
+       prev_state = exception_enter();
        /* XXX For now.  Fixme, this searches the wrong table ...  */
        if (data && !user_mode(regs))
                fixup = search_dbe_tables(exception_epc(regs));
@@ -436,11 +439,11 @@ asmlinkage void do_be(struct pt_regs *regs)
 
        switch (action) {
        case MIPS_BE_DISCARD:
-               return;
+               goto out;
        case MIPS_BE_FIXUP:
                if (fixup) {
                        regs->cp0_epc = fixup->nextinsn;
-                       return;
+                       goto out;
                }
                break;
        default:
@@ -455,10 +458,13 @@ asmlinkage void do_be(struct pt_regs *regs)
               field, regs->cp0_epc, field, regs->regs[31]);
        if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs), SIGBUS)
            == NOTIFY_STOP)
-               return;
+               goto out;
 
        die_if_kernel("Oops", regs);
        force_sig(SIGBUS, current);
+
+out:
+       exception_exit(prev_state);
 }
 
 /*
@@ -673,8 +679,10 @@ static int simulate_sync(struct pt_regs *regs, unsigned int opcode)
 
 asmlinkage void do_ov(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
        siginfo_t info;
 
+       prev_state = exception_enter();
        die_if_kernel("Integer overflow", regs);
 
        info.si_code = FPE_INTOVF;
@@ -682,6 +690,7 @@ asmlinkage void do_ov(struct pt_regs *regs)
        info.si_errno = 0;
        info.si_addr = (void __user *) regs->cp0_epc;
        force_sig_info(SIGFPE, &info, current);
+       exception_exit(prev_state);
 }
 
 int process_fpemu_return(int sig, void __user *fault_addr)
@@ -713,11 +722,13 @@ int process_fpemu_return(int sig, void __user *fault_addr)
  */
 asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
 {
+       enum ctx_state prev_state;
        siginfo_t info = {0};
 
+       prev_state = exception_enter();
        if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE)
            == NOTIFY_STOP)
-               return;
+               goto out;
        die_if_kernel("FP exception in kernel code", regs);
 
        if (fcr31 & FPU_CSR_UNI_X) {
@@ -753,7 +764,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                /* If something went wrong, signal */
                process_fpemu_return(sig, fault_addr);
 
-               return;
+               goto out;
        } else if (fcr31 & FPU_CSR_INV_X)
                info.si_code = FPE_FLTINV;
        else if (fcr31 & FPU_CSR_DIV_X)
@@ -770,6 +781,9 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
        info.si_errno = 0;
        info.si_addr = (void __user *) regs->cp0_epc;
        force_sig_info(SIGFPE, &info, current);
+
+out:
+       exception_exit(prev_state);
 }
 
 static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
@@ -835,9 +849,11 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
 asmlinkage void do_bp(struct pt_regs *regs)
 {
        unsigned int opcode, bcode;
+       enum ctx_state prev_state;
        unsigned long epc;
        u16 instr[2];
 
+       prev_state = exception_enter();
        if (get_isa16_mode(regs->cp0_epc)) {
                /* Calculate EPC. */
                epc = exception_epc(regs);
@@ -852,7 +868,7 @@ asmlinkage void do_bp(struct pt_regs *regs)
                                goto out_sigsegv;
                    bcode = (instr[0] >> 6) & 0x3f;
                    do_trap_or_bp(regs, bcode, "Break");
-                   return;
+                   goto out;
                }
        } else {
                if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
@@ -876,12 +892,12 @@ asmlinkage void do_bp(struct pt_regs *regs)
        switch (bcode) {
        case BRK_KPROBE_BP:
                if (notify_die(DIE_BREAK, "debug", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
-                       return;
+                       goto out;
                else
                        break;
        case BRK_KPROBE_SSTEPBP:
                if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
-                       return;
+                       goto out;
                else
                        break;
        default:
@@ -889,18 +905,24 @@ asmlinkage void do_bp(struct pt_regs *regs)
        }
 
        do_trap_or_bp(regs, bcode, "Break");
+
+out:
+       exception_exit(prev_state);
        return;
 
 out_sigsegv:
        force_sig(SIGSEGV, current);
+       goto out;
 }
 
 asmlinkage void do_tr(struct pt_regs *regs)
 {
        u32 opcode, tcode = 0;
+       enum ctx_state prev_state;
        u16 instr[2];
        unsigned long epc = msk_isa16_mode(exception_epc(regs));
 
+       prev_state = exception_enter();
        if (get_isa16_mode(regs->cp0_epc)) {
                if (__get_user(instr[0], (u16 __user *)(epc + 0)) ||
                    __get_user(instr[1], (u16 __user *)(epc + 2)))
@@ -918,10 +940,14 @@ asmlinkage void do_tr(struct pt_regs *regs)
        }
 
        do_trap_or_bp(regs, tcode, "Trap");
+
+out:
+       exception_exit(prev_state);
        return;
 
 out_sigsegv:
        force_sig(SIGSEGV, current);
+       goto out;
 }
 
 asmlinkage void do_ri(struct pt_regs *regs)
@@ -929,17 +955,19 @@ asmlinkage void do_ri(struct pt_regs *regs)
        unsigned int __user *epc = (unsigned int __user *)exception_epc(regs);
        unsigned long old_epc = regs->cp0_epc;
        unsigned long old31 = regs->regs[31];
+       enum ctx_state prev_state;
        unsigned int opcode = 0;
        int status = -1;
 
+       prev_state = exception_enter();
        if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs), SIGILL)
            == NOTIFY_STOP)
-               return;
+               goto out;
 
        die_if_kernel("Reserved instruction in kernel code", regs);
 
        if (unlikely(compute_return_epc(regs) < 0))
-               return;
+               goto out;
 
        if (get_isa16_mode(regs->cp0_epc)) {
                unsigned short mmop[2] = { 0 };
@@ -974,6 +1002,9 @@ asmlinkage void do_ri(struct pt_regs *regs)
                regs->regs[31] = old31;
                force_sig(status, current);
        }
+
+out:
+       exception_exit(prev_state);
 }
 
 /*
@@ -1040,6 +1071,7 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
 
 asmlinkage void do_cpu(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
        unsigned int __user *epc;
        unsigned long old_epc, old31;
        unsigned int opcode;
@@ -1047,6 +1079,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
        int status;
        unsigned long __maybe_unused flags;
 
+       prev_state = exception_enter();
        die_if_kernel("do_cpu invoked from kernel context!", regs);
 
        cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
@@ -1060,7 +1093,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                status = -1;
 
                if (unlikely(compute_return_epc(regs) < 0))
-                       return;
+                       goto out;
 
                if (get_isa16_mode(regs->cp0_epc)) {
                        unsigned short mmop[2] = { 0 };
@@ -1093,7 +1126,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                        force_sig(status, current);
                }
 
-               return;
+               goto out;
 
        case 3:
                /*
@@ -1131,19 +1164,26 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                                mt_ase_fp_affinity();
                }
 
-               return;
+               goto out;
 
        case 2:
                raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs);
-               return;
+               goto out;
        }
 
        force_sig(SIGILL, current);
+
+out:
+       exception_exit(prev_state);
 }
 
 asmlinkage void do_mdmx(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
+
+       prev_state = exception_enter();
        force_sig(SIGILL, current);
+       exception_exit(prev_state);
 }
 
 /*
@@ -1151,8 +1191,10 @@ asmlinkage void do_mdmx(struct pt_regs *regs)
  */
 asmlinkage void do_watch(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
        u32 cause;
 
+       prev_state = exception_enter();
        /*
         * Clear WP (bit 22) bit of cause register so we don't loop
         * forever.
@@ -1174,13 +1216,16 @@ asmlinkage void do_watch(struct pt_regs *regs)
                mips_clear_watch_registers();
                local_irq_enable();
        }
+       exception_exit(prev_state);
 }
 
 asmlinkage void do_mcheck(struct pt_regs *regs)
 {
        const int field = 2 * sizeof(unsigned long);
        int multi_match = regs->cp0_status & ST0_TS;
+       enum ctx_state prev_state;
 
+       prev_state = exception_enter();
        show_regs(regs);
 
        if (multi_match) {
@@ -1202,6 +1247,7 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
        panic("Caught Machine Check exception - %scaused by multiple "
              "matching entries in the TLB.",
              (multi_match) ? "" : "not ");
+       exception_exit(prev_state);
 }
 
 asmlinkage void do_mt(struct pt_regs *regs)
index 203d8857070dd225f2d8fdea7bf986ad7a6560cc..3eaa02aa8ae0840efdca0e151f1af823d90cb89f 100644 (file)
@@ -72,6 +72,7 @@
  *      A store crossing a page boundary might be executed only partially.
  *      Undo the partial store in this case.
  */
+#include <linux/context_tracking.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
@@ -1550,9 +1551,11 @@ sigill:
 }
 asmlinkage void do_ade(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
        unsigned int __user *pc;
        mm_segment_t seg;
 
+       prev_state = exception_enter();
        perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
                        1, regs, regs->cp0_badvaddr);
        /*
@@ -1628,6 +1631,7 @@ sigbus:
        /*
         * XXX On return from the signal handler we should advance the epc
         */
+       exception_exit(prev_state);
 }
 
 #ifdef CONFIG_DEBUG_FS
index 0fead53d1c26b261affa89d00c1fa06844f9e602..85df1cd8d446c0b7b1fccbbcb3617175f6314289 100644 (file)
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 1995 - 2000 by Ralf Baechle
  */
+#include <linux/context_tracking.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -32,8 +33,8 @@
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  */
-asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long write,
-                             unsigned long address)
+static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write,
+       unsigned long address)
 {
        struct vm_area_struct * vma = NULL;
        struct task_struct *tsk = current;
@@ -312,3 +313,13 @@ vmalloc_fault:
        }
 #endif
 }
+
+asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
+       unsigned long write, unsigned long address)
+{
+       enum ctx_state prev_state;
+
+       prev_state = exception_enter();
+       __do_page_fault(regs, write, address);
+       exception_exit(prev_state);
+}