summaryrefslogtreecommitdiff
path: root/arch/mips/mm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-21 19:41:38 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-21 19:41:38 -0800
commita135c717d5cdb311cff7661af4c17fef0562e590 (patch)
tree830a276ee80b95f02ae243c641690c9f2014922d /arch/mips/mm
parent21770332330800194cb9a76f802e9c77bcb690d3 (diff)
parent44923c9cfa1a32c5a4013cb4b4853ddcdcd59142 (diff)
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle: "This is the main pull request for MIPS: - a number of fixes that didn't make the 3.19 release. - a number of cleanups. - preliminary support for Cavium's Octeon 3 SOCs which feature up to 48 MIPS64 R3 cores with FPU and hardware virtualization. - support for MIPS R6 processors. Revision 6 of the MIPS architecture is a major revision of the MIPS architecture which does away with many of original sins of the architecture such as branch delay slots. This and other changes in R6 require major changes throughout the entire MIPS core architecture code and make up for the lion share of this pull request. - finally some preparatory work for eXtendend Physical Address support, which allows support of up to 40 bit of physical address space on 32 bit processors" [ Ahh, MIPS can't leave the PAE brain damage alone. It's like every CPU architect has to make that mistake, but pee in the snow by changing the TLA. But whether it's called PAE, LPAE or XPA, it's horrid crud - Linus ] * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (114 commits) MIPS: sead3: Corrected get_c0_perfcount_int MIPS: mm: Remove dead macro definitions MIPS: OCTEON: irq: add CIB and other fixes MIPS: OCTEON: Don't do acknowledge operations for level triggered irqs. MIPS: OCTEON: More OCTEONIII support MIPS: OCTEON: Remove setting of processor specific CVMCTL icache bits. MIPS: OCTEON: Core-15169 Workaround and general CVMSEG cleanup. MIPS: OCTEON: Update octeon-model.h code for new SoCs. MIPS: OCTEON: Implement DCache errata workaround for all CN6XXX MIPS: OCTEON: Add little-endian support to asm/octeon/octeon.h MIPS: OCTEON: Implement the core-16057 workaround MIPS: OCTEON: Delete unused COP2 saving code MIPS: OCTEON: Use correct instruction to read 64-bit COP0 register MIPS: OCTEON: Save and restore CP2 SHA3 state MIPS: OCTEON: Fix FP context save. MIPS: OCTEON: Save/Restore wider multiply registers in OCTEON III CPUs MIPS: boot: Provide more uImage options MIPS: Remove unneeded #ifdef __KERNEL__ from asm/processor.h MIPS: ip22-gio: Remove legacy suspend/resume support mips: pci: Add ifdef around pci_proc_domain ...
Diffstat (limited to 'arch/mips/mm')
-rw-r--r--arch/mips/mm/c-r4k.c6
-rw-r--r--arch/mips/mm/fault.c29
-rw-r--r--arch/mips/mm/page.c30
-rw-r--r--arch/mips/mm/sc-mips.c4
-rw-r--r--arch/mips/mm/tlb-r4k.c8
-rw-r--r--arch/mips/mm/tlbex.c7
-rw-r--r--arch/mips/mm/uasm-micromips.c8
-rw-r--r--arch/mips/mm/uasm-mips.c38
-rw-r--r--arch/mips/mm/uasm.c15
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'.