diff options
Diffstat (limited to 'arch/mips/mm')
-rw-r--r-- | arch/mips/mm/c-r4k.c | 6 | ||||
-rw-r--r-- | arch/mips/mm/fault.c | 29 | ||||
-rw-r--r-- | arch/mips/mm/page.c | 30 | ||||
-rw-r--r-- | arch/mips/mm/sc-mips.c | 4 | ||||
-rw-r--r-- | arch/mips/mm/tlb-r4k.c | 8 | ||||
-rw-r--r-- | arch/mips/mm/tlbex.c | 7 | ||||
-rw-r--r-- | arch/mips/mm/uasm-micromips.c | 8 | ||||
-rw-r--r-- | arch/mips/mm/uasm-mips.c | 38 | ||||
-rw-r--r-- | arch/mips/mm/uasm.c | 15 |
9 files changed, 104 insertions, 41 deletions
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index dd261df005c2..3f8059602765 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -794,7 +794,7 @@ static void local_r4k_flush_cache_sigtramp(void * arg) __asm__ __volatile__ ( ".set push\n\t" ".set noat\n\t" - ".set mips3\n\t" + ".set "MIPS_ISA_LEVEL"\n\t" #ifdef CONFIG_32BIT "la $at,1f\n\t" #endif @@ -1255,6 +1255,7 @@ static void probe_pcache(void) case CPU_P5600: case CPU_PROAPTIV: case CPU_M5150: + case CPU_QEMU_GENERIC: if (!(read_c0_config7() & MIPS_CONF7_IAR) && (c->icache.waysize > PAGE_SIZE)) c->icache.flags |= MIPS_CACHE_ALIASES; @@ -1472,7 +1473,8 @@ static void setup_scache(void) default: if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | - MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) { + MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 | + MIPS_CPU_ISA_M64R2 | MIPS_CPU_ISA_M64R6)) { #ifdef CONFIG_MIPS_CPU_SCACHE if (mips_sc_init ()) { scache_size = c->scache.ways * c->scache.sets * c->scache.linesz; diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 70ab5d664332..7ff8637e530d 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -14,6 +14,7 @@ #include <linux/string.h> #include <linux/types.h> #include <linux/ptrace.h> +#include <linux/ratelimit.h> #include <linux/mman.h> #include <linux/mm.h> #include <linux/smp.h> @@ -28,6 +29,8 @@ #include <asm/highmem.h> /* For VMALLOC_END */ #include <linux/kdebug.h> +int show_unhandled_signals = 1; + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -44,6 +47,8 @@ static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write, int fault; unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; + static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10); + #if 0 printk("Cpu%d[%s:%d:%0*lx:%ld:%0*lx]\n", raw_smp_processor_id(), current->comm, current->pid, field, address, write, @@ -203,15 +208,21 @@ bad_area_nosemaphore: if (user_mode(regs)) { tsk->thread.cp0_badvaddr = address; tsk->thread.error_code = write; -#if 0 - printk("do_page_fault() #2: sending SIGSEGV to %s for " - "invalid %s\n%0*lx (epc == %0*lx, ra == %0*lx)\n", - tsk->comm, - write ? "write access to" : "read access from", - field, address, - field, (unsigned long) regs->cp0_epc, - field, (unsigned long) regs->regs[31]); -#endif + if (show_unhandled_signals && + unhandled_signal(tsk, SIGSEGV) && + __ratelimit(&ratelimit_state)) { + pr_info("\ndo_page_fault(): sending SIGSEGV to %s for invalid %s %0*lx", + tsk->comm, + write ? "write access to" : "read access from", + field, address); + pr_info("epc = %0*lx in", field, + (unsigned long) regs->cp0_epc); + print_vma_addr(" ", regs->cp0_epc); + pr_info("ra = %0*lx in", field, + (unsigned long) regs->regs[31]); + print_vma_addr(" ", regs->regs[31]); + pr_info("\n"); + } info.si_signo = SIGSEGV; info.si_errno = 0; /* info.si_code has been set above */ diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c index b611102e23b5..3f85f921801b 100644 --- a/arch/mips/mm/page.c +++ b/arch/mips/mm/page.c @@ -72,6 +72,20 @@ static struct uasm_reloc relocs[5]; #define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010) #define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020) +/* + * R6 has a limited offset of the pref instruction. + * Skip it if the offset is more than 9 bits. + */ +#define _uasm_i_pref(a, b, c, d) \ +do { \ + if (cpu_has_mips_r6) { \ + if (c <= 0xff && c >= -0x100) \ + uasm_i_pref(a, b, c, d);\ + } else { \ + uasm_i_pref(a, b, c, d); \ + } \ +} while(0) + static int pref_bias_clear_store; static int pref_bias_copy_load; static int pref_bias_copy_store; @@ -178,7 +192,15 @@ static void set_prefetch_parameters(void) pref_bias_copy_load = 256; pref_bias_copy_store = 128; pref_src_mode = Pref_LoadStreamed; - pref_dst_mode = Pref_PrepareForStore; + if (cpu_has_mips_r6) + /* + * Bit 30 (Pref_PrepareForStore) has been + * removed from MIPS R6. Use bit 5 + * (Pref_StoreStreamed). + */ + pref_dst_mode = Pref_StoreStreamed; + else + pref_dst_mode = Pref_PrepareForStore; break; } } else { @@ -214,7 +236,7 @@ static inline void build_clear_pref(u32 **buf, int off) return; if (pref_bias_clear_store) { - uasm_i_pref(buf, pref_dst_mode, pref_bias_clear_store + off, + _uasm_i_pref(buf, pref_dst_mode, pref_bias_clear_store + off, A0); } else if (cache_line_size == (half_clear_loop_size << 1)) { if (cpu_has_cache_cdex_s) { @@ -357,7 +379,7 @@ static inline void build_copy_load_pref(u32 **buf, int off) return; if (pref_bias_copy_load) - uasm_i_pref(buf, pref_src_mode, pref_bias_copy_load + off, A1); + _uasm_i_pref(buf, pref_src_mode, pref_bias_copy_load + off, A1); } static inline void build_copy_store_pref(u32 **buf, int off) @@ -366,7 +388,7 @@ static inline void build_copy_store_pref(u32 **buf, int off) return; if (pref_bias_copy_store) { - uasm_i_pref(buf, pref_dst_mode, pref_bias_copy_store + off, + _uasm_i_pref(buf, pref_dst_mode, pref_bias_copy_store + off, A0); } else if (cache_line_size == (half_copy_loop_size << 1)) { if (cpu_has_cache_cdex_s) { diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 99eb8fabab60..4ceafd13870c 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -81,6 +81,7 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c) case CPU_PROAPTIV: case CPU_P5600: case CPU_BMIPS5000: + case CPU_QEMU_GENERIC: if (config2 & (1 << 12)) return 0; } @@ -104,7 +105,8 @@ static inline int __init mips_sc_probe(void) /* Ignore anything but MIPSxx processors */ if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | - MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2))) + MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 | + MIPS_CPU_ISA_M64R2 | MIPS_CPU_ISA_M64R6))) return 0; /* Does this MIPS32/MIPS64 CPU have a config2 register? */ diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 30639a6e9b8c..b2afa49beab0 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -485,13 +485,11 @@ static void r4k_tlb_configure(void) * Enable the no read, no exec bits, and enable large virtual * address. */ - u32 pg = PG_RIE | PG_XIE; #ifdef CONFIG_64BIT - pg |= PG_ELPA; + set_c0_pagegrain(PG_RIE | PG_XIE | PG_ELPA); +#else + set_c0_pagegrain(PG_RIE | PG_XIE); #endif - if (cpu_has_rixiex) - pg |= PG_IEC; - write_c0_pagegrain(pg); } temp_tlb_entry = current_cpu_data.tlbsize - 1; diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 3978a3d81366..d75ff73a2012 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -501,7 +501,7 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l, case tlb_indexed: tlbw = uasm_i_tlbwi; break; } - if (cpu_has_mips_r2) { + if (cpu_has_mips_r2_exec_hazard) { /* * The architecture spec says an ehb is required here, * but a number of cores do not have the hazard and @@ -514,6 +514,7 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l, case CPU_PROAPTIV: case CPU_P5600: case CPU_M5150: + case CPU_QEMU_GENERIC: break; default: @@ -1952,7 +1953,7 @@ static void build_r4000_tlb_load_handler(void) switch (current_cpu_type()) { default: - if (cpu_has_mips_r2) { + if (cpu_has_mips_r2_exec_hazard) { uasm_i_ehb(&p); case CPU_CAVIUM_OCTEON: @@ -2019,7 +2020,7 @@ static void build_r4000_tlb_load_handler(void) switch (current_cpu_type()) { default: - if (cpu_has_mips_r2) { + if (cpu_has_mips_r2_exec_hazard) { uasm_i_ehb(&p); case CPU_CAVIUM_OCTEON: diff --git a/arch/mips/mm/uasm-micromips.c b/arch/mips/mm/uasm-micromips.c index 8399ddf03a02..d78178daea4b 100644 --- a/arch/mips/mm/uasm-micromips.c +++ b/arch/mips/mm/uasm-micromips.c @@ -38,14 +38,6 @@ | (e) << RE_SH \ | (f) << FUNC_SH) -/* Define these when we are not the ISA the kernel is being compiled with. */ -#ifndef CONFIG_CPU_MICROMIPS -#define MM_uasm_i_b(buf, off) ISAOPC(_beq)(buf, 0, 0, off) -#define MM_uasm_i_beqz(buf, rs, off) ISAOPC(_beq)(buf, rs, 0, off) -#define MM_uasm_i_beqzl(buf, rs, off) ISAOPC(_beql)(buf, rs, 0, off) -#define MM_uasm_i_bnez(buf, rs, off) ISAOPC(_bne)(buf, rs, 0, off) -#endif - #include "uasm.c" static struct insn insn_table_MM[] = { diff --git a/arch/mips/mm/uasm-mips.c b/arch/mips/mm/uasm-mips.c index 8e02291cfc0c..b4a837893562 100644 --- a/arch/mips/mm/uasm-mips.c +++ b/arch/mips/mm/uasm-mips.c @@ -38,13 +38,13 @@ | (e) << RE_SH \ | (f) << FUNC_SH) -/* Define these when we are not the ISA the kernel is being compiled with. */ -#ifdef CONFIG_CPU_MICROMIPS -#define CL_uasm_i_b(buf, off) ISAOPC(_beq)(buf, 0, 0, off) -#define CL_uasm_i_beqz(buf, rs, off) ISAOPC(_beq)(buf, rs, 0, off) -#define CL_uasm_i_beqzl(buf, rs, off) ISAOPC(_beql)(buf, rs, 0, off) -#define CL_uasm_i_bnez(buf, rs, off) ISAOPC(_bne)(buf, rs, 0, off) -#endif +/* This macro sets the non-variable bits of an R6 instruction. */ +#define M6(a, b, c, d, e) \ + ((a) << OP_SH \ + | (b) << RS_SH \ + | (c) << RT_SH \ + | (d) << SIMM9_SH \ + | (e) << FUNC_SH) #include "uasm.c" @@ -62,7 +62,11 @@ static struct insn insn_table[] = { { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM }, { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM }, { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, +#ifndef CONFIG_CPU_MIPSR6 { insn_cache, M(cache_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, +#else + { insn_cache, M6(cache_op, 0, 0, 0, cache6_op), RS | RT | SIMM9 }, +#endif { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD }, { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE }, @@ -85,13 +89,22 @@ static struct insn insn_table[] = { { insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM }, { insn_jalr, M(spec_op, 0, 0, 0, 0, jalr_op), RS | RD }, { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM }, +#ifndef CONFIG_CPU_MIPSR6 { insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS }, +#else + { insn_jr, M(spec_op, 0, 0, 0, 0, jalr_op), RS }, +#endif { insn_lb, M(lb_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD }, { insn_lh, M(lh_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, +#ifndef CONFIG_CPU_MIPSR6 { insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, +#else + { insn_lld, M6(spec3_op, 0, 0, 0, lld6_op), RS | RT | SIMM9 }, + { insn_ll, M6(spec3_op, 0, 0, 0, ll6_op), RS | RT | SIMM9 }, +#endif { insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM }, { insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD }, @@ -104,11 +117,20 @@ static struct insn insn_table[] = { { insn_mul, M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD}, { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, { insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD }, +#ifndef CONFIG_CPU_MIPSR6 { insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, +#else + { insn_pref, M6(spec3_op, 0, 0, 0, pref6_op), RS | RT | SIMM9 }, +#endif { insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 }, { insn_rotr, M(spec_op, 1, 0, 0, 0, srl_op), RT | RD | RE }, +#ifndef CONFIG_CPU_MIPSR6 { insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, +#else + { insn_scd, M6(spec3_op, 0, 0, 0, scd6_op), RS | RT | SIMM9 }, + { insn_sc, M6(spec3_op, 0, 0, 0, sc6_op), RS | RT | SIMM9 }, +#endif { insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE }, { insn_sllv, M(spec_op, 0, 0, 0, 0, sllv_op), RS | RT | RD }, @@ -198,6 +220,8 @@ static void build_insn(u32 **buf, enum opcode opc, ...) op |= build_set(va_arg(ap, u32)); if (ip->fields & SCIMM) op |= build_scimm(va_arg(ap, u32)); + if (ip->fields & SIMM9) + op |= build_scimm9(va_arg(ap, u32)); va_end(ap); **buf = op; diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index 4adf30284813..319051c34343 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c @@ -24,7 +24,8 @@ enum fields { JIMM = 0x080, FUNC = 0x100, SET = 0x200, - SCIMM = 0x400 + SCIMM = 0x400, + SIMM9 = 0x800, }; #define OP_MASK 0x3f @@ -41,6 +42,8 @@ enum fields { #define FUNC_SH 0 #define SET_MASK 0x7 #define SET_SH 0 +#define SIMM9_SH 7 +#define SIMM9_MASK 0x1ff enum opcode { insn_invalid, @@ -116,6 +119,14 @@ static inline u32 build_scimm(u32 arg) return (arg & SCIMM_MASK) << SCIMM_SH; } +static inline u32 build_scimm9(s32 arg) +{ + WARN((arg > 0xff || arg < -0x100), + KERN_WARNING "Micro-assembler field overflow\n"); + + return (arg & SIMM9_MASK) << SIMM9_SH; +} + static inline u32 build_func(u32 arg) { WARN(arg & ~FUNC_MASK, KERN_WARNING "Micro-assembler field overflow\n"); @@ -330,7 +341,7 @@ I_u3u1u2(_ldx) void ISAFUNC(uasm_i_pref)(u32 **buf, unsigned int a, signed int b, unsigned int c) { - if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) && a <= 24 && a != 5) + if (CAVIUM_OCTEON_DCACHE_PREFETCH_WAR && a <= 24 && a != 5) /* * As per erratum Core-14449, replace prefetches 0-4, * 6-24 with 'pref 28'. |