aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/kernel/linux32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/linux32.c')
-rw-r--r--arch/mips/kernel/linux32.c205
1 files changed, 11 insertions, 194 deletions
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 6343b4a5b83..0b29646bcee 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -3,7 +3,6 @@
*
* Copyright (C) 2000 Silicon Graphics, Inc.
* Written by Ulf Carlsson (ulfc@engr.sgi.com)
- * sys32_execve from ia64/ia32 code, Feb 2000, Kanoj Sarcar (kanoj@sgi.com)
*/
#include <linux/compiler.h>
#include <linux/mm.h>
@@ -77,27 +76,7 @@ out:
return error;
}
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs)
-{
- int error;
- char * filename;
-
- filename = getname(compat_ptr(regs.regs[4]));
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = compat_do_execve(filename, compat_ptr(regs.regs[5]),
- compat_ptr(regs.regs[6]), &regs);
- putname(filename);
-
-out:
- return error;
-}
-
-#define RLIM_INFINITY32 0x7fffffff
+#define RLIM_INFINITY32 0x7fffffff
#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
struct rlimit32 {
@@ -126,7 +105,7 @@ SYSCALL_DEFINE5(32_llseek, unsigned int, fd, unsigned int, offset_high,
/* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
lseek back to original location. They fail just like lseek does on
- non-seekable files. */
+ non-seekable files. */
SYSCALL_DEFINE6(32_pread, unsigned long, fd, char __user *, buf, size_t, count,
unsigned long, unused, unsigned long, a4, unsigned long, a5)
@@ -140,150 +119,22 @@ SYSCALL_DEFINE6(32_pwrite, unsigned int, fd, const char __user *, buf,
return sys_pwrite64(fd, buf, count, merge_64(a4, a5));
}
-SYSCALL_DEFINE2(32_sched_rr_get_interval, compat_pid_t, pid,
- struct compat_timespec __user *, interval)
-{
- struct timespec t;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
- set_fs(old_fs);
- if (put_user (t.tv_sec, &interval->tv_sec) ||
- __put_user(t.tv_nsec, &interval->tv_nsec))
- return -EFAULT;
- return ret;
-}
-
-#ifdef CONFIG_SYSVIPC
-
-SYSCALL_DEFINE6(32_ipc, u32, call, long, first, long, second, long, third,
- unsigned long, ptr, unsigned long, fifth)
-{
- int version, err;
-
- version = call >> 16; /* hack for backward compatibility */
- call &= 0xffff;
-
- switch (call) {
- case SEMOP:
- /* struct sembuf is the same on 32 and 64bit :)) */
- err = sys_semtimedop(first, compat_ptr(ptr), second, NULL);
- break;
- case SEMTIMEDOP:
- err = compat_sys_semtimedop(first, compat_ptr(ptr), second,
- compat_ptr(fifth));
- break;
- case SEMGET:
- err = sys_semget(first, second, third);
- break;
- case SEMCTL:
- err = compat_sys_semctl(first, second, third, compat_ptr(ptr));
- break;
- case MSGSND:
- err = compat_sys_msgsnd(first, second, third, compat_ptr(ptr));
- break;
- case MSGRCV:
- err = compat_sys_msgrcv(first, second, fifth, third,
- version, compat_ptr(ptr));
- break;
- case MSGGET:
- err = sys_msgget((key_t) first, second);
- break;
- case MSGCTL:
- err = compat_sys_msgctl(first, second, compat_ptr(ptr));
- break;
- case SHMAT:
- err = compat_sys_shmat(first, second, third, version,
- compat_ptr(ptr));
- break;
- case SHMDT:
- err = sys_shmdt(compat_ptr(ptr));
- break;
- case SHMGET:
- err = sys_shmget(first, (unsigned)second, third);
- break;
- case SHMCTL:
- err = compat_sys_shmctl(first, second, compat_ptr(ptr));
- break;
- default:
- err = -EINVAL;
- break;
- }
-
- return err;
-}
-
-#else
-
-SYSCALL_DEFINE6(32_ipc, u32, call, int, first, int, second, int, third,
- u32, ptr, u32, fifth)
-{
- return -ENOSYS;
-}
-
-#endif /* CONFIG_SYSVIPC */
-
-#ifdef CONFIG_MIPS32_N32
-SYSCALL_DEFINE4(n32_semctl, int, semid, int, semnum, int, cmd, u32, arg)
-{
- /* compat_sys_semctl expects a pointer to union semun */
- u32 __user *uptr = compat_alloc_user_space(sizeof(u32));
- if (put_user(arg, uptr))
- return -EFAULT;
- return compat_sys_semctl(semid, semnum, cmd, uptr);
-}
-
-SYSCALL_DEFINE4(n32_msgsnd, int, msqid, u32, msgp, unsigned int, msgsz,
- int, msgflg)
-{
- return compat_sys_msgsnd(msqid, msgsz, msgflg, compat_ptr(msgp));
-}
-
-SYSCALL_DEFINE5(n32_msgrcv, int, msqid, u32, msgp, size_t, msgsz,
- int, msgtyp, int, msgflg)
-{
- return compat_sys_msgrcv(msqid, msgsz, msgtyp, msgflg, IPC_64,
- compat_ptr(msgp));
-}
-#endif
-
SYSCALL_DEFINE1(32_personality, unsigned long, personality)
{
+ unsigned int p = personality & 0xffffffff;
int ret;
- personality &= 0xffffffff;
- if (personality(current->personality) == PER_LINUX32 &&
- personality == PER_LINUX)
- personality = PER_LINUX32;
- ret = sys_personality(personality);
- if (ret == PER_LINUX32)
- ret = PER_LINUX;
- return ret;
-}
-
-SYSCALL_DEFINE4(32_sendfile, long, out_fd, long, in_fd,
- compat_off_t __user *, offset, s32, count)
-{
- mm_segment_t old_fs = get_fs();
- int ret;
- off_t of;
-
- if (offset && get_user(of, offset))
- return -EFAULT;
-
- set_fs(KERNEL_DS);
- ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
- set_fs(old_fs);
-
- if (offset && put_user(of, offset))
- return -EFAULT;
+ if (personality(current->personality) == PER_LINUX32 &&
+ personality(p) == PER_LINUX)
+ p = (p & ~PER_MASK) | PER_LINUX32;
+ ret = sys_personality(p);
+ if (ret != -1 && personality(ret) == PER_LINUX32)
+ ret = (ret & ~PER_MASK) | PER_LINUX;
return ret;
}
asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3,
- size_t count)
+ size_t count)
{
return sys_readahead(fd, merge_64(a2, a3), count);
}
@@ -312,39 +163,5 @@ asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_a2,
unsigned offset_a3, unsigned len_a4, unsigned len_a5)
{
return sys_fallocate(fd, mode, merge_64(offset_a2, offset_a3),
- merge_64(len_a4, len_a5));
-}
-
-save_static_function(sys32_clone);
-static int noinline __used
-_sys32_clone(nabi_no_regargs struct pt_regs regs)
-{
- unsigned long clone_flags;
- unsigned long newsp;
- int __user *parent_tidptr, *child_tidptr;
-
- clone_flags = regs.regs[4];
- newsp = regs.regs[5];
- if (!newsp)
- newsp = regs.regs[29];
- parent_tidptr = (int __user *) regs.regs[6];
-
- /* Use __dummy4 instead of getting it off the stack, so that
- syscall() works. */
- child_tidptr = (int __user *) __dummy4;
- return do_fork(clone_flags, newsp, &regs, 0,
- parent_tidptr, child_tidptr);
-}
-
-asmlinkage long sys32_lookup_dcookie(u32 a0, u32 a1, char __user *buf,
- size_t len)
-{
- return sys_lookup_dcookie(merge_64(a0, a1), buf, len);
-}
-
-SYSCALL_DEFINE6(32_fanotify_mark, int, fanotify_fd, unsigned int, flags,
- u64, a3, u64, a4, int, dfd, const char __user *, pathname)
-{
- return sys_fanotify_mark(fanotify_fd, flags, merge_64(a3, a4),
- dfd, pathname);
+ merge_64(len_a4, len_a5));
}
m' style='width: 1.2%;'/> -rw-r--r--arch/mips/kernel/irq_cpu.c2
-rw-r--r--arch/mips/kernel/kgdb.c18
-rw-r--r--arch/mips/kernel/kprobes.c5
-rw-r--r--arch/mips/kernel/linux32.c126
-rw-r--r--arch/mips/kernel/mcount.S17
-rw-r--r--arch/mips/kernel/mips-cm.c121
-rw-r--r--arch/mips/kernel/mips-cpc.c80
-rw-r--r--arch/mips/kernel/mips-mt-fpaff.c6
-rw-r--r--arch/mips/kernel/mips-mt.c18
-rw-r--r--arch/mips/kernel/mips_ksyms.c24
-rw-r--r--arch/mips/kernel/mips_machine.c22
-rw-r--r--arch/mips/kernel/module.c3
-rw-r--r--arch/mips/kernel/octeon_switch.S64
-rw-r--r--arch/mips/kernel/perf_event_mipsxx.c84
-rw-r--r--arch/mips/kernel/pm-cps.c716
-rw-r--r--arch/mips/kernel/pm.c99
-rw-r--r--arch/mips/kernel/proc.c73
-rw-r--r--arch/mips/kernel/process.c229
-rw-r--r--arch/mips/kernel/prom.c60
-rw-r--r--arch/mips/kernel/ptrace.c392
-rw-r--r--arch/mips/kernel/ptrace32.c88
-rw-r--r--arch/mips/kernel/r2300_switch.S7
-rw-r--r--arch/mips/kernel/r4k_fpu.S84
-rw-r--r--arch/mips/kernel/r4k_switch.S147
-rw-r--r--arch/mips/kernel/relocate_kernel.S6
-rw-r--r--arch/mips/kernel/rtlx-cmp.c119
-rw-r--r--arch/mips/kernel/rtlx-mt.c150
-rw-r--r--arch/mips/kernel/rtlx.c290
-rw-r--r--arch/mips/kernel/scall32-o32.S863
-rw-r--r--arch/mips/kernel/scall64-64.S14
-rw-r--r--arch/mips/kernel/scall64-n32.S19
-rw-r--r--arch/mips/kernel/scall64-o32.S40
-rw-r--r--arch/mips/kernel/segment.c110
-rw-r--r--arch/mips/kernel/setup.c140
-rw-r--r--arch/mips/kernel/signal.c105
-rw-r--r--arch/mips/kernel/signal32.c65
-rw-r--r--arch/mips/kernel/smp-bmips.c334
-rw-r--r--arch/mips/kernel/smp-cmp.c80
-rw-r--r--arch/mips/kernel/smp-cps.c466
-rw-r--r--arch/mips/kernel/smp-gic.c64
-rw-r--r--arch/mips/kernel/smp-mt.c43
-rw-r--r--arch/mips/kernel/smp-up.c12
-rw-r--r--arch/mips/kernel/smp.c72
-rw-r--r--arch/mips/kernel/smtc-asm.S130
-rw-r--r--arch/mips/kernel/smtc-proc.c91
-rw-r--r--arch/mips/kernel/smtc.c1529
-rw-r--r--arch/mips/kernel/spram.c22
-rw-r--r--arch/mips/kernel/sync-r4k.c31
-rw-r--r--arch/mips/kernel/syscall.c4
-rw-r--r--arch/mips/kernel/time.c12
-rw-r--r--arch/mips/kernel/traps.c801
-rw-r--r--arch/mips/kernel/unaligned.c1580
-rw-r--r--arch/mips/kernel/vmlinux.lds.S1
-rw-r--r--arch/mips/kernel/vpe-cmp.c180
-rw-r--r--arch/mips/kernel/vpe-mt.c521
-rw-r--r--arch/mips/kernel/vpe.c907
-rw-r--r--arch/mips/kernel/watch.c10
90 files changed, 8714 insertions, 6049 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index f81d98f6184..008a2fed058 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -4,8 +4,8 @@
extra-y := head.o vmlinux.lds
-obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
- ptrace.o reset.o setup.o signal.o syscall.o \
+obj-y += cpu-probe.o branch.o entry.o genex.o idle.o irq.o process.o \
+ prom.o ptrace.o reset.o setup.o signal.o syscall.o \
time.o topology.o traps.o unaligned.o watch.o vdso.o
ifdef CONFIG_FUNCTION_TRACER
@@ -17,30 +17,31 @@ endif
obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o
obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o
-obj-$(CONFIG_MIPS_MT_SMTC) += cevt-smtc.o
obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o
+obj-$(CONFIG_CEVT_GIC) += cevt-gic.o
obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o
obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o
obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o
obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o
+obj-$(CONFIG_CSRC_GIC) += csrc-gic.o
obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o
-obj-$(CONFIG_CSRC_POWERTV) += csrc-powertv.o
obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o
obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o
-obj-$(CONFIG_CSRC_GIC) += csrc-gic.o
obj-$(CONFIG_SYNC_R4K) += sync-r4k.o
+obj-$(CONFIG_DEBUG_FS) += segment.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
obj-$(CONFIG_MODULES_USE_ELF_RELA) += module-rela.o
+obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
obj-$(CONFIG_CPU_R4K_FPU) += r4k_fpu.o r4k_switch.o
obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o
obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o
obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o
-obj-$(CONFIG_CPU_CAVIUM_OCTEON) += octeon_switch.o
+obj-$(CONFIG_CPU_CAVIUM_OCTEON) += r4k_fpu.o octeon_switch.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SMP_UP) += smp-up.o
@@ -48,13 +49,18 @@ obj-$(CONFIG_CPU_BMIPS) += smp-bmips.o bmips_vec.o
obj-$(CONFIG_MIPS_MT) += mips-mt.o
obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o
-obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o
obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
obj-$(CONFIG_MIPS_CMP) += smp-cmp.o
+obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o
+obj-$(CONFIG_MIPS_GIC_IPI) += smp-gic.o
obj-$(CONFIG_CPU_MIPSR2) += spram.o
obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o
+obj-$(CONFIG_MIPS_VPE_LOADER_CMP) += vpe-cmp.o
+obj-$(CONFIG_MIPS_VPE_LOADER_MT) += vpe-mt.o
obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o
+obj-$(CONFIG_MIPS_VPE_APSP_API_CMP) += rtlx-cmp.o
+obj-$(CONFIG_MIPS_VPE_APSP_API_MT) += rtlx-mt.o
obj-$(CONFIG_I8259) += i8259.o
obj-$(CONFIG_IRQ_CPU) += irq_cpu.o
@@ -83,45 +89,35 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_EARLY_PRINTK_8250) += early_printk_8250.o
obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o
obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o
-obj-$(CONFIG_OF) += prom.o
-
CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -x c /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o
-obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/
-
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
-#
-# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is safe
-# to enable DSP assembler support here even if the MIPS Release 2 CPU we
-# are targetting does not support DSP because all code-paths making use of
-# it properly check that the running CPU *actually does* support these
-# instructions.
-#
-ifeq ($(CONFIG_CPU_MIPSR2), y)
-CFLAGS_DSP = -DHAVE_AS_DSP
+obj-$(CONFIG_MIPS_CM) += mips-cm.o
+obj-$(CONFIG_MIPS_CPC) += mips-cpc.o
-#
-# Check if assembler supports DSP ASE
-#
-ifeq ($(call cc-option-yn,-mdsp), y)
-CFLAGS_DSP += -mdsp
-endif
+obj-$(CONFIG_CPU_PM) += pm.o
+obj-$(CONFIG_MIPS_CPS_PM) += pm-cps.o
#
-# Check if assembler supports DSP ASE Rev2
+# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is not
+# safe to unconditionnaly use the assembler -mdsp / -mdspr2 switches
+# here because the compiler may use DSP ASE instructions (such as lwx) in
+# code paths where we cannot check that the CPU we are running on supports it.
+# Proper abstraction using HAVE_AS_DSP and macros is done in
+# arch/mips/include/asm/mipsregs.h.
#
-ifeq ($(call cc-option-yn,-mdspr2), y)
-CFLAGS_DSP += -mdspr2
-endif
+ifeq ($(CONFIG_CPU_MIPSR2), y)
+CFLAGS_DSP = -DHAVE_AS_DSP
CFLAGS_signal.o = $(CFLAGS_DSP)
CFLAGS_signal32.o = $(CFLAGS_DSP)
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 50285b2c7ff..4bb5107511e 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -14,8 +14,12 @@
#include <linux/mm.h>
#include <linux/kbuild.h>
#include <linux/suspend.h>
+#include <asm/pm.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
+#include <asm/smp-cps.h>
+
+#include <linux/kvm_host.h>
void output_ptreg_defines(void)
{
@@ -61,9 +65,6 @@ void output_ptreg_defines(void)
OFFSET(PT_BVADDR, pt_regs, cp0_badvaddr);
OFFSET(PT_STATUS, pt_regs, cp0_status);
OFFSET(PT_CAUSE, pt_regs, cp0_cause);
-#ifdef CONFIG_MIPS_MT_SMTC
- OFFSET(PT_TCSTATUS, pt_regs, cp0_tcstatus);
-#endif /* CONFIG_MIPS_MT_SMTC */
#ifdef CONFIG_CPU_CAVIUM_OCTEON
OFFSET(PT_MPL, pt_regs, mpl);
OFFSET(PT_MTP, pt_regs, mtp);
@@ -80,6 +81,9 @@ void output_task_defines(void)
OFFSET(TASK_FLAGS, task_struct, flags);
OFFSET(TASK_MM, task_struct, mm);
OFFSET(TASK_PID, task_struct, pid);
+#if defined(CONFIG_CC_STACKPROTECTOR)
+ OFFSET(TASK_STACK_CANARY, task_struct, stack_canary);
+#endif
DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct));
BLANK();
}
@@ -163,6 +167,72 @@ void output_thread_fpu_defines(void)
OFFSET(THREAD_FPR30, task_struct, thread.fpu.fpr[30]);
OFFSET(THREAD_FPR31, task_struct, thread.fpu.fpr[31]);
+ /* the least significant 64 bits of each FP register */
+ OFFSET(THREAD_FPR0_LS64, task_struct,
+ thread.fpu.fpr[0].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR1_LS64, task_struct,
+ thread.fpu.fpr[1].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR2_LS64, task_struct,
+ thread.fpu.fpr[2].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR3_LS64, task_struct,
+ thread.fpu.fpr[3].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR4_LS64, task_struct,
+ thread.fpu.fpr[4].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR5_LS64, task_struct,
+ thread.fpu.fpr[5].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR6_LS64, task_struct,
+ thread.fpu.fpr[6].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR7_LS64, task_struct,
+ thread.fpu.fpr[7].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR8_LS64, task_struct,
+ thread.fpu.fpr[8].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR9_LS64, task_struct,
+ thread.fpu.fpr[9].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR10_LS64, task_struct,
+ thread.fpu.fpr[10].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR11_LS64, task_struct,
+ thread.fpu.fpr[11].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR12_LS64, task_struct,
+ thread.fpu.fpr[12].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR13_LS64, task_struct,
+ thread.fpu.fpr[13].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR14_LS64, task_struct,
+ thread.fpu.fpr[14].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR15_LS64, task_struct,
+ thread.fpu.fpr[15].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR16_LS64, task_struct,
+ thread.fpu.fpr[16].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR17_LS64, task_struct,
+ thread.fpu.fpr[17].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR18_LS64, task_struct,
+ thread.fpu.fpr[18].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR19_LS64, task_struct,
+ thread.fpu.fpr[19].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR20_LS64, task_struct,
+ thread.fpu.fpr[20].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR21_LS64, task_struct,
+ thread.fpu.fpr[21].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR22_LS64, task_struct,
+ thread.fpu.fpr[22].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR23_LS64, task_struct,
+ thread.fpu.fpr[23].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR24_LS64, task_struct,
+ thread.fpu.fpr[24].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR25_LS64, task_struct,
+ thread.fpu.fpr[25].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR26_LS64, task_struct,
+ thread.fpu.fpr[26].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR27_LS64, task_struct,
+ thread.fpu.fpr[27].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR28_LS64, task_struct,
+ thread.fpu.fpr[28].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR29_LS64, task_struct,
+ thread.fpu.fpr[29].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR30_LS64, task_struct,
+ thread.fpu.fpr[30].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR31_LS64, task_struct,
+ thread.fpu.fpr[31].val64[FPR_IDX(64, 0)]);
+
OFFSET(THREAD_FCR31, task_struct, thread.fpu.fcr31);
BLANK();
}
@@ -328,3 +398,97 @@ void output_pbe_defines(void)
BLANK();
}
#endif
+
+#ifdef CONFIG_CPU_PM
+void output_pm_defines(void)
+{
+ COMMENT(" PM offsets. ");
+#ifdef CONFIG_EVA
+ OFFSET(SSS_SEGCTL0, mips_static_suspend_state, segctl[0]);
+ OFFSET(SSS_SEGCTL1, mips_static_suspend_state, segctl[1]);
+ OFFSET(SSS_SEGCTL2, mips_static_suspend_state, segctl[2]);
+#endif
+ OFFSET(SSS_SP, mips_static_suspend_state, sp);
+ BLANK();
+}
+#endif
+
+void output_kvm_defines(void)
+{
+ COMMENT(" KVM/MIPS Specfic offsets. ");
+ DEFINE(VCPU_ARCH_SIZE, sizeof(struct kvm_vcpu_arch));
+ OFFSET(VCPU_RUN, kvm_vcpu, run);
+ OFFSET(VCPU_HOST_ARCH, kvm_vcpu, arch);
+
+ OFFSET(VCPU_HOST_EBASE, kvm_vcpu_arch, host_ebase);
+ OFFSET(VCPU_GUEST_EBASE, kvm_vcpu_arch, guest_ebase);
+
+ OFFSET(VCPU_HOST_STACK, kvm_vcpu_arch, host_stack);
+ OFFSET(VCPU_HOST_GP, kvm_vcpu_arch, host_gp);
+
+ OFFSET(VCPU_HOST_CP0_BADVADDR, kvm_vcpu_arch, host_cp0_badvaddr);
+ OFFSET(VCPU_HOST_CP0_CAUSE, kvm_vcpu_arch, host_cp0_cause);
+ OFFSET(VCPU_HOST_EPC, kvm_vcpu_arch, host_cp0_epc);
+ OFFSET(VCPU_HOST_ENTRYHI, kvm_vcpu_arch, host_cp0_entryhi);
+
+ OFFSET(VCPU_GUEST_INST, kvm_vcpu_arch, guest_inst);
+
+ OFFSET(VCPU_R0, kvm_vcpu_arch, gprs[0]);
+ OFFSET(VCPU_R1, kvm_vcpu_arch, gprs[1]);
+ OFFSET(VCPU_R2, kvm_vcpu_arch, gprs[2]);
+ OFFSET(VCPU_R3, kvm_vcpu_arch, gprs[3]);
+ OFFSET(VCPU_R4, kvm_vcpu_arch, gprs[4]);
+ OFFSET(VCPU_R5, kvm_vcpu_arch, gprs[5]);
+ OFFSET(VCPU_R6, kvm_vcpu_arch, gprs[6]);
+ OFFSET(VCPU_R7, kvm_vcpu_arch, gprs[7]);
+ OFFSET(VCPU_R8, kvm_vcpu_arch, gprs[8]);
+ OFFSET(VCPU_R9, kvm_vcpu_arch, gprs[9]);
+ OFFSET(VCPU_R10, kvm_vcpu_arch, gprs[10]);
+ OFFSET(VCPU_R11, kvm_vcpu_arch, gprs[11]);
+ OFFSET(VCPU_R12, kvm_vcpu_arch, gprs[12]);
+ OFFSET(VCPU_R13, kvm_vcpu_arch, gprs[13]);
+ OFFSET(VCPU_R14, kvm_vcpu_arch, gprs[14]);
+ OFFSET(VCPU_R15, kvm_vcpu_arch, gprs[15]);
+ OFFSET(VCPU_R16, kvm_vcpu_arch, gprs[16]);
+ OFFSET(VCPU_R17, kvm_vcpu_arch, gprs[17]);
+ OFFSET(VCPU_R18, kvm_vcpu_arch, gprs[18]);
+ OFFSET(VCPU_R19, kvm_vcpu_arch, gprs[19]);
+ OFFSET(VCPU_R20, kvm_vcpu_arch, gprs[20]);
+ OFFSET(VCPU_R21, kvm_vcpu_arch, gprs[21]);
+ OFFSET(VCPU_R22, kvm_vcpu_arch, gprs[22]);
+ OFFSET(VCPU_R23, kvm_vcpu_arch, gprs[23]);
+ OFFSET(VCPU_R24, kvm_vcpu_arch, gprs[24]);
+ OFFSET(VCPU_R25, kvm_vcpu_arch, gprs[25]);
+ OFFSET(VCPU_R26, kvm_vcpu_arch, gprs[26]);
+ OFFSET(VCPU_R27, kvm_vcpu_arch, gprs[27]);
+ OFFSET(VCPU_R28, kvm_vcpu_arch, gprs[28]);
+ OFFSET(VCPU_R29, kvm_vcpu_arch, gprs[29]);
+ OFFSET(VCPU_R30, kvm_vcpu_arch, gprs[30]);
+ OFFSET(VCPU_R31, kvm_vcpu_arch, gprs[31]);
+ OFFSET(VCPU_LO, kvm_vcpu_arch, lo);
+ OFFSET(VCPU_HI, kvm_vcpu_arch, hi);
+ OFFSET(VCPU_PC, kvm_vcpu_arch, pc);
+ OFFSET(VCPU_COP0, kvm_vcpu_arch, cop0);
+ OFFSET(VCPU_GUEST_KERNEL_ASID, kvm_vcpu_arch, guest_kernel_asid);
+ OFFSET(VCPU_GUEST_USER_ASID, kvm_vcpu_arch, guest_user_asid);
+
+ OFFSET(COP0_TLB_HI, mips_coproc, reg[MIPS_CP0_TLB_HI][0]);
+ OFFSET(COP0_STATUS, mips_coproc, reg[MIPS_CP0_STATUS][0]);
+ BLANK();
+}
+
+#ifdef CONFIG_MIPS_CPS
+void output_cps_defines(void)
+{
+ COMMENT(" MIPS CPS offsets. ");
+
+ OFFSET(COREBOOTCFG_VPEMASK, core_boot_config, vpe_mask);
+ OFFSET(COREBOOTCFG_VPECONFIG, core_boot_config, vpe_config);
+ DEFINE(COREBOOTCFG_SIZE, sizeof(struct core_boot_config));
+
+ OFFSET(VPEBOOTCFG_PC, vpe_boot_config, pc);
+ OFFSET(VPEBOOTCFG_SP, vpe_boot_config, sp);
+ OFFSET(VPEBOOTCFG_GP, vpe_boot_config, gp);
+ DEFINE(VPEBOOTCFG_SIZE, sizeof(struct vpe_boot_config));
+}
+#endif
diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c
index e06f777e9c4..1188e00bb12 100644
--- a/arch/mips/kernel/binfmt_elfn32.c
+++ b/arch/mips/kernel/binfmt_elfn32.c
@@ -119,4 +119,15 @@ MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)");
#undef TASK_SIZE
#define TASK_SIZE TASK_SIZE32
+#undef cputime_to_timeval
+#define cputime_to_timeval cputime_to_compat_timeval
+static __inline__ void
+cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
+{
+ unsigned long jiffies = cputime_to_jiffies(cputime);
+
+ value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
+ value->tv_sec = jiffies / HZ;
+}
+
#include "../../../fs/binfmt_elf.c"
diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c
index 556a4357d7f..7faf5f2bee2 100644
--- a/arch/mips/kernel/binfmt_elfo32.c
+++ b/arch/mips/kernel/binfmt_elfo32.c
@@ -28,6 +28,18 @@ typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
/*
+ * In order to be sure that we don't attempt to execute an O32 binary which
+ * requires 64 bit FP (FR=1) on a system which does not support it we refuse
+ * to execute any binary which has bits specified by the following macro set
+ * in its ELF header flags.
+ */
+#ifdef CONFIG_MIPS_O32_FP64_SUPPORT
+# define __MIPS_O32_FP64_MUST_BE_ZERO 0
+#else
+# define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64
+#endif
+
+/*
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch(hdr) \
@@ -44,11 +56,17 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
__res = 0; \
+ if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \
+ __res = 0; \
\
__res; \
})
+#ifdef CONFIG_KVM_GUEST
+#define TASK32_SIZE 0x3fff8000UL
+#else
#define TASK32_SIZE 0x7fff8000UL
+#endif
#undef ELF_ET_DYN_BASE
#define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2)
@@ -158,4 +176,15 @@ MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)");
#undef TASK_SIZE
#define TASK_SIZE TASK_SIZE32
+#undef cputime_to_timeval
+#define cputime_to_timeval cputime_to_compat_timeval
+static __inline__ void
+cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
+{
+ unsigned long jiffies = cputime_to_jiffies(cputime);
+
+ value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
+ value->tv_sec = jiffies / HZ;
+}
+
#include "../../../fs/binfmt_elf.c"
diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S
index 64c4fd62cf0..290c23b5167 100644
--- a/arch/mips/kernel/bmips_vec.S
+++ b/arch/mips/kernel/bmips_vec.S
@@ -8,11 +8,11 @@
* Reset/NMI/re-entry vectors for BMIPS processors
*/
-#include <linux/init.h>
#include <asm/asm.h>
#include <asm/asmmacro.h>
#include <asm/cacheops.h>
+#include <asm/cpu.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
@@ -28,8 +28,6 @@
.set mips0
.endm
- __CPUINIT
-
/***********************************************************************
* Alternate CPU1 startup vector for BMIPS4350
*
@@ -56,7 +54,11 @@ LEAF(bmips_smp_movevec)
/* set up CPU1 CBR; move BASE to 0xa000_0000 */
li k0, 0xff400000
mtc0 k0, $22, 6
- li k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_1
+ /* set up relocation vector address based on thread ID */
+ mfc0 k1, $22, 3
+ srl k1, 16
+ andi k1, 0x8000
+ or k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_0
or k0, k1
li k1, 0xa0080000
sw k1, 0(k0)
@@ -89,12 +91,18 @@ NESTED(bmips_reset_nmi_vec, PT_SIZE, sp)
beqz k0, bmips_smp_entry
#if defined(CONFIG_CPU_BMIPS5000)
+ mfc0 k0, CP0_PRID
+ li k1, PRID_IMP_BMIPS5000
+ andi k0, 0xff00
+ bne k0, k1, 1f
+
/* if we're not on core 0, this must be the SMP boot signal */
li k1, (3 << 25)
mfc0 k0, $22
and k0, k1
bnez k0, bmips_smp_entry
-#endif
+1:
+#endif /* CONFIG_CPU_BMIPS5000 */
#endif /* CONFIG_SMP */
/* nope, it's just a regular NMI */
@@ -114,7 +122,7 @@ NESTED(bmips_reset_nmi_vec, PT_SIZE, sp)
jr k0
RESTORE_ALL
- .set mips3
+ .set arch=r4000
eret
/***********************************************************************
@@ -137,7 +145,12 @@ bmips_smp_entry:
xori k0, 0x04
mtc0 k0, CP0_CONFIG
+ mfc0 k0, CP0_PRID
+ andi k0, 0xff00
#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
+ li k1, PRID_IMP_BMIPS43XX
+ bne k0, k1, 2f
+
/* initialize CPU1's local I-cache */
li k0, 0x80000000
li k1, 0x80010000
@@ -148,14 +161,21 @@ bmips_smp_entry:
1: cache Index_Store_Tag_I, 0(k0)
addiu k0, 16
bne k0, k1, 1b
-#elif defined(CONFIG_CPU_BMIPS5000)
+
+ b 3f
+2:
+#endif /* CONFIG_CPU_BMIPS4350 || CONFIG_CPU_BMIPS4380 */
+#if defined(CONFIG_CPU_BMIPS5000)
/* set exception vector base */
+ li k1, PRID_IMP_BMIPS5000
+ bne k0, k1, 3f
+
la k0, ebase
lw k0, 0(k0)
mtc0 k0, $15, 1
BARRIER
-#endif
-
+#endif /* CONFIG_CPU_BMIPS5000 */
+3:
/* jump back to kseg0 in case we need to remap the kseg1 area */
la k0, 1f
jr k0
@@ -216,13 +236,21 @@ END(bmips_smp_int_vec)
* Certain CPUs support extending kseg0 to 1024MB.
***********************************************************************/
- __CPUINIT
-
LEAF(bmips_enable_xks01)
#if defined(CONFIG_XKS01)
-
+ mfc0 t0, CP0_PRID
+ andi t2, t0, 0xff00
#if defined(CONFIG_CPU_BMIPS4380)
+ li t1, PRID_IMP_BMIPS43XX
+ bne t2, t1, 1f
+
+ andi t0, 0xff
+ addiu t1, t0, -PRID_REV_BMIPS4380_HI
+ bgtz t1, 2f
+ addiu t0, -PRID_REV_BMIPS4380_LO
+ bltz t0, 2f
+
mfc0 t0, $22, 3
li t1, 0x1ff0
li t2, (1 << 12) | (1 << 9)
@@ -231,7 +259,13 @@ LEAF(bmips_enable_xks01)
or t0, t2
mtc0 t0, $22, 3
BARRIER
-#elif defined(CONFIG_CPU_BMIPS5000)
+ b 2f
+1:
+#endif /* CONFIG_CPU_BMIPS4380 */
+#if defined(CONFIG_CPU_BMIPS5000)
+ li t1, PRID_IMP_BMIPS5000
+ bne t2, t1, 2f
+
mfc0 t0, $22, 5
li t1, 0x01ff
li t2, (1 << 8) | (1 << 5)
@@ -240,12 +274,8 @@ LEAF(bmips_enable_xks01)
or t0, t2
mtc0 t0, $22, 5
BARRIER
-#else
-
-#error Missing XKS01 setup
-
-#endif
-
+#endif /* CONFIG_CPU_BMIPS5000 */
+2:
#endif /* defined(CONFIG_XKS01) */
jr ra
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c
index 83ffe950f71..7b2df224f04 100644
--- a/arch/mips/kernel/branch.c
+++ b/arch/mips/kernel/branch.c
@@ -14,10 +14,382 @@
#include <asm/cpu.h>
#include <asm/cpu-features.h>
#include <asm/fpu.h>
+#include <asm/fpu_emulator.h>
#include <asm/inst.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
+/*
+ * Calculate and return exception PC in case of branch delay slot
+ * for microMIPS and MIPS16e. It does not clear the ISA mode bit.
+ */
+int __isa_exception_epc(struct pt_regs *regs)
+{
+ unsigned short inst;
+ long epc = regs->cp0_epc;
+
+ /* Calculate exception PC in branch delay slot. */
+ if (__get_user(inst, (u16 __user *) msk_isa16_mode(epc))) {
+ /* This should never happen because delay slot was checked. */
+ force_sig(SIGSEGV, current);
+ return epc;
+ }
+ if (cpu_has_mips16) {
+ if (((union mips16e_instruction)inst).ri.opcode
+ == MIPS16e_jal_op)
+ epc += 4;
+ else
+ epc += 2;
+ } else if (mm_insn_16bit(inst))
+ epc += 2;
+ else
+ epc += 4;
+
+ return epc;
+}
+
+/* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */
+static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7};
+
+int __mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
+ unsigned long *contpc)
+{
+ union mips_instruction insn = (union mips_instruction)dec_insn.insn;
+ int bc_false = 0;
+ unsigned int fcr31;
+ unsigned int bit;
+
+ if (!cpu_has_mmips)
+ return 0;
+
+ switch (insn.mm_i_format.opcode) {
+ case mm_pool32a_op:
+ if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) ==
+ mm_pool32axf_op) {
+ switch (insn.mm_i_format.simmediate >>
+ MM_POOL32A_MINOR_SHIFT) {
+ case mm_jalr_op:
+ case mm_jalrhb_op:
+ case mm_jalrs_op:
+ case mm_jalrshb_op:
+ if (insn.mm_i_format.rt != 0) /* Not mm_jr */
+ regs->regs[insn.mm_i_format.rt] =
+ regs->cp0_epc +
+ dec_insn.pc_inc +
+ dec_insn.next_pc_inc;
+ *contpc = regs->regs[insn.mm_i_format.rs];
+ return 1;
+ }
+ }
+ break;
+ case mm_pool32i_op:
+ switch (insn.mm_i_format.rt) {
+ case mm_bltzals_op:
+ case mm_bltzal_op:
+ regs->regs[31] = regs->cp0_epc +
+ dec_insn.pc_inc +
+ dec_insn.next_pc_inc;
+ /* Fall through */
+ case mm_bltz_op:
+ if ((long)regs->regs[insn.mm_i_format.rs] < 0)
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ (insn.mm_i_format.simmediate << 1);
+ else
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ dec_insn.next_pc_inc;
+ return 1;
+ case mm_bgezals_op:
+ case mm_bgezal_op:
+ regs->regs[31] = regs->cp0_epc +
+ dec_insn.pc_inc +
+ dec_insn.next_pc_inc;
+ /* Fall through */
+ case mm_bgez_op:
+ if ((long)regs->regs[insn.mm_i_format.rs] >= 0)
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ (insn.mm_i_format.simmediate << 1);
+ else
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ dec_insn.next_pc_inc;
+ return 1;
+ case mm_blez_op:
+ if ((long)regs->regs[insn.mm_i_format.rs] <= 0)
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ (insn.mm_i_format.simmediate << 1);
+ else
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ dec_insn.next_pc_inc;
+ return 1;
+ case mm_bgtz_op:
+ if ((long)regs->regs[insn.mm_i_format.rs] <= 0)
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ (insn.mm_i_format.simmediate << 1);
+ else
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ dec_insn.next_pc_inc;
+ return 1;
+ case mm_bc2f_op:
+ case mm_bc1f_op:
+ bc_false = 1;
+ /* Fall through */
+ case mm_bc2t_op:
+ case mm_bc1t_op:
+ preempt_disable();
+ if (is_fpu_owner())
+ asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
+ else
+ fcr31 = current->thread.fpu.fcr31;
+ preempt_enable();
+
+ if (bc_false)
+ fcr31 = ~fcr31;
+
+ bit = (insn.mm_i_format.rs >> 2);
+ bit += (bit != 0);
+ bit += 23;
+ if (fcr31 & (1 << bit))
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ (insn.mm_i_format.simmediate << 1);
+ else
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc + dec_insn.next_pc_inc;
+ return 1;
+ }
+ break;
+ case mm_pool16c_op:
+ switch (insn.mm_i_format.rt) {
+ case mm_jalr16_op:
+ case mm_jalrs16_op:
+ regs->regs[31] = regs->cp0_epc +
+ dec_insn.pc_inc + dec_insn.next_pc_inc;
+ /* Fall through */
+ case mm_jr16_op:
+ *contpc = regs->regs[insn.mm_i_format.rs];
+ return 1;
+ }
+ break;
+ case mm_beqz16_op:
+ if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0)
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ (insn.mm_b1_format.simmediate << 1);
+ else
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc + dec_insn.next_pc_inc;
+ return 1;
+ case mm_bnez16_op:
+ if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0)
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ (insn.mm_b1_format.simmediate << 1);
+ else
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc + dec_insn.next_pc_inc;
+ return 1;
+ case mm_b16_op:
+ *contpc = regs->cp0_epc + dec_insn.pc_inc +
+ (insn.mm_b0_format.simmediate << 1);
+ return 1;
+ case mm_beq32_op:
+ if (regs->regs[insn.mm_i_format.rs] ==
+ regs->regs[insn.mm_i_format.rt])
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ (insn.mm_i_format.simmediate << 1);
+ else
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ dec_insn.next_pc_inc;
+ return 1;
+ case mm_bne32_op:
+ if (regs->regs[insn.mm_i_format.rs] !=
+ regs->regs[insn.mm_i_format.rt])
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc +
+ (insn.mm_i_format.simmediate << 1);
+ else
+ *contpc = regs->cp0_epc +
+ dec_insn.pc_inc + dec_insn.next_pc_inc;
+ return 1;
+ case mm_jalx32_op:
+ regs->regs[31] = regs->cp0_epc +
+ dec_insn.pc_inc + dec_insn.next_pc_inc;
+ *contpc = regs->cp0_epc + dec_insn.pc_inc;
+ *contpc >>= 28;
+ *contpc <<= 28;
+ *contpc |= (insn.j_format.target << 2);
+ return 1;
+ case mm_jals32_op:
+ case mm_jal32_op:
+ regs->regs[31] = regs->cp0_epc +
+ dec_insn.pc_inc + dec_insn.next_pc_inc;
+ /* Fall through */
+ case mm_j32_op:
+ *contpc = regs->cp0_epc + dec_insn.pc_inc;
+ *contpc >>= 27;
+ *contpc <<= 27;
+ *contpc |= (insn.j_format.target << 1);
+ set_isa16_mode(*contpc);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Compute return address and emulate branch in microMIPS mode after an
+ * exception only. It does not handle compact branches/jumps and cannot
+ * be used in interrupt context. (Compact branches/jumps do not cause
+ * exceptions.)
+ */
+int __microMIPS_compute_return_epc(struct pt_regs *regs)
+{
+ u16 __user *pc16;
+ u16 halfword;
+ unsigned int word;
+ unsigned long contpc;
+ struct mm_decoded_insn mminsn = { 0 };
+
+ mminsn.micro_mips_mode = 1;
+
+ /* This load never faults. */
+ pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
+ __get_user(halfword, pc16);
+ pc16++;
+ contpc = regs->cp0_epc + 2;
+ word = ((unsigned int)halfword << 16);
+ mminsn.pc_inc = 2;
+
+ if (!mm_insn_16bit(halfword)) {
+ __get_user(halfword, pc16);
+ pc16++;
+ contpc = regs->cp0_epc + 4;
+ mminsn.pc_inc = 4;
+ word |= halfword;
+ }
+ mminsn.insn = word;
+
+ if (get_user(halfword, pc16))
+ goto sigsegv;
+ mminsn.next_pc_inc = 2;
+ word = ((unsigned int)halfword << 16);
+
+ if (!mm_insn_16bit(halfword)) {
+ pc16++;
+ if (get_user(halfword, pc16))
+ goto sigsegv;
+ mminsn.next_pc_inc = 4;
+ word |= halfword;
+ }
+ mminsn.next_insn = word;
+
+ mm_isBranchInstr(regs, mminsn, &contpc);
+
+ regs->cp0_epc = contpc;
+
+ return 0;
+
+sigsegv:
+ force_sig(SIGSEGV, current);
+ return -EFAULT;
+}
+
+/*
+ * Compute return address and emulate branch in MIPS16e mode after an
+ * exception only. It does not handle compact branches/jumps and cannot
+ * be used in interrupt context. (Compact branches/jumps do not cause
+ * exceptions.)
+ */
+int __MIPS16e_compute_return_epc(struct pt_regs *regs)
+{
+ u16 __user *addr;
+ union mips16e_instruction inst;
+ u16 inst2;
+ u32 fullinst;
+ long epc;
+
+ epc = regs->cp0_epc;
+
+ /* Read the instruction. */
+ addr = (u16 __user *)msk_isa16_mode(epc);
+ if (__get_user(inst.full, addr)) {
+ force_sig(SIGSEGV, current);
+ return -EFAULT;
+ }
+
+ switch (inst.ri.opcode) {
+ case MIPS16e_extend_op:
+ regs->cp0_epc += 4;
+ return 0;
+
+ /*
+ * JAL and JALX in MIPS16e mode
+ */
+ case MIPS16e_jal_op:
+ addr += 1;
+ if (__get_user(inst2, addr)) {
+ force_sig(SIGSEGV, current);
+ return -EFAULT;
+ }
+ fullinst = ((unsigned)inst.full << 16) | inst2;
+ regs->regs[31] = epc + 6;
+ epc += 4;
+ epc >>= 28;
+ epc <<= 28;
+ /*
+ * JAL:5 X:1 TARGET[20-16]:5 TARGET[25:21]:5 TARGET[15:0]:16
+ *
+ * ......TARGET[15:0].................TARGET[20:16]...........
+ * ......TARGET[25:21]
+ */
+ epc |=
+ ((fullinst & 0xffff) << 2) | ((fullinst & 0x3e00000) >> 3) |
+ ((fullinst & 0x1f0000) << 7);
+ if (!inst.jal.x)
+ set_isa16_mode(epc); /* Set ISA mode bit. */
+ regs->cp0_epc = epc;
+ return 0;
+
+ /*
+ * J(AL)R(C)
+ */
+ case MIPS16e_rr_op:
+ if (inst.rr.func == MIPS16e_jr_func) {
+
+ if (inst.rr.ra)
+ regs->cp0_epc = regs->regs[31];
+ else
+ regs->cp0_epc =
+ regs->regs[reg16to32[inst.rr.rx]];
+
+ if (inst.rr.l) {
+ if (inst.rr.nd)
+ regs->regs[31] = epc + 2;
+ else
+ regs->regs[31] = epc + 4;
+ }
+ return 0;
+ }
+ break;
+ }
+
+ /*
+ * All other cases have no branch delay slot and are 16-bits.
+ * Branches do not cause an exception.
+ */
+ regs->cp0_epc += 2;
+
+ return 0;
+}
+
/**
* __compute_return_epc_for_insn - Computes the return address and do emulate
* branch simulation, if required.
@@ -129,6 +501,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
epc <<= 28;
epc |= (insn.j_format.target << 2);
regs->cp0_epc = epc;
+ if (insn.i_format.opcode == jalx_op)
+ set_isa16_mode(regs->cp0_epc);
break;
/*
@@ -139,7 +513,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
if (regs->regs[insn.i_format.rs] ==
regs->regs[insn.i_format.rt]) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
- if (insn.i_format.rt == beql_op)
+ if (insn.i_format.opcode == beql_op)
ret = BRANCH_LIKELY_TAKEN;
} else
epc += 8;
@@ -151,7 +525,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
if (regs->regs[insn.i_format.rs] !=
regs->regs[insn.i_format.rt]) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
- if (insn.i_format.rt == bnel_op)
+ if (insn.i_format.opcode == bnel_op)
ret = BRANCH_LIKELY_TAKEN;
} else
epc += 8;
@@ -163,7 +537,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
/* rt field assumed to be zero */
if ((long)regs->regs[insn.i_format.rs] <= 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
- if (insn.i_format.rt == bnel_op)
+ if (insn.i_format.opcode == blezl_op)
ret = BRANCH_LIKELY_TAKEN;
} else
epc += 8;
@@ -175,7 +549,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
/* rt field assumed to be zero */
if ((long)regs->regs[insn.i_format.rs] > 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
- if (insn.i_format.rt == bnel_op)
+ if (insn.i_format.opcode == bgtzl_op)
ret = BRANCH_LIKELY_TAKEN;
} else
epc += 8;
@@ -188,7 +562,11 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
case cop1_op:
preempt_disable();
if (is_fpu_owner())
- asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
+ asm volatile(
+ ".set push\n"
+ "\t.set mips1\n"
+ "\tcfc1\t%0,$31\n"
+ "\t.set pop" : "=r" (fcr31));
else
fcr31 = current->thread.fpu.fcr31;
preempt_enable();
@@ -289,5 +667,4 @@ unaligned:
printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
force_sig(SIGBUS, current);
return -EFAULT;
-
}
diff --git a/arch/mips/kernel/cevt-bcm1480.c b/arch/mips/kernel/cevt-bcm1480.c
index 15f618b40cf..7976457184b 100644
--- a/arch/mips/kernel/cevt-bcm1480.c
+++ b/arch/mips/kernel/cevt-bcm1480.c
@@ -109,7 +109,7 @@ static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
-void __cpuinit sb1480_clockevent_init(void)
+void sb1480_clockevent_init(void)
{
unsigned int cpu = smp_processor_id();
unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu;
diff --git a/arch/mips/kernel/cevt-gic.c b/arch/mips/kernel/cevt-gic.c
new file mode 100644
index 00000000000..6093716980b
--- /dev/null
+++ b/arch/mips/kernel/cevt-gic.c
@@ -0,0 +1,105 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ */
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+
+#include <asm/time.h>
+#include <asm/gic.h>
+#include <asm/mips-boards/maltaint.h>
+
+DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device);
+int gic_timer_irq_installed;
+
+
+static int gic_next_event(unsigned long delta, struct clock_event_device *evt)
+{
+ u64 cnt;
+ int res;
+
+ cnt = gic_read_count();
+ cnt += (u64)delta;
+ gic_write_cpu_compare(cnt, cpumask_first(evt->cpumask));
+ res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0;
+ return res;
+}
+
+void gic_set_clock_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ /* Nothing to do ... */
+}
+
+irqreturn_t gic_compare_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd;
+ int cpu = smp_processor_id();
+
+ gic_write_compare(gic_read_compare());
+ cd = &per_cpu(gic_clockevent_device, cpu);
+ cd->event_handler(cd);
+ return IRQ_HANDLED;
+}
+
+struct irqaction gic_compare_irqaction = {
+ .handler = gic_compare_interrupt,
+ .flags = IRQF_PERCPU | IRQF_TIMER,
+ .name = "timer",
+};
+
+
+void gic_event_handler(struct clock_event_device *dev)
+{
+}
+
+int gic_clockevent_init(void)
+{
+ unsigned int cpu = smp_processor_id();
+ struct clock_event_device *cd;
+ unsigned int irq;
+
+ if (!cpu_has_counter || !gic_frequency)
+ return -ENXIO;
+
+ irq = MIPS_GIC_IRQ_BASE;
+
+ cd = &per_cpu(gic_clockevent_device, cpu);
+
+ cd->name = "MIPS GIC";
+ cd->features = CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_C3STOP;
+
+ clockevent_set_clock(cd, gic_frequency);
+
+ /* Calculate the min / max delta */
+ cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
+ cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
+
+ cd->rating = 300;
+ cd->irq = irq;
+ cd->cpumask = cpumask_of(cpu);
+ cd->set_next_event = gic_next_event;
+ cd->set_mode = gic_set_clock_mode;
+ cd->event_handler = gic_event_handler;
+
+ clockevents_register_device(cd);
+
+ GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP), 0x80000002);
+ GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK);
+
+ if (gic_timer_irq_installed)
+ return 0;
+
+ gic_timer_irq_installed = 1;
+
+ setup_irq(irq, &gic_compare_irqaction);
+ irq_set_handler(irq, handle_percpu_irq);
+ return 0;
+}
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 07b847d77f5..bc127e22fda 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -12,18 +12,10 @@
#include <linux/smp.h>
#include <linux/irq.h>
-#include <asm/smtc_ipi.h>
#include <asm/time.h>
#include <asm/cevt-r4k.h>
#include <asm/gic.h>
-/*
- * The SMTC Kernel for the 34K, 1004K, et. al. replaces several
- * of these routines with SMTC-specific variants.
- */
-
-#ifndef CONFIG_MIPS_MT_SMTC
-
static int mips_next_event(unsigned long delta,
struct clock_event_device *evt)
{
@@ -37,8 +29,6 @@ static int mips_next_event(unsigned long delta,
return res;
}
-#endif /* CONFIG_MIPS_MT_SMTC */
-
void mips_set_clock_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
@@ -48,8 +38,6 @@ void mips_set_clock_mode(enum clock_event_mode mode,
DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device);
int cp0_timer_irq_installed;
-#ifndef CONFIG_MIPS_MT_SMTC
-
irqreturn_t c0_compare_interrupt(int irq, void *dev_id)
{
const int r2 = cpu_has_mips_r2;
@@ -81,8 +69,6 @@ out:
return IRQ_HANDLED;
}
-#endif /* Not CONFIG_MIPS_MT_SMTC */
-
struct irqaction c0_compare_irqaction = {
.handler = c0_compare_interrupt,
.flags = IRQF_PERCPU | IRQF_TIMER,
@@ -118,6 +104,10 @@ int c0_compare_int_usable(void)
unsigned int delta;
unsigned int cnt;
+#ifdef CONFIG_KVM_GUEST
+ return 1;
+#endif
+
/*
* IP7 already pending? Try to clear it by acking the timer.
*/
@@ -165,9 +155,7 @@ int c0_compare_int_usable(void)
return 1;
}
-#ifndef CONFIG_MIPS_MT_SMTC
-
-int __cpuinit r4k_clockevent_init(void)
+int r4k_clockevent_init(void)
{
unsigned int cpu = smp_processor_id();
struct clock_event_device *cd;
@@ -191,7 +179,9 @@ int __cpuinit r4k_clockevent_init(void)
cd = &per_cpu(mips_clockevent_device, cpu);
cd->name = "MIPS";
- cd->features = CLOCK_EVT_FEAT_ONESHOT;
+ cd->features = CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_C3STOP |
+ CLOCK_EVT_FEAT_PERCPU;
clockevent_set_clock(cd, mips_hpt_frequency);
@@ -218,4 +208,3 @@ int __cpuinit r4k_clockevent_init(void)
return 0;
}
-#endif /* Not CONFIG_MIPS_MT_SMTC */
diff --git a/arch/mips/kernel/cevt-sb1250.c b/arch/mips/kernel/cevt-sb1250.c
index 200f2778bf3..5ea6d6b1de1 100644
--- a/arch/mips/kernel/cevt-sb1250.c
+++ b/arch/mips/kernel/cevt-sb1250.c
@@ -107,7 +107,7 @@ static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
-void __cpuinit sb1250_clockevent_init(void)
+void sb1250_clockevent_init(void)
{
unsigned int cpu = smp_processor_id();
unsigned int irq = K_INT_TIMER_0 + cpu;
diff --git a/arch/mips/kernel/cevt-smtc.c b/arch/mips/kernel/cevt-smtc.c
deleted file mode 100644
index 9de5ed7ef1a..00000000000
--- a/arch/mips/kernel/cevt-smtc.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2007 MIPS Technologies, Inc.
- * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org>
- * Copyright (C) 2008 Kevin D. Kissell, Paralogos sarl
- */
-#include <linux/clockchips.h>
-#include <linux/interrupt.h>
-#include <linux/percpu.h>
-#include <linux/smp.h>
-#include <linux/irq.h>
-
-#include <asm/smtc_ipi.h>
-#include <asm/time.h>
-#include <asm/cevt-r4k.h>
-
-/*
- * Variant clock event timer support for SMTC on MIPS 34K, 1004K
- * or other MIPS MT cores.
- *
- * Notes on SMTC Support:
- *
- * SMTC has multiple microthread TCs pretending to be Linux CPUs.
- * But there's only one Count/Compare pair per VPE, and Compare
- * interrupts are taken opportunisitically by available TCs
- * bound to the VPE with the Count register. The new timer
- * framework provides for global broadcasts, but we really
- * want VPE-level multicasts for best behavior. So instead
- * of invoking the high-level clock-event broadcast code,
- * this version of SMTC support uses the historical SMTC
- * multicast mechanisms "under the hood", appearing to the
- * generic clock layer as if the interrupts are per-CPU.
- *
- * The approach taken here is to maintain a set of NR_CPUS
- * virtual timers, and track which "CPU" needs to be alerted
- * at each event.
- *
- * It's unlikely that we'll see a MIPS MT core with more than
- * 2 VPEs, but we *know* that we won't need to handle more
- * VPEs than we have "CPUs". So NCPUs arrays of NCPUs elements
- * is always going to be overkill, but always going to be enough.
- */
-
-unsigned long smtc_nexttime[NR_CPUS][NR_CPUS];
-static int smtc_nextinvpe[NR_CPUS];
-
-/*
- * Timestamps stored are absolute values to be programmed
- * into Count register. Valid timestamps will never be zero.
- * If a Zero Count value is actually calculated, it is converted
- * to be a 1, which will introduce 1 or two CPU cycles of error
- * roughly once every four billion events, which at 1000 HZ means
- * about once every 50 days. If that's actually a problem, one
- * could alternate squashing 0 to 1 and to -1.
- */
-
-#define MAKEVALID(x) (((x) == 0L) ? 1L : (x))
-#define ISVALID(x) ((x) != 0L)
-
-/*
- * Time comparison is subtle, as it's really truncated
- * modular arithmetic.
- */
-
-#define IS_SOONER(a, b, reference) \
- (((a) - (unsigned long)(reference)) < ((b) - (unsigned long)(reference)))
-
-/*
- * CATCHUP_INCREMENT, used when the function falls behind the counter.
- * Could be an increasing function instead of a constant;
- */
-
-#define CATCHUP_INCREMENT 64
-
-static int mips_next_event(unsigned long delta,
- struct clock_event_device *evt)
-{
- unsigned long flags;
- unsigned int mtflags;
- unsigned long timestamp, reference, previous;
- unsigned long nextcomp = 0L;
- int vpe = current_cpu_data.vpe_id;
- int cpu = smp_processor_id();
- local_irq_save(flags);
- mtflags = dmt();
-
- /*
- * Maintain the per-TC virtual timer
- * and program the per-VPE shared Count register
- * as appropriate here...
- */
- reference = (unsigned long)read_c0_count();
- timestamp = MAKEVALID(reference + delta);
- /*
- * To really model the clock, we have to catch the case
- * where the current next-in-VPE timestamp is the old
- * timestamp for the calling CPE, but the new value is
- * in fact later. In that case, we have to do a full
- * scan and discover the new next-in-VPE CPU id and
- * timestamp.
- */
- previous = smtc_nexttime[vpe][cpu];
- if (cpu == smtc_nextinvpe[vpe] && ISVALID(previous)
- && IS_SOONER(previous, timestamp, reference)) {
- int i;
- int soonest = cpu;
-
- /*
- * Update timestamp array here, so that new
- * value gets considered along with those of
- * other virtual CPUs on the VPE.
- */
- smtc_nexttime[vpe][cpu] = timestamp;
- for_each_online_cpu(i) {
- if (ISVALID(smtc_nexttime[vpe][i])
- && IS_SOONER(smtc_nexttime[vpe][i],
- smtc_nexttime[vpe][soonest], reference)) {
- soonest = i;
- }
- }
- smtc_nextinvpe[vpe] = soonest;
- nextcomp = smtc_nexttime[vpe][soonest];
- /*
- * Otherwise, we don't have to process the whole array rank,
- * we just have to see if the event horizon has gotten closer.
- */
- } else {
- if (!ISVALID(smtc_nexttime[vpe][smtc_nextinvpe[vpe]]) ||
- IS_SOONER(timestamp,
- smtc_nexttime[vpe][smtc_nextinvpe[vpe]], reference)) {
- smtc_nextinvpe[vpe] = cpu;
- nextcomp = timestamp;
- }
- /*
- * Since next-in-VPE may me the same as the executing
- * virtual CPU, we update the array *after* checking
- * its value.
- */
- smtc_nexttime[vpe][cpu] = timestamp;
- }
-
- /*
- * It may be that, in fact, we don't need to update Compare,
- * but if we do, we want to make sure we didn't fall into
- * a crack just behind Count.
- */
- if (ISVALID(nextcomp)) {
- write_c0_compare(nextcomp);
- ehb();
- /*
- * We never return an error, we just make sure
- * that we trigger the handlers as quickly as
- * we can if we fell behind.
- */
- while ((nextcomp - (unsigned long)read_c0_count())
- > (unsigned long)LONG_MAX) {
- nextcomp += CATCHUP_INCREMENT;
- write_c0_compare(nextcomp);
- ehb();
- }
- }
- emt(mtflags);
- local_irq_restore(flags);
- return 0;
-}
-
-
-void smtc_distribute_timer(int vpe)
-{
- unsigned long flags;
- unsigned int mtflags;
- int cpu;
- struct clock_event_device *cd;
- unsigned long nextstamp;
- unsigned long reference;
-
-
-repeat:
- nextstamp = 0L;
- for_each_online_cpu(cpu) {
- /*
- * Find virtual CPUs within the current VPE who have
- * unserviced timer requests whose time is now past.
- */
- local_irq_save(flags);
- mtflags = dmt();
- if (cpu_data[cpu].vpe_id == vpe &&
- ISVALID(smtc_nexttime[vpe][cpu])) {
- reference = (unsigned long)read_c0_count();
- if ((smtc_nexttime[vpe][cpu] - reference)
- > (unsigned long)LONG_MAX) {
- smtc_nexttime[vpe][cpu] = 0L;
- emt(mtflags);
- local_irq_restore(flags);
- /*
- * We don't send IPIs to ourself.
- */
- if (cpu != smp_processor_id()) {
- smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0);
- } else {
- cd = &per_cpu(mips_clockevent_device, cpu);
- cd->event_handler(cd);
- }
- } else {
- /* Local to VPE but Valid Time not yet reached. */
- if (!ISVALID(nextstamp) ||
- IS_SOONER(smtc_nexttime[vpe][cpu], nextstamp,
- reference)) {
- smtc_nextinvpe[vpe] = cpu;
- nextstamp = smtc_nexttime[vpe][cpu];
- }
- emt(mtflags);
- local_irq_restore(flags);
- }
- } else {
- emt(mtflags);
- local_irq_restore(flags);
-
- }
- }
- /* Reprogram for interrupt at next soonest timestamp for VPE */
- if (ISVALID(nextstamp)) {
- write_c0_compare(nextstamp);
- ehb();
- if ((nextstamp - (unsigned long)read_c0_count())
- > (unsigned long)LONG_MAX)
- goto repeat;
- }
-}
-
-
-irqreturn_t c0_compare_interrupt(int irq, void *dev_id)
-{
- int cpu = smp_processor_id();
-
- /* If we're running SMTC, we've got MIPS MT and therefore MIPS32R2 */
- handle_perf_irq(1);
-
- if (read_c0_cause() & (1 << 30)) {
- /* Clear Count/Compare Interrupt */
- write_c0_compare(read_c0_compare());
- smtc_distribute_timer(cpu_data[cpu].vpe_id);
- }
- return IRQ_HANDLED;
-}
-
-
-int __cpuinit smtc_clockevent_init(void)
-{
- uint64_t mips_freq = mips_hpt_frequency;
- unsigned int cpu = smp_processor_id();
- struct clock_event_device *cd;
- unsigned int irq;
- int i;
- int j;
-
- if (!cpu_has_counter || !mips_hpt_frequency)
- return -ENXIO;
- if (cpu == 0) {
- for (i = 0; i < num_possible_cpus(); i++) {
- smtc_nextinvpe[i] = 0;
- for (j = 0; j < num_possible_cpus(); j++)
- smtc_nexttime[i][j] = 0L;
- }
- /*
- * SMTC also can't have the usablility test
- * run by secondary TCs once Compare is in use.
- */
- if (!c0_compare_int_usable())
- return -ENXIO;
- }
-
- /*
- * With vectored interrupts things are getting platform specific.
- * get_c0_compare_int is a hook to allow a platform to return the
- * interrupt number of it's liking.
- */
- irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
- if (get_c0_compare_int)
- irq = get_c0_compare_int();
-
- cd = &per_cpu(mips_clockevent_device, cpu);
-
- cd->name = "MIPS";
- cd->features = CLOCK_EVT_FEAT_ONESHOT;
-
- /* Calculate the min / max delta */
- cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32);
- cd->shift = 32;
- cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
- cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
-
- cd->rating = 300;
- cd->irq = irq;
- cd->cpumask = cpumask_of(cpu);
- cd->set_next_event = mips_next_event;
- cd->set_mode = mips_set_clock_mode;
- cd->event_handler = mips_event_handler;
-
- clockevents_register_device(cd);
-
- /*
- * On SMTC we only want to do the data structure
- * initialization and IRQ setup once.
- */
- if (cpu)
- return 0;
- /*
- * And we need the hwmask associated with the c0_compare
- * vector to be initialized.
- */
- irq_hwmask[irq] = (0x100 << cp0_compare_irq);
- if (cp0_timer_irq_installed)
- return 0;
-
- cp0_timer_irq_installed = 1;
-
- setup_irq(irq, &c0_compare_irqaction);
-
- return 0;
-}
diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S
new file mode 100644
index 00000000000..6f4f739dad9
--- /dev/null
+++ b/arch/mips/kernel/cps-vec.S
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <asm/addrspace.h>
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/asmmacro.h>
+#include <asm/cacheops.h>
+#include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
+#include <asm/pm.h>
+
+#define GCR_CL_COHERENCE_OFS 0x2008
+#define GCR_CL_ID_OFS 0x2028
+
+.extern mips_cm_base
+
+.set noreorder
+
+ /*
+ * Set dest to non-zero if the core supports the MT ASE, else zero. If
+ * MT is not supported then branch to nomt.
+ */
+ .macro has_mt dest, nomt
+ mfc0 \dest, CP0_CONFIG
+ bgez \dest, \nomt
+ mfc0 \dest, CP0_CONFIG, 1
+ bgez \dest, \nomt
+ mfc0 \dest, CP0_CONFIG, 2
+ bgez \dest, \nomt
+ mfc0 \dest, CP0_CONFIG, 3
+ andi \dest, \dest, MIPS_CONF3_MT
+ beqz \dest, \nomt
+ .endm
+
+.section .text.cps-vec
+.balign 0x1000
+
+LEAF(mips_cps_core_entry)
+ /*
+ * These first 12 bytes will be patched by cps_smp_setup to load the
+ * base address of the CM GCRs into register v1 and the CCA to use into
+ * register s0.
+ */
+ .quad 0
+ .word 0
+
+ /* Check whether we're here due to an NMI */
+ mfc0 k0, CP0_STATUS
+ and k0, k0, ST0_NMI
+ beqz k0, not_nmi
+ nop
+
+ /* This is an NMI */
+ la k0, nmi_handler
+ jr k0
+ nop
+
+not_nmi:
+ /* Setup Cause */
+ li t0, CAUSEF_IV
+ mtc0 t0, CP0_CAUSE
+
+ /* Setup Status */
+ li t0, ST0_CU1 | ST0_CU0
+ mtc0 t0, CP0_STATUS
+
+ /*
+ * Clear the bits used to index the caches. Note that the architecture
+ * dictates that writing to any of TagLo or TagHi selects 0 or 2 should
+ * be valid for all MIPS32 CPUs, even those for which said writes are
+ * unnecessary.
+ */
+ mtc0 zero, CP0_TAGLO, 0
+ mtc0 zero, CP0_TAGHI, 0
+ mtc0 zero, CP0_TAGLO, 2
+ mtc0 zero, CP0_TAGHI, 2
+ ehb
+
+ /* Primary cache configuration is indicated by Config1 */
+ mfc0 v0, CP0_CONFIG, 1
+
+ /* Detect I-cache line size */
+ _EXT t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ
+ beqz t0, icache_done
+ li t1, 2
+ sllv t0, t1, t0
+
+ /* Detect I-cache size */
+ _EXT t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ
+ xori t2, t1, 0x7
+ beqz t2, 1f
+ li t3, 32
+ addi t1, t1, 1
+ sllv t1, t3, t1
+1: /* At this point t1 == I-cache sets per way */
+ _EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ
+ addi t2, t2, 1
+ mul t1, t1, t0
+ mul t1, t1, t2
+
+ li a0, KSEG0
+ add a1, a0, t1
+1: cache Index_Store_Tag_I, 0(a0)
+ add a0, a0, t0
+ bne a0, a1, 1b
+ nop
+icache_done:
+
+ /* Detect D-cache line size */
+ _EXT t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ
+ beqz t0, dcache_done
+ li t1, 2
+ sllv t0, t1, t0
+
+ /* Detect D-cache size */
+ _EXT t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ
+ xori t2, t1, 0x7
+ beqz t2, 1f
+ li t3, 32
+ addi t1, t1, 1
+ sllv t1, t3, t1
+1: /* At this point t1 == D-cache sets per way */
+ _EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ
+ addi t2, t2, 1
+ mul t1, t1, t0
+ mul t1, t1, t2
+
+ li a0, KSEG0
+ addu a1, a0, t1
+ subu a1, a1, t0
+1: cache Index_Store_Tag_D, 0(a0)
+ bne a0, a1, 1b
+ add a0, a0, t0
+dcache_done:
+
+ /* Set Kseg0 CCA to that in s0 */
+ mfc0 t0, CP0_CONFIG
+ ori t0, 0x7
+ xori t0, 0x7
+ or t0, t0, s0
+ mtc0 t0, CP0_CONFIG
+ ehb
+
+ /* Enter the coherent domain */
+ li t0, 0xff
+ sw t0, GCR_CL_COHERENCE_OFS(v1)
+ ehb
+
+ /* Jump to kseg0 */
+ la t0, 1f
+ jr t0
+ nop
+
+ /*
+ * We're up, cached & coherent. Perform any further required core-level
+ * initialisation.
+ */
+1: jal mips_cps_core_init
+ nop
+
+ /*
+ * Boot any other VPEs within this core that should be online, and
+ * deactivate this VPE if it should be offline.
+ */
+ jal mips_cps_boot_vpes
+ nop
+
+ /* Off we go! */
+ lw t1, VPEBOOTCFG_PC(v0)
+ lw gp, VPEBOOTCFG_GP(v0)
+ lw sp, VPEBOOTCFG_SP(v0)
+ jr t1
+ nop
+ END(mips_cps_core_entry)
+
+.org 0x200
+LEAF(excep_tlbfill)
+ b .
+ nop
+ END(excep_tlbfill)
+
+.org 0x280
+LEAF(excep_xtlbfill)
+ b .
+ nop
+ END(excep_xtlbfill)
+
+.org 0x300
+LEAF(excep_cache)
+ b .
+ nop
+ END(excep_cache)
+
+.org 0x380
+LEAF(excep_genex)
+ b .
+ nop
+ END(excep_genex)
+
+.org 0x400
+LEAF(excep_intex)
+ b .
+ nop
+ END(excep_intex)
+
+.org 0x480
+LEAF(excep_ejtag)
+ la k0, ejtag_debug_handler
+ jr k0
+ nop
+ END(excep_ejtag)
+
+LEAF(mips_cps_core_init)
+#ifdef CONFIG_MIPS_MT
+ /* Check that the core implements the MT ASE */
+ has_mt t0, 3f
+ nop
+
+ .set push
+ .set mt
+
+ /* Only allow 1 TC per VPE to execute... */
+ dmt
+
+ /* ...and for the moment only 1 VPE */
+ dvpe
+ la t1, 1f
+ jr.hb t1
+ nop
+
+ /* Enter VPE configuration state */
+1: mfc0 t0, CP0_MVPCONTROL
+ ori t0, t0, MVPCONTROL_VPC
+ mtc0 t0, CP0_MVPCONTROL
+
+ /* Retrieve the number of VPEs within the core */
+ mfc0 t0, CP0_MVPCONF0
+ srl t0, t0, MVPCONF0_PVPE_SHIFT
+ andi t0, t0, (MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT)
+ addi t7, t0, 1
+
+ /* If there's only 1, we're done */
+ beqz t0, 2f
+ nop
+
+ /* Loop through each VPE within this core */
+ li t5, 1
+
+1: /* Operate on the appropriate TC */
+ mtc0 t5, CP0_VPECONTROL
+ ehb
+
+ /* Bind TC to VPE (1:1 TC:VPE mapping) */
+ mttc0 t5, CP0_TCBIND
+
+ /* Set exclusive TC, non-active, master */
+ li t0, VPECONF0_MVP
+ sll t1, t5, VPECONF0_XTC_SHIFT
+ or t0, t0, t1
+ mttc0 t0, CP0_VPECONF0
+
+ /* Set TC non-active, non-allocatable */
+ mttc0 zero, CP0_TCSTATUS
+
+ /* Set TC halted */
+ li t0, TCHALT_H
+ mttc0 t0, CP0_TCHALT
+
+ /* Next VPE */
+ addi t5, t5, 1
+ slt t0, t5, t7
+ bnez t0, 1b
+ nop
+
+ /* Leave VPE configuration state */
+2: mfc0 t0, CP0_MVPCONTROL
+ xori t0, t0, MVPCONTROL_VPC
+ mtc0 t0, CP0_MVPCONTROL
+
+3: .set pop
+#endif
+ jr ra
+ nop
+ END(mips_cps_core_init)
+
+LEAF(mips_cps_boot_vpes)
+ /* Retrieve CM base address */
+ la t0, mips_cm_base
+ lw t0, 0(t0)
+
+ /* Calculate a pointer to this cores struct core_boot_config */
+ lw t0, GCR_CL_ID_OFS(t0)
+ li t1, COREBOOTCFG_SIZE
+ mul t0, t0, t1
+ la t1, mips_cps_core_bootcfg
+ lw t1, 0(t1)
+ addu t0, t0, t1
+
+ /* Calculate this VPEs ID. If the core doesn't support MT use 0 */
+ has_mt t6, 1f
+ li t9, 0
+
+ /* Find the number of VPEs present in the core */
+ mfc0 t1, CP0_MVPCONF0
+ srl t1, t1, MVPCONF0_PVPE_SHIFT
+ andi t1, t1, MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT
+ addi t1, t1, 1
+
+ /* Calculate a mask for the VPE ID from EBase.CPUNum */
+ clz t1, t1
+ li t2, 31
+ subu t1, t2, t1
+ li t2, 1
+ sll t1, t2, t1
+ addiu t1, t1, -1
+
+ /* Retrieve the VPE ID from EBase.CPUNum */
+ mfc0 t9, $15, 1
+ and t9, t9, t1
+
+1: /* Calculate a pointer to this VPEs struct vpe_boot_config */
+ li t1, VPEBOOTCFG_SIZE
+ mul v0, t9, t1
+ lw t7, COREBOOTCFG_VPECONFIG(t0)
+ addu v0, v0, t7
+
+#ifdef CONFIG_MIPS_MT
+
+ /* If the core doesn't support MT then return */
+ bnez t6, 1f
+ nop
+ jr ra
+ nop
+
+ .set push
+ .set mt
+
+1: /* Enter VPE configuration state */
+ dvpe
+ la t1, 1f
+ jr.hb t1
+ nop
+1: mfc0 t1, CP0_MVPCONTROL
+ ori t1, t1, MVPCONTROL_VPC
+ mtc0 t1, CP0_MVPCONTROL
+ ehb
+
+ /* Loop through each VPE */
+ lw t6, COREBOOTCFG_VPEMASK(t0)
+ move t8, t6
+ li t5, 0
+
+ /* Check whether the VPE should be running. If not, skip it */
+1: andi t0, t6, 1
+ beqz t0, 2f
+ nop
+
+ /* Operate on the appropriate TC */
+ mfc0 t0, CP0_VPECONTROL
+ ori t0, t0, VPECONTROL_TARGTC
+ xori t0, t0, VPECONTROL_TARGTC
+ or t0, t0, t5
+ mtc0 t0, CP0_VPECONTROL
+ ehb
+
+ /* Skip the VPE if its TC is not halted */
+ mftc0 t0, CP0_TCHALT
+ beqz t0, 2f
+ nop
+
+ /* Calculate a pointer to the VPEs struct vpe_boot_config */
+ li t0, VPEBOOTCFG_SIZE
+ mul t0, t0, t5
+ addu t0, t0, t7
+
+ /* Set the TC restart PC */
+ lw t1, VPEBOOTCFG_PC(t0)
+ mttc0 t1, CP0_TCRESTART
+
+ /* Set the TC stack pointer */
+ lw t1, VPEBOOTCFG_SP(t0)
+ mttgpr t1, sp
+
+ /* Set the TC global pointer */
+ lw t1, VPEBOOTCFG_GP(t0)
+ mttgpr t1, gp
+
+ /* Copy config from this VPE */
+ mfc0 t0, CP0_CONFIG
+ mttc0 t0, CP0_CONFIG
+
+ /* Ensure no software interrupts are pending */
+ mttc0 zero, CP0_CAUSE
+ mttc0 zero, CP0_STATUS
+
+ /* Set TC active, not interrupt exempt */
+ mftc0 t0, CP0_TCSTATUS
+ li t1, ~TCSTATUS_IXMT
+ and t0, t0, t1
+ ori t0, t0, TCSTATUS_A
+ mttc0 t0, CP0_TCSTATUS
+
+ /* Clear the TC halt bit */
+ mttc0 zero, CP0_TCHALT
+
+ /* Set VPE active */
+ mftc0 t0, CP0_VPECONF0
+ ori t0, t0, VPECONF0_VPA
+ mttc0 t0, CP0_VPECONF0
+
+ /* Next VPE */
+2: srl t6, t6, 1
+ addi t5, t5, 1
+ bnez t6, 1b
+ nop
+
+ /* Leave VPE configuration state */
+ mfc0 t1, CP0_MVPCONTROL
+ xori t1, t1, MVPCONTROL_VPC
+ mtc0 t1, CP0_MVPCONTROL
+ ehb
+ evpe
+
+ /* Check whether this VPE is meant to be running */
+ li t0, 1
+ sll t0, t0, t9
+ and t0, t0, t8
+ bnez t0, 2f
+ nop
+
+ /* This VPE should be offline, halt the TC */
+ li t0, TCHALT_H
+ mtc0 t0, CP0_TCHALT
+ la t0, 1f
+1: jr.hb t0
+ nop
+
+2: .set pop
+
+#endif /* CONFIG_MIPS_MT */
+
+ /* Return */
+ jr ra
+ nop
+ END(mips_cps_boot_vpes)
+
+#if defined(CONFIG_MIPS_CPS_PM) && defined(CONFIG_CPU_PM)
+
+ /* Calculate a pointer to this CPUs struct mips_static_suspend_state */
+ .macro psstate dest
+ .set push
+ .set noat
+ lw $1, TI_CPU(gp)
+ sll $1, $1, LONGLOG
+ la \dest, __per_cpu_offset
+ addu $1, $1, \dest
+ lw $1, 0($1)
+ la \dest, cps_cpu_state
+ addu \dest, \dest, $1
+ .set pop
+ .endm
+
+LEAF(mips_cps_pm_save)
+ /* Save CPU state */
+ SUSPEND_SAVE_REGS
+ psstate t1
+ SUSPEND_SAVE_STATIC
+ jr v0
+ nop
+ END(mips_cps_pm_save)
+
+LEAF(mips_cps_pm_restore)
+ /* Restore CPU state */
+ psstate t1
+ RESUME_RESTORE_STATIC
+ RESUME_RESTORE_REGS_RETURN
+ END(mips_cps_pm_restore)
+
+#endif /* CONFIG_MIPS_CPS_PM && CONFIG_CPU_PM */
diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c
index de3c25ffd9f..2d80b5f1aea 100644
--- a/arch/mips/kernel/cpu-bugs64.c
+++ b/arch/mips/kernel/cpu-bugs64.c
@@ -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>
@@ -167,12 +168,16 @@ static inline void check_mult_sh(void)
panic(bug64hit, !R4000_WAR ? r4kwar : nowar);
}
-static volatile int daddi_ov __cpuinitdata;
+static volatile int daddi_ov;
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)
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 6bfccc227a9..d74f957c561 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -20,113 +20,17 @@
#include <asm/bugs.h>
#include <asm/cpu.h>
+#include <asm/cpu-type.h>
#include <asm/fpu.h>
#include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
+#include <asm/msa.h>
#include <asm/watch.h>
#include <asm/elf.h>
#include <asm/spram.h>
#include <asm/uaccess.h>
-/*
- * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
- * the implementation of the "wait" feature differs between CPU families. This
- * points to the function that implements CPU specific wait.
- * The wait instruction stops the pipeline and reduces the power consumption of
- * the CPU very much.
- */
-void (*cpu_wait)(void);
-EXPORT_SYMBOL(cpu_wait);
-
-static void r3081_wait(void)
-{
- unsigned long cfg = read_c0_conf();
- write_c0_conf(cfg | R30XX_CONF_HALT);
-}
-
-static void r39xx_wait(void)
-{
- local_irq_disable();
- if (!need_resched())
- write_c0_conf(read_c0_conf() | TX39_CONF_HALT);
- local_irq_enable();
-}
-
-extern void r4k_wait(void);
-
-/*
- * This variant is preferable as it allows testing need_resched and going to
- * sleep depending on the outcome atomically. Unfortunately the "It is
- * implementation-dependent whether the pipeline restarts when a non-enabled
- * interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes
- * using this version a gamble.
- */
-void r4k_wait_irqoff(void)
-{
- local_irq_disable();
- if (!need_resched())
- __asm__(" .set push \n"
- " .set mips3 \n"
- " wait \n"
- " .set pop \n");
- local_irq_enable();
- __asm__(" .globl __pastwait \n"
- "__pastwait: \n");
-}
-
-/*
- * The RM7000 variant has to handle erratum 38. The workaround is to not
- * have any pending stores when the WAIT instruction is executed.
- */
-static void rm7k_wait_irqoff(void)
-{
- local_irq_disable();
- if (!need_resched())
- __asm__(
- " .set push \n"
- " .set mips3 \n"
- " .set noat \n"
- " mfc0 $1, $12 \n"
- " sync \n"
- " mtc0 $1, $12 # stalls until W stage \n"
- " wait \n"
- " mtc0 $1, $12 # stalls until W stage \n"
- " .set pop \n");
- local_irq_enable();
-}
-
-/*
- * The Au1xxx wait is available only if using 32khz counter or
- * external timer source, but specifically not CP0 Counter.
- * alchemy/common/time.c may override cpu_wait!
- */
-static void au1k_wait(void)
-{
- __asm__(" .set mips3 \n"
- " cache 0x14, 0(%0) \n"
- " cache 0x14, 32(%0) \n"
- " sync \n"
- " nop \n"
- " wait \n"
- " nop \n"
- " nop \n"
- " nop \n"
- " nop \n"
- " .set mips0 \n"
- : : "r" (au1k_wait));
-}
-
-static int __initdata nowait;
-
-static int __init wait_disable(char *s)
-{
- nowait = 1;
-
- return 1;
-}
-
-__setup("nowait", wait_disable);
-
-static int __cpuinitdata mips_fpu_disabled;
+static int mips_fpu_disabled;
static int __init fpu_disable(char *s)
{
@@ -138,7 +42,7 @@ static int __init fpu_disable(char *s)
__setup("nofpu", fpu_disable);
-int __cpuinitdata mips_dsp_disabled;
+int mips_dsp_disabled;
static int __init dsp_disable(char *s)
{
@@ -150,114 +54,15 @@ static int __init dsp_disable(char *s)
__setup("nodsp", dsp_disable);
-void __init check_wait(void)
-{
- struct cpuinfo_mips *c = &current_cpu_data;
-
- if (nowait) {
- printk("Wait instruction disabled.\n");
- return;
- }
-
- switch (c->cputype) {
- case CPU_R3081:
- case CPU_R3081E:
- cpu_wait = r3081_wait;
- break;
- case CPU_TX3927:
- cpu_wait = r39xx_wait;
- break;
- case CPU_R4200:
-/* case CPU_R4300: */
- case CPU_R4600:
- case CPU_R4640:
- case CPU_R4650:
- case CPU_R4700:
- case CPU_R5000:
- case CPU_R5500:
- case CPU_NEVADA:
- case CPU_4KC:
- case CPU_4KEC:
- case CPU_4KSC:
- case CPU_5KC:
- case CPU_25KF:
- case CPU_PR4450:
- case CPU_BMIPS3300:
- case CPU_BMIPS4350:
- case CPU_BMIPS4380:
- case CPU_BMIPS5000:
- case CPU_CAVIUM_OCTEON:
- case CPU_CAVIUM_OCTEON_PLUS:
- case CPU_CAVIUM_OCTEON2:
- case CPU_JZRISC:
- case CPU_LOONGSON1:
- case CPU_XLR:
- case CPU_XLP:
- cpu_wait = r4k_wait;
- break;
-
- case CPU_RM7000:
- cpu_wait = rm7k_wait_irqoff;
- break;
-
- case CPU_M14KC:
- case CPU_M14KEC:
- case CPU_24K:
- case CPU_34K:
- case CPU_1004K:
- cpu_wait = r4k_wait;
- if (read_c0_config7() & MIPS_CONF7_WII)
- cpu_wait = r4k_wait_irqoff;
- break;
-
- case CPU_74K:
- cpu_wait = r4k_wait;
- if ((c->processor_id & 0xff) >= PRID_REV_ENCODE_332(2, 1, 0))
- cpu_wait = r4k_wait_irqoff;
- break;
-
- case CPU_TX49XX:
- cpu_wait = r4k_wait_irqoff;
- break;
- case CPU_ALCHEMY:
- cpu_wait = au1k_wait;
- break;
- case CPU_20KC:
- /*
- * WAIT on Rev1.0 has E1, E2, E3 and E16.
- * WAIT on Rev2.0 and Rev3.0 has E16.
- * Rev3.1 WAIT is nop, why bother
- */
- if ((c->processor_id & 0xff) <= 0x64)
- break;
-
- /*
- * Another rev is incremeting c0_count at a reduced clock
- * rate while in WAIT mode. So we basically have the choice
- * between using the cp0 timer as clocksource or avoiding
- * the WAIT instruction. Until more details are known,
- * disable the use of WAIT for 20Kc entirely.
- cpu_wait = r4k_wait;
- */
- break;
- case CPU_RM9000:
- if ((c->processor_id & 0x00ff) >= 0x40)
- cpu_wait = r4k_wait;
- break;
- default:
- break;
- }
-}
-
static inline void check_errata(void)
{
struct cpuinfo_mips *c = &current_cpu_data;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_34K:
/*
* Erratum "RPS May Cause Incorrect Instruction Execution"
- * This code only handles VPE0, any SMP/SMTC/RTOS code
+ * This code only handles VPE0, any SMP/RTOS code
* making use of VPE1 will be responsable for that VPE.
*/
if ((c->processor_id & PRID_REV_MASK) <= PRID_REV_34K_V1_0_2)
@@ -309,7 +114,7 @@ static inline unsigned long cpu_get_fpu_id(void)
unsigned long tmp, fpu_id;
tmp = read_c0_status();
- __enable_fpu();
+ __enable_fpu(FPU_AS_IS);
fpu_id = read_32bit_cp1_register(CP1_REVISION);
write_c0_status(tmp);
return fpu_id;
@@ -320,7 +125,21 @@ static inline unsigned long cpu_get_fpu_id(void)
*/
static inline int __cpu_has_fpu(void)
{
- return ((cpu_get_fpu_id() & 0xff00) != FPIR_IMP_NONE);
+ return ((cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE);
+}
+
+static inline unsigned long cpu_get_msa_id(void)
+{
+ unsigned long status, conf5, msa_id;
+
+ status = read_c0_status();
+ __enable_fpu(FPU_64BIT);
+ conf5 = read_c0_config5();
+ enable_msa();
+ msa_id = read_msa_ir();
+ write_c0_config5(conf5);
+ write_c0_status(status);
+ return msa_id;
}
static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
@@ -332,7 +151,7 @@ static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
#endif
}
-static void __cpuinit set_isa(struct cpuinfo_mips *c, unsigned int isa)
+static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
{
switch (isa) {
case MIPS_CPU_ISA_M64R2:
@@ -344,8 +163,7 @@ static void __cpuinit set_isa(struct cpuinfo_mips *c, unsigned int isa)
case MIPS_CPU_ISA_IV:
c->isa_level |= MIPS_CPU_ISA_IV;
case MIPS_CPU_ISA_III:
- c->isa_level |= MIPS_CPU_ISA_I | MIPS_CPU_ISA_II |
- MIPS_CPU_ISA_III;
+ c->isa_level |= MIPS_CPU_ISA_II | MIPS_CPU_ISA_III;
break;
case MIPS_CPU_ISA_M32R2:
@@ -354,15 +172,34 @@ static void __cpuinit set_isa(struct cpuinfo_mips *c, unsigned int isa)
c->isa_level |= MIPS_CPU_ISA_M32R1;
case MIPS_CPU_ISA_II:
c->isa_level |= MIPS_CPU_ISA_II;
- case MIPS_CPU_ISA_I:
- c->isa_level |= MIPS_CPU_ISA_I;
break;
}
}
-static char unknown_isa[] __cpuinitdata = KERN_ERR \
+static char unknown_isa[] = KERN_ERR \
"Unsupported ISA type, c0.config0: %d.";
+static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
+{
+ unsigned int config6;
+
+ /* It's implementation dependent how the FTLB can be enabled */
+ switch (c->cputype) {
+ case CPU_PROAPTIV:
+ case CPU_P5600:
+ /* proAptiv & related cores use Config6 to enable the FTLB */
+ config6 = read_c0_config6();
+ if (enable)
+ /* Enable FTLB */
+ write_c0_config6(config6 | MIPS_CONF6_FTLBEN);
+ else
+ /* Disable FTLB */
+ write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN);
+ back_to_back_c0_hazard();
+ break;
+ }
+}
+
static inline unsigned int decode_config0(struct cpuinfo_mips *c)
{
unsigned int config0;
@@ -370,8 +207,13 @@ static inline unsigned int decode_config0(struct cpuinfo_mips *c)
config0 = read_c0_config();
- if (((config0 & MIPS_CONF_MT) >> 7) == 1)
+ /*
+ * Look for Standard TLB or Dual VTLB and FTLB
+ */
+ if ((((config0 & MIPS_CONF_MT) >> 7) == 1) ||
+ (((config0 & MIPS_CONF_MT) >> 7) == 4))
c->options |= MIPS_CPU_TLB;
+
isa = (config0 & MIPS_CONF_AT) >> 13;
switch (isa) {
case 0:
@@ -426,8 +268,11 @@ static inline unsigned int decode_config1(struct cpuinfo_mips *c)
c->options |= MIPS_CPU_FPU;
c->options |= MIPS_CPU_32FPR;
}
- if (cpu_has_tlb)
+ if (cpu_has_tlb) {
c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1;
+ c->tlbsizevtlb = c->tlbsize;
+ c->tlbsizeftlbsets = 0;
+ }
return config1 & MIPS_CONF_M;
}
@@ -472,6 +317,10 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
c->options |= MIPS_CPU_MICROMIPS;
if (config3 & MIPS_CONF3_VZ)
c->ases |= MIPS_ASE_VZ;
+ if (config3 & MIPS_CONF3_SC)
+ c->options |= MIPS_CPU_SEGMENTS;
+ if (config3 & MIPS_CONF3_MSA)
+ c->ases |= MIPS_ASE_MSA;
return config3 & MIPS_CONF_M;
}
@@ -479,19 +328,72 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
static inline unsigned int decode_config4(struct cpuinfo_mips *c)
{
unsigned int config4;
+ unsigned int newcf4;
+ unsigned int mmuextdef;
+ unsigned int ftlb_page = MIPS_CONF4_FTLBPAGESIZE;
config4 = read_c0_config4();
- if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT
- && cpu_has_tlb)
- c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
+ if (cpu_has_tlb) {
+ if (((config4 & MIPS_CONF4_IE) >> 29) == 2)
+ c->options |= MIPS_CPU_TLBINV;
+ mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF;
+ switch (mmuextdef) {
+ case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT:
+ c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
+ c->tlbsizevtlb = c->tlbsize;
+ break;
+ case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT:
+ c->tlbsizevtlb +=
+ ((config4 & MIPS_CONF4_VTLBSIZEEXT) >>
+ MIPS_CONF4_VTLBSIZEEXT_SHIFT) * 0x40;
+ c->tlbsize = c->tlbsizevtlb;
+ ftlb_page = MIPS_CONF4_VFTLBPAGESIZE;
+ /* fall through */
+ case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT:
+ newcf4 = (config4 & ~ftlb_page) |
+ (page_size_ftlb(mmuextdef) <<
+ MIPS_CONF4_FTLBPAGESIZE_SHIFT);
+ write_c0_config4(newcf4);
+ back_to_back_c0_hazard();
+ config4 = read_c0_config4();
+ if (config4 != newcf4) {
+ pr_err("PAGE_SIZE 0x%lx is not supported by FTLB (config4=0x%x)\n",
+ PAGE_SIZE, config4);
+ /* Switch FTLB off */
+ set_ftlb_enable(c, 0);
+ break;
+ }
+ c->tlbsizeftlbsets = 1 <<
+ ((config4 & MIPS_CONF4_FTLBSETS) >>
+ MIPS_CONF4_FTLBSETS_SHIFT);
+ c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >>
+ MIPS_CONF4_FTLBWAYS_SHIFT) + 2;
+ c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets;
+ break;
+ }
+ }
c->kscratch_mask = (config4 >> 16) & 0xff;
return config4 & MIPS_CONF_M;
}
-static void __cpuinit decode_configs(struct cpuinfo_mips *c)
+static inline unsigned int decode_config5(struct cpuinfo_mips *c)
+{
+ unsigned int config5;
+
+ config5 = read_c0_config5();
+ config5 &= ~MIPS_CONF5_UFR;
+ write_c0_config5(config5);
+
+ if (config5 & MIPS_CONF5_EVA)
+ c->options |= MIPS_CPU_EVA;
+
+ return config5 & MIPS_CONF_M;
+}
+
+static void decode_configs(struct cpuinfo_mips *c)
{
int ok;
@@ -501,6 +403,9 @@ static void __cpuinit decode_configs(struct cpuinfo_mips *c)
c->scache.flags = MIPS_CACHE_NOT_PRESENT;
+ /* Enable FTLB if present */
+ set_ftlb_enable(c, 1);
+
ok = decode_config0(c); /* Read Config registers. */
BUG_ON(!ok); /* Arch spec violation! */
if (ok)
@@ -511,11 +416,18 @@ static void __cpuinit decode_configs(struct cpuinfo_mips *c)
ok = decode_config3(c);
if (ok)
ok = decode_config4(c);
+ if (ok)
+ ok = decode_config5(c);
mips_probe_watch_registers(c);
- if (cpu_has_mips_r2)
- c->core = read_c0_ebase() & 0x3ff;
+#ifndef CONFIG_MIPS_CPS
+ if (cpu_has_mips_r2) {
+ c->core = get_ebase_cpunum();
+ if (cpu_has_mipsmt)
+ c->core >>= fls(core_nvpes()) - 1;
+ }
+#endif
}
#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \
@@ -523,11 +435,10 @@ static void __cpuinit decode_configs(struct cpuinfo_mips *c)
static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
{
- switch (c->processor_id & 0xff00) {
+ switch (c->processor_id & PRID_IMP_MASK) {
case PRID_IMP_R2000:
c->cputype = CPU_R2000;
__cpu_name[cpu] = "R2000";
- set_isa(c, MIPS_CPU_ISA_I);
c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
MIPS_CPU_NOFPUEX;
if (__cpu_has_fpu())
@@ -535,7 +446,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
c->tlbsize = 64;
break;
case PRID_IMP_R3000:
- if ((c->processor_id & 0xff) == PRID_REV_R3000A) {
+ if ((c->processor_id & PRID_REV_MASK) == PRID_REV_R3000A) {
if (cpu_has_confreg()) {
c->cputype = CPU_R3081E;
__cpu_name[cpu] = "R3081";
@@ -547,7 +458,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
c->cputype = CPU_R3000;
__cpu_name[cpu] = "R3000";
}
- set_isa(c, MIPS_CPU_ISA_I);
c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
MIPS_CPU_NOFPUEX;
if (__cpu_has_fpu())
@@ -556,7 +466,8 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
break;
case PRID_IMP_R4000:
if (read_c0_config() & CONF_SC) {
- if ((c->processor_id & 0xff) >= PRID_REV_R4400) {
+ if ((c->processor_id & PRID_REV_MASK) >=
+ PRID_REV_R4400) {
c->cputype = CPU_R4400PC;
__cpu_name[cpu] = "R4400PC";
} else {
@@ -564,12 +475,33 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
__cpu_name[cpu] = "R4000PC";
}
} else {
- if ((c->processor_id & 0xff) >= PRID_REV_R4400) {
- c->cputype = CPU_R4400SC;
- __cpu_name[cpu] = "R4400SC";
+ int cca = read_c0_config() & CONF_CM_CMASK;
+ int mc;
+
+ /*
+ * SC and MC versions can't be reliably told apart,
+ * but only the latter support coherent caching
+ * modes so assume the firmware has set the KSEG0
+ * coherency attribute reasonably (if uncached, we
+ * assume SC).
+ */
+ switch (cca) {
+ case CONF_CM_CACHABLE_CE:
+ case CONF_CM_CACHABLE_COW:
+ case CONF_CM_CACHABLE_CUW:
+ mc = 1;
+ break;
+ default:
+ mc = 0;
+ break;
+ }
+ if ((c->processor_id & PRID_REV_MASK) >=
+ PRID_REV_R4400) {
+ c->cputype = mc ? CPU_R4400MC : CPU_R4400SC;
+ __cpu_name[cpu] = mc ? "R4400MC" : "R4400SC";
} else {
- c->cputype = CPU_R4000SC;
- __cpu_name[cpu] = "R4000SC";
+ c->cputype = mc ? CPU_R4000MC : CPU_R4000SC;
+ __cpu_name[cpu] = mc ? "R4000MC" : "R4000SC";
}
}
@@ -580,6 +512,9 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
c->tlbsize = 48;
break;
case PRID_IMP_VR41XX:
+ set_isa(c, MIPS_CPU_ISA_III);
+ c->options = R4K_OPTS;
+ c->tlbsize = 32;
switch (c->processor_id & 0xf0) {
case PRID_REV_VR4111:
c->cputype = CPU_VR4111;
@@ -604,6 +539,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
__cpu_name[cpu] = "NEC VR4131";
} else {
c->cputype = CPU_VR4133;
+ c->options |= MIPS_CPU_LLSC;
__cpu_name[cpu] = "NEC VR4133";
}
break;
@@ -613,9 +549,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
__cpu_name[cpu] = "NEC Vr41xx";
break;
}
- set_isa(c, MIPS_CPU_ISA_III);
- c->options = R4K_OPTS;
- c->tlbsize = 32;
break;
case PRID_IMP_R4300:
c->cputype = CPU_R4300;
@@ -649,7 +582,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
break;
#endif
case PRID_IMP_TX39:
- set_isa(c, MIPS_CPU_ISA_I);
c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE;
if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) {
@@ -657,7 +589,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
__cpu_name[cpu] = "TX3927";
c->tlbsize = 64;
} else {
- switch (c->processor_id & 0xff) {
+ switch (c->processor_id & PRID_REV_MASK) {
case PRID_REV_TX3912:
c->cputype = CPU_TX3912;
__cpu_name[cpu] = "TX3912";
@@ -752,21 +684,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
*/
c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48;
break;
- case PRID_IMP_RM9000:
- c->cputype = CPU_RM9000;
- __cpu_name[cpu] = "RM9000";
- set_isa(c, MIPS_CPU_ISA_IV);
- c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
- MIPS_CPU_LLSC;
- /*
- * Bit 29 in the info register of the RM9000
- * indicates if the TLB has 48 or 64 entries.
- *
- * 29 1 => 64 entry JTLB
- * 0 => 48 entry JTLB
- */
- c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48;
- break;
case PRID_IMP_R8000:
c->cputype = CPU_R8000;
__cpu_name[cpu] = "RM8000";
@@ -806,17 +723,23 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
MIPS_CPU_LLSC;
c->tlbsize = 64;
break;
- case PRID_IMP_LOONGSON2:
- c->cputype = CPU_LOONGSON2;
- __cpu_name[cpu] = "ICT Loongson-2";
-
+ case PRID_IMP_LOONGSON_64: /* Loongson-2/3 */
switch (c->processor_id & PRID_REV_MASK) {
case PRID_REV_LOONGSON2E:
+ c->cputype = CPU_LOONGSON2;
+ __cpu_name[cpu] = "ICT Loongson-2";
set_elf_platform(cpu, "loongson2e");
break;
case PRID_REV_LOONGSON2F:
+ c->cputype = CPU_LOONGSON2;
+ __cpu_name[cpu] = "ICT Loongson-2";
set_elf_platform(cpu, "loongson2f");
break;
+ case PRID_REV_LOONGSON3A:
+ c->cputype = CPU_LOONGSON3;
+ __cpu_name[cpu] = "ICT Loongson-3";
+ set_elf_platform(cpu, "loongson3a");
+ break;
}
set_isa(c, MIPS_CPU_ISA_III);
@@ -825,7 +748,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
MIPS_CPU_32FPR;
c->tlbsize = 64;
break;
- case PRID_IMP_LOONGSON1:
+ case PRID_IMP_LOONGSON_32: /* Loongson-1 */
decode_configs(c);
c->cputype = CPU_LOONGSON1;
@@ -842,8 +765,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
{
- decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (c->processor_id & PRID_IMP_MASK) {
case PRID_IMP_4KC:
c->cputype = CPU_4KC;
__cpu_name[cpu] = "MIPS 4Kc";
@@ -903,18 +825,44 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
__cpu_name[cpu] = "MIPS 1004Kc";
break;
case PRID_IMP_1074K:
- c->cputype = CPU_74K;
+ c->cputype = CPU_1074K;
__cpu_name[cpu] = "MIPS 1074Kc";
break;
+ case PRID_IMP_INTERAPTIV_UP:
+ c->cputype = CPU_INTERAPTIV;
+ __cpu_name[cpu] = "MIPS interAptiv";
+ break;
+ case PRID_IMP_INTERAPTIV_MP:
+ c->cputype = CPU_INTERAPTIV;
+ __cpu_name[cpu] = "MIPS interAptiv (multi)";
+ break;
+ case PRID_IMP_PROAPTIV_UP:
+ c->cputype = CPU_PROAPTIV;
+ __cpu_name[cpu] = "MIPS proAptiv";
+ break;
+ case PRID_IMP_PROAPTIV_MP:
+ c->cputype = CPU_PROAPTIV;
+ __cpu_name[cpu] = "MIPS proAptiv (multi)";
+ break;
+ case PRID_IMP_P5600:
+ c->cputype = CPU_P5600;
+ __cpu_name[cpu] = "MIPS P5600";
+ break;
+ case PRID_IMP_M5150:
+ c->cputype = CPU_M5150;
+ __cpu_name[cpu] = "MIPS M5150";
+ break;
}
+ decode_configs(c);
+
spram_config();
}
static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (c->processor_id & PRID_IMP_MASK) {
case PRID_IMP_AU1_REV1:
case PRID_IMP_AU1_REV2:
c->cputype = CPU_ALCHEMY;
@@ -933,7 +881,7 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
break;
case 4:
__cpu_name[cpu] = "Au1200";
- if ((c->processor_id & 0xff) == 2)
+ if ((c->processor_id & PRID_REV_MASK) == 2)
__cpu_name[cpu] = "Au1250";
break;
case 5:
@@ -951,12 +899,12 @@ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (c->processor_id & PRID_IMP_MASK) {
case PRID_IMP_SB1:
c->cputype = CPU_SB1;
__cpu_name[cpu] = "SiByte SB1";
/* FPU in pass1 is known to have issues. */
- if ((c->processor_id & 0xff) < 0x02)
+ if ((c->processor_id & PRID_REV_MASK) < 0x02)
c->options &= ~(MIPS_CPU_FPU | MIPS_CPU_32FPR);
break;
case PRID_IMP_SB1A:
@@ -969,7 +917,7 @@ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c, unsigned int cpu)
static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (c->processor_id & PRID_IMP_MASK) {
case PRID_IMP_SR71000:
c->cputype = CPU_SR71000;
__cpu_name[cpu] = "Sandcraft SR71000";
@@ -982,7 +930,7 @@ static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c, unsigned int cpu)
static inline void cpu_probe_nxp(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (c->processor_id & PRID_IMP_MASK) {
case PRID_IMP_PR4450:
c->cputype = CPU_PR4450;
__cpu_name[cpu] = "Philips PR4450";
@@ -994,7 +942,7 @@ static inline void cpu_probe_nxp(struct cpuinfo_mips *c, unsigned int cpu)
static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (c->processor_id & PRID_IMP_MASK) {
case PRID_IMP_BMIPS32_REV4:
case PRID_IMP_BMIPS32_REV8:
c->cputype = CPU_BMIPS32;
@@ -1009,7 +957,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
set_elf_platform(cpu, "bmips3300");
break;
case PRID_IMP_BMIPS43XX: {
- int rev = c->processor_id & 0xff;
+ int rev = c->processor_id & PRID_REV_MASK;
if (rev >= PRID_REV_BMIPS4380_LO &&
rev <= PRID_REV_BMIPS4380_HI) {
@@ -1035,7 +983,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (c->processor_id & PRID_IMP_MASK) {
case PRID_IMP_CAVIUM_CN38XX:
case PRID_IMP_CAVIUM_CN31XX:
case PRID_IMP_CAVIUM_CN30XX:
@@ -1055,10 +1003,17 @@ platform:
case PRID_IMP_CAVIUM_CN63XX:
case PRID_IMP_CAVIUM_CN66XX:
case PRID_IMP_CAVIUM_CN68XX:
+ case PRID_IMP_CAVIUM_CNF71XX:
c->cputype = CPU_CAVIUM_OCTEON2;
__cpu_name[cpu] = "Cavium Octeon II";
set_elf_platform(cpu, "octeon2");
break;
+ case PRID_IMP_CAVIUM_CN70XX:
+ case PRID_IMP_CAVIUM_CN78XX:
+ c->cputype = CPU_CAVIUM_OCTEON3;
+ __cpu_name[cpu] = "Cavium Octeon III";
+ set_elf_platform(cpu, "octeon3");
+ break;
default:
printk(KERN_INFO "Unknown Octeon chip!\n");
c->cputype = CPU_UNKNOWN;
@@ -1071,7 +1026,8 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
decode_configs(c);
/* JZRISC does not implement the CP0 counter. */
c->options &= ~MIPS_CPU_COUNTER;
- switch (c->processor_id & 0xff00) {
+ BUG_ON(!__builtin_constant_p(cpu_has_counter) || cpu_has_counter);
+ switch (c->processor_id & PRID_IMP_MASK) {
case PRID_IMP_JZRISC:
c->cputype = CPU_JZRISC;
__cpu_name[cpu] = "Ingenic JZRISC";
@@ -1086,7 +1042,7 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
{
decode_configs(c);
- if ((c->processor_id & 0xff00) == PRID_IMP_NETLOGIC_AU13XX) {
+ if ((c->processor_id & PRID_IMP_MASK) == PRID_IMP_NETLOGIC_AU13XX) {
c->cputype = CPU_ALCHEMY;
__cpu_name[cpu] = "Au1300";
/* following stuff is not for Alchemy */
@@ -1101,7 +1057,14 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
MIPS_CPU_EJTAG |
MIPS_CPU_LLSC);
- switch (c->processor_id & 0xff00) {
+ switch (c->processor_id & PRID_IMP_MASK) {
+ case PRID_IMP_NETLOGIC_XLP2XX:
+ case PRID_IMP_NETLOGIC_XLP9XX:
+ case PRID_IMP_NETLOGIC_XLP5XX:
+ c->cputype = CPU_XLP;
+ __cpu_name[cpu] = "Broadcom XLPII";
+ break;
+
case PRID_IMP_NETLOGIC_XLP8XX:
case PRID_IMP_NETLOGIC_XLP3XX:
c->cputype = CPU_XLP;
@@ -1153,6 +1116,7 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
set_isa(c, MIPS_CPU_ISA_M64R1);
c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1;
}
+ c->kscratch_mask = 0xf;
}
#ifdef CONFIG_64BIT
@@ -1164,7 +1128,7 @@ EXPORT_SYMBOL(__ua_limit);
const char *__cpu_name[NR_CPUS];
const char *__elf_platform;
-__cpuinit void cpu_probe(void)
+void cpu_probe(void)
{
struct cpuinfo_mips *c = &current_cpu_data;
unsigned int cpu = smp_processor_id();
@@ -1174,7 +1138,7 @@ __cpuinit void cpu_probe(void)
c->cputype = CPU_UNKNOWN;
c->processor_id = read_c0_prid();
- switch (c->processor_id & 0xff0000) {
+ switch (c->processor_id & PRID_COMP_MASK) {
case PRID_COMP_LEGACY:
cpu_probe_legacy(c, cpu);
break;
@@ -1226,10 +1190,8 @@ __cpuinit void cpu_probe(void)
if (c->options & MIPS_CPU_FPU) {
c->fpu_id = cpu_get_fpu_id();
- if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
- c->isa_level == MIPS_CPU_ISA_M32R2 ||
- c->isa_level == MIPS_CPU_ISA_M64R1 ||
- c->isa_level == MIPS_CPU_ISA_M64R2) {
+ if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
+ MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) {
if (c->fpu_id & MIPS_FPIR_3D)
c->ases |= MIPS_ASE_MIPS3D;
}
@@ -1243,6 +1205,12 @@ __cpuinit void cpu_probe(void)
else
c->srsets = 1;
+ if (cpu_has_msa) {
+ c->msa_id = cpu_get_msa_id();
+ WARN(c->msa_id & MSA_IR_WRPF,
+ "Vector register partitioning unimplemented!");
+ }
+
cpu_probe_vmbits(c);
#ifdef CONFIG_64BIT
@@ -1251,12 +1219,14 @@ __cpuinit void cpu_probe(void)
#endif
}
-__cpuinit void cpu_report(void)
+void cpu_report(void)
{
struct cpuinfo_mips *c = &current_cpu_data;
- printk(KERN_INFO "CPU revision is: %08x (%s)\n",
- c->processor_id, cpu_name_string());
+ pr_info("CPU%d revision is: %08x (%s)\n",
+ smp_processor_id(), c->processor_id, cpu_name_string());
if (c->options & MIPS_CPU_FPU)
printk(KERN_INFO "FPU revision is: %08x\n", c->fpu_id);
+ if (cpu_has_msa)
+ pr_info("MSA revision is: %08x\n", c->msa_id);
}
diff --git a/arch/mips/kernel/cpufreq/Kconfig b/arch/mips/kernel/cpufreq/Kconfig
deleted file mode 100644
index 58c601eee6f..00000000000
--- a/arch/mips/kernel/cpufreq/Kconfig
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# CPU Frequency scaling
-#
-
-config MIPS_EXTERNAL_TIMER
- bool
-
-config MIPS_CPUFREQ
- bool
- default y
- depends on CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER
-
-if MIPS_CPUFREQ
-
-menu "CPU Frequency scaling"
-
-source "drivers/cpufreq/Kconfig"
-
-if CPU_FREQ
-
-comment "CPUFreq processor drivers"
-
-config LOONGSON2_CPUFREQ
- tristate "Loongson2 CPUFreq Driver"
- select CPU_FREQ_TABLE
- depends on MIPS_CPUFREQ
- help
- This option adds a CPUFreq driver for loongson processors which
- support software configurable cpu frequency.
-
- Loongson2F and it's successors support this feature.
-
- For details, take a look at <file:Documentation/cpu-freq/>.
-
- If in doubt, say N.
-
-endif # CPU_FREQ
-
-endmenu
-
-endif # MIPS_CPUFREQ
diff --git a/arch/mips/kernel/cpufreq/Makefile b/arch/mips/kernel/cpufreq/Makefile
deleted file mode 100644
index 05a5715ee38..00000000000
--- a/arch/mips/kernel/cpufreq/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the Linux/MIPS cpufreq.
-#
-
-obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o
diff --git a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c b/arch/mips/kernel/cpufreq/loongson2_cpufreq.c
deleted file mode 100644
index 3237c5235f9..00000000000
--- a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Cpufreq driver for the loongson-2 processors
- *
- * The 2E revision of loongson processor not support this feature.
- *
- * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology
- * Author: Yanhua, yanh@lemote.com
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/cpufreq.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/sched.h> /* set_cpus_allowed() */
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-
-#include <asm/clock.h>
-
-#include <asm/mach-loongson/loongson.h>
-
-static uint nowait;
-
-static struct clk *cpuclk;
-
-static void (*saved_cpu_wait) (void);
-
-static int loongson2_cpu_freq_notifier(struct notifier_block *nb,
- unsigned long val, void *data);
-
-static struct notifier_block loongson2_cpufreq_notifier_block = {
- .notifier_call = loongson2_cpu_freq_notifier
-};
-
-static int loongson2_cpu_freq_notifier(struct notifier_block *nb,
- unsigned long val, void *data)
-{
- if (val == CPUFREQ_POSTCHANGE)
- current_cpu_data.udelay_val = loops_per_jiffy;
-
- return 0;
-}
-
-static unsigned int loongson2_cpufreq_get(unsigned int cpu)
-{
- return clk_get_rate(cpuclk);
-}
-
-/*
- * Here we notify other drivers of the proposed change and the final change.
- */
-static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation)
-{
- unsigned int cpu = policy->cpu;
- unsigned int newstate = 0;
- cpumask_t cpus_allowed;
- struct cpufreq_freqs freqs;
- unsigned int freq;
-
- if (!cpu_online(cpu))
- return -ENODEV;
-
- cpus_allowed = current->cpus_allowed;
- set_cpus_allowed_ptr(current, cpumask_of(cpu));
-
- if (cpufreq_frequency_table_target
- (policy, &loongson2_clockmod_table[0], target_freq, relation,
- &newstate))
- return -EINVAL;
-
- freq =
- ((cpu_clock_freq / 1000) *
- loongson2_clockmod_table[newstate].index) / 8;
- if (freq < policy->min || freq > policy->max)
- return -EINVAL;
-
- pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
-
- freqs.cpu = cpu;
- freqs.old = loongson2_cpufreq_get(cpu);
- freqs.new = freq;
- freqs.flags = 0;
-
- if (freqs.new == freqs.old)
- return 0;
-
- /* notifiers */
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
- set_cpus_allowed_ptr(current, &cpus_allowed);
-
- /* setting the cpu frequency */
- clk_set_rate(cpuclk, freq);
-
- /* notifiers */
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
- pr_debug("cpufreq: set frequency %u kHz\n", freq);
-
- return 0;
-}
-
-static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
-{
- int i;
- unsigned long rate;
- int ret;
-
- if (!cpu_online(policy->cpu))
- return -ENODEV;
-
- cpuclk = clk_get(NULL, "cpu_clk");
- if (IS_ERR(cpuclk)) {
- printk(KERN_ERR "cpufreq: couldn't get CPU clk\n");
- return PTR_ERR(cpuclk);
- }
-
- rate = cpu_clock_freq / 1000;
- if (!rate) {
- clk_put(cpuclk);
- return -EINVAL;
- }
- ret = clk_set_rate(cpuclk, rate);
- if (ret) {
- clk_put(cpuclk);
- return ret;
- }
-
- /* clock table init */
- for (i = 2;
- (loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END);
- i++)
- loongson2_clockmod_table[i].frequency = (rate * i) / 8;
-
- policy->cur = loongson2_cpufreq_get(policy->cpu);
-
- cpufreq_frequency_table_get_attr(&loongson2_clockmod_table[0],
- policy->cpu);
-
- return cpufreq_frequency_table_cpuinfo(policy,
- &loongson2_clockmod_table[0]);
-}
-
-static int loongson2_cpufreq_verify(struct cpufreq_policy *policy)
-{
- return cpufreq_frequency_table_verify(policy,
- &loongson2_clockmod_table[0]);
-}
-
-static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)
-{
- clk_put(cpuclk);
- return 0;
-}
-
-static struct freq_attr *loongson2_table_attr[] = {
- &cpufreq_freq_attr_scaling_available_freqs,
- NULL,
-};
-
-static struct cpufreq_driver loongson2_cpufreq_driver = {
- .owner = THIS_MODULE,
- .name = "loongson2",
- .init = loongson2_cpufreq_cpu_init,
- .verify = loongson2_cpufreq_verify,
- .target = loongson2_cpufreq_target,
- .get = loongson2_cpufreq_get,
- .exit = loongson2_cpufreq_exit,
- .attr = loongson2_table_attr,
-};
-
-static struct platform_device_id platform_device_ids[] = {
- {
- .name = "loongson2_cpufreq",
- },
- {}
-};
-
-MODULE_DEVICE_TABLE(platform, platform_device_ids);
-
-static struct platform_driver platform_driver = {
- .driver = {
- .name = "loongson2_cpufreq",
- .owner = THIS_MODULE,
- },
- .id_table = platform_device_ids,
-};
-
-/*
- * This is the simple version of Loongson-2 wait, Maybe we need do this in
- * interrupt disabled context.
- */
-
-static DEFINE_SPINLOCK(loongson2_wait_lock);
-
-static void loongson2_cpu_wait(void)
-{
- unsigned long flags;
- u32 cpu_freq;
-
- spin_lock_irqsave(&loongson2_wait_lock, flags);
- cpu_freq = LOONGSON_CHIPCFG0;
- LOONGSON_CHIPCFG0 &= ~0x7; /* Put CPU into wait mode */
- LOONGSON_CHIPCFG0 = cpu_freq; /* Restore CPU state */
- spin_unlock_irqrestore(&loongson2_wait_lock, flags);
-}
-
-static int __init cpufreq_init(void)
-{
- int ret;
-
- /* Register platform stuff */
- ret = platform_driver_register(&platform_driver);
- if (ret)
- return ret;
-
- pr_info("cpufreq: Loongson-2F CPU frequency driver.\n");
-
- cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
-
- ret = cpufreq_register_driver(&loongson2_cpufreq_driver);
-
- if (!ret && !nowait) {
- saved_cpu_wait = cpu_wait;
- cpu_wait = loongson2_cpu_wait;
- }
-
- return ret;
-}
-
-static void __exit cpufreq_exit(void)
-{
- if (!nowait && saved_cpu_wait)
- cpu_wait = saved_cpu_wait;
- cpufreq_unregister_driver(&loongson2_cpufreq_driver);
- cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
-
- platform_driver_unregister(&platform_driver);
-}
-
-module_init(cpufreq_init);
-module_exit(cpufreq_exit);
-
-module_param(nowait, uint, 0644);
-MODULE_PARM_DESC(nowait, "Disable Loongson-2F specific wait");
-
-MODULE_AUTHOR("Yanhua <yanh@lemote.com>");
-MODULE_DESCRIPTION("cpufreq driver for Loongson2F");
-MODULE_LICENSE("GPL");
diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c
index 93aa302948d..d21264681e9 100644
--- a/arch/mips/kernel/crash.c
+++ b/arch/mips/kernel/crash.c
@@ -5,7 +5,6 @@
#include <linux/bootmem.h>
#include <linux/crash_dump.h>
#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/irq.h>
#include <linux/types.h>
#include <linux/sched.h>
diff --git a/arch/mips/kernel/crash_dump.c b/arch/mips/kernel/crash_dump.c
index 35bed0d2342..f291cf99b03 100644
--- a/arch/mips/kernel/crash_dump.c
+++ b/arch/mips/kernel/crash_dump.c
@@ -2,16 +2,7 @@
#include <linux/bootmem.h>
#include <linux/crash_dump.h>
#include <asm/uaccess.h>
-
-static int __init parse_savemaxmem(char *p)
-{
- if (p)
- saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1;
-
- return 1;
-}
-__setup("savemaxmem=", parse_savemaxmem);
-
+#include <linux/slab.h>
static void *kdump_buf_page;
diff --git a/arch/mips/kernel/csrc-gic.c b/arch/mips/kernel/csrc-gic.c
index 5dca24bce51..e0262090111 100644
--- a/arch/mips/kernel/csrc-gic.c
+++ b/arch/mips/kernel/csrc-gic.c
@@ -5,23 +5,14 @@
*
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
*/
-#include <linux/clocksource.h>
#include <linux/init.h>
+#include <linux/time.h>
-#include <asm/time.h>
#include <asm/gic.h>
static cycle_t gic_hpt_read(struct clocksource *cs)
{
- unsigned int hi, hi2, lo;
-
- do {
- GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi);
- GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo);
- GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2);
- } while (hi2 != hi);
-
- return (((cycle_t) hi) << 32) + lo;
+ return gic_read_count();
}
static struct clocksource gic_clocksource = {
diff --git a/arch/mips/kernel/csrc-ioasic.c b/arch/mips/kernel/csrc-ioasic.c
index 0654bff9b69..6cbbf6e106b 100644
--- a/arch/mips/kernel/csrc-ioasic.c
+++ b/arch/mips/kernel/csrc-ioasic.c
@@ -37,13 +37,13 @@ static struct clocksource clocksource_dec = {
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
-void __init dec_ioasic_clocksource_init(void)
+int __init dec_ioasic_clocksource_init(void)
{
unsigned int freq;
u32 start, end;
- int i = HZ / 10;
-
+ int i = HZ / 8;
+ ds1287_timer_state();
while (!ds1287_timer_state())
;
@@ -55,9 +55,15 @@ void __init dec_ioasic_clocksource_init(void)
end = dec_ioasic_hpt_read(&clocksource_dec);
- freq = (end - start) * 10;
+ freq = (end - start) * 8;
+
+ /* An early revision of the I/O ASIC didn't have the counter. */
+ if (!freq)
+ return -ENXIO;
+
printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq);
clocksource_dec.rating = 200 + freq / 10000000;
clocksource_register_hz(&clocksource_dec, freq);
+ return 0;
}
diff --git a/arch/mips/kernel/csrc-powertv.c b/arch/mips/kernel/csrc-powertv.c
deleted file mode 100644
index abd99ea911a..00000000000
--- a/arch/mips/kernel/csrc-powertv.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2008 Scientific-Atlanta, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-/*
- * The file comes from kernel/csrc-r4k.c
- */
-#include <linux/clocksource.h>
-#include <linux/init.h>
-
-#include <asm/time.h> /* Not included in linux/time.h */
-
-#include <asm/mach-powertv/asic_regs.h>
-#include "powertv-clock.h"
-
-/* MIPS PLL Register Definitions */
-#define PLL_GET_M(x) (((x) >> 8) & 0x000000FF)
-#define PLL_GET_N(x) (((x) >> 16) & 0x000000FF)
-#define PLL_GET_P(x) (((x) >> 24) & 0x00000007)
-
-/*
- * returns: Clock frequency in kHz
- */
-unsigned int __init mips_get_pll_freq(void)
-{
- unsigned int pll_reg, m, n, p;
- unsigned int fin = 54000; /* Base frequency in kHz */
- unsigned int fout;
-
- /* Read PLL register setting */
- pll_reg = asic_read(mips_pll_setup);
- m = PLL_GET_M(pll_reg);
- n = PLL_GET_N(pll_reg);
- p = PLL_GET_P(pll_reg);
- pr_info("MIPS PLL Register:0x%x M=%d N=%d P=%d\n", pll_reg, m, n, p);
-
- /* Calculate clock frequency = (2 * N * 54MHz) / (M * (2**P)) */
- fout = ((2 * n * fin) / (m * (0x01 << p)));
-
- pr_info("MIPS Clock Freq=%d kHz\n", fout);
-
- return fout;
-}
-
-static cycle_t c0_hpt_read(struct clocksource *cs)
-{
- return read_c0_count();
-}
-
-static struct clocksource clocksource_mips = {
- .name = "powertv-counter",
- .read = c0_hpt_read,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static void __init powertv_c0_hpt_clocksource_init(void)
-{
- unsigned int pll_freq = mips_get_pll_freq();
-
- pr_info("CPU frequency %d.%02d MHz\n", pll_freq / 1000,
- (pll_freq % 1000) * 100 / 1000);
-
- mips_hpt_frequency = pll_freq / 2 * 1000;
-
- clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
-
- clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
-}
-
-/**
- * struct tim_c - free running counter
- * @hi: High 16 bits of the counter
- * @lo: Low 32 bits of the counter
- *
- * Lays out the structure of the free running counter in memory. This counter
- * increments at a rate of 27 MHz/8 on all platforms.
- */
-struct tim_c {
- unsigned int hi;
- unsigned int lo;
-};
-
-static struct tim_c *tim_c;
-
-static cycle_t tim_c_read(struct clocksource *cs)
-{
- unsigned int hi;
- unsigned int next_hi;
- unsigned int lo;
-
- hi = readl(&tim_c->hi);
-
- for (;;) {
- lo = readl(&tim_c->lo);
- next_hi = readl(&tim_c->hi);
- if (next_hi == hi)
- break;
- hi = next_hi;
- }
-
-pr_crit("%s: read %llx\n", __func__, ((u64) hi << 32) | lo);
- return ((u64) hi << 32) | lo;
-}
-
-#define TIM_C_SIZE 48 /* # bits in the timer */
-
-static struct clocksource clocksource_tim_c = {
- .name = "powertv-tim_c",
- .read = tim_c_read,
- .mask = CLOCKSOURCE_MASK(TIM_C_SIZE),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-/**
- * powertv_tim_c_clocksource_init - set up a clock source for the TIM_C clock
- *
- * We know that TIM_C counts at 27 MHz/8, so each cycle corresponds to
- * 1 / (27,000,000/8) seconds.
- */
-static void __init powertv_tim_c_clocksource_init(void)
-{
- const unsigned long counts_per_second = 27000000 / 8;
-
- clocksource_tim_c.rating = 200;
-
- clocksource_register_hz(&clocksource_tim_c, counts_per_second);
- tim_c = (struct tim_c *) asic_reg_addr(tim_ch);
-}
-
-/**
- powertv_clocksource_init - initialize all clocksources
- */
-void __init powertv_clocksource_init(void)
-{
- powertv_c0_hpt_clocksource_init();
- powertv_tim_c_clocksource_init();
-}
diff --git a/arch/mips/kernel/early_printk.c b/arch/mips/kernel/early_printk.c
index 9e6440eaa45..505cb77d128 100644
--- a/arch/mips/kernel/early_printk.c
+++ b/arch/mips/kernel/early_printk.c
@@ -7,7 +7,9 @@
* Copyright (C) 2007 MIPS Technologies, Inc.
* written by Ralf Baechle (ralf@linux-mips.org)
*/
+#include <linux/kernel.h>
#include <linux/console.h>
+#include <linux/printk.h>
#include <linux/init.h>
#include <asm/setup.h>
@@ -24,20 +26,18 @@ static void early_console_write(struct console *con, const char *s, unsigned n)
}
}
-static struct console early_console = {
+static struct console early_console_prom = {
.name = "early",
.write = early_console_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1
};
-static int early_console_initialized __initdata;
-
void __init setup_early_printk(void)
{
- if (early_console_initialized)
+ if (early_console)
return;
- early_console_initialized = 1;
+ early_console = &early_console_prom;
- register_console(&early_console);
+ register_console(&early_console_prom);
}
diff --git a/arch/mips/kernel/early_printk_8250.c b/arch/mips/kernel/early_printk_8250.c
new file mode 100644
index 00000000000..83cea376755
--- /dev/null
+++ b/arch/mips/kernel/early_printk_8250.c
@@ -0,0 +1,66 @@
+/*
+ * 8250/16550-type serial ports prom_putchar()
+ *
+ * Copyright (C) 2010 Yoichi Yuasa <yuasa@linux-mips.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/io.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+
+static void __iomem *serial8250_base;
+static unsigned int serial8250_reg_shift;
+static unsigned int serial8250_tx_timeout;
+
+void setup_8250_early_printk_port(unsigned long base, unsigned int reg_shift,
+ unsigned int timeout)
+{
+ serial8250_base = (void __iomem *)base;
+ serial8250_reg_shift = reg_shift;
+ serial8250_tx_timeout = timeout;
+}
+
+static inline u8 serial_in(int offset)
+{
+ return readb(serial8250_base + (offset << serial8250_reg_shift));
+}
+
+static inline void serial_out(int offset, char value)
+{
+ writeb(value, serial8250_base + (offset << serial8250_reg_shift));
+}
+
+void prom_putchar(char c)
+{
+ unsigned int timeout;
+ int status, bits;
+
+ if (!serial8250_base)
+ return;
+
+ timeout = serial8250_tx_timeout;
+ bits = UART_LSR_TEMT | UART_LSR_THRE;
+
+ do {
+ status = serial_in(UART_LSR);
+
+ if (--timeout == 0)
+ break;
+ } while ((status & bits) != bits);
+
+ if (timeout)
+ serial_out(UART_TX, c);
+}
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index e5786858cdb..4353d323f01 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -16,9 +16,6 @@
#include <asm/isadep.h>
#include <asm/thread_info.h>
#include <asm/war.h>
-#ifdef CONFIG_MIPS_MT_SMTC
-#include <asm/mipsmtregs.h>
-#endif
#ifndef CONFIG_PREEMPT
#define resume_kernel restore_all
@@ -89,41 +86,6 @@ FEXPORT(syscall_exit)
bnez t0, syscall_exit_work
restore_all: # restore full frame
-#ifdef CONFIG_MIPS_MT_SMTC
-#ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
-/* Re-arm any temporarily masked interrupts not explicitly "acked" */
- mfc0 v0, CP0_TCSTATUS
- ori v1, v0, TCSTATUS_IXMT
- mtc0 v1, CP0_TCSTATUS
- andi v0, TCSTATUS_IXMT
- _ehb
- mfc0 t0, CP0_TCCONTEXT
- DMT 9 # dmt t1
- jal mips_ihb
- mfc0 t2, CP0_STATUS
- andi t3, t0, 0xff00
- or t2, t2, t3
- mtc0 t2, CP0_STATUS
- _ehb
- andi t1, t1, VPECONTROL_TE
- beqz t1, 1f
- EMT
-1:
- mfc0 v1, CP0_TCSTATUS
- /* We set IXMT above, XOR should clear it here */
- xori v1, v1, TCSTATUS_IXMT
- or v1, v0, v1
- mtc0 v1, CP0_TCSTATUS
- _ehb
- xor t0, t0, t3
- mtc0 t0, CP0_TCCONTEXT
-#endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */
-/* Detect and execute deferred IPI "interrupts" */
- LONG_L s0, TI_REGS($28)
- LONG_S sp, TI_REGS($28)
- jal deferred_smtc_ipi
- LONG_S s0, TI_REGS($28)
-#endif /* CONFIG_MIPS_MT_SMTC */
.set noat
RESTORE_TEMP
RESTORE_AT
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
index cf5509f13dd..60e7e5e45af 100644
--- a/arch/mips/kernel/ftrace.c
+++ b/arch/mips/kernel/ftrace.c
@@ -11,11 +11,14 @@
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/ftrace.h>
+#include <linux/syscalls.h>
#include <asm/asm.h>
#include <asm/asm-offsets.h>
#include <asm/cacheflush.h>
+#include <asm/syscall.h>
#include <asm/uasm.h>
+#include <asm/unistd.h>
#include <asm-generic/sections.h>
@@ -25,12 +28,16 @@
#define MCOUNT_OFFSET_INSNS 4
#endif
+#ifdef CONFIG_DYNAMIC_FTRACE
+
/* Arch override because MIPS doesn't need to run this from stop_machine() */
void arch_ftrace_update_code(int command)
{
ftrace_modify_all_code(command);
}
+#endif
+
/*
* Check if the address is in kernel space
*
@@ -83,6 +90,7 @@ static inline void ftrace_dyn_arch_init_insns(void)
static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
{
int faulted;
+ mm_segment_t old_fs;
/* *(unsigned int *)ip = new_code; */
safe_store_code(new_code, ip, faulted);
@@ -90,7 +98,10 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
if (unlikely(faulted))
return -EFAULT;
+ old_fs = get_fs();
+ set_fs(get_ds());
flush_icache_range(ip, ip + 8);
+ set_fs(old_fs);
return 0;
}
@@ -104,11 +115,10 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
safe_store_code(new_code1, ip, faulted);
if (unlikely(faulted))
return -EFAULT;
- ip += 4;
- safe_store_code(new_code2, ip, faulted);
+ safe_store_code(new_code2, ip + 4, faulted);
if (unlikely(faulted))
return -EFAULT;
- flush_icache_range(ip, ip + 8); /* original ip + 12 */
+ flush_icache_range(ip, ip + 8);
return 0;
}
#endif
@@ -191,7 +201,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return ftrace_modify_code(FTRACE_CALL_IP, new);
}
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
/* Encode the instructions when booting */
ftrace_dyn_arch_init_insns();
@@ -199,9 +209,6 @@ int __init ftrace_dyn_arch_init(void *data)
/* Remove "b ftrace_stub" to ensure ftrace_caller() is executed */
ftrace_modify_code(MCOUNT_ADDR, INSN_NOP);
- /* The return code is retured via data */
- *(unsigned long *)data = 0;
-
return 0;
}
#endif /* CONFIG_DYNAMIC_FTRACE */
@@ -360,3 +367,33 @@ out:
WARN_ON(1);
}
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_FTRACE_SYSCALLS
+
+#ifdef CONFIG_32BIT
+unsigned long __init arch_syscall_addr(int nr)
+{
+ return (unsigned long)sys_call_table[nr - __NR_O32_Linux];
+}
+#endif
+
+#ifdef CONFIG_64BIT
+
+unsigned long __init arch_syscall_addr(int nr)
+{
+#ifdef CONFIG_MIPS32_N32
+ if (nr >= __NR_N32_Linux && nr <= __NR_N32_Linux + __NR_N32_Linux_syscalls)
+ return (unsigned long)sysn32_call_table[nr - __NR_N32_Linux];
+#endif
+ if (nr >= __NR_64_Linux && nr <= __NR_64_Linux + __NR_64_Linux_syscalls)
+ return (unsigned long)sys_call_table[nr - __NR_64_Linux];
+#ifdef CONFIG_MIPS32_O32
+ if (nr >= __NR_O32_Linux && nr <= __NR_O32_Linux + __NR_O32_Linux_syscalls)
+ return (unsigned long)sys32_call_table[nr - __NR_O32_Linux];
+#endif
+
+ return (unsigned long) &sys_ni_syscall;
+}
+#endif
+
+#endif /* CONFIG_FTRACE_SYSCALLS */
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index ecb347ce1b3..ac35e12cb1f 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -5,8 +5,8 @@
*
* Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- * Copyright (C) 2001 MIPS Technologies, Inc.
* Copyright (C) 2002, 2007 Maciej W. Rozycki
+ * Copyright (C) 2001, 2012 MIPS Technologies, Inc. All rights reserved.
*/
#include <linux/init.h>
@@ -21,27 +21,8 @@
#include <asm/war.h>
#include <asm/thread_info.h>
-#define PANIC_PIC(msg) \
- .set push; \
- .set reorder; \
- PTR_LA a0,8f; \
- .set noat; \
- PTR_LA AT, panic; \
- jr AT; \
-9: b 9b; \
- .set pop; \
- TEXT(msg)
-
__INIT
-NESTED(except_vec0_generic, 0, sp)
- PANIC_PIC("Exception vector 0 called")
- END(except_vec0_generic)
-
-NESTED(except_vec1_generic, 0, sp)
- PANIC_PIC("Exception vector 1 called")
- END(except_vec1_generic)
-
/*
* General exception vector for all other CPUs.
*
@@ -72,7 +53,7 @@ NESTED(except_vec3_generic, 0, sp)
*/
NESTED(except_vec3_r4000, 0, sp)
.set push
- .set mips3
+ .set arch=r4000
.set noat
mfc0 k1, CP0_CAUSE
li k0, 31<<2
@@ -127,7 +108,7 @@ handle_vcei:
__FINIT
.align 5 /* 32 byte rollback region */
-LEAF(r4k_wait)
+LEAF(__r4k_wait)
.set push
.set noreorder
/* start of rollback region */
@@ -138,20 +119,27 @@ LEAF(r4k_wait)
nop
nop
nop
- .set mips3
+#ifdef CONFIG_CPU_MICROMIPS
+ nop
+ nop
+ nop
+ nop
+#endif
+ .set arch=r4000
wait
/* end of rollback region (the region size must be power of two) */
- .set pop
1:
jr ra
- END(r4k_wait)
+ nop
+ .set pop
+ END(__r4k_wait)
.macro BUILD_ROLLBACK_PROLOGUE handler
FEXPORT(rollback_\handler)
.set push
.set noat
MFC0 k0, CP0_EPC
- PTR_LA k1, r4k_wait
+ PTR_LA k1, __r4k_wait
ori k0, 0x1f /* 32 byte rollback region */
xori k0, 0x1f
bne k0, k1, 9f
@@ -201,7 +189,11 @@ NESTED(handle_int, PT_SIZE, sp)
LONG_L s0, TI_REGS($28)
LONG_S sp, TI_REGS($28)
PTR_LA ra, ret_from_irq
- j plat_irq_dispatch
+ PTR_LA v0, plat_irq_dispatch
+ jr v0
+#ifdef CONFIG_CPU_MICROMIPS
+ nop
+#endif
END(handle_int)
__INIT
@@ -222,11 +214,14 @@ NESTED(except_vec4, 0, sp)
/*
* EJTAG debug exception handler.
* The EJTAG debug exception entry point is 0xbfc00480, which
- * normally is in the boot PROM, so the boot PROM must do a
+ * normally is in the boot PROM, so the boot PROM must do an
* unconditional jump to this vector.
*/
NESTED(except_vec_ejtag_debug, 0, sp)
j ejtag_debug_handler
+#ifdef CONFIG_CPU_MICROMIPS
+ nop
+#endif
END(except_vec_ejtag_debug)
__FINIT
@@ -242,18 +237,10 @@ NESTED(except_vec_vi, 0, sp)
SAVE_AT
.set push
.set noreorder
-#ifdef CONFIG_MIPS_MT_SMTC
- /*
- * To keep from blindly blocking *all* interrupts
- * during service by SMTC kernel, we also want to
- * pass the IM value to be cleared.
- */
-FEXPORT(except_vec_vi_mori)
- ori a0, $0, 0
-#endif /* CONFIG_MIPS_MT_SMTC */
+ PTR_LA v1, except_vec_vi_handler
FEXPORT(except_vec_vi_lui)
lui v0, 0 /* Patched */
- j except_vec_vi_handler
+ jr v1
FEXPORT(except_vec_vi_ori)
ori v0, 0 /* Patched */
.set pop
@@ -267,37 +254,10 @@ EXPORT(except_vec_vi_end)
NESTED(except_vec_vi_handler, 0, sp)
SAVE_TEMP
SAVE_STATIC
-#ifdef CONFIG_MIPS_MT_SMTC
- /*
- * SMTC has an interesting problem that interrupts are level-triggered,
- * and the CLI macro will clear EXL, potentially causing a duplicate
- * interrupt service invocation. So we need to clear the associated
- * IM bit of Status prior to doing CLI, and restore it after the
- * service routine has been invoked - we must assume that the
- * service routine will have cleared the state, and any active
- * level represents a new or otherwised unserviced event...
- */
- mfc0 t1, CP0_STATUS
- and t0, a0, t1
-#ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
- mfc0 t2, CP0_TCCONTEXT
- or t2, t0, t2
- mtc0 t2, CP0_TCCONTEXT
-#endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */
- xor t1, t1, t0
- mtc0 t1, CP0_STATUS
- _ehb
-#endif /* CONFIG_MIPS_MT_SMTC */
CLI
#ifdef CONFIG_TRACE_IRQFLAGS
move s0, v0
-#ifdef CONFIG_MIPS_MT_SMTC
- move s1, a0
-#endif
TRACE_IRQS_OFF
-#ifdef CONFIG_MIPS_MT_SMTC
- move a0, s1
-#endif
move v0, s0
#endif
@@ -354,6 +314,9 @@ EXPORT(ejtag_debug_buffer)
*/
NESTED(except_vec_nmi, 0, sp)
j nmi_handler
+#ifdef CONFIG_CPU_MICROMIPS
+ nop
+#endif
END(except_vec_nmi)
__FINIT
@@ -361,12 +324,20 @@ NESTED(except_vec_nmi, 0, sp)
NESTED(nmi_handler, PT_SIZE, sp)
.set push
.set noat
+ /*
+ * Clear ERL - restore segment mapping
+ * Clear BEV - required for page fault exception handler to work
+ */
+ mfc0 k0, CP0_STATUS
+ ori k0, k0, ST0_EXL
+ li k1, ~(ST0_BEV | ST0_ERL)
+ and k0, k0, k1
+ mtc0 k0, CP0_STATUS
+ _ehb
SAVE_ALL
move a0, sp
jal nmi_exception_handler
- RESTORE_ALL
- .set mips3
- eret
+ /* nmi_exception_handler never returns */
.set pop
END(nmi_handler)
@@ -454,7 +425,10 @@ NESTED(nmi_handler, PT_SIZE, sp)
BUILD_HANDLER cpu cpu sti silent /* #11 */
BUILD_HANDLER ov ov sti silent /* #12 */
BUILD_HANDLER tr tr sti silent /* #13 */
+ BUILD_HANDLER msa_fpe msa_fpe sti silent /* #14 */
BUILD_HANDLER fpe fpe fpe silent /* #15 */
+ BUILD_HANDLER ftlb ftlb none silent /* #16 */
+ BUILD_HANDLER msa msa sti silent /* #21 */
BUILD_HANDLER mdmx mdmx sti silent /* #22 */
#ifdef CONFIG_HARDWARE_WATCHPOINTS
/*
@@ -472,9 +446,6 @@ NESTED(nmi_handler, PT_SIZE, sp)
.align 5
LEAF(handle_ri_rdhwr_vivt)
-#ifdef CONFIG_MIPS_MT_SMTC
- PANIC_PIC("handle_ri_rdhwr_vivt called")
-#else
.set push
.set noat
.set noreorder
@@ -493,20 +464,41 @@ NESTED(nmi_handler, PT_SIZE, sp)
.set pop
bltz k1, handle_ri /* slow path */
/* fall thru */
-#endif
END(handle_ri_rdhwr_vivt)
LEAF(handle_ri_rdhwr)
.set push
.set noat
.set noreorder
- /* 0x7c03e83b: rdhwr v1,$29 */
+ /* MIPS32: 0x7c03e83b: rdhwr v1,$29 */
+ /* microMIPS: 0x007d6b3c: rdhwr v1,$29 */
MFC0 k1, CP0_EPC
- lui k0, 0x7c03
- lw k1, (k1)
- ori k0, 0xe83b
- .set reorder
+#if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS64_R2)
+ and k0, k1, 1
+ beqz k0, 1f
+ xor k1, k0
+ lhu k0, (k1)
+ lhu k1, 2(k1)
+ ins k1, k0, 16, 16
+ lui k0, 0x007d
+ b docheck
+ ori k0, 0x6b3c
+1:
+ lui k0, 0x7c03
+ lw k1, (k1)
+ ori k0, 0xe83b
+#else
+ andi k0, k1, 1
+ bnez k0, handle_ri
+ lui k0, 0x7c03
+ lw k1, (k1)
+ ori k0, 0xe83b
+#endif
+ .set reorder
+docheck:
bne k0, k1, handle_ri /* if not ours */
+
+isrdhwr:
/* The insn is rdhwr. No need to check CAUSE.BD here. */
get_saved_sp /* k1 := current_thread_info */
.set noreorder
@@ -531,7 +523,7 @@ NESTED(nmi_handler, PT_SIZE, sp)
ori k1, _THREAD_MASK
xori k1, _THREAD_MASK
LONG_L v1, TI_TP_VALUE(k1)
- .set mips3
+ .set arch=r4000
eret
.set mips0
#endif
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index c61cdaed2b1..95afd663cd4 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -28,45 +28,6 @@
#include <kernel-entry-init.h>
/*
- * inputs are the text nasid in t1, data nasid in t2.
- */
- .macro MAPPED_KERNEL_SETUP_TLB
-#ifdef CONFIG_MAPPED_KERNEL
- /*
- * This needs to read the nasid - assume 0 for now.
- * Drop in 0xffffffffc0000000 in tlbhi, 0+VG in tlblo_0,
- * 0+DVG in tlblo_1.
- */
- dli t0, 0xffffffffc0000000
- dmtc0 t0, CP0_ENTRYHI
- li t0, 0x1c000 # Offset of text into node memory
- dsll t1, NASID_SHFT # Shift text nasid into place
- dsll t2, NASID_SHFT # Same for data nasid
- or t1, t1, t0 # Physical load address of kernel text
- or t2, t2, t0 # Physical load address of kernel data
- dsrl t1, 12 # 4K pfn
- dsrl t2, 12 # 4K pfn
- dsll t1, 6 # Get pfn into place
- dsll t2, 6 # Get pfn into place
- li t0, ((_PAGE_GLOBAL|_PAGE_VALID| _CACHE_CACHABLE_COW) >> 6)
- or t0, t0, t1
- mtc0 t0, CP0_ENTRYLO0 # physaddr, VG, cach exlwr
- li t0, ((_PAGE_GLOBAL|_PAGE_VALID| _PAGE_DIRTY|_CACHE_CACHABLE_COW) >> 6)
- or t0, t0, t2
- mtc0 t0, CP0_ENTRYLO1 # physaddr, DVG, cach exlwr
- li t0, 0x1ffe000 # MAPPED_KERN_TLBMASK, TLBPGMASK_16M
- mtc0 t0, CP0_PAGEMASK
- li t0, 0 # KMAP_INX
- mtc0 t0, CP0_INDEX
- li t0, 1
- mtc0 t0, CP0_WIRED
- tlbwi
-#else
- mtc0 zero, CP0_WIRED
-#endif
- .endm
-
- /*
* For the moment disable interrupts, mark the kernel mode and
* set ST0_KX so that the CPU does not spit fire when using
* 64-bit addresses. A full initialization of the CPU's status
@@ -74,33 +35,12 @@
*/
.macro setup_c0_status set clr
.set push
-#ifdef CONFIG_MIPS_MT_SMTC
- /*
- * For SMTC, we need to set privilege and disable interrupts only for
- * the current TC, using the TCStatus register.
- */
- mfc0 t0, CP0_TCSTATUS
- /* Fortunately CU 0 is in the same place in both registers */
- /* Set TCU0, TMX, TKSU (for later inversion) and IXMT */
- li t1, ST0_CU0 | 0x08001c00
- or t0, t1
- /* Clear TKSU, leave IXMT */
- xori t0, 0x00001800
- mtc0 t0, CP0_TCSTATUS
- _ehb
- /* We need to leave the global IE bit set, but clear EXL...*/
- mfc0 t0, CP0_STATUS
- or t0, ST0_CU0 | ST0_EXL | ST0_ERL | \set | \clr
- xor t0, ST0_EXL | ST0_ERL | \clr
- mtc0 t0, CP0_STATUS
-#else
mfc0 t0, CP0_STATUS
or t0, ST0_CU0|\set|0x1f|\clr
xor t0, 0x1f|\clr
mtc0 t0, CP0_STATUS
.set noreorder
sll zero,3 # ehb
-#endif
.set pop
.endm
@@ -154,24 +94,6 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
jr t0
0:
-#ifdef CONFIG_MIPS_MT_SMTC
- /*
- * In SMTC kernel, "CLI" is thread-specific, in TCStatus.
- * We still need to enable interrupts globally in Status,
- * and clear EXL/ERL.
- *
- * TCContext is used to track interrupt levels under
- * service in SMTC kernel. Clear for boot TC before
- * allowing any interrupts.
- */
- mtc0 zero, CP0_TCCONTEXT
-
- mfc0 t0, CP0_STATUS
- ori t0, t0, 0xff1f
- xori t0, t0, 0x001e
- mtc0 t0, CP0_STATUS
-#endif /* CONFIG_MIPS_MT_SMTC */
-
PTR_LA t0, __bss_start # clear .bss
LONG_S zero, (t0)
PTR_LA t1, __bss_stop - LONGSIZE
@@ -197,35 +119,14 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
j start_kernel
END(kernel_entry)
- __CPUINIT
-
#ifdef CONFIG_SMP
/*
* SMP slave cpus entry point. Board specific code for bootstrap calls this
* function after setting up the stack and gp registers.
*/
NESTED(smp_bootstrap, 16, sp)
-#ifdef CONFIG_MIPS_MT_SMTC
- /*
- * Read-modify-writes of Status must be atomic, and this
- * is one case where CLI is invoked without EXL being
- * necessarily set. The CLI and setup_c0_status will
- * in fact be redundant for all but the first TC of
- * each VPE being booted.
- */
- DMT 10 # dmt t2 /* t0, t1 are used by CLI and setup_c0_status() */
- jal mips_ihb
-#endif /* CONFIG_MIPS_MT_SMTC */
- setup_c0_status_sec
smp_slave_setup
-#ifdef CONFIG_MIPS_MT_SMTC
- andi t2, t2, VPECONTROL_TE
- beqz t2, 2f
- EMT # emt
-2:
-#endif /* CONFIG_MIPS_MT_SMTC */
+ setup_c0_status_sec
j start_secondary
END(smp_bootstrap)
#endif /* CONFIG_SMP */
-
- __FINIT
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
index 2b91fe80c43..50b364897dd 100644
--- a/arch/mips/kernel/i8259.c
+++ b/arch/mips/kernel/i8259.c
@@ -42,9 +42,6 @@ static struct irq_chip i8259A_chip = {
.irq_disable = disable_8259A_irq,
.irq_unmask = enable_8259A_irq,
.irq_mask_ack = mask_and_ack_8259A,
-#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF
- .irq_set_affinity = plat_set_irq_affinity,
-#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
};
/*
@@ -180,7 +177,6 @@ handle_real_irq:
outb(cached_master_mask, PIC_MASTER_IMR);
outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */
}
- smtc_im_ack_irq(irq);
raw_spin_unlock_irqrestore(&i8259A_lock, flags);
return;
diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c
new file mode 100644
index 00000000000..09ce4598075
--- /dev/null
+++ b/arch/mips/kernel/idle.c
@@ -0,0 +1,249 @@
+/*
+ * MIPS idle loop and WAIT instruction support.
+ *
+ * Copyright (C) xxxx the Anonymous
+ * Copyright (C) 1994 - 2006 Ralf Baechle
+ * Copyright (C) 2003, 2004 Maciej W. Rozycki
+ * Copyright (C) 2001, 2004, 2011, 2012 MIPS Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/irqflags.h>
+#include <linux/printk.h>
+#include <linux/sched.h>
+#include <asm/cpu.h>
+#include <asm/cpu-info.h>
+#include <asm/cpu-type.h>
+#include <asm/idle.h>
+#include <asm/mipsregs.h>
+
+/*
+ * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
+ * the implementation of the "wait" feature differs between CPU families. This
+ * points to the function that implements CPU specific wait.
+ * The wait instruction stops the pipeline and reduces the power consumption of
+ * the CPU very much.
+ */
+void (*cpu_wait)(void);
+EXPORT_SYMBOL(cpu_wait);
+
+static void r3081_wait(void)
+{
+ unsigned long cfg = read_c0_conf();
+ write_c0_conf(cfg | R30XX_CONF_HALT);
+ local_irq_enable();
+}
+
+static void r39xx_wait(void)
+{
+ if (!need_resched())
+ write_c0_conf(read_c0_conf() | TX39_CONF_HALT);
+ local_irq_enable();
+}
+
+void r4k_wait(void)
+{
+ local_irq_enable();
+ __r4k_wait();
+}
+
+/*
+ * This variant is preferable as it allows testing need_resched and going to
+ * sleep depending on the outcome atomically. Unfortunately the "It is
+ * implementation-dependent whether the pipeline restarts when a non-enabled
+ * interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes
+ * using this version a gamble.
+ */
+void r4k_wait_irqoff(void)
+{
+ if (!need_resched())
+ __asm__(
+ " .set push \n"
+ " .set arch=r4000 \n"
+ " wait \n"
+ " .set pop \n");
+ local_irq_enable();
+ __asm__(
+ " .globl __pastwait \n"
+ "__pastwait: \n");
+}
+
+/*
+ * The RM7000 variant has to handle erratum 38. The workaround is to not
+ * have any pending stores when the WAIT instruction is executed.
+ */
+static void rm7k_wait_irqoff(void)
+{
+ if (!need_resched())
+ __asm__(
+ " .set push \n"
+ " .set arch=r4000 \n"
+ " .set noat \n"
+ " mfc0 $1, $12 \n"
+ " sync \n"
+ " mtc0 $1, $12 # stalls until W stage \n"
+ " wait \n"
+ " mtc0 $1, $12 # stalls until W stage \n"
+ " .set pop \n");
+ local_irq_enable();
+}
+
+/*
+ * Au1 'wait' is only useful when the 32kHz counter is used as timer,
+ * since coreclock (and the cp0 counter) stops upon executing it. Only an
+ * interrupt can wake it, so they must be enabled before entering idle modes.
+ */
+static void au1k_wait(void)
+{
+ unsigned long c0status = read_c0_status() | 1; /* irqs on */
+
+ __asm__(
+ " .set arch=r4000 \n"
+ " cache 0x14, 0(%0) \n"
+ " cache 0x14, 32(%0) \n"
+ " sync \n"
+ " mtc0 %1, $12 \n" /* wr c0status */
+ " wait \n"
+ " nop \n"
+ " nop \n"
+ " nop \n"
+ " nop \n"
+ " .set mips0 \n"
+ : : "r" (au1k_wait), "r" (c0status));
+}
+
+static int __initdata nowait;
+
+static int __init wait_disable(char *s)
+{
+ nowait = 1;
+
+ return 1;
+}
+
+__setup("nowait", wait_disable);
+
+void __init check_wait(void)
+{
+ struct cpuinfo_mips *c = &current_cpu_data;
+
+ if (nowait) {
+ printk("Wait instruction disabled.\n");
+ return;
+ }
+
+ switch (current_cpu_type()) {
+ case CPU_R3081:
+ case CPU_R3081E:
+ cpu_wait = r3081_wait;
+ break;
+ case CPU_TX3927:
+ cpu_wait = r39xx_wait;
+ break;
+ case CPU_R4200:
+/* case CPU_R4300: */
+ case CPU_R4600:
+ case CPU_R4640:
+ case CPU_R4650:
+ case CPU_R4700:
+ case CPU_R5000:
+ case CPU_R5500:
+ case CPU_NEVADA:
+ case CPU_4KC:
+ case CPU_4KEC:
+ case CPU_4KSC:
+ case CPU_5KC:
+ case CPU_25KF:
+ case CPU_PR4450:
+ case CPU_BMIPS3300:
+ case CPU_BMIPS4350:
+ case CPU_BMIPS4380:
+ case CPU_BMIPS5000:
+ case CPU_CAVIUM_OCTEON:
+ case CPU_CAVIUM_OCTEON_PLUS:
+ case CPU_CAVIUM_OCTEON2:
+ case CPU_CAVIUM_OCTEON3:
+ case CPU_JZRISC:
+ case CPU_LOONGSON1:
+ case CPU_XLR:
+ case CPU_XLP:
+ cpu_wait = r4k_wait;
+ break;
+
+ case CPU_RM7000:
+ cpu_wait = rm7k_wait_irqoff;
+ break;
+
+ case CPU_M14KC:
+ case CPU_M14KEC:
+ case CPU_24K:
+ case CPU_34K:
+ case CPU_1004K:
+ case CPU_1074K:
+ case CPU_INTERAPTIV:
+ case CPU_PROAPTIV:
+ case CPU_P5600:
+ case CPU_M5150:
+ cpu_wait = r4k_wait;
+ if (read_c0_config7() & MIPS_CONF7_WII)
+ cpu_wait = r4k_wait_irqoff;
+ break;
+
+ case CPU_74K:
+ cpu_wait = r4k_wait;
+ if ((c->processor_id & 0xff) >= PRID_REV_ENCODE_332(2, 1, 0))
+ cpu_wait = r4k_wait_irqoff;
+ break;
+
+ case CPU_TX49XX:
+ cpu_wait = r4k_wait_irqoff;
+ break;
+ case CPU_ALCHEMY:
+ cpu_wait = au1k_wait;
+ break;
+ case CPU_20KC:
+ /*
+ * WAIT on Rev1.0 has E1, E2, E3 and E16.
+ * WAIT on Rev2.0 and Rev3.0 has E16.
+ * Rev3.1 WAIT is nop, why bother
+ */
+ if ((c->processor_id & 0xff) <= 0x64)
+ break;
+
+ /*
+ * Another rev is incremeting c0_count at a reduced clock
+ * rate while in WAIT mode. So we basically have the choice
+ * between using the cp0 timer as clocksource or avoiding
+ * the WAIT instruction. Until more details are known,
+ * disable the use of WAIT for 20Kc entirely.
+ cpu_wait = r4k_wait;
+ */
+ break;
+ default:
+ break;
+ }
+}
+
+void arch_cpu_idle(void)
+{
+ if (cpu_wait)
+ cpu_wait();
+ else
+ local_irq_enable();
+}
+
+#ifdef CONFIG_CPU_IDLE
+
+int mips_cpuidle_wait_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ arch_cpu_idle();
+ return index;
+}
+
+#endif
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c
index 485e6a961b3..88e4c323382 100644
--- a/arch/mips/kernel/irq-gic.c
+++ b/arch/mips/kernel/irq-gic.c
@@ -10,15 +10,17 @@
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/irq.h>
+#include <linux/clocksource.h>
#include <asm/io.h>
#include <asm/gic.h>
#include <asm/setup.h>
#include <asm/traps.h>
-#include <asm/gcmpregs.h>
#include <linux/hardirq.h>
#include <asm-generic/bitops/find.h>
+unsigned int gic_frequency;
+unsigned int gic_present;
unsigned long _gic_base;
unsigned int gic_irq_base;
unsigned int gic_irq_flags[GIC_NUM_INTRS];
@@ -30,6 +32,54 @@ static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
static struct gic_pending_regs pending_regs[NR_CPUS];
static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
+#if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC)
+cycle_t gic_read_count(void)
+{
+ unsigned int hi, hi2, lo;
+
+ do {
+ GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi);
+ GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo);
+ GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2);
+ } while (hi2 != hi);
+
+ return (((cycle_t) hi) << 32) + lo;
+}
+
+void gic_write_compare(cycle_t cnt)
+{
+ GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI),
+ (int)(cnt >> 32));
+ GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO),
+ (int)(cnt & 0xffffffff));
+}
+
+void gic_write_cpu_compare(cycle_t cnt, int cpu)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu);
+ GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI),
+ (int)(cnt >> 32));
+ GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO),
+ (int)(cnt & 0xffffffff));
+
+ local_irq_restore(flags);
+}
+
+cycle_t gic_read_compare(void)
+{
+ unsigned int hi, lo;
+
+ GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), hi);
+ GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), lo);
+
+ return (((cycle_t) hi) << 32) + lo;
+}
+#endif
+
unsigned int gic_get_timer_pending(void)
{
unsigned int vpe_pending;
@@ -116,6 +166,17 @@ static void __init vpe_local_setup(unsigned int numvpes)
}
}
+unsigned int gic_compare_int(void)
+{
+ unsigned int pending;
+
+ GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending);
+ if (pending & GIC_VPE_PEND_CMP_MSK)
+ return 1;
+ else
+ return 0;
+}
+
unsigned int gic_get_int(void)
{
unsigned int i;
@@ -172,16 +233,15 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
/* Assumption : cpumask refers to a single CPU */
spin_lock_irqsave(&gic_lock, flags);
- for (;;) {
- /* Re-route this IRQ */
- GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp));
- /* Update the pcpu_masks */
- for (i = 0; i < NR_CPUS; i++)
- clear_bit(irq, pcpu_masks[i].pcpu_mask);
- set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
+ /* Re-route this IRQ */
+ GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp));
+
+ /* Update the pcpu_masks */
+ for (i = 0; i < NR_CPUS; i++)
+ clear_bit(irq, pcpu_masks[i].pcpu_mask);
+ set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
- }
cpumask_copy(d->affinity, cpumask);
spin_unlock_irqrestore(&gic_lock, flags);
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
index fab40f7d2e0..a734b2c2f9e 100644
--- a/arch/mips/kernel/irq-msc01.c
+++ b/arch/mips/kernel/irq-msc01.c
@@ -53,13 +53,9 @@ static inline void unmask_msc_irq(struct irq_data *d)
*/
static void level_mask_and_ack_msc_irq(struct irq_data *d)
{
- unsigned int irq = d->irq;
-
mask_msc_irq(d);
if (!cpu_has_veic)
MSCIC_WRITE(MSC01_IC_EOI, 0);
- /* This actually needs to be a call into platform code */
- smtc_im_ack_irq(irq);
}
/*
@@ -78,7 +74,6 @@ static void edge_mask_and_ack_msc_irq(struct irq_data *d)
MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT);
MSCIC_WRITE(MSC01_IC_SUP+irq*8, r);
}
- smtc_im_ack_irq(irq);
}
/*
@@ -131,7 +126,7 @@ void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqma
board_bind_eic_interrupt = &msc_bind_eic_interrupt;
- for (; nirq >= 0; nirq--, imp++) {
+ for (; nirq > 0; nirq--, imp++) {
int n = imp->im_irq;
switch (imp->im_type) {
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index d1fea7a054b..d2bfbc2e899 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -62,9 +62,9 @@ void __init alloc_legacy_irqno(void)
void free_irqno(unsigned int irq)
{
- smp_mb__before_clear_bit();
+ smp_mb__before_atomic();
clear_bit(irq, irq_map);
- smp_mb__after_clear_bit();
+ smp_mb__after_atomic();
}
/*
@@ -73,7 +73,6 @@ void free_irqno(unsigned int irq)
*/
void ack_bad_irq(unsigned int irq)
{
- smtc_im_ack_irq(irq);
printk("unexpected IRQ # %d\n", irq);
}
@@ -142,23 +141,7 @@ void __irq_entry do_IRQ(unsigned int irq)
{
irq_enter();
check_stack_overflow();
- if (!smtc_handle_on_other_cpu(irq))
- generic_handle_irq(irq);
- irq_exit();
-}
-
-#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF
-/*
- * To avoid inefficient and in some cases pathological re-checking of
- * IRQ affinity, we have this variant that skips the affinity check.
- */
-
-void __irq_entry do_IRQ_no_affinity(unsigned int irq)
-{
- irq_enter();
- smtc_im_backstop(irq);
generic_handle_irq(irq);
irq_exit();
}
-#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
index 72ef2d25cbf..e498f2b3646 100644
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -150,7 +150,7 @@ int __init mips_cpu_intc_init(struct device_node *of_node,
domain = irq_domain_add_legacy(of_node, 8, MIPS_CPU_IRQ_BASE, 0,
&mips_cpu_intc_irq_domain_ops, NULL);
if (!domain)
- panic("Failed to add irqdomain for MIPS CPU\n");
+ panic("Failed to add irqdomain for MIPS CPU");
return 0;
}
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c
index fcaac2f132f..7afcc2f22c0 100644
--- a/arch/mips/kernel/kgdb.c
+++ b/arch/mips/kernel/kgdb.c
@@ -32,6 +32,7 @@
#include <asm/cacheflush.h>
#include <asm/processor.h>
#include <asm/sigcontext.h>
+#include <asm/uaccess.h>
static struct hard_trap_info {
unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */
@@ -208,7 +209,14 @@ void arch_kgdb_breakpoint(void)
static void kgdb_call_nmi_hook(void *ignored)
{
+ mm_segment_t old_fs;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+
kgdb_nmicallback(raw_smp_processor_id(), NULL);
+
+ set_fs(old_fs);
}
void kgdb_roundup_cpus(unsigned long flags)
@@ -282,6 +290,7 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
struct die_args *args = (struct die_args *)ptr;
struct pt_regs *regs = args->regs;
int trap = (regs->cp0_cause & 0x7c) >> 2;
+ mm_segment_t old_fs;
#ifdef CONFIG_KPROBES
/*
@@ -296,11 +305,17 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
if (user_mode(regs))
return NOTIFY_DONE;
+ /* Kernel mode. Set correct address limit */
+ old_fs = get_fs();
+ set_fs(get_ds());
+
if (atomic_read(&kgdb_active) != -1)
kgdb_nmicallback(smp_processor_id(), regs);
- if (kgdb_handle_exception(trap, compute_signal(trap), cmd, regs))
+ if (kgdb_handle_exception(trap, compute_signal(trap), cmd, regs)) {
+ set_fs(old_fs);
return NOTIFY_DONE;
+ }
if (atomic_read(&kgdb_setting_breakpoint))
if ((trap == 9) && (regs->cp0_epc == (unsigned long)breakinst))
@@ -310,6 +325,7 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
local_irq_enable();
__flush_cache_all();
+ set_fs(old_fs);
return NOTIFY_STOP;
}
diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c
index 12bc4ebdf55..1f8187ab099 100644
--- a/arch/mips/kernel/kprobes.c
+++ b/arch/mips/kernel/kprobes.c
@@ -207,7 +207,10 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
void __kprobes arch_remove_kprobe(struct kprobe *p)
{
- free_insn_slot(p->ainsn.insn, 0);
+ if (p->ainsn.insn) {
+ free_insn_slot(p->ainsn.insn, 0);
+ p->ainsn.insn = NULL;
+ }
}
static void save_previous_kprobe(struct kprobe_ctlblk *kcb)
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 8eeee1c860c..0b29646bcee 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -119,99 +119,6 @@ SYSCALL_DEFINE6(32_pwrite, unsigned int, fd, const char __user *, buf,
return sys_pwrite64(fd, buf, count, merge_64(a4, a5));
}
-#ifdef CONFIG_SYSVIPC
-
-SYSCALL_DEFINE6(32_ipc, u32, call, long, first, long, second, long, third,
- unsigned long, ptr, unsigned long, fifth)
-{
- int version, err;
-
- version = call >> 16; /* hack for backward compatibility */
- call &= 0xffff;
-
- switch (call) {
- case SEMOP:
- /* struct sembuf is the same on 32 and 64bit :)) */
- err = sys_semtimedop(first, compat_ptr(ptr), second, NULL);
- break;
- case SEMTIMEDOP:
- err = compat_sys_semtimedop(first, compat_ptr(ptr), second,
- compat_ptr(fifth));
- break;
- case SEMGET:
- err = sys_semget(first, second, third);
- break;
- case SEMCTL:
- err = compat_sys_semctl(first, second, third, compat_ptr(ptr));
- break;
- case MSGSND:
- err = compat_sys_msgsnd(first, second, third, compat_ptr(ptr));
- break;
- case MSGRCV:
- err = compat_sys_msgrcv(first, second, fifth, third,
- version, compat_ptr(ptr));
- break;
- case MSGGET:
- err = sys_msgget((key_t) first, second);
- break;
- case MSGCTL:
- err = compat_sys_msgctl(first, second, compat_ptr(ptr));
- break;
- case SHMAT:
- err = compat_sys_shmat(first, second, third, version,
- compat_ptr(ptr));
- break;
- case SHMDT:
- err = sys_shmdt(compat_ptr(ptr));
- break;
- case SHMGET:
- err = sys_shmget(first, (unsigned)second, third);
- break;
- case SHMCTL:
- err = compat_sys_shmctl(first, second, compat_ptr(ptr));
- break;
- default:
- err = -EINVAL;
- break;
- }
-
- return err;
-}
-
-#else
-
-SYSCALL_DEFINE6(32_ipc, u32, call, int, first, int, second, int, third,
- u32, ptr, u32, fifth)
-{
- return -ENOSYS;
-}
-
-#endif /* CONFIG_SYSVIPC */
-
-#ifdef CONFIG_MIPS32_N32
-SYSCALL_DEFINE4(n32_semctl, int, semid, int, semnum, int, cmd, u32, arg)
-{
- /* compat_sys_semctl expects a pointer to union semun */
- u32 __user *uptr = compat_alloc_user_space(sizeof(u32));
- if (put_user(arg, uptr))
- return -EFAULT;
- return compat_sys_semctl(semid, semnum, cmd, uptr);
-}
-
-SYSCALL_DEFINE4(n32_msgsnd, int, msqid, u32, msgp, unsigned int, msgsz,
- int, msgflg)
-{
- return compat_sys_msgsnd(msqid, msgsz, msgflg, compat_ptr(msgp));
-}
-
-SYSCALL_DEFINE5(n32_msgrcv, int, msqid, u32, msgp, size_t, msgsz,
- int, msgtyp, int, msgflg)
-{
- return compat_sys_msgrcv(msqid, msgsz, msgtyp, msgflg, IPC_64,
- compat_ptr(msgp));
-}
-#endif
-
SYSCALL_DEFINE1(32_personality, unsigned long, personality)
{
unsigned int p = personality & 0xffffffff;
@@ -226,26 +133,6 @@ SYSCALL_DEFINE1(32_personality, unsigned long, personality)
return ret;
}
-SYSCALL_DEFINE4(32_sendfile, long, out_fd, long, in_fd,
- compat_off_t __user *, offset, s32, count)
-{
- mm_segment_t old_fs = get_fs();
- int ret;
- off_t of;
-
- if (offset && get_user(of, offset))
- return -EFAULT;
-
- set_fs(KERNEL_DS);
- ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
- set_fs(old_fs);
-
- if (offset && put_user(of, offset))
- return -EFAULT;
-
- return ret;
-}
-
asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3,
size_t count)
{
@@ -278,16 +165,3 @@ asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_a2,
return sys_fallocate(fd, mode, merge_64(offset_a2, offset_a3),
merge_64(len_a4, len_a5));
}
-
-asmlinkage long sys32_lookup_dcookie(u32 a0, u32 a1, char __user *buf,
- size_t len)
-{
- return sys_lookup_dcookie(merge_64(a0, a1), buf, len);
-}
-
-SYSCALL_DEFINE6(32_fanotify_mark, int, fanotify_fd, unsigned int, flags,
- u64, a3, u64, a4, int, dfd, const char __user *, pathname)
-{
- return sys_fanotify_mark(fanotify_fd, flags, merge_64(a3, a4),
- dfd, pathname);
-}
diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S
index 16586767335..539b6294b61 100644
--- a/arch/mips/kernel/mcount.S
+++ b/arch/mips/kernel/mcount.S
@@ -46,10 +46,9 @@
PTR_L a5, PT_R9(sp)
PTR_L a6, PT_R10(sp)
PTR_L a7, PT_R11(sp)
-#else
- PTR_ADDIU sp, PT_SIZE
#endif
-.endm
+ PTR_ADDIU sp, PT_SIZE
+ .endm
.macro RETURN_BACK
jr ra
@@ -68,7 +67,11 @@ NESTED(ftrace_caller, PT_SIZE, ra)
.globl _mcount
_mcount:
b ftrace_stub
- addiu sp,sp,8
+#ifdef CONFIG_32BIT
+ addiu sp,sp,8
+#else
+ nop
+#endif
/* When tracing is activated, it calls ftrace_caller+8 (aka here) */
lw t1, function_trace_stop
@@ -80,7 +83,7 @@ _mcount:
PTR_S MCOUNT_RA_ADDRESS_REG, PT_R12(sp)
#endif
- move a0, ra /* arg1: self return address */
+ PTR_SUBU a0, ra, 8 /* arg1: self address */
.globl ftrace_call
ftrace_call:
nop /* a placeholder for the call to a real tracing function */
@@ -165,15 +168,11 @@ NESTED(ftrace_graph_caller, PT_SIZE, ra)
#endif
/* arg3: Get frame pointer of current stack */
-#ifdef CONFIG_FRAME_POINTER
- move a2, fp
-#else /* ! CONFIG_FRAME_POINTER */
#ifdef CONFIG_64BIT
PTR_LA a2, PT_SIZE(sp)
#else
PTR_LA a2, (PT_SIZE+8)(sp)
#endif
-#endif
jal prepare_ftrace_return
nop
diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c
new file mode 100644