|
@@ -284,7 +284,12 @@ static inline void dump_handler(const char *symbol, const u32 *handler, int coun
|
|
|
#define C0_ENTRYLO1 3, 0
|
|
|
#define C0_CONTEXT 4, 0
|
|
|
#define C0_PAGEMASK 5, 0
|
|
|
+#define C0_PWBASE 5, 5
|
|
|
+#define C0_PWFIELD 5, 6
|
|
|
+#define C0_PWSIZE 5, 7
|
|
|
+#define C0_PWCTL 6, 6
|
|
|
#define C0_BADVADDR 8, 0
|
|
|
+#define C0_PGD 9, 7
|
|
|
#define C0_ENTRYHI 10, 0
|
|
|
#define C0_EPC 14, 0
|
|
|
#define C0_XCONTEXT 20, 0
|
|
@@ -808,7 +813,10 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
|
|
|
|
|
|
if (pgd_reg != -1) {
|
|
|
/* pgd is in pgd_reg */
|
|
|
- UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg);
|
|
|
+ if (cpu_has_ldpte)
|
|
|
+ UASM_i_MFC0(p, ptr, C0_PWBASE);
|
|
|
+ else
|
|
|
+ UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg);
|
|
|
} else {
|
|
|
#if defined(CONFIG_MIPS_PGD_C0_CONTEXT)
|
|
|
/*
|
|
@@ -1421,6 +1429,108 @@ static void build_r4000_tlb_refill_handler(void)
|
|
|
dump_handler("r4000_tlb_refill", (u32 *)ebase, 64);
|
|
|
}
|
|
|
|
|
|
+static void setup_pw(void)
|
|
|
+{
|
|
|
+ unsigned long pgd_i, pgd_w;
|
|
|
+#ifndef __PAGETABLE_PMD_FOLDED
|
|
|
+ unsigned long pmd_i, pmd_w;
|
|
|
+#endif
|
|
|
+ unsigned long pt_i, pt_w;
|
|
|
+ unsigned long pte_i, pte_w;
|
|
|
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
|
|
|
+ unsigned long psn;
|
|
|
+
|
|
|
+ psn = ilog2(_PAGE_HUGE); /* bit used to indicate huge page */
|
|
|
+#endif
|
|
|
+ pgd_i = PGDIR_SHIFT; /* 1st level PGD */
|
|
|
+#ifndef __PAGETABLE_PMD_FOLDED
|
|
|
+ pgd_w = PGDIR_SHIFT - PMD_SHIFT + PGD_ORDER;
|
|
|
+
|
|
|
+ pmd_i = PMD_SHIFT; /* 2nd level PMD */
|
|
|
+ pmd_w = PMD_SHIFT - PAGE_SHIFT;
|
|
|
+#else
|
|
|
+ pgd_w = PGDIR_SHIFT - PAGE_SHIFT + PGD_ORDER;
|
|
|
+#endif
|
|
|
+
|
|
|
+ pt_i = PAGE_SHIFT; /* 3rd level PTE */
|
|
|
+ pt_w = PAGE_SHIFT - 3;
|
|
|
+
|
|
|
+ pte_i = ilog2(_PAGE_GLOBAL);
|
|
|
+ pte_w = 0;
|
|
|
+
|
|
|
+#ifndef __PAGETABLE_PMD_FOLDED
|
|
|
+ write_c0_pwfield(pgd_i << 24 | pmd_i << 12 | pt_i << 6 | pte_i);
|
|
|
+ write_c0_pwsize(1 << 30 | pgd_w << 24 | pmd_w << 12 | pt_w << 6 | pte_w);
|
|
|
+#else
|
|
|
+ write_c0_pwfield(pgd_i << 24 | pt_i << 6 | pte_i);
|
|
|
+ write_c0_pwsize(1 << 30 | pgd_w << 24 | pt_w << 6 | pte_w);
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
|
|
|
+ write_c0_pwctl(1 << 6 | psn);
|
|
|
+#endif
|
|
|
+ write_c0_kpgd(swapper_pg_dir);
|
|
|
+ kscratch_used_mask |= (1 << 7); /* KScratch6 is used for KPGD */
|
|
|
+}
|
|
|
+
|
|
|
+static void build_loongson3_tlb_refill_handler(void)
|
|
|
+{
|
|
|
+ u32 *p = tlb_handler;
|
|
|
+ struct uasm_label *l = labels;
|
|
|
+ struct uasm_reloc *r = relocs;
|
|
|
+
|
|
|
+ memset(labels, 0, sizeof(labels));
|
|
|
+ memset(relocs, 0, sizeof(relocs));
|
|
|
+ memset(tlb_handler, 0, sizeof(tlb_handler));
|
|
|
+
|
|
|
+ if (check_for_high_segbits) {
|
|
|
+ uasm_i_dmfc0(&p, K0, C0_BADVADDR);
|
|
|
+ uasm_i_dsrl_safe(&p, K1, K0, PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3);
|
|
|
+ uasm_il_beqz(&p, &r, K1, label_vmalloc);
|
|
|
+ uasm_i_nop(&p);
|
|
|
+
|
|
|
+ uasm_il_bgez(&p, &r, K0, label_large_segbits_fault);
|
|
|
+ uasm_i_nop(&p);
|
|
|
+ uasm_l_vmalloc(&l, p);
|
|
|
+ }
|
|
|
+
|
|
|
+ uasm_i_dmfc0(&p, K1, C0_PGD);
|
|
|
+
|
|
|
+ uasm_i_lddir(&p, K0, K1, 3); /* global page dir */
|
|
|
+#ifndef __PAGETABLE_PMD_FOLDED
|
|
|
+ uasm_i_lddir(&p, K1, K0, 1); /* middle page dir */
|
|
|
+#endif
|
|
|
+ uasm_i_ldpte(&p, K1, 0); /* even */
|
|
|
+ uasm_i_ldpte(&p, K1, 1); /* odd */
|
|
|
+ uasm_i_tlbwr(&p);
|
|
|
+
|
|
|
+ /* restore page mask */
|
|
|
+ if (PM_DEFAULT_MASK >> 16) {
|
|
|
+ uasm_i_lui(&p, K0, PM_DEFAULT_MASK >> 16);
|
|
|
+ uasm_i_ori(&p, K0, K0, PM_DEFAULT_MASK & 0xffff);
|
|
|
+ uasm_i_mtc0(&p, K0, C0_PAGEMASK);
|
|
|
+ } else if (PM_DEFAULT_MASK) {
|
|
|
+ uasm_i_ori(&p, K0, 0, PM_DEFAULT_MASK);
|
|
|
+ uasm_i_mtc0(&p, K0, C0_PAGEMASK);
|
|
|
+ } else {
|
|
|
+ uasm_i_mtc0(&p, 0, C0_PAGEMASK);
|
|
|
+ }
|
|
|
+
|
|
|
+ uasm_i_eret(&p);
|
|
|
+
|
|
|
+ if (check_for_high_segbits) {
|
|
|
+ uasm_l_large_segbits_fault(&l, p);
|
|
|
+ UASM_i_LA(&p, K1, (unsigned long)tlb_do_page_fault_0);
|
|
|
+ uasm_i_jr(&p, K1);
|
|
|
+ uasm_i_nop(&p);
|
|
|
+ }
|
|
|
+
|
|
|
+ uasm_resolve_relocs(relocs, labels);
|
|
|
+ memcpy((void *)(ebase + 0x80), tlb_handler, 0x80);
|
|
|
+ local_flush_icache_range(ebase + 0x80, ebase + 0x100);
|
|
|
+ dump_handler("loongson3_tlb_refill", (u32 *)(ebase + 0x80), 32);
|
|
|
+}
|
|
|
+
|
|
|
extern u32 handle_tlbl[], handle_tlbl_end[];
|
|
|
extern u32 handle_tlbs[], handle_tlbs_end[];
|
|
|
extern u32 handle_tlbm[], handle_tlbm_end[];
|
|
@@ -1468,7 +1578,10 @@ static void build_setup_pgd(void)
|
|
|
} else {
|
|
|
/* PGD in c0_KScratch */
|
|
|
uasm_i_jr(&p, 31);
|
|
|
- UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg);
|
|
|
+ if (cpu_has_ldpte)
|
|
|
+ UASM_i_MTC0(&p, a0, C0_PWBASE);
|
|
|
+ else
|
|
|
+ UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg);
|
|
|
}
|
|
|
#else
|
|
|
#ifdef CONFIG_SMP
|
|
@@ -2437,13 +2550,18 @@ void build_tlb_refill_handler(void)
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
+ if (cpu_has_ldpte)
|
|
|
+ setup_pw();
|
|
|
+
|
|
|
if (!run_once) {
|
|
|
scratch_reg = allocate_kscratch();
|
|
|
build_setup_pgd();
|
|
|
build_r4000_tlb_load_handler();
|
|
|
build_r4000_tlb_store_handler();
|
|
|
build_r4000_tlb_modify_handler();
|
|
|
- if (!cpu_has_local_ebase)
|
|
|
+ if (cpu_has_ldpte)
|
|
|
+ build_loongson3_tlb_refill_handler();
|
|
|
+ else if (!cpu_has_local_ebase)
|
|
|
build_r4000_tlb_refill_handler();
|
|
|
flush_tlb_handlers();
|
|
|
run_once++;
|