diff options
Diffstat (limited to 'arch/mips/kernel')
33 files changed, 592 insertions, 516 deletions
diff --git a/arch/mips/kernel/8250-platform.c b/arch/mips/kernel/8250-platform.c new file mode 100644 index 00000000000..cbf3fe20ad1 --- /dev/null +++ b/arch/mips/kernel/8250-platform.c @@ -0,0 +1,47 @@ +/* + * 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 Ralf Baechle (ralf@linux-mips.org) + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/serial_8250.h> + +#define PORT(base, int) \ +{ \ + .iobase = base, \ + .irq = int, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \ + .regshift = 0, \ +} + +static struct plat_serial8250_port uart8250_data[] = { + PORT(0x3F8, 4), + PORT(0x2F8, 3), + PORT(0x3E8, 4), + PORT(0x2E8, 3), + { }, +}; + +static struct platform_device uart8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = uart8250_data, + }, +}; + +static int __init uart8250_init(void) +{ + return platform_device_register(&uart8250_device); +} + +module_init(uart8250_init); + +MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic 8250 UART probe driver"); diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 49246264cc7..5c8085b6d7a 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -14,14 +14,15 @@ binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_MODULES) += mips_ksyms.o module.o +obj-$(CONFIG_CPU_LOONGSON2) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_MIPS32) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_MIPS64) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o -obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o -obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R4000) += r4k_fpu.o r4k_switch.o -obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R4300) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R4X00) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R5000) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R5432) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R8000) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_RM7000) += r4k_fpu.o r4k_switch.o @@ -29,13 +30,14 @@ obj-$(CONFIG_CPU_RM9000) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_NEVADA) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R10000) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_SB1) += r4k_fpu.o r4k_switch.o -obj-$(CONFIG_CPU_MIPS32) += r4k_fpu.o r4k_switch.o -obj-$(CONFIG_CPU_MIPS64) += r4k_fpu.o r4k_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_TX49XX) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_SMP) += smp.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 @@ -47,7 +49,6 @@ obj-$(CONFIG_I8259) += i8259.o obj-$(CONFIG_IRQ_CPU) += irq_cpu.o obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o -obj-$(CONFIG_IRQ_MV64340) += irq-mv6434x.o obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o obj-$(CONFIG_32BIT) += scall32-o32.o @@ -62,9 +63,11 @@ obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_64BIT) += cpu-bugs64.o -obj-$(CONFIG_I8253) += i8253.o +obj-$(CONFIG_PCSPEAKER) += pcspeaker.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) + +obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 76fd3f22c76..6b5df8bfab8 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -22,7 +22,8 @@ */ int __compute_return_epc(struct pt_regs *regs) { - unsigned int *addr, bit, fcr31, dspcontrol; + unsigned int __user *addr; + unsigned int bit, fcr31, dspcontrol; long epc; union mips_instruction insn; @@ -33,7 +34,7 @@ int __compute_return_epc(struct pt_regs *regs) /* * Read the instruction */ - addr = (unsigned int *) epc; + addr = (unsigned int __user *) epc; if (__get_user(insn.word, addr)) { force_sig(SIGSEGV, current); return -EFAULT; diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index ab755ea26c6..06448a9656d 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -75,6 +75,27 @@ static void r4k_wait_irqoff(void) local_irq_enable(); } +/* + * 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. */ int allow_au1k_wait; @@ -132,19 +153,32 @@ static inline void check_wait(void) case CPU_R4700: case CPU_R5000: case CPU_NEVADA: - case CPU_RM7000: case CPU_4KC: case CPU_4KEC: case CPU_4KSC: case CPU_5KC: -/* case CPU_20KC:*/ - case CPU_24K: case CPU_25KF: + case CPU_PR4450: + cpu_wait = r4k_wait; + break; + + case CPU_RM7000: + cpu_wait = rm7k_wait_irqoff; + break; + + case CPU_24K: case CPU_34K: + cpu_wait = r4k_wait; + if (read_c0_config7() & MIPS_CONF7_WII) + cpu_wait = r4k_wait_irqoff; + break; + case CPU_74K: - case CPU_PR4450: 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; @@ -156,6 +190,17 @@ static inline void check_wait(void) if (allow_au1k_wait) 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; + + cpu_wait = r4k_wait; + break; case CPU_RM9000: if ((c->processor_id & 0x00ff) >= 0x40) cpu_wait = r4k_wait; @@ -165,9 +210,29 @@ static inline void check_wait(void) } } +static inline void check_errata(void) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + + switch (c->cputype) { + case CPU_34K: + /* + * Erratum "RPS May Cause Incorrect Instruction Execution" + * This code only handles VPE0, any SMP/SMTC/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) + write_c0_config7(read_c0_config7() | MIPS_CONF7_RPS); + break; + default: + break; + } +} + void __init check_bugs32(void) { check_wait(); + check_errata(); } /* @@ -464,6 +529,14 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c) MIPS_CPU_LLSC; c->tlbsize = 64; break; + case PRID_IMP_LOONGSON2: + c->cputype = CPU_LOONGSON2; + c->isa_level = MIPS_CPU_ISA_III; + c->options = R4K_OPTS | + MIPS_CPU_FPU | MIPS_CPU_LLSC | + MIPS_CPU_32FPR; + c->tlbsize = 64; + break; } } @@ -567,6 +640,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) c->options |= MIPS_CPU_VEIC; if (config3 & MIPS_CONF3_MT) c->ases |= MIPS_ASE_MIPSMT; + if (config3 & MIPS_CONF3_ULRI) + c->options |= MIPS_CPU_ULRI; return config3 & MIPS_CONF_M; } diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 686249c5c32..e29598ae939 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -84,6 +84,7 @@ FEXPORT(restore_all) # restore full frame LONG_S sp, TI_REGS($28) jal deferred_smtc_ipi LONG_S s0, TI_REGS($28) +#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 @@ -110,6 +111,7 @@ FEXPORT(restore_all) # restore full frame _ehb xor t0, t0, t3 mtc0 t0, CP0_TCCONTEXT +#endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */ #endif /* CONFIG_MIPS_MT_SMTC */ .set noat RESTORE_TEMP diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index 297bd56c234..c0f19d638b9 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -243,9 +243,11 @@ NESTED(except_vec_vi_handler, 0, sp) */ mfc0 t1, CP0_STATUS and t0, a0, t1 +#ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP mfc0 t2, CP0_TCCONTEXT or t0, t0, t2 mtc0 t0, CP0_TCCONTEXT +#endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */ xor t1, t1, t0 mtc0 t1, CP0_STATUS _ehb diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 6f57ca44291..f78538eceef 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -16,6 +16,7 @@ #include <linux/init.h> #include <linux/threads.h> +#include <asm/addrspace.h> #include <asm/asm.h> #include <asm/asmmacro.h> #include <asm/irqflags.h> @@ -129,24 +130,25 @@ #endif .endm +#ifndef CONFIG_NO_EXCEPT_FILL /* * Reserved space for exception handlers. * Necessary for machines which link their kernels at KSEG0. */ .fill 0x400 +#endif EXPORT(stext) # used for profiling EXPORT(_stext) -#ifdef CONFIG_MIPS_SIM +#ifdef CONFIG_BOOT_RAW /* * Give us a fighting chance of running if execution beings at the * kernel load address. This is needed because this platform does * not have a ELF loader yet. */ - j kernel_entry -#endif __INIT +#endif NESTED(kernel_entry, 16, sp) # kernel entry point @@ -197,9 +199,7 @@ NESTED(kernel_entry, 16, sp) # kernel entry point j start_kernel END(kernel_entry) -#ifdef CONFIG_QEMU __INIT -#endif #ifdef CONFIG_SMP /* diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c deleted file mode 100644 index 3dd561832e4..00000000000 --- a/arch/mips/kernel/irq-mv6434x.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2002 Momentum Computer - * Author: mdharm@momenco.com - * Copyright (C) 2004, 06 Ralf Baechle <ralf@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. - */ -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/kernel_stat.h> -#include <linux/mv643xx.h> -#include <linux/sched.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/marvell.h> - -static unsigned int irq_base; - -static inline int ls1bit32(unsigned int x) -{ - int b = 31, s; - - s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; - s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; - s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; - s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; - s = 1; if (x << 1 == 0) s = 0; b -= s; - - return b; -} - -/* mask off an interrupt -- 1 is enable, 0 is disable */ -static inline void mask_mv64340_irq(unsigned int irq) -{ - uint32_t value; - - if (irq < (irq_base + 32)) { - value = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW); - value &= ~(1 << (irq - irq_base)); - MV_WRITE(MV64340_INTERRUPT0_MASK_0_LOW, value); - } else { - value = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH); - value &= ~(1 << (irq - irq_base - 32)); - MV_WRITE(MV64340_INTERRUPT0_MASK_0_HIGH, value); - } -} - -/* unmask an interrupt -- 1 is enable, 0 is disable */ -static inline void unmask_mv64340_irq(unsigned int irq) -{ - uint32_t value; - - if (irq < (irq_base + 32)) { - value = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW); - value |= 1 << (irq - irq_base); - MV_WRITE(MV64340_INTERRUPT0_MASK_0_LOW, value); - } else { - value = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH); - value |= 1 << (irq - irq_base - 32); - MV_WRITE(MV64340_INTERRUPT0_MASK_0_HIGH, value); - } -} - -/* - * Interrupt handler for interrupts coming from the Marvell chip. - * It could be built in ethernet ports etc... - */ -void ll_mv64340_irq(void) -{ - unsigned int irq_src_low, irq_src_high; - unsigned int irq_mask_low, irq_mask_high; - - /* read the interrupt status registers */ - irq_mask_low = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW); - irq_mask_high = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH); - irq_src_low = MV_READ(MV64340_MAIN_INTERRUPT_CAUSE_LOW); - irq_src_high = MV_READ(MV64340_MAIN_INTERRUPT_CAUSE_HIGH); - - /* mask for just the interrupts we want */ - irq_src_low &= irq_mask_low; - irq_src_high &= irq_mask_high; - - if (irq_src_low) - do_IRQ(ls1bit32(irq_src_low) + irq_base); - else - do_IRQ(ls1bit32(irq_src_high) + irq_base + 32); -} - -struct irq_chip mv64340_irq_type = { - .name = "MV-64340", - .ack = mask_mv64340_irq, - .mask = mask_mv64340_irq, - .mask_ack = mask_mv64340_irq, - .unmask = unmask_mv64340_irq, -}; - -void __init mv64340_irq_init(unsigned int base) -{ - int i; - - for (i = base; i < base + 64; i++) - set_irq_chip_and_handler(i, &mv64340_irq_type, - handle_level_irq); - - irq_base = base; -} diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 37849edd064..06e04da211d 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -556,6 +556,16 @@ asmlinkage long sys32_sync_file_range(int fd, int __pad, flags); } +asmlinkage long sys32_fadvise64_64(int fd, int __pad, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + int flags) +{ + return sys_fadvise64_64(fd, + merge_64(a2, a3), merge_64(a4, a5), + flags); +} + save_static_function(sys32_clone); __attribute_used__ noinline static int _sys32_clone(nabi_no_regargs struct pt_regs regs) diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c new file mode 100644 index 00000000000..ede5d73d652 --- /dev/null +++ b/arch/mips/kernel/mips-mt-fpaff.c @@ -0,0 +1,176 @@ +/* + * General MIPS MT support routines, usable in AP/SP, SMVP, or SMTC kernels + * Copyright (C) 2005 Mips Technologies, Inc + */ +#include <linux/cpu.h> +#include <linux/cpumask.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/security.h> +#include <linux/types.h> +#include <asm/uaccess.h> + +/* + * CPU mask used to set process affinity for MT VPEs/TCs with FPUs + */ +cpumask_t mt_fpu_cpumask; + +static int fpaff_threshold = -1; +unsigned long mt_fpemul_threshold = 0; + +/* + * Replacement functions for the sys_sched_setaffinity() and + * sys_sched_getaffinity() system calls, so that we can integrate + * FPU affinity with the user's requested processor affinity. + * This code is 98% identical with the sys_sched_setaffinity() + * and sys_sched_getaffinity() system calls, and should be + * updated when kernel/sched.c changes. + */ + +/* + * find_process_by_pid - find a process with a matching PID value. + * used in sys_sched_set/getaffinity() in kernel/sched.c, so + * cloned here. + */ +static inline struct task_struct *find_process_by_pid(pid_t pid) +{ + return pid ? find_task_by_pid(pid) : current; +} + + +/* + * mipsmt_sys_sched_setaffinity - set the cpu affinity of a process + */ +asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, + unsigned long __user *user_mask_ptr) +{ + cpumask_t new_mask; + cpumask_t effective_mask; + int retval; + struct task_struct *p; + + if (len < sizeof(new_mask)) + return -EINVAL; + + if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask))) + return -EFAULT; + + lock_cpu_hotplug(); + read_lock(&tasklist_lock); + + p = find_process_by_pid(pid); + if (!p) { + read_unlock(&tasklist_lock); + unlock_cpu_hotplug(); + return -ESRCH; + } + + /* + * It is not safe to call set_cpus_allowed with the + * tasklist_lock held. We will bump the task_struct's + * usage count and drop tasklist_lock before invoking + * set_cpus_allowed. + */ + get_task_struct(p); + + retval = -EPERM; + if ((current->euid != p->euid) && (current->euid != p->uid) && + !capable(CAP_SYS_NICE)) { + read_unlock(&tasklist_lock); + goto out_unlock; + } + + retval = security_task_setscheduler(p, 0, NULL); + if (retval) + goto out_unlock; + + /* Record new user-specified CPU set for future reference */ + p->thread.user_cpus_allowed = new_mask; + + /* Unlock the task list */ + read_unlock(&tasklist_lock); + + /* Compute new global allowed CPU set if necessary */ + if ((p->thread.mflags & MF_FPUBOUND) + && cpus_intersects(new_mask, mt_fpu_cpumask)) { + cpus_and(effective_mask, new_mask, mt_fpu_cpumask); + retval = set_cpus_allowed(p, effective_mask); + } else { + p->thread.mflags &= ~MF_FPUBOUND; + retval = set_cpus_allowed(p, new_mask); + } + + +out_unlock: + put_task_struct(p); + unlock_cpu_hotplug(); + return retval; +} + +/* + * mipsmt_sys_sched_getaffinity - get the cpu affinity of a process + */ +asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, + unsigned long __user *user_mask_ptr) +{ + unsigned int real_len; + cpumask_t mask; + int retval; + struct task_struct *p; + + real_len = sizeof(mask); + if (len < real_len) + return -EINVAL; + + lock_cpu_hotplug(); + read_lock(&tasklist_lock); + + retval = -ESRCH; + p = find_process_by_pid(pid); + if (!p) + goto out_unlock; + retval = security_task_getscheduler(p); + if (retval) + goto out_unlock; + + cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map); + +out_unlock: + read_unlock(&tasklist_lock); + unlock_cpu_hotplug(); + if (retval) + return retval; + if (copy_to_user(user_mask_ptr, &mask, real_len)) + return -EFAULT; + return real_len; +} + + +static int __init fpaff_thresh(char *str) +{ + get_option(&str, &fpaff_threshold); + return 1; +} +__setup("fpaff=", fpaff_thresh); + +/* + * FPU Use Factor empirically derived from experiments on 34K + */ +#define FPUSEFACTOR 333 + +static __init int mt_fp_affinity_init(void) +{ + if (fpaff_threshold >= 0) { + mt_fpemul_threshold = fpaff_threshold; + } else { + mt_fpemul_threshold = + (FPUSEFACTOR * (loops_per_jiffy/(500000/HZ))) / HZ; + } + printk(KERN_DEBUG "FPU Affinity set after %ld emulations\n", + mt_fpemul_threshold); + + return 0; +} +arch_initcall(mt_fp_affinity_init); diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index ba01800b601..1a7d8923129 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -6,7 +6,6 @@ #include <linux/device.h> #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/cpumask.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/security.h> @@ -23,149 +22,6 @@ #include <asm/cacheflush.h> /* - * CPU mask used to set process affinity for MT VPEs/TCs with FPUs - */ - -cpumask_t mt_fpu_cpumask; - -#ifdef CONFIG_MIPS_MT_FPAFF - -#include <linux/cpu.h> -#include <linux/delay.h> -#include <asm/uaccess.h> - -unsigned long mt_fpemul_threshold = 0; - -/* - * Replacement functions for the sys_sched_setaffinity() and - * sys_sched_getaffinity() system calls, so that we can integrate - * FPU affinity with the user's requested processor affinity. - * This code is 98% identical with the sys_sched_setaffinity() - * and sys_sched_getaffinity() system calls, and should be - * updated when kernel/sched.c changes. - */ - -/* - * find_process_by_pid - find a process with a matching PID value. - * used in sys_sched_set/getaffinity() in kernel/sched.c, so - * cloned here. - */ -static inline struct task_struct *find_process_by_pid(pid_t pid) -{ - return pid ? find_task_by_pid(pid) : current; -} - - -/* - * mipsmt_sys_sched_setaffinity - set the cpu affinity of a process - */ -asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, - unsigned long __user *user_mask_ptr) -{ - cpumask_t new_mask; - cpumask_t effective_mask; - int retval; - struct task_struct *p; - - if (len < sizeof(new_mask)) - return -EINVAL; - - if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask))) - return -EFAULT; - - lock_cpu_hotplug(); - read_lock(&tasklist_lock); - - p = find_process_by_pid(pid); - if (!p) { - read_unlock(&tasklist_lock); - unlock_cpu_hotplug(); - return -ESRCH; - } - - /* - * It is not safe to call set_cpus_allowed with the - * tasklist_lock held. We will bump the task_struct's - * usage count and drop tasklist_lock before invoking - * set_cpus_allowed. - */ - get_task_struct(p); - - retval = -EPERM; - if ((current->euid != p->euid) && (current->euid != p->uid) && - !capable(CAP_SYS_NICE)) { - read_unlock(&tasklist_lock); - goto out_unlock; - } - - retval = security_task_setscheduler(p, 0, NULL); - if (retval) - goto out_unlock; - - /* Record new user-specified CPU set for future reference */ - p->thread.user_cpus_allowed = new_mask; - - /* Unlock the task list */ - read_unlock(&tasklist_lock); - - /* Compute new global allowed CPU set if necessary */ - if( (p->thread.mflags & MF_FPUBOUND) - && cpus_intersects(new_mask, mt_fpu_cpumask)) { - cpus_and(effective_mask, new_mask, mt_fpu_cpumask); - retval = set_cpus_allowed(p, effective_mask); - } else { - p->thread.mflags &= ~MF_FPUBOUND; - retval = set_cpus_allowed(p, new_mask); - } - - -out_unlock: - put_task_struct(p); - unlock_cpu_hotplug(); - return retval; -} - -/* - * mipsmt_sys_sched_getaffinity - get the cpu affinity of a process - */ -asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, - unsigned long __user *user_mask_ptr) -{ - unsigned int real_len; - cpumask_t mask; - int retval; - struct task_struct *p; - - real_len = sizeof(mask); - if (len < real_len) - return -EINVAL; - - lock_cpu_hotplug(); - read_lock(&tasklist_lock); - - retval = -ESRCH; - p = find_process_by_pid(pid); - if (!p) - goto out_unlock; - retval = security_task_getscheduler(p); - if (retval) - goto out_unlock; - - cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map); - -out_unlock: - read_unlock(&tasklist_lock); - unlock_cpu_hotplug(); - if (retval) - return retval; - if (copy_to_user(user_mask_ptr, &mask, real_len)) - return -EFAULT; - return real_len; -} - -#endif /* CONFIG_MIPS_MT_FPAFF */ - -/* * Dump new MIPS MT state for the core. Does not leave TCs halted. * Takes an argument which taken to be a pre-call MVPControl value. */ @@ -195,27 +51,31 @@ void mips_mt_regdump(unsigned long mvpctl) nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; ntc = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; printk("-- per-VPE State --\n"); - for(i = 0; i < nvpe; i++) { - for(tc = 0; tc < ntc; tc++) { + for (i = 0; i < nvpe; i++) { + for (tc = 0; tc < ntc; tc++) { settc(tc); - if((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) { - printk(" VPE %d\n", i); - printk(" VPEControl : %08lx\n", read_vpe_c0_vpecontrol()); - printk(" VPEConf0 : %08lx\n", read_vpe_c0_vpeconf0()); - printk(" VPE%d.Status : %08lx\n", - i, read_vpe_c0_status()); - printk(" VPE%d.EPC : %08lx\n", i, read_vpe_c0_epc()); - printk(" VPE%d.Cause : %08lx\n", i, read_vpe_c0_cause()); - printk(" VPE%d.Config7 : %08lx\n", - i, read_vpe_c0_config7()); - break; /* Next VPE */ + if ((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) { + printk(" VPE %d\n", i); + printk(" VPEControl : %08lx\n", + read_vpe_c0_vpecontrol()); + printk(" VPEConf0 : %08lx\n", + read_vpe_c0_vpeconf0()); + printk(" VPE%d.Status : %08lx\n", + i, read_vpe_c0_status()); + printk(" VPE%d.EPC : %08lx\n", + i, read_vpe_c0_epc()); + printk(" VPE%d.Cause : %08lx\n", + i, read_vpe_c0_cause()); + printk(" VPE%d.Config7 : %08lx\n", + i, read_vpe_c0_config7()); + break; /* Next VPE */ + } } - } } printk("-- per-TC State --\n"); - for(tc = 0; tc < ntc; tc++) { + for (tc = 0; tc < ntc; tc++) { settc(tc); - if(read_tc_c0_tcbind() == read_c0_tcbind()) { + if (read_tc_c0_tcbind() == read_c0_tcbind()) { /* Are we dumping ourself? */ haltval = 0; /* Then we're not halted, and mustn't be */ tcstatval = flags; /* And pre-dump TCStatus is flags */ @@ -310,17 +170,6 @@ static int __init ndflush(char *s) return 1; } __setup("ndflush=", ndflush); -#ifdef CONFIG_MIPS_MT_FPAFF -static int fpaff_threshold = -1; - -static int __init fpaff_thresh(char *str) -{ - get_option(&str, &fpaff_threshold); - return 1; -} - -__setup("fpaff=", fpaff_thresh); -#endif /* CONFIG_MIPS_MT_FPAFF */ static unsigned int itc_base = 0; @@ -376,20 +225,6 @@ void mips_mt_set_cpuoptions(void) if (mt_n_dflushes != 1) printk("D-Cache Flushes Repeated %d times\n", mt_n_dflushes); -#ifdef CONFIG_MIPS_MT_FPAFF - /* FPU Use Factor empirically derived from experiments on 34K */ -#define FPUSEFACTOR 333 - - if (fpaff_threshold >= 0) { - mt_fpemul_threshold = fpaff_threshold; - } else { - mt_fpemul_threshold = - (FPUSEFACTOR * (loops_per_jiffy/(500000/HZ))) / HZ; - } - printk("FPU Affinity set after %ld emulations\n", - mt_fpemul_threshold); -#endif /* CONFIG_MIPS_MT_FPAFF */ - if (itc_base != 0) { /* * Configure ITC mapping. This code is very diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/pcspeaker.c index 475df690421..475df690421 100644 --- a/arch/mips/kernel/i8253.c +++ b/arch/mips/kernel/pcspeaker.c diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 5ddc2e9deec..ec04f5a1a5e 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -14,7 +14,6 @@ #include <asm/cpu-features.h> #include <asm/mipsregs.h> #include <asm/processor.h> -#include <asm/watch.h> unsigned int vced_count, vcei_count; @@ -84,6 +83,7 @@ static const char *cpu_name[] = { [CPU_VR4181A] = "NEC VR4181A", [CPU_SR71000] = "Sandcraft SR71000", [CPU_PR4450] = "Philips PR4450", + [CPU_LOONGSON2] = "ICT Loongson-2", }; diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 6bdfb5a9fa1..bd05f5a927e 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -25,7 +25,9 @@ #include <linux/init.h> #include <linux/completion.h> #include <linux/kallsyms.h> +#include <linux/random.h> +#include <asm/asm.h> #include <asm/bootinfo.h> #include <asm/cpu.h> #include <asm/dsp.h> @@ -46,7 +48,7 @@ * power and have a low exit latency (ie sit in a loop waiting for somebody to * say that they'd like to reschedule) */ -ATTRIB_NORET void cpu_idle(void) +void __noreturn cpu_idle(void) { /* endless idle loop with no priority at all */ while (1) { @@ -213,7 +215,7 @@ int dump_task_fpu (struct task_struct *t, elf_fpregset_t *fpr) /* * Create a kernel thread */ -static ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *)) +static void __noreturn kernel_thread_helper(void *arg, int (*fn)(void *)) { do_exit(fn(arg)); } @@ -460,3 +462,15 @@ unsigned long get_wchan(struct task_struct *task) out: return pc; } + +/* + * Don't forget that the stack pointer must be aligned on a 8 bytes + * boundary for 32-bits ABI and 16 bytes for 64-bits ABI. + */ +unsigned long arch_align_stack(unsigned long sp) +{ + if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) + sp -= get_random_int() & ~PAGE_MASK; + + return sp & ALMASK; +} diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index b5a7b46bbc4..893e7bccf22 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -174,17 +174,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp,(unsigned long __user *) data); + case PTRACE_PEEKDATA: + ret = generic_ptrace_peekdata(child, addr, data); break; - } /* Read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { @@ -313,11 +305,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) - == sizeof(data)) - break; - ret = -EIO; + ret = generic_ptrace_pokedata(child, addr, data); break; case PTRACE_POKEUSR: { diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index cc566cf1224..d9bfae53c43 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -85,12 +85,7 @@ move $28, a2 cpu_restore_nonscratch a1 -#if (_THREAD_SIZE - 32) < 0x10000 - PTR_ADDIU t0, $28, _THREAD_SIZE - 32 -#else - PTR_LI t0, _THREAD_SIZE - 32 - PTR_ADDU t0, $28 -#endif + PTR_ADDU t0, $28, _THREAD_SIZE - 32 set_saved_sp t0, t1, t2 #ifdef CONFIG_MIPS_MT_SMTC /* Read-modify-writes of Status must be atomic on a VPE */ @@ -174,7 +169,7 @@ LEAF(_init_fpu) or t0, t1 mtc0 t0, CP0_STATUS #endif /* CONFIG_MIPS_MT_SMTC */ - fpu_enable_hazard + enable_fpu_hazard li t1, FPU_DEFAULT ctc1 t1, fcr31 diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 0c9a9ff8cd2..ae985d1fcca 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -657,7 +657,11 @@ einval: li v0, -EINVAL sys sys_getcpu 3 sys sys_epoll_pwait 6 sys sys_ioprio_set 3 - sys sys_ioprio_get 2 + sys sys_ioprio_get 2 /* 4315 */ + sys sys_utimensat 4 + sys sys_signalfd 3 + sys sys_timerfd 4 + sys sys_eventfd 1 .endm /* We pre-compute the number of _instruction_ bytes needed to diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 23f3b118f71..7bcd5a1a85f 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -473,4 +473,8 @@ sys_call_table: PTR sys_epoll_pwait PTR sys_ioprio_set PTR sys_ioprio_get + PTR sys_utimensat /* 5275 */ + PTR sys_signalfd + PTR sys_timerfd + PTR sys_eventfd .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 6eac2833742..532a2f3b42f 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -299,7 +299,7 @@ EXPORT(sysn32_call_table) PTR sys_ni_syscall /* res. for afs_syscall */ PTR sys_ni_syscall /* res. for security */ PTR sys_gettid - PTR sys32_readahead + PTR sys_readahead PTR sys_setxattr /* 6180 */ PTR sys_lsetxattr PTR sys_fsetxattr @@ -399,4 +399,8 @@ EXPORT(sysn32_call_table) PTR compat_sys_epoll_pwait PTR sys_ioprio_set PTR sys_ioprio_get + PTR compat_sys_utimensat + PTR compat_sys_signalfd /* 5280 */ + PTR compat_sys_timerfd + PTR sys_eventfd .size sysn32_call_table,.-sysn32_call_table diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 7e74b412a78..6bbe0f4ed8b 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -459,7 +459,7 @@ sys_call_table: PTR sys_remap_file_pages PTR sys_set_tid_address PTR sys_restart_syscall - PTR sys_fadvise64_64 + PTR sys32_fadvise64_64 PTR compat_sys_statfs64 /* 4255 */ PTR compat_sys_fstatfs64 PTR compat_sys_timer_create @@ -521,4 +521,8 @@ sys_call_table: PTR compat_sys_epoll_pwait PTR sys_ioprio_set PTR sys_ioprio_get /* 4315 */ + PTR compat_sys_utimensat + PTR compat_sys_signalfd + PTR compat_sys_timerfd + PTR sys_eventfd .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 4975da0bfb6..316685fca05 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -20,6 +20,7 @@ #include <linux/highmem.h> #include <linux/console.h> #include <linux/pfn.h> +#include <linux/debugfs.h> #include <asm/addrspace.h> #include <asm/bootinfo.h> @@ -574,3 +575,18 @@ __setup("nodsp", dsp_disable); unsigned long kernelsp[NR_CPUS]; unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3; + +#ifdef CONFIG_DEBUG_FS +struct dentry *mips_debugfs_dir; +static int __init debugfs_mips(void) +{ + struct dentry *d; + + d = debugfs_create_dir("mips", NULL); + if (IS_ERR(d)) + return PTR_ERR(d); + mips_debugfs_dir = d; + return 0; +} +arch_initcall(debugfs_mips); +#endif diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 003f8152b9e..486b8e5f52d 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -36,68 +36,6 @@ #include "signal-common.h" -#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) - -typedef struct compat_siginfo { - int si_signo; - int si_code; - int si_errno; - - union { - int _pad[SI_PAD_SIZE32]; - - /* kill() */ - struct { - compat_pid_t _pid; /* sender's pid */ - compat_uid_t _uid; /* sender's uid */ - } _kill; - - /* SIGCHLD */ - struct { - compat_pid_t _pid; /* which child */ - compat_uid_t _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* IRIX SIGCHLD */ - struct { - compat_pid_t _pid; /* which child */ - compat_clock_t _utime; - int _status; /* exit code */ - compat_clock_t _stime; - } _irix_sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - s32 _addr; /* faulting insn/memory ref. */ - } _sigfault; - - /* SIGPOLL, SIGXFSZ (To do ...) */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - - /* POSIX.1b timers */ - struct { - timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval;/* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - compat_pid_t _pid; /* sender's pid */ - compat_uid_t _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - } _sifields; -} compat_siginfo_t; - /* * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... */ diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 4cf9ff24d1f..eb7e05926eb 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -72,7 +72,7 @@ struct ucontextn32 { struct rt_sigframe_n32 { u32 rs_ass[4]; /* argument save space for o32 */ u32 rs_code[2]; /* signal trampoline */ - struct siginfo rs_info; + struct compat_siginfo rs_info; struct ucontextn32 rs_uc; }; @@ -81,7 +81,7 @@ struct rt_sigframe_n32 { struct rt_sigframe_n32 { u32 rs_ass[4]; /* argument save space for o32 */ u32 rs_pad[2]; - struct siginfo rs_info; + struct compat_siginfo rs_info; struct ucontextn32 rs_uc; u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ }; @@ -187,7 +187,7 @@ static int setup_rt_frame_n32(struct k_sigaction * ka, install_sigtramp(frame->rs_code, __NR_N32_rt_sigreturn); /* Create siginfo. */ - err |= copy_siginfo_to_user(&frame->rs_info, info); + err |= copy_siginfo_to_user32(&frame->rs_info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 64b62bdfb4f..19b30d6f172 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -129,13 +129,13 @@ static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) static struct irqaction irq_resched = { .handler = ipi_resched_interrupt, - .flags = IRQF_DISABLED, + .flags = IRQF_DISABLED|IRQF_PERCPU, .name = "IPI_resched" }; static struct irqaction irq_call = { .handler = ipi_call_interrupt, - .flags = IRQF_DISABLED, + .flags = IRQF_DISABLED|IRQF_PERCPU, .name = "IPI_call" }; @@ -236,8 +236,6 @@ void __init plat_smp_setup(void) dvpe(); dmt(); - mips_mt_set_cpuoptions(); - /* Put MVPE's into 'configuration state' */ set_c0_mvpcontrol(MVPCONTROL_VPC); @@ -263,6 +261,8 @@ void __init plat_smp_setup(void) void __init plat_prepare_cpus(unsigned int max_cpus) { + mips_mt_set_cpuoptions(); + /* set up ipi interrupts */ if (cpu_has_vint) { set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); @@ -275,10 +275,7 @@ void __init plat_prepare_cpus(unsigned int max_cpus) setup_irq(cpu_ipi_resched_irq, &irq_resched); setup_irq(cpu_ipi_call_irq, &irq_call); - /* need to mark IPI's as IRQ_PER_CPU */ - irq_desc[cpu_ipi_resched_irq].status |= IRQ_PER_CPU; set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq); - irq_desc[cpu_ipi_call_irq].status |= IRQ_PER_CPU; set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq); } @@ -326,8 +323,11 @@ void prom_boot_secondary(int cpu, struct task_struct *idle) void prom_init_secondary(void) { + /* Enable per-cpu interrupts */ + + /* This is Malta specific: IPI,performance and timer inetrrupts */ write_c0_status((read_c0_status() & ~ST0_IM ) | - (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP7)); + (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP6 | STATUSF_IP7)); } void prom_smp_finish(void) diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index c46e479c992..be7362bc2c9 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -51,24 +51,14 @@ int __cpu_logical_map[NR_CPUS]; /* Map logical to physical */ EXPORT_SYMBOL(phys_cpu_present_map); EXPORT_SYMBOL(cpu_online_map); -/* This happens early in bootup, can't really do it better */ -static void smp_tune_scheduling (void) -{ - struct cache_desc *cd = ¤t_cpu_data.scache; - unsigned long cachesize = cd->linesz * cd->sets * cd->ways; - - if (cachesize > max_cache_size) - max_cache_size = cachesize; -} - extern void __init calibrate_delay(void); -extern ATTRIB_NORET void cpu_idle(void); +extern void cpu_idle(void); /* * First C code run on the secondary CPUs after being started up by * the master. */ -asmlinkage void start_secondary(void) +asmlinkage __cpuinit void start_secondary(void) { unsigned int cpu; @@ -228,7 +218,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) { init_new_context(current, &init_mm); current_thread_info()->cpu = 0; - smp_tune_scheduling(); plat_prepare_cpus(max_cpus); #ifndef CONFIG_HOTPLUG_CPU cpu_present_map = cpu_possible_map; diff --git a/arch/mips/kernel/smtc-asm.S b/arch/mips/kernel/smtc-asm.S index 921207c4a83..20938a4cb52 100644 --- a/arch/mips/kernel/smtc-asm.S +++ b/arch/mips/kernel/smtc-asm.S @@ -121,10 +121,7 @@ LEAF(self_ipi) subu t1,sp,PT_SIZE sw ra,PT_EPC(t1) sw a0,PT_PADSLOT4(t1) - LONG_L s0, TI_REGS($28) - LONG_S sp, TI_REGS($28) la t2,ipi_decode - LONG_S s0, TI_REGS($28) sw t2,PT_PADSLOT5(t1) /* Save pre-disable value of TCStatus */ sw t0,PT_TCSTATUS(t1) diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index b361edb83dc..342d873b2ec 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -13,9 +13,9 @@ #include <asm/system.h> #include <asm/hardirq.h> #include <asm/hazards.h> +#include <asm/irq.h> #include <asm/mmu_context.h> #include <asm/smp.h> -#include <asm/mips-boards/maltaint.h> #include <asm/mipsregs.h> #include <asm/cacheflush.h> #include <asm/time.h> @@ -611,12 +611,12 @@ void smtc_cpus_done(void) int setup_irq_smtc(unsigned int irq, struct irqaction * new, unsigned long hwmask) { +#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG unsigned int vpe = current_cpu_data.vpe_id; - irq_hwmask[irq] = hwmask; -#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG - vpemask[vpe][irq - MIPSCPU_INT_BASE] = 1; + vpemask[vpe][irq - MIPS_CPU_IRQ_BASE] = 1; #endif + irq_hwmask[irq] = hwmask; return setup_irq(irq, new); } @@ -822,7 +822,7 @@ void ipi_decode(struct smtc_ipi *pipi) switch (type_copy) { case SMTC_CLOCK_TICK: irq_enter(); - kstat_this_cpu.irqs[MIPSCPU_INT_BASE + MIPSCPU_INT_CPUCTR]++; + kstat_this_cpu.irqs[MIPS_CPU_IRQ_BASE + cp0_compare_irq]++; /* Invoke Clock "Interrupt" */ ipi_timer_latch[dest_copy] = 0; #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG @@ -1104,7 +1104,7 @@ void smtc_idle_loop_hook(void) mtflags = dmt(); pdb_msg = &id_ho_db_msg[0]; im = read_c0_status(); - vpe = cpu_data[smp_processor_id()].vpe_id; + vpe = current_cpu_data.vpe_id; for (bit = 0; bit < 8; bit++) { /* * In current prototype, I/O interrupts diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 9dd5a2df8ea..b947c61c0cc 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -272,9 +272,8 @@ asmlinkage int sys_set_thread_area(unsigned long addr) struct thread_info *ti = task_thread_info(current); ti->tp_value = addr; - - /* If some future MIPS implementation has this register in hardware, - * we will need to update it here (and in context switches). */ + if (cpu_has_userlocal) + write_c0_userlocal(addr); return 0; } diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 751b4a18b13..d48d1d5bea0 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -199,6 +199,35 @@ int (*perf_irq)(void) = null_perf_irq; EXPORT_SYMBOL(null_perf_irq); EXPORT_SYMBOL(perf_irq); +/* + * Timer interrupt + */ +int cp0_compare_irq; + +/* + * Performance counter IRQ or -1 if shared with timer + */ +int cp0_perfcount_irq; +EXPORT_SYMBOL_GPL(cp0_perfcount_irq); + +/* + * Possibly handle a performance counter interrupt. + * Return true if the timer interrupt should not be checked + */ +static inline int handle_perf_irq (int r2) +{ + /* + * The performance counter overflow interrupt may be shared with the + * timer interrupt (cp0_perfcount_irq < 0). If it is and a + * performance counter has overflowed (perf_irq() == IRQ_HANDLED) + * and we can't reliably determine if a counter interrupt has also + * happened (!r2) then don't check for a timer interrupt. + */ + return (cp0_perfcount_irq < 0) && + perf_irq() == IRQ_HANDLED && + !r2; +} + asmlinkage void ll_timer_interrupt(int irq) { int r2 = cpu_has_mips_r2; @@ -206,19 +235,13 @@ asmlinkage void ll_timer_interrupt(int irq) irq_enter(); kstat_this_cpu.irqs[irq]++; - /* - * Suckage alert: - * Before R2 of the architecture there was no way to see if a - * performance counter interrupt was pending, so we have to run the - * performance counter interrupt handler anyway. - */ - if (!r2 || (read_c0_cause() & (1 << 26))) - if (perf_irq()) - goto out; + if (handle_perf_irq(r2)) + goto out; - /* we keep interrupt disabled all the time */ - if (!r2 || (read_c0_cause() & (1 << 30))) - timer_interrupt(irq, NULL); + if (r2 && ((read_c0_cause() & (1 << 30)) == 0)) + goto out; + + timer_interrupt(irq, NULL); out: irq_exit(); @@ -258,7 +281,7 @@ unsigned int mips_hpt_frequency; static struct irqaction timer_irqaction = { .handler = timer_interrupt, - .flags = IRQF_DISABLED, + .flags = IRQF_DISABLED | IRQF_PERCPU, .name = "timer", }; diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 200de027f35..ce277cb34dd 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -11,6 +11,7 @@ * Copyright (C) 2000, 01 MIPS Technologies, Inc. * Copyright (C) 2002, 2003, 2004, 2005 Maciej W. Rozycki */ +#include <linux/bug.h> #include <linux/init.h> #include <linux/mm.h> #include <linux/module.h> @@ -38,7 +39,6 @@ #include <asm/traps.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> -#include <asm/watch.h> #include <asm/types.h> #include <asm/stacktrace.h> @@ -69,6 +69,7 @@ extern asmlinkage void handle_reserved(void); extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, int has_fpu); +void (*board_watchpoint_handler)(struct pt_regs *regs); void (*board_be_init)(void); int (*board_be_handler)(struct pt_regs *regs, int is_fixup); void (*board_nmi_handler_setup)(void); @@ -130,7 +131,7 @@ static void show_stacktrace(struct task_struct *task, struct pt_regs *regs) const int field = 2 * sizeof(unsigned long); long stackdata; int i; - unsigned long *sp = (unsigned long *)regs->regs[29]; + unsigned long __user *sp = (unsigned long __user *)regs->regs[29]; printk("Stack :"); i = 0; @@ -186,7 +187,7 @@ void dump_stack(void) EXPORT_SYMBOL(dump_stack); -void show_code(unsigned int *pc) +static void show_code(unsigned int __user *pc) { long i; @@ -304,13 +305,13 @@ void show_registers(struct pt_regs *regs) printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", current->comm, current->pid, current_thread_info(), current); show_stacktrace(current, regs); - show_code((unsigned int *) regs->cp0_epc); + show_code((unsigned int __user *) regs->cp0_epc); printk("\n"); } static DEFINE_SPINLOCK(die_lock); -NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs) +void __noreturn die(const char * str, struct pt_regs * regs) { static int die_counter; #ifdef CONFIG_MIPS_MT_SMTC @@ -325,6 +326,7 @@ NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs) #endif /* CONFIG_MIPS_MT_SMTC */ printk("%s[#%d]:\n", str, ++die_counter); show_registers(regs); + add_taint(TAINT_DIE); spin_unlock_irq(&die_lock); if (in_interrupt()) @@ -372,7 +374,7 @@ asmlinkage void do_be(struct pt_regs *regs) action = MIPS_BE_FIXUP; if (board_be_handler) - action = board_be_handler(regs, fixup != 0); + action = board_be_handler(regs, fixup != NULL); switch (action) { case MIPS_BE_DISCARD: @@ -752,6 +754,33 @@ asmlinkage void do_ri(struct pt_regs *regs) force_sig(SIGILL, current); } +/* + * MIPS MT processors may have fewer FPU contexts than CPU threads. If we've + * emulated more than some threshold number of instructions, force migration to + * a "CPU" that has FP support. + */ +static void mt_ase_fp_affinity(void) +{ +#ifdef CONFIG_MIPS_MT_FPAFF + if (mt_fpemul_threshold > 0 && + ((current->thread.emulated_fp++ > mt_fpemul_threshold))) { + /* + * If there's no FPU present, or if the application has already + * restricted the allowed set to exclude any CPUs with FPUs, + * we'll skip the procedure. + */ + if (cpus_intersects(current->cpus_allowed, mt_fpu_cpumask)) { + cpumask_t tmask; + + cpus_and(tmask, current->thread.user_cpus_allowed, + mt_fpu_cpumask); + set_cpus_allowed(current, tmask); + current->thread.mflags |= MF_FPUBOUND; + } + } +#endif /* CONFIG_MIPS_MT_FPAFF */ +} + asmlinkage void do_cpu(struct pt_regs *regs) { unsigned int cpid; @@ -785,36 +814,8 @@ asmlinkage void do_cpu(struct pt_regs *regs) ¤t->thread.fpu, 0); if (sig) force_sig(sig, current); -#ifdef CONFIG_MIPS_MT_FPAFF - else { - /* - * MIPS MT processors may have fewer FPU contexts - * than CPU threads. If we've emulated more than - * some threshold number of instructions, force - * migration to a "CPU" that has FP support. - */ - if(mt_fpemul_threshold > 0 - && ((current->thread.emulated_fp++ - > mt_fpemul_threshold))) { - /* - * If there's no FPU present, or if the - * application has already restricted - * the allowed set to exclude any CPUs - * with FPUs, we'll skip the procedure. - */ - if (cpus_intersects(current->cpus_allowed, - mt_fpu_cpumask)) { - cpumask_t tmask; - - cpus_and(tmask, - current->thread.user_cpus_allowed, - mt_fpu_cpumask); - set_cpus_allowed(current, tmask); - current->thread.mflags |= MF_FPUBOUND; - } - } - } -#endif /* CONFIG_MIPS_MT_FPAFF */ + else + mt_ase_fp_affinity(); } return; @@ -834,6 +835,11 @@ asmlinkage void do_mdmx(struct pt_regs *regs) asmlinkage void do_watch(struct pt_regs *regs) { + if (board_watchpoint_handler) { + (*board_watchpoint_handler)(regs); + return; + } + /* * We use the watch exception where available to detect stack * overflows. @@ -860,7 +866,7 @@ asmlinkage void do_mcheck(struct pt_regs *regs) dump_tlb_all(); } - show_code((unsigned int *) regs->cp0_epc); + show_code((unsigned int __user *) regs->cp0_epc); /* * Some chips may have other causes of machine check (e.g. SB1 @@ -927,12 +933,6 @@ asmlinkage void do_reserved(struct pt_regs *regs) (regs->cp0_cause & 0x7f) >> 2); } -static asmlinkage void do_default_vi(void) -{ - show_regs(get_irq_regs()); - panic("Caught unexpected vectored interrupt."); -} - /* * Some MIPS CPUs can enable/disable for cache parity detection, but do * it different ways. @@ -1128,6 +1128,12 @@ void mips_srs_free(int set) clear_bit(set, &sr->sr_allocated); } +static asmlinkage void do_default_vi(void) +{ + show_regs(get_irq_regs()); + panic("Caught unexpected vectored interrupt."); +} + static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) { unsigned long handler; @@ -1190,8 +1196,8 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) memcpy (b, &except_vec_vi, handler_len); #ifdef CONFIG_MIPS_MT_SMTC - if (n > 7) - printk("Vector index %d exceeds SMTC maximum\n", n); + BUG_ON(n > 7); /* Vector index %d exceeds SMTC maximum. */ + w = (u32 *)(b + mori_offset); *w = (*w & 0xffff0000) | (0x100 << n); #endif /* CONFIG_MIPS_MT_SMTC */ @@ -1342,16 +1348,20 @@ void __init per_cpu_trap_init(void) set_c0_status(ST0_MX); #ifdef CONFIG_CPU_MIPSR2 - write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */ + if (cpu_has_mips_r2) { + unsigned int enable = 0x0000000f; + + if (cpu_has_userlocal) + enable |= (1 << 29); + + write_c0_hwrena(enable); + } #endif #ifdef CONFIG_MIPS_MT_SMTC if (!secondaryTC) { #endif /* CONFIG_MIPS_MT_SMTC */ - /* - * Interrupt handling. - */ if (cpu_has_veic || cpu_has_vint) { write_c0_ebase (ebase); /* Setting vector spacing enables EI/VI mode */ @@ -1365,6 +1375,23 @@ void __init per_cpu_trap_init(void) } else set_c0_cause(CAUSEF_IV); } + + /* + * Before R2 both interrupt numbers were fixed to 7, so on R2 only: + * + * o read IntCtl.IPTI to determine the timer interrupt + * o read IntCtl.IPPCI to determine the performance counter interrupt + */ + if (cpu_has_mips_r2) { + cp0_compare_irq = (read_c0_intctl () >> 29) & 7; + cp0_perfcount_irq = (read_c0_intctl () >> 26) & 7; + if (cp0_perfcount_irq == cp0_compare_irq) + cp0_perfcount_irq = -1; + } else { + cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ; + cp0_perfcount_irq = -1; + } + #ifdef CONFIG_MIPS_MT_SMTC } #endif /* CONFIG_MIPS_MT_SMTC */ @@ -1383,6 +1410,13 @@ void __init per_cpu_trap_init(void) cpu_cache_init(); tlb_init(); #ifdef CONFIG_MIPS_MT_SMTC + } else if (!secondaryTC) { + /* + * First TC in non-boot VPE must do subset of tlb_init() + * for MMU countrol registers. + */ + write_c0_pagemask(PM_DEFAULT_MASK); + write_c0_wired(0); } #endif /* CONFIG_MIPS_MT_SMTC */ } @@ -1531,8 +1565,7 @@ void __init trap_init(void) if (cpu_has_mipsmt) set_except_vector(25, handle_mt); - if (cpu_has_dsp) - set_except_vector(26, handle_dsp); + set_except_vector(26, handle_dsp); if (cpu_has_vce) /* Special exception: R4[04]00 uses also the divec space. */ diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 18c4a3c45a3..8b9c34ffae1 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -77,6 +77,7 @@ #include <linux/signal.h> #include <linux/smp.h> #include <linux/sched.h> +#include <linux/debugfs.h> #include <asm/asm.h> #include <asm/branch.h> #include <asm/byteorder.h> @@ -87,9 +88,18 @@ #define STR(x) __STR(x) #define __STR(x) #x -#ifdef CONFIG_PROC_FS -unsigned long unaligned_instructions; +enum { + UNALIGNED_ACTION_QUIET, + UNALIGNED_ACTION_SIGNAL, + UNALIGNED_ACTION_SHOW, +}; +#ifdef CONFIG_DEBUG_FS +static u32 unaligned_instructions; +static u32 unaligned_action; +#else +#define unaligned_action UNALIGNED_ACTION_QUIET #endif +extern void show_registers(struct pt_regs *regs); static inline int emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned int __user *pc, @@ -459,7 +469,7 @@ static inline int emulate_load_store_insn(struct pt_regs *regs, goto sigill; } -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_DEBUG_FS unaligned_instructions++; #endif @@ -516,6 +526,10 @@ asmlinkage void do_ade(struct pt_regs *regs) pc = (unsigned int __user *) exception_epc(regs); if (user_mode(regs) && (current->thread.mflags & MF_FIXADE) == 0) goto sigbus; + if (unaligned_action == UNALIGNED_ACTION_SIGNAL) + goto sigbus; + else if (unaligned_action == UNALIGNED_ACTION_SHOW) + show_registers(regs); /* * Do branch emulation only if we didn't forward the exception. @@ -546,3 +560,24 @@ sigbus: * XXX On return from the signal handler we should advance the epc */ } + +#ifdef CONFIG_DEBUG_FS +extern struct dentry *mips_debugfs_dir; +static int __init debugfs_unaligned(void) +{ + struct dentry *d; + + if (!mips_debugfs_dir) + return -ENODEV; + d = debugfs_create_u32("unaligned_instructions", S_IRUGO, + mips_debugfs_dir, &unaligned_instructions); + if (IS_ERR(d)) + return PTR_ERR(d); + d = debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR, + mips_debugfs_dir, &unaligned_action); + if (IS_ERR(d)) + return PTR_ERR(d); + return 0; +} +__initcall(debugfs_unaligned); +#endif diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 9b9992cd562..bc9bae2a73f 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -119,10 +119,7 @@ SECTIONS .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; #endif - . = ALIGN(_PAGE_SIZE); - __per_cpu_start = .; - .data.percpu : { *(.data.percpu) } - __per_cpu_end = .; + PERCPU(_PAGE_SIZE) . = ALIGN(_PAGE_SIZE); __init_end = .; /* freed after init ends here */ diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index c9ee9d2d585..9e66354dee8 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -1436,10 +1436,6 @@ static int __init vpe_module_init(void) write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); if (i != 0) { - write_vpe_c0_status((read_c0_status() & - ~(ST0_IM | ST0_IE | ST0_KSU)) - | ST0_CU0); - /* * Set config to be the same as vpe0, * particularly kseg0 coherency alg |