diff options
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/kernel/process.c | 158 | ||||
-rw-r--r-- | arch/mips/kernel/scall32-o32.S | 2 | ||||
-rw-r--r-- | arch/mips/kernel/signal-common.h | 2 | ||||
-rw-r--r-- | arch/mips/kernel/signal32.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/signal_n32.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/smp_mt.c | 34 | ||||
-rw-r--r-- | arch/mips/mm/c-r4k.c | 104 | ||||
-rw-r--r-- | arch/mips/mm/c-tx39.c | 70 |
9 files changed, 109 insertions, 266 deletions
diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 6a57407df1b..38c0f3360d5 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -94,7 +94,6 @@ endif # machines may also. Since BFD is incredibly buggy with respect to # crossformat linking we rely on the elf2ecoff tool for format conversion. # -cflags-y += -I $(TOPDIR)/include/asm/gcc cflags-y += -G 0 -mno-abicalls -fno-pic -pipe LDFLAGS_vmlinux += -G 0 -static -n -nostdlib MODFLAGS += -mlong-calls diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 5232fc75293..092679c2dca 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -25,6 +25,7 @@ #include <linux/a.out.h> #include <linux/init.h> #include <linux/completion.h> +#include <linux/kallsyms.h> #include <asm/abi.h> #include <asm/bootinfo.h> @@ -272,46 +273,19 @@ long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) static struct mips_frame_info { void *func; - int omit_fp; /* compiled without fno-omit-frame-pointer */ - int frame_offset; + unsigned long func_size; + int frame_size; int pc_offset; -} schedule_frame, mfinfo[] = { - { schedule, 0 }, /* must be first */ - /* arch/mips/kernel/semaphore.c */ - { __down, 1 }, - { __down_interruptible, 1 }, - /* kernel/sched.c */ -#ifdef CONFIG_PREEMPT - { preempt_schedule, 0 }, -#endif - { wait_for_completion, 0 }, - { interruptible_sleep_on, 0 }, - { interruptible_sleep_on_timeout, 0 }, - { sleep_on, 0 }, - { sleep_on_timeout, 0 }, - { yield, 0 }, - { io_schedule, 0 }, - { io_schedule_timeout, 0 }, -#if defined(CONFIG_SMP) && defined(CONFIG_PREEMPT) - { __preempt_spin_lock, 0 }, - { __preempt_write_lock, 0 }, -#endif - /* kernel/timer.c */ - { schedule_timeout, 1 }, -/* { nanosleep_restart, 1 }, */ - /* lib/rwsem-spinlock.c */ - { __down_read, 1 }, - { __down_write, 1 }, -}; +} *schedule_frame, mfinfo[64]; +static int mfinfo_num; -static int mips_frame_info_initialized; static int __init get_frame_info(struct mips_frame_info *info) { int i; void *func = info->func; union mips_instruction *ip = (union mips_instruction *)func; info->pc_offset = -1; - info->frame_offset = info->omit_fp ? 0 : -1; + info->frame_size = 0; for (i = 0; i < 128; i++, ip++) { /* if jal, jalr, jr, stop. */ if (ip->j_format.opcode == jal_op || @@ -320,6 +294,23 @@ static int __init get_frame_info(struct mips_frame_info *info) ip->r_format.func == jr_op))) break; + if (info->func_size && i >= info->func_size / 4) + break; + if ( +#ifdef CONFIG_32BIT + ip->i_format.opcode == addiu_op && +#endif +#ifdef CONFIG_64BIT + ip->i_format.opcode == daddiu_op && +#endif + ip->i_format.rs == 29 && + ip->i_format.rt == 29) { + /* addiu/daddiu sp,sp,-imm */ + if (info->frame_size) + continue; + info->frame_size = - ip->i_format.simmediate; + } + if ( #ifdef CONFIG_32BIT ip->i_format.opcode == sw_op && @@ -327,31 +318,20 @@ static int __init get_frame_info(struct mips_frame_info *info) #ifdef CONFIG_64BIT ip->i_format.opcode == sd_op && #endif - ip->i_format.rs == 29) - { + ip->i_format.rs == 29 && + ip->i_format.rt == 31) { /* sw / sd $ra, offset($sp) */ - if (ip->i_format.rt == 31) { - if (info->pc_offset != -1) - continue; - info->pc_offset = - ip->i_format.simmediate / sizeof(long); - } - /* sw / sd $s8, offset($sp) */ - if (ip->i_format.rt == 30) { -//#if 0 /* gcc 3.4 does aggressive optimization... */ - if (info->frame_offset != -1) - continue; -//#endif - info->frame_offset = - ip->i_format.simmediate / sizeof(long); - } + if (info->pc_offset != -1) + continue; + info->pc_offset = + ip->i_format.simmediate / sizeof(long); } } - if (info->pc_offset == -1 || info->frame_offset == -1) { - printk("Can't analyze prologue code at %p\n", func); + if (info->pc_offset == -1 || info->frame_size == 0) { + if (func == schedule) + printk("Can't analyze prologue code at %p\n", func); info->pc_offset = -1; - info->frame_offset = -1; - return -1; + info->frame_size = 0; } return 0; @@ -359,25 +339,36 @@ static int __init get_frame_info(struct mips_frame_info *info) static int __init frame_info_init(void) { - int i, found; - for (i = 0; i < ARRAY_SIZE(mfinfo); i++) - if (get_frame_info(&mfinfo[i])) - return -1; - schedule_frame = mfinfo[0]; - /* bubble sort */ - do { - struct mips_frame_info tmp; - found = 0; - for (i = 1; i < ARRAY_SIZE(mfinfo); i++) { - if (mfinfo[i-1].func > mfinfo[i].func) { - tmp = mfinfo[i]; - mfinfo[i] = mfinfo[i-1]; - mfinfo[i-1] = tmp; - found = 1; - } - } - } while (found); - mips_frame_info_initialized = 1; + int i; +#ifdef CONFIG_KALLSYMS + char *modname; + char namebuf[KSYM_NAME_LEN + 1]; + unsigned long start, size, ofs; + extern char __sched_text_start[], __sched_text_end[]; + extern char __lock_text_start[], __lock_text_end[]; + + start = (unsigned long)__sched_text_start; + for (i = 0; i < ARRAY_SIZE(mfinfo); i++) { + if (start == (unsigned long)schedule) + schedule_frame = &mfinfo[i]; + if (!kallsyms_lookup(start, &size, &ofs, &modname, namebuf)) + break; + mfinfo[i].func = (void *)(start + ofs); + mfinfo[i].func_size = size; + start += size - ofs; + if (start >= (unsigned long)__lock_text_end) + break; + if (start == (unsigned long)__sched_text_end) + start = (unsigned long)__lock_text_start; + } +#else + mfinfo[0].func = schedule; + schedule_frame = &mfinfo[0]; +#endif + for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) + get_frame_info(&mfinfo[i]); + + mfinfo_num = i; return 0; } @@ -394,47 +385,52 @@ unsigned long thread_saved_pc(struct task_struct *tsk) if (t->reg31 == (unsigned long) ret_from_fork) return t->reg31; - if (schedule_frame.pc_offset < 0) + if (!schedule_frame || schedule_frame->pc_offset < 0) return 0; - return ((unsigned long *)t->reg29)[schedule_frame.pc_offset]; + return ((unsigned long *)t->reg29)[schedule_frame->pc_offset]; } /* get_wchan - a maintenance nightmare^W^Wpain in the ass ... */ unsigned long get_wchan(struct task_struct *p) { unsigned long stack_page; - unsigned long frame, pc; + unsigned long pc; +#ifdef CONFIG_KALLSYMS + unsigned long frame; +#endif if (!p || p == current || p->state == TASK_RUNNING) return 0; stack_page = (unsigned long)task_stack_page(p); - if (!stack_page || !mips_frame_info_initialized) + if (!stack_page || !mfinfo_num) return 0; pc = thread_saved_pc(p); +#ifdef CONFIG_KALLSYMS if (!in_sched_functions(pc)) return pc; - frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset]; + frame = p->thread.reg29 + schedule_frame->frame_size; do { int i; if (frame < stack_page || frame > stack_page + THREAD_SIZE - 32) return 0; - for (i = ARRAY_SIZE(mfinfo) - 1; i >= 0; i--) { + for (i = mfinfo_num - 1; i >= 0; i--) { if (pc >= (unsigned long) mfinfo[i].func) break; } if (i < 0) break; - if (mfinfo[i].omit_fp) - break; pc = ((unsigned long *)frame)[mfinfo[i].pc_offset]; - frame = ((unsigned long *)frame)[mfinfo[i].frame_offset]; + if (!mfinfo[i].frame_size) + break; + frame += mfinfo[i].frame_size; } while (in_sched_functions(pc)); +#endif return pc; } diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index d7c4a38ed5a..d83e033dbc8 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -623,7 +623,7 @@ einval: li v0, -EINVAL sys sys_mknodat 4 /* 4290 */ sys sys_fchownat 5 sys sys_futimesat 3 - sys sys_newfstatat 4 + sys sys_fstatat64 4 sys sys_unlinkat 3 sys sys_renameat 4 /* 4295 */ sys sys_linkat 4 diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 0fbc492d24b..36bfc2588aa 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -176,7 +176,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) sp = current->sas_ss_sp + current->sas_ss_size; - return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? 32 : ALMASK)); + return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); } static inline int install_sigtramp(unsigned int __user *tramp, diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index da3271e1fda..8a8b8dd9041 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -537,7 +537,7 @@ _sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) /* The ucontext contains a stack32_t, so we must convert! */ if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) goto badframe; - st.ss_size = (long) sp; + st.ss_sp = (void *)(long) sp; if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size)) goto badframe; if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags)) diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 384fc4a639a..5a3776096f0 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -108,7 +108,7 @@ _sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) /* The ucontext contains a stack32_t, so we must convert! */ if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) goto badframe; - st.ss_size = (long) sp; + st.ss_sp = (void *)(long) sp; if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size)) goto badframe; if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags)) diff --git a/arch/mips/kernel/smp_mt.c b/arch/mips/kernel/smp_mt.c index 794a1c3de2a..c930364830d 100644 --- a/arch/mips/kernel/smp_mt.c +++ b/arch/mips/kernel/smp_mt.c @@ -68,6 +68,8 @@ void __init sanitize_tlb_entries(void) set_c0_mvpcontrol(MVPCONTROL_VPC); + back_to_back_c0_hazard(); + /* Disable TLB sharing */ clear_c0_mvpcontrol(MVPCONTROL_STLB); @@ -102,35 +104,6 @@ void __init sanitize_tlb_entries(void) clear_c0_mvpcontrol(MVPCONTROL_VPC); } -#if 0 -/* - * Use c0_MVPConf0 to find out how many CPUs are available, setting up - * phys_cpu_present_map and the logical/physical mappings. - */ -void __init prom_build_cpu_map(void) -{ - int i, num, ncpus; - - cpus_clear(phys_cpu_present_map); - - /* assume we boot on cpu 0.... */ - cpu_set(0, phys_cpu_present_map); - __cpu_number_map[0] = 0; - __cpu_logical_map[0] = 0; - - if (cpu_has_mipsmt) { - ncpus = ((read_c0_mvpconf0() & (MVPCONF0_PVPE)) >> MVPCONF0_PVPE_SHIFT) + 1; - for (i=1, num=0; i< NR_CPUS && i<ncpus; i++) { - cpu_set(i, phys_cpu_present_map); - __cpu_number_map[i] = ++num; - __cpu_logical_map[num] = i; - } - - printk(KERN_INFO "%i available secondary CPU(s)\n", num); - } -} -#endif - static void ipi_resched_dispatch (struct pt_regs *regs) { do_IRQ(MIPS_CPU_IPI_RESCHED_IRQ, regs); @@ -222,6 +195,9 @@ void prom_prepare_cpus(unsigned int max_cpus) /* set config to be the same as vpe0, particularly kseg0 coherency alg */ write_vpe_c0_config( read_c0_config()); + + /* Propagate Config7 */ + write_vpe_c0_config7(read_c0_config7()); } } diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index e51c38cef88..1b71d91e826 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -471,61 +471,29 @@ struct flush_icache_range_args { static inline void local_r4k_flush_icache_range(void *args) { struct flush_icache_range_args *fir_args = args; - unsigned long dc_lsize = cpu_dcache_line_size(); - unsigned long ic_lsize = cpu_icache_line_size(); - unsigned long sc_lsize = cpu_scache_line_size(); unsigned long start = fir_args->start; unsigned long end = fir_args->end; - unsigned long addr, aend; if (!cpu_has_ic_fills_f_dc) { if (end - start > dcache_size) { r4k_blast_dcache(); } else { R4600_HIT_CACHEOP_WAR_IMPL; - addr = start & ~(dc_lsize - 1); - aend = (end - 1) & ~(dc_lsize - 1); - - while (1) { - /* Hit_Writeback_Inv_D */ - protected_writeback_dcache_line(addr); - if (addr == aend) - break; - addr += dc_lsize; - } + protected_blast_dcache_range(start, end); } if (!cpu_icache_snoops_remote_store) { - if (end - start > scache_size) { + if (end - start > scache_size) r4k_blast_scache(); - } else { - addr = start & ~(sc_lsize - 1); - aend = (end - 1) & ~(sc_lsize - 1); - - while (1) { - /* Hit_Writeback_Inv_SD */ - protected_writeback_scache_line(addr); - if (addr == aend) - break; - addr += sc_lsize; - } - } + else + protected_blast_scache_range(start, end); } } if (end - start > icache_size) r4k_blast_icache(); - else { - addr = start & ~(ic_lsize - 1); - aend = (end - 1) & ~(ic_lsize - 1); - while (1) { - /* Hit_Invalidate_I */ - protected_flush_icache_line(addr); - if (addr == aend) - break; - addr += ic_lsize; - } - } + else + protected_blast_icache_range(start, end); } static void r4k_flush_icache_range(unsigned long start, unsigned long end) @@ -619,27 +587,14 @@ static void r4k_flush_icache_page(struct vm_area_struct *vma, static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) { - unsigned long end, a; - /* Catch bad driver code */ BUG_ON(size == 0); if (cpu_has_subset_pcaches) { - unsigned long sc_lsize = cpu_scache_line_size(); - - if (size >= scache_size) { + if (size >= scache_size) r4k_blast_scache(); - return; - } - - a = addr & ~(sc_lsize - 1); - end = (addr + size - 1) & ~(sc_lsize - 1); - while (1) { - flush_scache_line(a); /* Hit_Writeback_Inv_SD */ - if (a == end) - break; - a += sc_lsize; - } + else + blast_scache_range(addr, addr + size); return; } @@ -651,17 +606,8 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) if (size >= dcache_size) { r4k_blast_dcache(); } else { - unsigned long dc_lsize = cpu_dcache_line_size(); - R4600_HIT_CACHEOP_WAR_IMPL; - a = addr & ~(dc_lsize - 1); - end = (addr + size - 1) & ~(dc_lsize - 1); - while (1) { - flush_dcache_line(a); /* Hit_Writeback_Inv_D */ - if (a == end) - break; - a += dc_lsize; - } + blast_dcache_range(addr, addr + size); } bc_wback_inv(addr, size); @@ -669,44 +615,22 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) { - unsigned long end, a; - /* Catch bad driver code */ BUG_ON(size == 0); if (cpu_has_subset_pcaches) { - unsigned long sc_lsize = cpu_scache_line_size(); - - if (size >= scache_size) { + if (size >= scache_size) r4k_blast_scache(); - return; - } - - a = addr & ~(sc_lsize - 1); - end = (addr + size - 1) & ~(sc_lsize - 1); - while (1) { - flush_scache_line(a); /* Hit_Writeback_Inv_SD */ - if (a == end) - break; - a += sc_lsize; - } + else + blast_scache_range(addr, addr + size); return; } if (size >= dcache_size) { r4k_blast_dcache(); } else { - unsigned long dc_lsize = cpu_dcache_line_size(); - R4600_HIT_CACHEOP_WAR_IMPL; - a = addr & ~(dc_lsize - 1); - end = (addr + size - 1) & ~(dc_lsize - 1); - while (1) { - flush_dcache_line(a); /* Hit_Writeback_Inv_D */ - if (a == end) - break; - a += dc_lsize; - } + blast_dcache_range(addr, addr + size); } bc_inv(addr, size); diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c index 0a97a9434eb..7c572bea4a9 100644 --- a/arch/mips/mm/c-tx39.c +++ b/arch/mips/mm/c-tx39.c @@ -44,8 +44,6 @@ __asm__ __volatile__( \ /* TX39H-style cache flush routines. */ static void tx39h_flush_icache_all(void) { - unsigned long start = KSEG0; - unsigned long end = (start + icache_size); unsigned long flags, config; /* disable icache (set ICE#) */ @@ -53,33 +51,18 @@ static void tx39h_flush_icache_all(void) config = read_c0_conf(); write_c0_conf(config & ~TX39_CONF_ICE); TX39_STOP_STREAMING(); - - /* invalidate icache */ - while (start < end) { - cache16_unroll32(start, Index_Invalidate_I); - start += 0x200; - } - + blast_icache16(); write_c0_conf(config); local_irq_restore(flags); } static void tx39h_dma_cache_wback_inv(unsigned long addr, unsigned long size) { - unsigned long end, a; - unsigned long dc_lsize = current_cpu_data.dcache.linesz; - /* Catch bad driver code */ BUG_ON(size == 0); iob(); - a = addr & ~(dc_lsize - 1); - end = (addr + size - 1) & ~(dc_lsize - 1); - while (1) { - invalidate_dcache_line(a); /* Hit_Invalidate_D */ - if (a == end) break; - a += dc_lsize; - } + blast_inv_dcache_range(addr, addr + size); } @@ -241,42 +224,21 @@ static void tx39_flush_data_cache_page(unsigned long addr) static void tx39_flush_icache_range(unsigned long start, unsigned long end) { - unsigned long dc_lsize = current_cpu_data.dcache.linesz; - unsigned long addr, aend; - if (end - start > dcache_size) tx39_blast_dcache(); - else { - addr = start & ~(dc_lsize - 1); - aend = (end - 1) & ~(dc_lsize - 1); - - while (1) { - /* Hit_Writeback_Inv_D */ - protected_writeback_dcache_line(addr); - if (addr == aend) - break; - addr += dc_lsize; - } - } + else + protected_blast_dcache_range(start, end); if (end - start > icache_size) tx39_blast_icache(); else { unsigned long flags, config; - addr = start & ~(dc_lsize - 1); - aend = (end - 1) & ~(dc_lsize - 1); /* disable icache (set ICE#) */ local_irq_save(flags); config = read_c0_conf(); write_c0_conf(config & ~TX39_CONF_ICE); TX39_STOP_STREAMING(); - while (1) { - /* Hit_Invalidate_I */ - protected_flush_icache_line(addr); - if (addr == aend) - break; - addr += dc_lsize; - } + protected_blast_icache_range(start, end); write_c0_conf(config); local_irq_restore(flags); } @@ -311,7 +273,7 @@ static void tx39_flush_icache_page(struct vm_area_struct *vma, struct page *page static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size) { - unsigned long end, a; + unsigned long end; if (((size | addr) & (PAGE_SIZE - 1)) == 0) { end = addr + size; @@ -322,20 +284,13 @@ static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size) } else if (size > dcache_size) { tx39_blast_dcache(); } else { - unsigned long dc_lsize = current_cpu_data.dcache.linesz; - a = addr & ~(dc_lsize - 1); - end = (addr + size - 1) & ~(dc_lsize - 1); - while (1) { - flush_dcache_line(a); /* Hit_Writeback_Inv_D */ - if (a == end) break; - a += dc_lsize; - } + blast_dcache_range(addr, addr + size); } } static void tx39_dma_cache_inv(unsigned long addr, unsigned long size) { - unsigned long end, a; + unsigned long end; if (((size | addr) & (PAGE_SIZE - 1)) == 0) { end = addr + size; @@ -346,14 +301,7 @@ static void tx39_dma_cache_inv(unsigned long addr, unsigned long size) } else if (size > dcache_size) { tx39_blast_dcache(); } else { - unsigned long dc_lsize = current_cpu_data.dcache.linesz; - a = addr & ~(dc_lsize - 1); - end = (addr + size - 1) & ~(dc_lsize - 1); - while (1) { - invalidate_dcache_line(a); /* Hit_Invalidate_D */ - if (a == end) break; - a += dc_lsize; - } + blast_inv_dcache_range(addr, addr + size); } } |