diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-31 20:41:53 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-31 20:41:53 -0700 |
commit | d6dd9e93c7531fa31370e27d053a3940d8d662fb (patch) | |
tree | afab573031b3f0b9bbe5e417a890f7cae09a7224 /arch/mips/kernel | |
parent | dd9cd6d4351076c78bb8c0f9146d1904b481fdbb (diff) | |
parent | b4b2917cc8babe8eaf4bc133bca31b11ed7dac13 (diff) |
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: (50 commits)
[MIPS] Add smp_call_function_single()
[MIPS] thread_info.h: kmalloc + memset conversion to kzalloc
[MIPS] Kexec: Fix several 64-bit bugs.
[MIPS] Kexec: Fix several warnings.
[MIPS] DDB5477: Remove support
[MIPS] Fulong: Remove unneeded header file
[MIPS] Cobalt: Enable UART on RaQ1
[MIPS] Remove unused GROUP_TOSHIBA_NAMES
[MIPS] remove some duplicate includes
[MIPS] Oprofile: Fix rm9000 performance counter handler
[MIPS] Use -Werror on subdirectories which build cleanly.
[MIPS] Yosemite: Fix warning.
[MIPS] PMON: Fix cpustart declaration.
[MIPS] Yosemite: Only build ll_ht_smp_irq_handler() if HYPERTRANSPORT.
[MIPS] Yosemite: Fix build error due to undeclared titan_mailbox_irq().
[MIPS] Yosemite: Don't declare titan_mailbox_irq() as asmlinkage.
[MIPS] Yosemite: Fix warnings in i2c-yoesmite by deleting the unused code.
[MIPS] Delete unused arch/mips/gt64120/common/
[MIPS] Fix build warning in unaligned load/store emulator.
[MIPS] IP32: Don't ignore request_irq's return value.
...
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/mips/kernel/head.S | 1 | ||||
-rw-r--r-- | arch/mips/kernel/kspd.c | 19 | ||||
-rw-r--r-- | arch/mips/kernel/linux32.c | 7 | ||||
-rw-r--r-- | arch/mips/kernel/machine_kexec.c | 13 | ||||
-rw-r--r-- | arch/mips/kernel/mips-mt-fpaff.c | 9 | ||||
-rw-r--r-- | arch/mips/kernel/mips-mt.c | 22 | ||||
-rw-r--r-- | arch/mips/kernel/process.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace.c | 14 | ||||
-rw-r--r-- | arch/mips/kernel/relocate_kernel.S | 78 | ||||
-rw-r--r-- | arch/mips/kernel/rtlx.c | 24 | ||||
-rw-r--r-- | arch/mips/kernel/scall32-o32.S | 1 | ||||
-rw-r--r-- | arch/mips/kernel/scall64-64.S | 1 | ||||
-rw-r--r-- | arch/mips/kernel/scall64-n32.S | 1 | ||||
-rw-r--r-- | arch/mips/kernel/scall64-o32.S | 1 | ||||
-rw-r--r-- | arch/mips/kernel/signal32.c | 1 | ||||
-rw-r--r-- | arch/mips/kernel/smp.c | 55 | ||||
-rw-r--r-- | arch/mips/kernel/smtc.c | 36 | ||||
-rw-r--r-- | arch/mips/kernel/syscall.c | 18 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/unaligned.c | 53 | ||||
-rw-r--r-- | arch/mips/kernel/vpe.c | 359 |
23 files changed, 452 insertions, 268 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 5c8085b6d7a..07344cb3759 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -71,3 +71,5 @@ 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 + +EXTRA_CFLAGS += -Werror diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 3b27309d54b..013327286c2 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -132,7 +132,6 @@ void output_thread_defines(void) offset("#define THREAD_ECODE ", struct task_struct, \ thread.error_code); offset("#define THREAD_TRAPNO ", struct task_struct, thread.trap_no); - offset("#define THREAD_MFLAGS ", struct task_struct, thread.mflags); offset("#define THREAD_TRAMP ", struct task_struct, \ thread.irix_trampoline); offset("#define THREAD_OLDCTX ", struct task_struct, \ diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index c15bbc436bb..e46782b0ebc 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -138,7 +138,6 @@ .fill 0x400 #endif -EXPORT(stext) # used for profiling EXPORT(_stext) #ifndef CONFIG_BOOT_RAW diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c index c6580018c94..cb9a14a1ca5 100644 --- a/arch/mips/kernel/kspd.c +++ b/arch/mips/kernel/kspd.c @@ -89,7 +89,7 @@ static int sp_stopping = 0; #define MTSP_O_EXCL 0x0800 #define MTSP_O_BINARY 0x8000 -#define SP_VPE 1 +extern int tclimit; struct apsp_table { int sp; @@ -225,8 +225,8 @@ void sp_work_handle_request(void) /* Run the syscall at the priviledge of the user who loaded the SP program */ - if (vpe_getuid(SP_VPE)) - sp_setfsuidgid( vpe_getuid(SP_VPE), vpe_getgid(SP_VPE)); + if (vpe_getuid(tclimit)) + sp_setfsuidgid(vpe_getuid(tclimit), vpe_getgid(tclimit)); switch (sc.cmd) { /* needs the flags argument translating from SDE kit to @@ -245,7 +245,7 @@ void sp_work_handle_request(void) case MTSP_SYSCALL_EXIT: list_for_each_entry(n, &kspd_notifylist, list) - n->kspd_sp_exit(SP_VPE); + n->kspd_sp_exit(tclimit); sp_stopping = 1; printk(KERN_DEBUG "KSPD got exit syscall from SP exitcode %d\n", @@ -255,7 +255,7 @@ void sp_work_handle_request(void) case MTSP_SYSCALL_OPEN: generic.arg1 = translate_open_flags(generic.arg1); - vcwd = vpe_getcwd(SP_VPE); + vcwd = vpe_getcwd(tclimit); /* change to the cwd of the process that loaded the SP program */ old_fs = get_fs(); @@ -283,7 +283,7 @@ void sp_work_handle_request(void) break; } /* switch */ - if (vpe_getuid(SP_VPE)) + if (vpe_getuid(tclimit)) sp_setfsuidgid( 0, 0); old_fs = get_fs(); @@ -364,10 +364,9 @@ static void startwork(int vpe) } INIT_WORK(&work, sp_work); - queue_work(workqueue, &work); - } else - queue_work(workqueue, &work); + } + queue_work(workqueue, &work); } static void stopwork(int vpe) @@ -389,7 +388,7 @@ static int kspd_module_init(void) notify.start = startwork; notify.stop = stopwork; - vpe_notify(SP_VPE, ¬ify); + vpe_notify(tclimit, ¬ify); return 0; } diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index c37568d6fb5..135d9a5fe33 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -566,6 +566,13 @@ asmlinkage long sys32_fadvise64_64(int fd, int __pad, flags); } +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) diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 8f42fa85ac9..22960d67cf0 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -14,7 +14,7 @@ #include <asm/page.h> extern const unsigned char relocate_new_kernel[]; -extern const unsigned int relocate_new_kernel_size; +extern const size_t relocate_new_kernel_size; extern unsigned long kexec_start_address; extern unsigned long kexec_indirection_page; @@ -40,6 +40,8 @@ machine_crash_shutdown(struct pt_regs *regs) { } +typedef void (*noretfun_t)(void) __attribute__((noreturn)); + void machine_kexec(struct kimage *image) { @@ -51,7 +53,8 @@ machine_kexec(struct kimage *image) (unsigned long)page_address(image->control_code_page); kexec_start_address = image->start; - kexec_indirection_page = phys_to_virt(image->head & PAGE_MASK); + kexec_indirection_page = + (unsigned long) phys_to_virt(image->head & PAGE_MASK); memcpy((void*)reboot_code_buffer, relocate_new_kernel, relocate_new_kernel_size); @@ -67,7 +70,7 @@ machine_kexec(struct kimage *image) phys_to_virt(entry & PAGE_MASK) : ptr + 1) { if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION || *ptr & IND_DESTINATION) - *ptr = phys_to_virt(*ptr); + *ptr = (unsigned long) phys_to_virt(*ptr); } /* @@ -78,8 +81,8 @@ machine_kexec(struct kimage *image) flush_icache_range(reboot_code_buffer, reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); - printk("Will call new kernel at %08x\n", image->start); + printk("Will call new kernel at %08lx\n", image->start); printk("Bye ...\n"); flush_cache_all(); - ((void (*)(void))reboot_code_buffer)(); + ((noretfun_t) reboot_code_buffer)(); } diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c index ede5d73d652..892665bb12b 100644 --- a/arch/mips/kernel/mips-mt-fpaff.c +++ b/arch/mips/kernel/mips-mt-fpaff.c @@ -50,6 +50,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, cpumask_t effective_mask; int retval; struct task_struct *p; + struct thread_info *ti; if (len < sizeof(new_mask)) return -EINVAL; @@ -93,16 +94,16 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, 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)) { + ti = task_thread_info(p); + if (test_ti_thread_flag(ti, TIF_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; + clear_ti_thread_flag(ti, TIF_FPUBOUND); retval = set_cpus_allowed(p, new_mask); } - out_unlock: put_task_struct(p); unlock_cpu_hotplug(); diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index 1a7d8923129..7169a4db37b 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -21,6 +21,28 @@ #include <asm/r4kcache.h> #include <asm/cacheflush.h> +int vpelimit; + +static int __init maxvpes(char *str) +{ + get_option(&str, &vpelimit); + + return 1; +} + +__setup("maxvpes=", maxvpes); + +int tclimit; + +static int __init maxtcs(char *str) +{ + get_option(&str, &tclimit); + + return 1; +} + +__setup("maxtcs=", maxtcs); + /* * 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. diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index bd05f5a927e..e6ce943099a 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -77,7 +77,7 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|KU_MASK); #ifdef CONFIG_64BIT status &= ~ST0_FR; - status |= (current->thread.mflags & MF_32BIT_REGS) ? 0 : ST0_FR; + status |= test_thread_flag(TIF_32BIT_REGS) ? 0 : ST0_FR; #endif status |= KU_USER; regs->cp0_status = status; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 893e7bccf22..bbd57b20b43 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -20,11 +20,11 @@ #include <linux/mm.h> #include <linux/errno.h> #include <linux/ptrace.h> -#include <linux/audit.h> #include <linux/smp.h> #include <linux/user.h> #include <linux/security.h> -#include <linux/signal.h> +#include <linux/audit.h> +#include <linux/seccomp.h> #include <asm/byteorder.h> #include <asm/cpu.h> @@ -470,12 +470,17 @@ static inline int audit_arch(void) */ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) { + /* do the secure computing check first */ + if (!entryexit) + secure_computing(regs->regs[0]); + if (unlikely(current->audit_context) && entryexit) audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]), regs->regs[2]); if (!(current->ptrace & PT_PTRACED)) goto out; + if (!test_thread_flag(TIF_SYSCALL_TRACE)) goto out; @@ -493,9 +498,10 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) send_sig(current->exit_code, current, 1); current->exit_code = 0; } - out: + +out: if (unlikely(current->audit_context) && !entryexit) - audit_syscall_entry(audit_arch(), regs->regs[2], + audit_syscall_entry(audit_arch(), regs->regs[0], regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); } diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S index a3f0d00c133..87481f916a6 100644 --- a/arch/mips/kernel/relocate_kernel.S +++ b/arch/mips/kernel/relocate_kernel.S @@ -14,67 +14,69 @@ #include <asm/stackframe.h> #include <asm/addrspace.h> - .globl relocate_new_kernel -relocate_new_kernel: - - PTR_L s0, kexec_indirection_page - PTR_L s1, kexec_start_address +LEAF(relocate_new_kernel) + PTR_L s0, kexec_indirection_page + PTR_L s1, kexec_start_address process_entry: - PTR_L s2, (s0) - PTR_ADD s0, s0, SZREG + PTR_L s2, (s0) + PTR_ADD s0, s0, SZREG /* destination page */ - and s3, s2, 0x1 - beq s3, zero, 1f - and s4, s2, ~0x1 /* store destination addr in s4 */ - move a0, s4 - b process_entry + and s3, s2, 0x1 + beq s3, zero, 1f + and s4, s2, ~0x1 /* store destination addr in s4 */ + move a0, s4 + b process_entry 1: /* indirection page, update s0 */ - and s3, s2, 0x2 - beq s3, zero, 1f - and s0, s2, ~0x2 - b process_entry + and s3, s2, 0x2 + beq s3, zero, 1f + and s0, s2, ~0x2 + b process_entry 1: /* done page */ - and s3, s2, 0x4 - beq s3, zero, 1f - b done + and s3, s2, 0x4 + beq s3, zero, 1f + b done 1: /* source page */ - and s3, s2, 0x8 - beq s3, zero, process_entry - and s2, s2, ~0x8 - li s6, (1 << PAGE_SHIFT) / SZREG + and s3, s2, 0x8 + beq s3, zero, process_entry + and s2, s2, ~0x8 + li s6, (1 << PAGE_SHIFT) / SZREG copy_word: /* copy page word by word */ - REG_L s5, (s2) - REG_S s5, (s4) - INT_ADD s4, s4, SZREG - INT_ADD s2, s2, SZREG - INT_SUB s6, s6, 1 - beq s6, zero, process_entry - b copy_word - b process_entry + REG_L s5, (s2) + REG_S s5, (s4) + PTR_ADD s4, s4, SZREG + PTR_ADD s2, s2, SZREG + LONG_SUB s6, s6, 1 + beq s6, zero, process_entry + b copy_word + b process_entry done: /* jump to kexec_start_address */ - j s1 + j s1 + END(relocate_new_kernel) - .globl kexec_start_address kexec_start_address: - .long 0x0 + EXPORT(kexec_start_address) + PTR 0x0 + .size kexec_start_address, PTRSIZE - .globl kexec_indirection_page kexec_indirection_page: - .long 0x0 + EXPORT(kexec_indirection_page) + PTR 0 + .size kexec_indirection_page, PTRSIZE relocate_new_kernel_end: - .globl relocate_new_kernel_size relocate_new_kernel_size: - .long relocate_new_kernel_end - relocate_new_kernel + EXPORT(relocate_new_kernel_size) + PTR relocate_new_kernel_end - relocate_new_kernel + .size relocate_new_kernel_size, PTRSIZE diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 8cf24d716d4..aab89e97abb 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -40,12 +40,11 @@ #include <asm/atomic.h> #include <asm/cpu.h> #include <asm/processor.h> +#include <asm/mips_mt.h> #include <asm/system.h> #include <asm/vpe.h> #include <asm/rtlx.h> -#define RTLX_TARG_VPE 1 - static struct rtlx_info *rtlx; static int major; static char module_name[] = "rtlx"; @@ -165,10 +164,10 @@ int rtlx_open(int index, int can_sleep) } if (rtlx == NULL) { - if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { + if( (p = vpe_get_shared(tclimit)) == NULL) { if (can_sleep) { __wait_event_interruptible(channel_wqs[index].lx_queue, - (p = vpe_get_shared(RTLX_TARG_VPE)), + (p = vpe_get_shared(tclimit)), ret); if (ret) goto out_fail; @@ -472,11 +471,24 @@ static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ; static char register_chrdev_failed[] __initdata = KERN_ERR "rtlx_module_init: unable to register device\n"; -static int rtlx_module_init(void) +static int __init rtlx_module_init(void) { struct device *dev; int i, err; + if (!cpu_has_mipsmt) { + printk("VPE loader: not a MIPS MT capable processor\n"); + return -ENODEV; + } + + if (tclimit == 0) { + printk(KERN_WARNING "No TCs reserved for AP/SP, not " + "initializing RTLX.\nPass maxtcs=<n> argument as kernel " + "argument\n"); + + return -ENODEV; + } + major = register_chrdev(0, module_name, &rtlx_fops); if (major < 0) { printk(register_chrdev_failed); @@ -501,7 +513,7 @@ static int rtlx_module_init(void) /* set up notifiers */ notify.start = starting; notify.stop = stopping; - vpe_notify(RTLX_TARG_VPE, ¬ify); + vpe_notify(tclimit, ¬ify); if (cpu_has_vint) set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch); diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index ae985d1fcca..82480a1717d 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -662,6 +662,7 @@ einval: li v0, -EINVAL sys sys_signalfd 3 sys sys_timerfd 4 sys sys_eventfd 1 + sys sys_fallocate 6 /* 4320 */ .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 7bcd5a1a85f..c2c10876da2 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -477,4 +477,5 @@ sys_call_table: PTR sys_signalfd PTR sys_timerfd PTR sys_eventfd + PTR sys_fallocate .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 532a2f3b42f..53d7a977193 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -403,4 +403,5 @@ EXPORT(sysn32_call_table) PTR compat_sys_signalfd /* 5280 */ PTR compat_sys_timerfd PTR sys_eventfd + PTR sys_fallocate .size sysn32_call_table,.-sysn32_call_table diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 6bbe0f4ed8b..b3ed731a24c 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -525,4 +525,5 @@ sys_call_table: PTR compat_sys_signalfd PTR compat_sys_timerfd PTR sys_eventfd + PTR sys_fallocate /* 4320 */ .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 486b8e5f52d..64b612a0a62 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -18,7 +18,6 @@ #include <linux/errno.h> #include <linux/wait.h> #include <linux/ptrace.h> -#include <linux/compat.h> #include <linux/suspend.h> #include <linux/compiler.h> #include <linux/uaccess.h> diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 04bbbd8d91a..73b0dab0266 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -194,6 +194,61 @@ void smp_call_function_interrupt(void) } } +int smp_call_function_single(int cpu, void (*func) (void *info), void *info, + int retry, int wait) +{ + struct call_data_struct data; + int me; + + /* + * Can die spectacularly if this CPU isn't yet marked online + */ + if (!cpu_online(cpu)) + return 0; + + me = get_cpu(); + BUG_ON(!cpu_online(me)); + + if (cpu == me) { + local_irq_disable(); + func(info); + local_irq_enable(); + put_cpu(); + return 0; + } + + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + spin_lock(&smp_call_lock); + call_data = &data; + smp_mb(); + + /* Send a message to the other CPU */ + core_send_ipi(cpu, SMP_CALL_FUNCTION); + + /* Wait for response */ + /* FIXME: lock-up detection, backtrace on lock-up */ + while (atomic_read(&data.started) != 1) + barrier(); + + if (wait) + while (atomic_read(&data.finished) != 1) + barrier(); + call_data = NULL; + spin_unlock(&smp_call_lock); + + put_cpu(); + return 0; +} + static void stop_this_cpu(void *dummy) { /* diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 342d873b2ec..16aa5d37117 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -86,25 +86,11 @@ unsigned int smtc_status = 0; /* Boot command line configuration overrides */ -static int vpelimit = 0; -static int tclimit = 0; static int ipibuffers = 0; static int nostlb = 0; static int asidmask = 0; unsigned long smtc_asid_mask = 0xff; -static int __init maxvpes(char *str) -{ - get_option(&str, &vpelimit); - return 1; -} - -static int __init maxtcs(char *str) -{ - get_option(&str, &tclimit); - return 1; -} - static int __init ipibufs(char *str) { get_option(&str, &ipibuffers); @@ -137,8 +123,6 @@ static int __init asidmask_set(char *str) return 1; } -__setup("maxvpes=", maxvpes); -__setup("maxtcs=", maxtcs); __setup("ipibufs=", ipibufs); __setup("nostlb", stlb_disable); __setup("asidmask=", asidmask_set); @@ -168,9 +152,9 @@ static int __init tintq(char *str) __setup("tintq=", tintq); -int imstuckcount[2][8]; +static int imstuckcount[2][8]; /* vpemask represents IM/IE bits of per-VPE Status registers, low-to-high */ -int vpemask[2][8] = { +static int vpemask[2][8] = { {0, 0, 1, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1} }; @@ -540,7 +524,7 @@ void mipsmt_prepare_cpus(void) * (unsigned long)idle->thread_info the gp * */ -void smtc_boot_secondary(int cpu, struct task_struct *idle) +void __cpuinit smtc_boot_secondary(int cpu, struct task_struct *idle) { extern u32 kernelsp[NR_CPUS]; long flags; @@ -876,7 +860,7 @@ void deferred_smtc_ipi(void) * Send clock tick to all TCs except the one executing the funtion */ -void smtc_timer_broadcast(int vpe) +void smtc_timer_broadcast(void) { int cpu; int myTC = cpu_data[smp_processor_id()].tc_id; @@ -975,7 +959,12 @@ static void ipi_irq_dispatch(void) do_IRQ(cpu_ipi_irq); } -static struct irqaction irq_ipi; +static struct irqaction irq_ipi = { + .handler = ipi_interrupt, + .flags = IRQF_DISABLED, + .name = "SMTC_IPI", + .flags = IRQF_PERCPU +}; static void setup_cross_vpe_interrupts(unsigned int nvpe) { @@ -987,13 +976,8 @@ static void setup_cross_vpe_interrupts(unsigned int nvpe) set_vi_handler(MIPS_CPU_IPI_IRQ, ipi_irq_dispatch); - irq_ipi.handler = ipi_interrupt; - irq_ipi.flags = IRQF_DISABLED; - irq_ipi.name = "SMTC_IPI"; - setup_irq_smtc(cpu_ipi_irq, &irq_ipi, (0x100 << MIPS_CPU_IPI_IRQ)); - irq_desc[cpu_ipi_irq].status |= IRQ_PER_CPU; set_irq_handler(cpu_ipi_irq, handle_percpu_irq); } diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 541b5005957..7c800ec3ff5 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -281,16 +281,24 @@ asmlinkage int sys_set_thread_area(unsigned long addr) asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) { - int tmp; - - switch(cmd) { + switch (cmd) { case MIPS_ATOMIC_SET: printk(KERN_CRIT "How did I get here?\n"); return -EINVAL; case MIPS_FIXADE: - tmp = current->thread.mflags & ~3; - current->thread.mflags = tmp | (arg1 & 3); + if (arg1 & ~3) + return -EINVAL; + + if (arg1 & 1) + set_thread_flag(TIF_FIXADE); + else + clear_thread_flag(TIF_FIXADE); + if (arg1 & 2) + set_thread_flag(TIF_LOGADE); + else + clear_thread_flag(TIF_FIXADE); + return 0; case FLUSH_CACHE: diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index ce277cb34dd..c8e291c8305 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -775,7 +775,7 @@ static void mt_ase_fp_affinity(void) cpus_and(tmask, current->thread.user_cpus_allowed, mt_fpu_cpumask); set_cpus_allowed(current, tmask); - current->thread.mflags |= MF_FPUBOUND; + set_thread_flag(TIF_FPUBOUND); } } #endif /* CONFIG_MIPS_MT_FPAFF */ diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 8b9c34ffae1..d34b1fb3665 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -101,16 +101,14 @@ static u32 unaligned_action; #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, - unsigned long **regptr, unsigned long *newvalue) +static void emulate_load_store_insn(struct pt_regs *regs, + void __user *addr, unsigned int __user *pc) { union mips_instruction insn; unsigned long value; unsigned int res; regs->regs[0] = 0; - *regptr=NULL; /* * This load never faults. @@ -179,8 +177,8 @@ static inline int emulate_load_store_insn(struct pt_regs *regs, : "r" (addr), "i" (-EFAULT)); if (res) goto fault; - *newvalue = value; - *regptr = ®s->regs[insn.i_format.rt]; + compute_return_epc(regs); + regs->regs[insn.i_format.rt] = value; break; case lw_op: @@ -209,8 +207,8 @@ static inline int emulate_load_store_insn(struct pt_regs *regs, : "r" (addr), "i" (-EFAULT)); if (res) goto fault; - *newvalue = value; - *regptr = ®s->regs[insn.i_format.rt]; + compute_return_epc(regs); + regs->regs[insn.i_format.rt] = value; break; case lhu_op: @@ -243,8 +241,8 @@ static inline int emulate_load_store_insn(struct pt_regs *regs, : "r" (addr), "i" (-EFAULT)); if (res) goto fault; - *newvalue = value; - *regptr = ®s->regs[insn.i_format.rt]; + compute_return_epc(regs); + regs->regs[insn.i_format.rt] = value; break; case lwu_op: @@ -283,8 +281,8 @@ static inline int emulate_load_store_insn(struct pt_regs *regs, : "r" (addr), "i" (-EFAULT)); if (res) goto fault; - *newvalue = value; - *regptr = ®s->regs[insn.i_format.rt]; + compute_return_epc(regs); + regs->regs[insn.i_format.rt] = value; break; #endif /* CONFIG_64BIT */ @@ -325,8 +323,8 @@ static inline int emulate_load_store_insn(struct pt_regs *regs, : "r" (addr), "i" (-EFAULT)); if (res) goto fault; - *newvalue = value; - *regptr = ®s->regs[insn.i_format.rt]; + compute_return_epc(regs); + regs->regs[insn.i_format.rt] = value; break; #endif /* CONFIG_64BIT */ @@ -367,6 +365,7 @@ static inline int emulate_load_store_insn(struct pt_regs *regs, : "r" (value), "r" (addr), "i" (-EFAULT)); if (res) goto fault; + compute_return_epc(regs); break; case sw_op: @@ -397,6 +396,7 @@ static inline int emulate_load_store_insn(struct pt_regs *regs, : "r" (value), "r" (addr), "i" (-EFAULT)); if (res) goto fault; + compute_return_epc(regs); break; case sd_op: @@ -435,6 +435,7 @@ static inline int emulate_load_store_insn(struct pt_regs *regs, : "r" (value), "r" (addr), "i" (-EFAULT)); if (res) goto fault; + compute_return_epc(regs); break; #endif /* CONFIG_64BIT */ @@ -473,34 +474,31 @@ static inline int emulate_load_store_insn(struct pt_regs *regs, unaligned_instructions++; #endif - return 0; + return; fault: /* Did we have an exception handler installed? */ if (fixup_exception(regs)) - return 1; + return; die_if_kernel ("Unhandled kernel unaligned access", regs); send_sig(SIGSEGV, current, 1); - return 0; + return; sigbus: die_if_kernel("Unhandled kernel unaligned access", regs); send_sig(SIGBUS, current, 1); - return 0; + return; sigill: die_if_kernel("Unhandled kernel unaligned access or invalid instruction", regs); send_sig(SIGILL, current, 1); - - return 0; } asmlinkage void do_ade(struct pt_regs *regs) { - unsigned long *regptr, newval; extern int do_dsemulret(struct pt_regs *); unsigned int __user *pc; mm_segment_t seg; @@ -524,7 +522,7 @@ asmlinkage void do_ade(struct pt_regs *regs) goto sigbus; pc = (unsigned int __user *) exception_epc(regs); - if (user_mode(regs) && (current->thread.mflags & MF_FIXADE) == 0) + if (user_mode(regs) && !test_thread_flag(TIF_FIXADE)) goto sigbus; if (unaligned_action == UNALIGNED_ACTION_SIGNAL) goto sigbus; @@ -538,16 +536,7 @@ asmlinkage void do_ade(struct pt_regs *regs) seg = get_fs(); if (!user_mode(regs)) set_fs(KERNEL_DS); - if (!emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc, - ®ptr, &newval)) { - compute_return_epc(regs); - /* - * Now that branch is evaluated, update the dest - * register if necessary - */ - if (regptr) - *regptr = newval; - } + emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc); set_fs(seg); return; diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index a2bee10f04c..3c09b9785f4 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -27,7 +27,6 @@ * To load and run, simply cat a SP 'program file' to /dev/vpe1. * i.e cat spapp >/dev/vpe1. */ - #include <linux/kernel.h> #include <linux/device.h> #include <linux/module.h> @@ -54,6 +53,7 @@ #include <asm/system.h> #include <asm/vpe.h> #include <asm/kspd.h> +#include <asm/mips_mt.h> typedef void *vpe_handle; @@ -64,6 +64,10 @@ typedef void *vpe_handle; /* If this is set, the section belongs in the init part of the module */ #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) +/* + * The number of TCs and VPEs physically available on the core + */ +static int hw_tcs, hw_vpes; static char module_name[] = "vpe"; static int major; static const int minor = 1; /* fixed for now */ @@ -126,20 +130,17 @@ struct vpe { /* the list of who wants to know when something major happens */ struct list_head notify; + + unsigned int ntcs; }; struct tc { enum tc_state state; int index; - /* parent VPE */ - struct vpe *pvpe; - - /* The list of TC's with this VPE */ - struct list_head tc; - - /* The global list of tc's */ - struct list_head list; + struct vpe *pvpe; /* parent VPE */ + struct list_head tc; /* The list of TC's with this VPE */ + struct list_head list; /* The global list of tc's */ }; struct { @@ -217,18 +218,17 @@ struct vpe *alloc_vpe(int minor) /* allocate a tc. At startup only tc0 is running, all other can be halted. */ struct tc *alloc_tc(int index) { - struct tc *t; + struct tc *tc; - if ((t = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) { - return NULL; - } - - INIT_LIST_HEAD(&t->tc); - list_add_tail(&t->list, &vpecontrol.tc_list); + if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) + goto out; - t->index = index; + INIT_LIST_HEAD(&tc->tc); + tc->index = index; + list_add_tail(&tc->list, &vpecontrol.tc_list); - return t; +out: + return tc; } /* clean up and free everything */ @@ -663,66 +663,48 @@ static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex, } #endif -static void dump_tc(struct tc *t) -{ - unsigned long val; - - settc(t->index); - printk(KERN_DEBUG "VPE loader: TC index %d targtc %ld " - "TCStatus 0x%lx halt 0x%lx\n", - t->index, read_c0_vpecontrol() & VPECONTROL_TARGTC, - read_tc_c0_tcstatus(), read_tc_c0_tchalt()); - - printk(KERN_DEBUG " tcrestart 0x%lx\n", read_tc_c0_tcrestart()); - printk(KERN_DEBUG " tcbind 0x%lx\n", read_tc_c0_tcbind()); - - val = read_c0_vpeconf0(); - printk(KERN_DEBUG " VPEConf0 0x%lx MVP %ld\n", val, - (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT); - - printk(KERN_DEBUG " c0 status 0x%lx\n", read_vpe_c0_status()); - printk(KERN_DEBUG " c0 cause 0x%lx\n", read_vpe_c0_cause()); - - printk(KERN_DEBUG " c0 badvaddr 0x%lx\n", read_vpe_c0_badvaddr()); - printk(KERN_DEBUG " c0 epc 0x%lx\n", read_vpe_c0_epc()); -} - -static void dump_tclist(void) -{ - struct tc *t; - - list_for_each_entry(t, &vpecontrol.tc_list, list) { - dump_tc(t); - } -} - /* We are prepared so configure and start the VPE... */ static int vpe_run(struct vpe * v) { + unsigned long flags, val, dmt_flag; struct vpe_notifications *n; - unsigned long val, dmt_flag; + unsigned int vpeflags; struct tc *t; /* check we are the Master VPE */ + local_irq_save(flags); val = read_c0_vpeconf0(); if (!(val & VPECONF0_MVP)) { printk(KERN_WARNING "VPE loader: only Master VPE's are allowed to configure MT\n"); + local_irq_restore(flags); + return -1; } - /* disable MT (using dvpe) */ - dvpe(); + dmt_flag = dmt(); + vpeflags = dvpe(); if (!list_empty(&v->tc)) { if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { - printk(KERN_WARNING "VPE loader: TC %d is already in use.\n", - t->index); + evpe(vpeflags); + emt(dmt_flag); + local_irq_restore(flags); + + printk(KERN_WARNING + "VPE loader: TC %d is already in use.\n", + t->index); return -ENOEXEC; } } else { - printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n", + evpe(vpeflags); + emt(dmt_flag); + local_irq_restore(flags); + + printk(KERN_WARNING + "VPE loader: No TC's associated with VPE %d\n", v->minor); + return -ENOEXEC; } @@ -733,21 +715,20 @@ static int vpe_run(struct vpe * v) /* should check it is halted, and not activated */ if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) { - printk(KERN_WARNING "VPE loader: TC %d is already doing something!\n", + evpe(vpeflags); + emt(dmt_flag); + local_irq_restore(flags); + + printk(KERN_WARNING "VPE loader: TC %d is already active!\n", t->index); - dump_tclist(); + return -ENOEXEC; } - /* - * Disable multi-threaded execution whilst we activate, clear the - * halt bit and bound the tc to the other VPE... - */ - dmt_flag = dmt(); - /* Write the address we want it to start running from in the TCPC register. */ write_tc_c0_tcrestart((unsigned long)v->__start); write_tc_c0_tccontext((unsigned long)0); + /* * Mark the TC as activated, not interrupt exempt and not dynamically * allocatable @@ -763,15 +744,15 @@ static int vpe_run(struct vpe * v) * here... Or set $a3 to zero and define DFLT_STACK_SIZE and * DFLT_HEAP_SIZE when you compile your program */ - mttgpr(7, physical_memsize); - + mttgpr(6, v->ntcs); + mttgpr(7, physical_memsize); /* set up VPE1 */ /* * bind the TC to VPE 1 as late as possible so we only have the final * VPE registers to set up, and so an EJTAG probe can trigger on it */ - write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor); + write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1); write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA)); @@ -793,15 +774,16 @@ static int vpe_run(struct vpe * v) /* take system out of configuration state */ clear_c0_mvpcontrol(MVPCONTROL_VPC); - /* now safe to re-enable multi-threading */ - emt(dmt_flag); - - /* set it running */ +#ifdef CONFIG_SMP evpe(EVPE_ENABLE); +#else + evpe(vpeflags); +#endif + emt(dmt_flag); + local_irq_restore(flags); - list_for_each_entry(n, &v->notify, list) { - n->start(v->minor); - } + list_for_each_entry(n, &v->notify, list) + n->start(minor); return 0; } @@ -1023,23 +1005,15 @@ static int vpe_elfload(struct vpe * v) return 0; } -void __used dump_vpe(struct vpe * v) -{ - struct tc *t; - - settc(v->minor); - - printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol()); - printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0()); - - list_for_each_entry(t, &vpecontrol.tc_list, list) - dump_tc(t); -} - static void cleanup_tc(struct tc *tc) { + unsigned long flags; + unsigned int mtflags, vpflags; int tmp; + local_irq_save(flags); + mtflags = dmt(); + vpflags = dvpe(); /* Put MVPE's into 'configuration state' */ set_c0_mvpcontrol(MVPCONTROL_VPC); @@ -1054,9 +1028,12 @@ static void cleanup_tc(struct tc *tc) write_tc_c0_tchalt(TCHALT_H); /* bind it to anything other than VPE1 */ - write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE +// write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE clear_c0_mvpcontrol(MVPCONTROL_VPC); + evpe(vpflags); + emt(mtflags); + local_irq_restore(flags); } static int getcwd(char *buff, int size) @@ -1077,36 +1054,32 @@ static int getcwd(char *buff, int size) /* checks VPE is unused and gets ready to load program */ static int vpe_open(struct inode *inode, struct file *filp) { - int minor, ret; enum vpe_state state; - struct vpe *v; struct vpe_notifications *not; + struct vpe *v; + int ret; - /* assume only 1 device at the mo. */ - if ((minor = iminor(inode)) != 1) { + if (minor != iminor(inode)) { + /* assume only 1 device at the moment. */ printk(KERN_WARNING "VPE loader: only vpe1 is supported\n"); return -ENODEV; } - if ((v = get_vpe(minor)) == NULL) { + if ((v = get_vpe(tclimit)) == NULL) { printk(KERN_WARNING "VPE loader: unable to get vpe\n"); return -ENODEV; } state = xchg(&v->state, VPE_STATE_INUSE); if (state != VPE_STATE_UNUSED) { - dvpe(); - printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); - dump_tc(get_tc(minor)); - list_for_each_entry(not, &v->notify, list) { - not->stop(minor); + not->stop(tclimit); } release_progmem(v->load_addr); - cleanup_tc(get_tc(minor)); + cleanup_tc(get_tc(tclimit)); } /* this of-course trashes what was there before... */ @@ -1133,26 +1106,25 @@ static int vpe_open(struct inode *inode, struct file *filp) v->shared_ptr = NULL; v->__start = 0; + return 0; } static int vpe_release(struct inode *inode, struct file *filp) { - int minor, ret = 0; struct vpe *v; Elf_Ehdr *hdr; + int ret = 0; - minor = iminor(inode); - if ((v = get_vpe(minor)) == NULL) + v = get_vpe(tclimit); + if (v == NULL) return -ENODEV; - // simple case of fire and forget, so tell the VPE to run... - hdr = (Elf_Ehdr *) v->pbuffer; if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) { - if (vpe_elfload(v) >= 0) + if (vpe_elfload(v) >= 0) { vpe_run(v); - else { + } else { printk(KERN_WARNING "VPE loader: ELF load failed.\n"); ret = -ENOEXEC; } @@ -1179,12 +1151,14 @@ static int vpe_release(struct inode *inode, struct file *filp) static ssize_t vpe_write(struct file *file, const char __user * buffer, size_t count, loff_t * ppos) { - int minor; size_t ret = count; struct vpe *v; - minor = iminor(file->f_path.dentry->d_inode); - if ((v = get_vpe(minor)) == NULL) + if (iminor(file->f_path.dentry->d_inode) != minor) + return -ENODEV; + + v = get_vpe(tclimit); + if (v == NULL) return -ENODEV; if (v->pbuffer == NULL) { @@ -1366,62 +1340,173 @@ static void kspd_sp_exit( int sp_id) } #endif -static struct device *vpe_dev; +static ssize_t store_kill(struct class_device *dev, const char *buf, size_t len) +{ + struct vpe *vpe = get_vpe(tclimit); + struct vpe_notifications *not; + + list_for_each_entry(not, &vpe->notify, list) { + not->stop(tclimit); + } + + release_progmem(vpe->load_addr); + cleanup_tc(get_tc(tclimit)); + vpe_stop(vpe); + vpe_free(vpe); + + return len; +} + +static ssize_t show_ntcs(struct class_device *cd, char *buf) +{ + struct vpe *vpe = get_vpe(tclimit); + + return sprintf(buf, "%d\n", vpe->ntcs); +} + +static ssize_t store_ntcs(struct class_device *dev, const char *buf, size_t len) +{ + struct vpe *vpe = get_vpe(tclimit); + unsigned long new; + char *endp; + + new = simple_strtoul(buf, &endp, 0); + if (endp == buf) + goto out_einval; + + if (new == 0 || new > (hw_tcs - tclimit)) + goto out_einval; + + vpe->ntcs = new; + + return len; + +out_einval: + return -EINVAL;; +} + +static struct class_device_attribute vpe_class_attributes[] = { + __ATTR(kill, S_IWUSR, NULL, store_kill), + __ATTR(ntcs, S_IRUGO | S_IWUSR, show_ntcs, store_ntcs), + {} +}; + +static void vpe_class_device_release(struct class_device *cd) +{ + kfree(cd); +} + +struct class vpe_class = { + .name = "vpe", + .owner = THIS_MODULE, + .release = vpe_class_device_release, + .class_dev_attrs = vpe_class_attributes, +}; + +struct class_device vpe_device; static int __init vpe_module_init(void) { + unsigned int mtflags, vpflags; + unsigned long flags, val; struct vpe *v = NULL; - struct device *dev; struct tc *t; - unsigned long val; - int i, err; + int tc, err; if (!cpu_has_mipsmt) { printk("VPE loader: not a MIPS MT capable processor\n"); return -ENODEV; } + if (vpelimit == 0) { + printk(KERN_WARNING "No VPEs reserved for AP/SP, not " + "initializing VPE loader.\nPass maxvpes=<n> argument as " + "kernel argument\n"); + + return -ENODEV; + } + + if (tclimit == 0) { + printk(KERN_WARNING "No TCs reserved for AP/SP, not " + "initializing VPE loader.\nPass maxtcs=<n> argument as " + "kernel argument\n"); + + return -ENODEV; + } + major = register_chrdev(0, module_name, &vpe_fops); if (major < 0) { printk("VPE loader: unable to register character device\n"); return major; } - dev = device_create(mt_class, NULL, MKDEV(major, minor), - "tc%d", minor); - if (IS_ERR(dev)) { - err = PTR_ERR(dev); + err = class_register(&vpe_class); + if (err) { + printk(KERN_ERR "vpe_class registration failed\n"); goto out_chrdev; } - vpe_dev = dev; - dmt(); - dvpe(); + class_device_initialize(&vpe_device); + vpe_device.class = &vpe_class, + vpe_device.parent = NULL, + strlcpy(vpe_device.class_id, "vpe1", BUS_ID_SIZE); + vpe_device.devt = MKDEV(major, minor); + err = class_device_add(&vpe_device); + if (err) { + printk(KERN_ERR "Adding vpe_device failed\n"); + goto out_class; + } + + local_irq_save(flags); + mtflags = dmt(); + vpflags = dvpe(); /* Put MVPE's into 'configuration state' */ set_c0_mvpcontrol(MVPCONTROL_VPC); /* dump_mtregs(); */ - val = read_c0_mvpconf0(); - for (i = 0; i < ((val & MVPCONF0_PTC) + 1); i++) { - t = alloc_tc(i); + hw_tcs = (val & MVPCONF0_PTC) + 1; + hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; + + for (tc = tclimit; tc < hw_tcs; tc++) { + /* + * Must re-enable multithreading temporarily or in case we + * reschedule send IPIs or similar we might hang. + */ + clear_c0_mvpcontrol(MVPCONTROL_VPC); + evpe(vpflags); + emt(mtflags); + local_irq_restore(flags); + t = alloc_tc(tc); + if (!t) { + err = -ENOMEM; + goto out; + } + + local_irq_save(flags); + mtflags = dmt(); + vpflags = dvpe(); + set_c0_mvpcontrol(MVPCONTROL_VPC); /* VPE's */ - if (i < ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1) { - settc(i); + if (tc < hw_tcs) { + settc(tc); - if ((v = alloc_vpe(i)) == NULL) { + if ((v = alloc_vpe(tc)) == NULL) { printk(KERN_WARNING "VPE: unable to allocate VPE\n"); - return -ENODEV; + + goto out_reenable; } + v->ntcs = hw_tcs - tclimit; + /* add the tc to the list of this vpe's tc's. */ list_add(&t->tc, &v->tc); /* deactivate all but vpe0 */ - if (i != 0) { + if (tc >= tclimit) { unsigned long tmp = read_vpe_c0_vpeconf0(); tmp &= ~VPECONF0_VPA; @@ -1434,7 +1519,7 @@ static int __init vpe_module_init(void) /* disable multi-threading with TC's */ write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); - if (i != 0) { + if (tc >= vpelimit) { /* * Set config to be the same as vpe0, * particularly kseg0 coherency alg @@ -1446,10 +1531,10 @@ static int __init vpe_module_init(void) /* TC's */ t->pvpe = v; /* set the parent vpe */ - if (i != 0) { + if (tc >= tclimit) { unsigned long tmp; - settc(i); + settc(tc); /* Any TC that is bound to VPE0 gets left as is - in case we are running SMTC on VPE0. A TC that is bound to any @@ -1479,17 +1564,25 @@ static int __init vpe_module_init(void) } } +out_reenable: /* release config state */ clear_c0_mvpcontrol(MVPCONTROL_VPC); + evpe(vpflags); + emt(mtflags); + local_irq_restore(flags); + #ifdef CONFIG_MIPS_APSP_KSPD kspd_events.kspd_sp_exit = kspd_sp_exit; #endif return 0; +out_class: + class_unregister(&vpe_class); out_chrdev: unregister_chrdev(major, module_name); +out: return err; } @@ -1503,7 +1596,7 @@ static void __exit vpe_module_exit(void) } } - device_destroy(mt_class, MKDEV(major, minor)); + class_device_del(&vpe_device); unregister_chrdev(major, module_name); } |