*
* Synthesize TLB refill handlers at runtime.
*
- * Copyright (C) 2004,2005 by Thiemo Seufer
+ * Copyright (C) 2004,2005,2006 by Thiemo Seufer
* Copyright (C) 2005 Maciej W. Rozycki
+ * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
+ *
+ * ... and the days got worse and worse and now you see
+ * I've gone completly out of my mind.
+ *
+ * They're coming to take me a away haha
+ * they're coming to take me a away hoho hihi haha
+ * to the funny farm where code is beautiful all the time ...
+ *
+ * (Condolences to Napoleon XIV)
*/
#include <stdarg.h>
-#include <linux/config.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/smp.h>
#include <asm/war.h>
-/* #define DEBUG_TLB */
-
static __init int __attribute__((unused)) r45k_bvahwbug(void)
{
/* XXX: We should probe for the presence of this bug, but we don't. */
BIMM = 0x040,
JIMM = 0x080,
FUNC = 0x100,
+ SET = 0x200
};
#define OP_MASK 0x2f
#define JIMM_SH 0
#define FUNC_MASK 0x2f
#define FUNC_SH 0
+#define SET_MASK 0x7
+#define SET_SH 0
enum opcode {
insn_invalid,
{ insn_bne, M(bne_op,0,0,0,0,0), RS | RT | BIMM },
{ 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_dmfc0, M(cop0_op,dmfc_op,0,0,0,0), RT | RD },
- { insn_dmtc0, M(cop0_op,dmtc_op,0,0,0,0), RT | RD },
+ { insn_dmfc0, M(cop0_op,dmfc_op,0,0,0,0), RT | RD | SET},
+ { insn_dmtc0, M(cop0_op,dmtc_op,0,0,0,0), RT | RD | SET},
{ insn_dsll, M(spec_op,0,0,0,0,dsll_op), RT | RD | RE },
{ insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE },
{ insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE },
{ insn_lld, M(lld_op,0,0,0,0,0), RS | RT | SIMM },
{ 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_mfc0, M(cop0_op,mfc_op,0,0,0,0), RT | RD },
- { insn_mtc0, M(cop0_op,mtc_op,0,0,0,0), RT | RD },
+ { insn_mfc0, M(cop0_op,mfc_op,0,0,0,0), RT | RD | SET},
+ { insn_mtc0, M(cop0_op,mtc_op,0,0,0,0), RT | RD | SET},
{ insn_ori, M(ori_op,0,0,0,0,0), RS | RT | UIMM },
{ insn_rfe, M(cop0_op,cop_op,0,0,0,rfe_op), 0 },
{ insn_sc, M(sc_op,0,0,0,0,0), RS | RT | SIMM },
return arg & FUNC_MASK;
}
+static __init u32 build_set(u32 arg)
+{
+ if (arg & ~SET_MASK)
+ printk(KERN_WARNING "TLB synthesizer field overflow\n");
+
+ return arg & SET_MASK;
+}
+
/*
* The order of opcode arguments is implicitly left to right,
* starting with RS and ending with FUNC or IMM.
if (ip->fields & BIMM) op |= build_bimm(va_arg(ap, s32));
if (ip->fields & JIMM) op |= build_jimm(va_arg(ap, u32));
if (ip->fields & FUNC) op |= build_func(va_arg(ap, u32));
+ if (ip->fields & SET) op |= build_set(va_arg(ap, u32));
va_end(ap);
**buf = op;
I_u1s2(_bltz);
I_u1s2(_bltzl);
I_u1u2s3(_bne);
-I_u1u2(_dmfc0);
-I_u1u2(_dmtc0);
+I_u1u2u3(_dmfc0);
+I_u1u2u3(_dmtc0);
I_u2u1s3(_daddiu);
I_u3u1u2(_daddu);
I_u2u1u3(_dsll);
I_u2s3u1(_lld);
I_u1s2(_lui);
I_u2s3u1(_lw);
-I_u1u2(_mfc0);
-I_u1u2(_mtc0);
+I_u1u2u3(_mfc0);
+I_u1u2u3(_mtc0);
I_u2u1u3(_ori);
I_0(_rfe);
I_u2s3u1(_sc);
# define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh)
# define i_SRA(buf, rs, rt, sh) i_dsra(buf, rs, rt, sh)
# define i_SRL(buf, rs, rt, sh) i_dsrl(buf, rs, rt, sh)
-# define i_MFC0(buf, rt, rd) i_dmfc0(buf, rt, rd)
-# define i_MTC0(buf, rt, rd) i_dmtc0(buf, rt, rd)
+# define i_MFC0(buf, rt, rd...) i_dmfc0(buf, rt, rd)
+# define i_MTC0(buf, rt, rd...) i_dmtc0(buf, rt, rd)
# define i_ADDIU(buf, rs, rt, val) i_daddiu(buf, rs, rt, val)
# define i_ADDU(buf, rs, rt, rd) i_daddu(buf, rs, rt, rd)
# define i_SUBU(buf, rs, rt, rd) i_dsubu(buf, rs, rt, rd)
# define i_SLL(buf, rs, rt, sh) i_sll(buf, rs, rt, sh)
# define i_SRA(buf, rs, rt, sh) i_sra(buf, rs, rt, sh)
# define i_SRL(buf, rs, rt, sh) i_srl(buf, rs, rt, sh)
-# define i_MFC0(buf, rt, rd) i_mfc0(buf, rt, rd)
-# define i_MTC0(buf, rt, rd) i_mtc0(buf, rt, rd)
+# define i_MFC0(buf, rt, rd...) i_mfc0(buf, rt, rd)
+# define i_MTC0(buf, rt, rd...) i_mtc0(buf, rt, rd)
# define i_ADDIU(buf, rs, rt, val) i_addiu(buf, rs, rt, val)
# define i_ADDU(buf, rs, rt, rd) i_addu(buf, rs, rt, rd)
# define i_SUBU(buf, rs, rt, rd) i_subu(buf, rs, rt, rd)
#define K1 27
/* Some CP0 registers */
-#define C0_INDEX 0
-#define C0_ENTRYLO0 2
-#define C0_ENTRYLO1 3
-#define C0_CONTEXT 4
-#define C0_BADVADDR 8
-#define C0_ENTRYHI 10
-#define C0_EPC 14
-#define C0_XCONTEXT 20
+#define C0_INDEX 0, 0
+#define C0_ENTRYLO0 2, 0
+#define C0_TCBIND 2, 2
+#define C0_ENTRYLO1 3, 0
+#define C0_CONTEXT 4, 0
+#define C0_BADVADDR 8, 0
+#define C0_ENTRYHI 10, 0
+#define C0_EPC 14, 0
+#define C0_XCONTEXT 20, 0
#ifdef CONFIG_64BIT
# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT)
{
long pgdc = (long)pgd_current;
u32 *p;
+ int i;
memset(tlb_handler, 0, sizeof(tlb_handler));
p = tlb_handler;
if (p > tlb_handler + 32)
panic("TLB refill handler space exceeded");
- printk("Synthesized TLB refill handler (%u instructions).\n",
- (unsigned int)(p - tlb_handler));
-#ifdef DEBUG_TLB
- {
- int i;
+ pr_info("Synthesized TLB refill handler (%u instructions).\n",
+ (unsigned int)(p - tlb_handler));
- for (i = 0; i < (p - tlb_handler); i++)
- printk("%08x\n", tlb_handler[i]);
- }
-#endif
+ pr_debug("\t.set push\n");
+ pr_debug("\t.set noreorder\n");
+ for (i = 0; i < (p - tlb_handler); i++)
+ pr_debug("\t.word 0x%08x\n", tlb_handler[i]);
+ pr_debug("\t.set pop\n");
- memcpy((void *)CAC_BASE, tlb_handler, 0x80);
+ memcpy((void *)ebase, tlb_handler, 0x80);
}
/*
case CPU_R10000:
case CPU_R12000:
+ case CPU_R14000:
case CPU_4KC:
case CPU_SB1:
case CPU_SB1A:
case CPU_4KEC:
case CPU_24K:
case CPU_34K:
+ case CPU_74K:
i_ehb(p);
tlbw(p);
break;
/* No i_nop needed here, since the next insn doesn't touch TMP. */
#ifdef CONFIG_SMP
+# ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * SMTC uses TCBind value as "CPU" index
+ */
+ i_mfc0(p, ptr, C0_TCBIND);
+ i_dsrl(p, ptr, ptr, 19);
+# else
/*
* 64 bit SMP running in XKPHYS has smp_processor_id() << 3
* stored in CONTEXT.
*/
i_dmfc0(p, ptr, C0_CONTEXT);
i_dsrl(p, ptr, ptr, 23);
+#endif
i_LA_mostly(p, tmp, pgdc);
i_daddu(p, ptr, ptr, tmp);
i_dmfc0(p, tmp, C0_BADVADDR);
/* 32 bit SMP has smp_processor_id() stored in CONTEXT. */
#ifdef CONFIG_SMP
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * SMTC uses TCBind value as "CPU" index
+ */
+ i_mfc0(p, ptr, C0_TCBIND);
+ i_LA_mostly(p, tmp, pgdc);
+ i_srl(p, ptr, ptr, 19);
+#else
+ /*
+ * smp_processor_id() << 3 is stored in CONTEXT.
+ */
i_mfc0(p, ptr, C0_CONTEXT);
i_LA_mostly(p, tmp, pgdc);
i_srl(p, ptr, ptr, 23);
+#endif
i_addu(p, ptr, tmp, ptr);
#else
i_LA_mostly(p, ptr, pgdc);
struct reloc *r = relocs;
u32 *f;
unsigned int final_len;
+ int i;
memset(tlb_handler, 0, sizeof(tlb_handler));
memset(labels, 0, sizeof(labels));
#endif /* CONFIG_64BIT */
resolve_relocs(relocs, labels);
- printk("Synthesized TLB refill handler (%u instructions).\n",
- final_len);
+ pr_info("Synthesized TLB refill handler (%u instructions).\n",
+ final_len);
-#ifdef DEBUG_TLB
- {
- int i;
-
- f = final_handler;
+ f = final_handler;
#ifdef CONFIG_64BIT
- if (final_len > 32)
- final_len = 64;
- else
- f = final_handler + 32;
+ if (final_len > 32)
+ final_len = 64;
+ else
+ f = final_handler + 32;
#endif /* CONFIG_64BIT */
- for (i = 0; i < final_len; i++)
- printk("%08x\n", f[i]);
- }
-#endif
+ pr_debug("\t.set push\n");
+ pr_debug("\t.set noreorder\n");
+ for (i = 0; i < final_len; i++)
+ pr_debug("\t.word 0x%08x\n", f[i]);
+ pr_debug("\t.set pop\n");
- memcpy((void *)CAC_BASE, final_handler, 0x100);
+ memcpy((void *)ebase, final_handler, 0x100);
}
/*
u32 *p = handle_tlbl;
struct label *l = labels;
struct reloc *r = relocs;
+ int i;
memset(handle_tlbl, 0, sizeof(handle_tlbl));
memset(labels, 0, sizeof(labels));
panic("TLB load handler fastpath space exceeded");
resolve_relocs(relocs, labels);
- printk("Synthesized TLB load handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbl));
+ pr_info("Synthesized TLB load handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbl));
-#ifdef DEBUG_TLB
- {
- int i;
-
- for (i = 0; i < (p - handle_tlbl); i++)
- printk("%08x\n", handle_tlbl[i]);
- }
-#endif
+ pr_debug("\t.set push\n");
+ pr_debug("\t.set noreorder\n");
+ for (i = 0; i < (p - handle_tlbl); i++)
+ pr_debug("\t.word 0x%08x\n", handle_tlbl[i]);
+ pr_debug("\t.set pop\n");
}
static void __init build_r3000_tlb_store_handler(void)
u32 *p = handle_tlbs;
struct label *l = labels;
struct reloc *r = relocs;
+ int i;
memset(handle_tlbs, 0, sizeof(handle_tlbs));
memset(labels, 0, sizeof(labels));
panic("TLB store handler fastpath space exceeded");
resolve_relocs(relocs, labels);
- printk("Synthesized TLB store handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbs));
+ pr_info("Synthesized TLB store handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbs));
-#ifdef DEBUG_TLB
- {
- int i;
-
- for (i = 0; i < (p - handle_tlbs); i++)
- printk("%08x\n", handle_tlbs[i]);
- }
-#endif
+ pr_debug("\t.set push\n");
+ pr_debug("\t.set noreorder\n");
+ for (i = 0; i < (p - handle_tlbs); i++)
+ pr_debug("\t.word 0x%08x\n", handle_tlbs[i]);
+ pr_debug("\t.set pop\n");
}
static void __init build_r3000_tlb_modify_handler(void)
u32 *p = handle_tlbm;
struct label *l = labels;
struct reloc *r = relocs;
+ int i;
memset(handle_tlbm, 0, sizeof(handle_tlbm));
memset(labels, 0, sizeof(labels));
panic("TLB modify handler fastpath space exceeded");
resolve_relocs(relocs, labels);
- printk("Synthesized TLB modify handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbm));
+ pr_info("Synthesized TLB modify handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbm));
-#ifdef DEBUG_TLB
- {
- int i;
-
- for (i = 0; i < (p - handle_tlbm); i++)
- printk("%08x\n", handle_tlbm[i]);
- }
-#endif
+ pr_debug("\t.set push\n");
+ pr_debug("\t.set noreorder\n");
+ for (i = 0; i < (p - handle_tlbm); i++)
+ pr_debug("\t.word 0x%08x\n", handle_tlbm[i]);
+ pr_debug("\t.set pop\n");
}
/*
u32 *p = handle_tlbl;
struct label *l = labels;
struct reloc *r = relocs;
+ int i;
memset(handle_tlbl, 0, sizeof(handle_tlbl));
memset(labels, 0, sizeof(labels));
panic("TLB load handler fastpath space exceeded");
resolve_relocs(relocs, labels);
- printk("Synthesized TLB load handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbl));
-
-#ifdef DEBUG_TLB
- {
- int i;
+ pr_info("Synthesized TLB load handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbl));
- for (i = 0; i < (p - handle_tlbl); i++)
- printk("%08x\n", handle_tlbl[i]);
- }
-#endif
+ pr_debug("\t.set push\n");
+ pr_debug("\t.set noreorder\n");
+ for (i = 0; i < (p - handle_tlbl); i++)
+ pr_debug("\t.word 0x%08x\n", handle_tlbl[i]);
+ pr_debug("\t.set pop\n");
}
static void __init build_r4000_tlb_store_handler(void)
u32 *p = handle_tlbs;
struct label *l = labels;
struct reloc *r = relocs;
+ int i;
memset(handle_tlbs, 0, sizeof(handle_tlbs));
memset(labels, 0, sizeof(labels));
panic("TLB store handler fastpath space exceeded");
resolve_relocs(relocs, labels);
- printk("Synthesized TLB store handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbs));
-
-#ifdef DEBUG_TLB
- {
- int i;
+ pr_info("Synthesized TLB store handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbs));
- for (i = 0; i < (p - handle_tlbs); i++)
- printk("%08x\n", handle_tlbs[i]);
- }
-#endif
+ pr_debug("\t.set push\n");
+ pr_debug("\t.set noreorder\n");
+ for (i = 0; i < (p - handle_tlbs); i++)
+ pr_debug("\t.word 0x%08x\n", handle_tlbs[i]);
+ pr_debug("\t.set pop\n");
}
static void __init build_r4000_tlb_modify_handler(void)
u32 *p = handle_tlbm;
struct label *l = labels;
struct reloc *r = relocs;
+ int i;
memset(handle_tlbm, 0, sizeof(handle_tlbm));
memset(labels, 0, sizeof(labels));
panic("TLB modify handler fastpath space exceeded");
resolve_relocs(relocs, labels);
- printk("Synthesized TLB modify handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbm));
-
-#ifdef DEBUG_TLB
- {
- int i;
-
- for (i = 0; i < (p - handle_tlbm); i++)
- printk("%08x\n", handle_tlbm[i]);
- }
-#endif
+ pr_info("Synthesized TLB modify handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbm));
+
+ pr_debug("\t.set push\n");
+ pr_debug("\t.set noreorder\n");
+ for (i = 0; i < (p - handle_tlbm); i++)
+ pr_debug("\t.word 0x%08x\n", handle_tlbm[i]);
+ pr_debug("\t.set pop\n");
}
void __init build_tlb_refill_handler(void)