]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - arch/mips/mm/tlbex.c
MIPS: mm: Use scratch for PGD when !CONFIG_MIPS_PGD_C0_CONTEXT
[mirror_ubuntu-artful-kernel.git] / arch / mips / mm / tlbex.c
index 444d92108396d6ab530d135f9b4a4fabe5e869ce..fffa7fe319a0850575614ec07d262d1333cf5d07 100644 (file)
@@ -799,11 +799,11 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
        }
        /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */
 
-#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
        if (pgd_reg != -1) {
                /* pgd is in pgd_reg */
                UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg);
        } else {
+#if defined(CONFIG_MIPS_PGD_C0_CONTEXT)
                /*
                 * &pgd << 11 stored in CONTEXT [23..63].
                 */
@@ -815,18 +815,18 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
                /* 1 0  1 0 1  << 6  xkphys cached */
                uasm_i_ori(p, ptr, ptr, 0x540);
                uasm_i_drotr(p, ptr, ptr, 11);
-       }
 #elif defined(CONFIG_SMP)
-       UASM_i_CPUID_MFC0(p, ptr, SMP_CPUID_REG);
-       uasm_i_dsrl_safe(p, ptr, ptr, SMP_CPUID_PTRSHIFT);
-       UASM_i_LA_mostly(p, tmp, pgdc);
-       uasm_i_daddu(p, ptr, ptr, tmp);
-       uasm_i_dmfc0(p, tmp, C0_BADVADDR);
-       uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
+               UASM_i_CPUID_MFC0(p, ptr, SMP_CPUID_REG);
+               uasm_i_dsrl_safe(p, ptr, ptr, SMP_CPUID_PTRSHIFT);
+               UASM_i_LA_mostly(p, tmp, pgdc);
+               uasm_i_daddu(p, ptr, ptr, tmp);
+               uasm_i_dmfc0(p, tmp, C0_BADVADDR);
+               uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
 #else
-       UASM_i_LA_mostly(p, ptr, pgdc);
-       uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
+               UASM_i_LA_mostly(p, ptr, pgdc);
+               uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
 #endif
+       }
 
        uasm_l_vmalloc_done(l, *p);
 
