Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: Use C0_KScratch (if present) to hold PGD pointer.

Decide at runtime to use either Context or KScratch to hold the PGD
pointer.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
To: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/1876/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

David Daney and committed by
Ralf Baechle
3d8bfdd0 c42aef09

+108 -18
+1 -7
arch/mips/include/asm/mmu_context.h
··· 29 29 #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ 30 30 tlbmiss_handler_setup_pgd((unsigned long)(pgd)) 31 31 32 - static inline void tlbmiss_handler_setup_pgd(unsigned long pgd) 33 - { 34 - /* Check for swapper_pg_dir and convert to physical address. */ 35 - if ((pgd & CKSEG3) == CKSEG0) 36 - pgd = CPHYSADDR(pgd); 37 - write_c0_context(pgd << 11); 38 - } 32 + extern void tlbmiss_handler_setup_pgd(unsigned long pgd); 39 33 40 34 #define TLBMISS_HANDLER_SETUP() \ 41 35 do { \
+1 -1
arch/mips/kernel/traps.c
··· 1592 1592 #endif /* CONFIG_MIPS_MT_SMTC */ 1593 1593 1594 1594 cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; 1595 - TLBMISS_HANDLER_SETUP(); 1596 1595 1597 1596 atomic_inc(&init_mm.mm_count); 1598 1597 current->active_mm = &init_mm; ··· 1613 1614 write_c0_wired(0); 1614 1615 } 1615 1616 #endif /* CONFIG_MIPS_MT_SMTC */ 1617 + TLBMISS_HANDLER_SETUP(); 1616 1618 } 1617 1619 1618 1620 /* Install CPU exception handler */
+106 -10
arch/mips/mm/tlbex.c
··· 26 26 #include <linux/smp.h> 27 27 #include <linux/string.h> 28 28 #include <linux/init.h> 29 + #include <linux/cache.h> 29 30 30 - #include <asm/mmu_context.h> 31 + #include <asm/cacheflush.h> 32 + #include <asm/pgtable.h> 31 33 #include <asm/war.h> 32 34 #include <asm/uasm.h> 33 35 ··· 175 173 static int check_for_high_segbits __cpuinitdata; 176 174 #endif 177 175 178 - #ifndef CONFIG_MIPS_PGD_C0_CONTEXT 176 + #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 177 + 178 + static unsigned int kscratch_used_mask __cpuinitdata; 179 + 180 + static int __cpuinit allocate_kscratch(void) 181 + { 182 + int r; 183 + unsigned int a = cpu_data[0].kscratch_mask & ~kscratch_used_mask; 184 + 185 + r = ffs(a); 186 + 187 + if (r == 0) 188 + return -1; 189 + 190 + r--; /* make it zero based */ 191 + 192 + kscratch_used_mask |= (1 << r); 193 + 194 + return r; 195 + } 196 + 197 + static int pgd_reg __cpuinitdata; 198 + 199 + #else /* !CONFIG_MIPS_PGD_C0_CONTEXT*/ 179 200 /* 180 201 * CONFIG_MIPS_PGD_C0_CONTEXT implies 64 bit and lack of pgd_current, 181 202 * we cannot do r3000 under these circumstances. 203 + * 204 + * Declare pgd_current here instead of including mmu_context.h to avoid type 205 + * conflicts for tlbmiss_handler_setup_pgd 182 206 */ 207 + extern unsigned long pgd_current[]; 183 208 184 209 /* 185 210 * The R3000 TLB handler is simple. ··· 602 573 /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */ 603 574 604 575 #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 605 - /* 606 - * &pgd << 11 stored in CONTEXT [23..63]. 607 - */ 608 - UASM_i_MFC0(p, ptr, C0_CONTEXT); 609 - uasm_i_dins(p, ptr, 0, 0, 23); /* Clear lower 23 bits of context. */ 610 - uasm_i_ori(p, ptr, ptr, 0x540); /* 1 0 1 0 1 << 6 xkphys cached */ 611 - uasm_i_drotr(p, ptr, ptr, 11); 576 + if (pgd_reg != -1) { 577 + /* pgd is in pgd_reg */ 578 + UASM_i_MFC0(p, ptr, 31, pgd_reg); 579 + } else { 580 + /* 581 + * &pgd << 11 stored in CONTEXT [23..63]. 582 + */ 583 + UASM_i_MFC0(p, ptr, C0_CONTEXT); 584 + 585 + /* Clear lower 23 bits of context. */ 586 + uasm_i_dins(p, ptr, 0, 0, 23); 587 + 588 + /* 1 0 1 0 1 << 6 xkphys cached */ 589 + uasm_i_ori(p, ptr, ptr, 0x540); 590 + uasm_i_drotr(p, ptr, ptr, 11); 591 + } 612 592 #elif defined(CONFIG_SMP) 613 593 # ifdef CONFIG_MIPS_MT_SMTC 614 594 /* ··· 1052 1014 u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned; 1053 1015 u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned; 1054 1016 u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned; 1017 + #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 1018 + u32 tlbmiss_handler_setup_pgd[16] __cacheline_aligned; 1019 + 1020 + static void __cpuinit build_r4000_setup_pgd(void) 1021 + { 1022 + const int a0 = 4; 1023 + const int a1 = 5; 1024 + u32 *p = tlbmiss_handler_setup_pgd; 1025 + struct uasm_label *l = labels; 1026 + struct uasm_reloc *r = relocs; 1027 + 1028 + memset(tlbmiss_handler_setup_pgd, 0, sizeof(tlbmiss_handler_setup_pgd)); 1029 + memset(labels, 0, sizeof(labels)); 1030 + memset(relocs, 0, sizeof(relocs)); 1031 + 1032 + pgd_reg = allocate_kscratch(); 1033 + 1034 + if (pgd_reg == -1) { 1035 + /* PGD << 11 in c0_Context */ 1036 + /* 1037 + * If it is a ckseg0 address, convert to a physical 1038 + * address. Shifting right by 29 and adding 4 will 1039 + * result in zero for these addresses. 1040 + * 1041 + */ 1042 + UASM_i_SRA(&p, a1, a0, 29); 1043 + UASM_i_ADDIU(&p, a1, a1, 4); 1044 + uasm_il_bnez(&p, &r, a1, label_tlbl_goaround1); 1045 + uasm_i_nop(&p); 1046 + uasm_i_dinsm(&p, a0, 0, 29, 64 - 29); 1047 + uasm_l_tlbl_goaround1(&l, p); 1048 + UASM_i_SLL(&p, a0, a0, 11); 1049 + uasm_i_jr(&p, 31); 1050 + UASM_i_MTC0(&p, a0, C0_CONTEXT); 1051 + } else { 1052 + /* PGD in c0_KScratch */ 1053 + uasm_i_jr(&p, 31); 1054 + UASM_i_MTC0(&p, a0, 31, pgd_reg); 1055 + } 1056 + if (p - tlbmiss_handler_setup_pgd > ARRAY_SIZE(tlbmiss_handler_setup_pgd)) 1057 + panic("tlbmiss_handler_setup_pgd space exceeded"); 1058 + uasm_resolve_relocs(relocs, labels); 1059 + pr_debug("Wrote tlbmiss_handler_setup_pgd (%u instructions).\n", 1060 + (unsigned int)(p - tlbmiss_handler_setup_pgd)); 1061 + 1062 + dump_handler(tlbmiss_handler_setup_pgd, 1063 + ARRAY_SIZE(tlbmiss_handler_setup_pgd)); 1064 + } 1065 + #endif 1055 1066 1056 1067 static void __cpuinit 1057 1068 iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) ··· 1248 1161 } 1249 1162 1250 1163 #ifndef CONFIG_MIPS_PGD_C0_CONTEXT 1164 + 1165 + 1251 1166 /* 1252 1167 * R3000 style TLB load/store/modify handlers. 1253 1168 */ ··· 1712 1623 break; 1713 1624 1714 1625 default: 1715 - build_r4000_tlb_refill_handler(); 1716 1626 if (!run_once) { 1627 + #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 1628 + build_r4000_setup_pgd(); 1629 + #endif 1717 1630 build_r4000_tlb_load_handler(); 1718 1631 build_r4000_tlb_store_handler(); 1719 1632 build_r4000_tlb_modify_handler(); 1720 1633 run_once++; 1721 1634 } 1635 + build_r4000_tlb_refill_handler(); 1722 1636 } 1723 1637 } 1724 1638 ··· 1733 1641 (unsigned long)handle_tlbs + sizeof(handle_tlbs)); 1734 1642 local_flush_icache_range((unsigned long)handle_tlbm, 1735 1643 (unsigned long)handle_tlbm + sizeof(handle_tlbm)); 1644 + #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 1645 + local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd, 1646 + (unsigned long)tlbmiss_handler_setup_pgd + sizeof(handle_tlbm)); 1647 + #endif 1736 1648 }