@@ -921,19 +921,25 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
 static void __maybe_unused
 build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
 {
-       long pgdc = (long)pgd_current;
+       if (pgd_reg != -1) {
+               /* pgd is in pgd_reg */
+               uasm_i_mfc0(p, ptr, c0_kscratch(), pgd_reg);
+               uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+       } else {
+               long pgdc = (long)pgd_current;
 
-       /* 32 bit SMP has smp_processor_id() stored in CONTEXT. */
+               /* 32 bit SMP has smp_processor_id() stored in CONTEXT. */
 #ifdef CONFIG_SMP
-       uasm_i_mfc0(p, ptr, SMP_CPUID_REG);
-       UASM_i_LA_mostly(p, tmp, pgdc);
-       uasm_i_srl(p, ptr, ptr, SMP_CPUID_PTRSHIFT);
-       uasm_i_addu(p, ptr, tmp, ptr);
+               uasm_i_mfc0(p, ptr, SMP_CPUID_REG);
+               UASM_i_LA_mostly(p, tmp, pgdc);
+               uasm_i_srl(p, ptr, ptr, SMP_CPUID_PTRSHIFT);
+               uasm_i_addu(p, ptr, tmp, ptr);
 #else
-       UASM_i_LA_mostly(p, ptr, pgdc);
+               UASM_i_LA_mostly(p, ptr, pgdc);
 #endif
-       uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
-       uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
+               uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+               uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
+       }
        uasm_i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */
        uasm_i_sll(p, tmp, tmp, PGD_T_LOG2);
        uasm_i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
@@ -1407,28 +1413,30 @@ static void build_r4000_tlb_refill_handler(void)
 extern u32 handle_tlbl[], handle_tlbl_end[];
 extern u32 handle_tlbs[], handle_tlbs_end[];
 extern u32 handle_tlbm[], handle_tlbm_end[];
-
-#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
 extern u32 tlbmiss_handler_setup_pgd[], tlbmiss_handler_setup_pgd_end[];
 
-static void build_r4000_setup_pgd(void)
+static void build_setup_pgd(void)
 {
        const int a0 = 4;
-       const int a1 = 5;
+       const int __maybe_unused a1 = 5;
+       const int __maybe_unused a2 = 6;
        u32 *p = tlbmiss_handler_setup_pgd;
        const int tlbmiss_handler_setup_pgd_size =
                tlbmiss_handler_setup_pgd_end - tlbmiss_handler_setup_pgd;
-       struct uasm_label *l = labels;
-       struct uasm_reloc *r = relocs;
+#ifndef CONFIG_MIPS_PGD_C0_CONTEXT
+       long pgdc = (long)pgd_current;
+#endif
 
        memset(tlbmiss_handler_setup_pgd, 0, tlbmiss_handler_setup_pgd_size *
                                        sizeof(tlbmiss_handler_setup_pgd[0]));
        memset(labels, 0, sizeof(labels));
        memset(relocs, 0, sizeof(relocs));
-
        pgd_reg = allocate_kscratch();
-
+#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
        if (pgd_reg == -1) {
+               struct uasm_label *l = labels;
+               struct uasm_reloc *r = relocs;
+
                /* PGD << 11 in c0_Context */
                /*
                 * If it is a ckseg0 address, convert to a physical
@@ -1450,6 +1458,26 @@ static void build_r4000_setup_pgd(void)
                uasm_i_jr(&p, 31);
                UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg);
        }
+#else
+#ifdef CONFIG_SMP
+       /* Save PGD to pgd_current[smp_processor_id()] */
+       UASM_i_CPUID_MFC0(&p, a1, SMP_CPUID_REG);
+       UASM_i_SRL_SAFE(&p, a1, a1, SMP_CPUID_PTRSHIFT);
+       UASM_i_LA_mostly(&p, a2, pgdc);
+       UASM_i_ADDU(&p, a2, a2, a1);
+       UASM_i_SW(&p, a0, uasm_rel_lo(pgdc), a2);
+#else
+       UASM_i_LA_mostly(&p, a2, pgdc);
+       UASM_i_SW(&p, a0, uasm_rel_lo(pgdc), a2);
+#endif /* SMP */
+       uasm_i_jr(&p, 31);
+
+       /* if pgd_reg is allocated, save PGD also to scratch register */
+       if (pgd_reg != -1)
+               UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg);
+       else
+               uasm_i_nop(&p);
+#endif
        if (p >= tlbmiss_handler_setup_pgd_end)
                panic("tlbmiss_handler_setup_pgd space exceeded");
 
@@ -1460,7 +1488,6 @@ static void build_r4000_setup_pgd(void)
        dump_handler("tlbmiss_handler", tlbmiss_handler_setup_pgd,
                                        tlbmiss_handler_setup_pgd_size);
 }
-#endif
 
 static void
 iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr)
@@ -2153,10 +2180,8 @@ static void flush_tlb_handlers(void)
                           (unsigned long)handle_tlbs_end);
        local_flush_icache_range((unsigned long)handle_tlbm,
                           (unsigned long)handle_tlbm_end);
-#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
        local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd,
                           (unsigned long)tlbmiss_handler_setup_pgd_end);
-#endif
 }
 
 void build_tlb_refill_handler(void)
@@ -2188,6 +2213,7 @@ void build_tlb_refill_handler(void)
                if (!run_once) {
                        if (!cpu_has_local_ebase)
                                build_r3000_tlb_refill_handler();
+                       build_setup_pgd();
                        build_r3000_tlb_load_handler();
                        build_r3000_tlb_store_handler();
                        build_r3000_tlb_modify_handler();
@@ -2211,9 +2237,7 @@ void build_tlb_refill_handler(void)
        default:
                if (!run_once) {
                        scratch_reg = allocate_kscratch();
-#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
-                       build_r4000_setup_pgd();
-#endif
+                       build_setup_pgd();
                        build_r4000_tlb_load_handler();
                        build_r4000_tlb_store_handler();
                        build_r4000_tlb_modify_handler();