1 /* 2 * Dump R4x00 TLB for debugging purposes. 3 * 4 * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle. 5 * Copyright (C) 1999 by Silicon Graphics, Inc. 6 */ 7 #include <linux/kernel.h> 8 #include <linux/mm.h> 9 10 #include <asm/hazards.h> 11 #include <asm/mipsregs.h> 12 #include <asm/page.h> 13 #include <asm/pgtable.h> 14 #include <asm/tlbdebug.h> 15 16 static inline const char *msk2str(unsigned int mask) 17 { 18 switch (mask) { 19 case PM_4K: return "4kb"; 20 case PM_16K: return "16kb"; 21 case PM_64K: return "64kb"; 22 case PM_256K: return "256kb"; 23 #ifdef CONFIG_CPU_CAVIUM_OCTEON 24 case PM_8K: return "8kb"; 25 case PM_32K: return "32kb"; 26 case PM_128K: return "128kb"; 27 case PM_512K: return "512kb"; 28 case PM_2M: return "2Mb"; 29 case PM_8M: return "8Mb"; 30 case PM_32M: return "32Mb"; 31 #endif 32 #ifndef CONFIG_CPU_VR41XX 33 case PM_1M: return "1Mb"; 34 case PM_4M: return "4Mb"; 35 case PM_16M: return "16Mb"; 36 case PM_64M: return "64Mb"; 37 case PM_256M: return "256Mb"; 38 case PM_1G: return "1Gb"; 39 #endif 40 } 41 return ""; 42 } 43 44 static void dump_tlb(int first, int last) 45 { 46 unsigned long s_entryhi, entryhi, asid; 47 unsigned long long entrylo0, entrylo1, pa; 48 unsigned int s_index, s_pagemask, pagemask, c0, c1, i; 49 #ifdef CONFIG_32BIT 50 bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA); 51 int pwidth = xpa ? 11 : 8; 52 int vwidth = 8; 53 #else 54 bool xpa = false; 55 int pwidth = 11; 56 int vwidth = 11; 57 #endif 58 59 s_pagemask = read_c0_pagemask(); 60 s_entryhi = read_c0_entryhi(); 61 s_index = read_c0_index(); 62 asid = s_entryhi & 0xff; 63 64 for (i = first; i <= last; i++) { 65 write_c0_index(i); 66 mtc0_tlbr_hazard(); 67 tlb_read(); 68 tlb_read_hazard(); 69 pagemask = read_c0_pagemask(); 70 entryhi = read_c0_entryhi(); 71 entrylo0 = read_c0_entrylo0(); 72 entrylo1 = read_c0_entrylo1(); 73 74 /* EHINV bit marks entire entry as invalid */ 75 if (cpu_has_tlbinv && entryhi & MIPS_ENTRYHI_EHINV) 76 continue; 77 /* 78 * Prior to tlbinv, unused entries have a virtual address of 79 * CKSEG0. 80 */ 81 if ((entryhi & ~0x1ffffUL) == CKSEG0) 82 continue; 83 /* 84 * ASID takes effect in absence of G (global) bit. 85 * We check both G bits, even though architecturally they should 86 * match one another, because some revisions of the SB1 core may 87 * leave only a single G bit set after a machine check exception 88 * due to duplicate TLB entry. 89 */ 90 if (!((entrylo0 | entrylo1) & MIPS_ENTRYLO_G) && 91 (entryhi & 0xff) != asid) 92 continue; 93 94 /* 95 * Only print entries in use 96 */ 97 printk("Index: %2d pgmask=%s ", i, msk2str(pagemask)); 98 99 c0 = (entrylo0 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; 100 c1 = (entrylo1 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; 101 102 printk("va=%0*lx asid=%02lx\n", 103 vwidth, (entryhi & ~0x1fffUL), 104 entryhi & 0xff); 105 /* RI/XI are in awkward places, so mask them off separately */ 106 pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); 107 if (xpa) 108 pa |= (unsigned long long)readx_c0_entrylo0() << 30; 109 pa = (pa << 6) & PAGE_MASK; 110 printk("\t["); 111 if (cpu_has_rixi) 112 printk("ri=%d xi=%d ", 113 (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0, 114 (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0); 115 printk("pa=%0*llx c=%d d=%d v=%d g=%d] [", 116 pwidth, pa, c0, 117 (entrylo0 & MIPS_ENTRYLO_D) ? 1 : 0, 118 (entrylo0 & MIPS_ENTRYLO_V) ? 1 : 0, 119 (entrylo0 & MIPS_ENTRYLO_G) ? 1 : 0); 120 /* RI/XI are in awkward places, so mask them off separately */ 121 pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); 122 if (xpa) 123 pa |= (unsigned long long)readx_c0_entrylo1() << 30; 124 pa = (pa << 6) & PAGE_MASK; 125 if (cpu_has_rixi) 126 printk("ri=%d xi=%d ", 127 (entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0, 128 (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0); 129 printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n", 130 pwidth, pa, c1, 131 (entrylo1 & MIPS_ENTRYLO_D) ? 1 : 0, 132 (entrylo1 & MIPS_ENTRYLO_V) ? 1 : 0, 133 (entrylo1 & MIPS_ENTRYLO_G) ? 1 : 0); 134 } 135 printk("\n"); 136 137 write_c0_entryhi(s_entryhi); 138 write_c0_index(s_index); 139 write_c0_pagemask(s_pagemask); 140 } 141 142 void dump_tlb_all(void) 143 { 144 dump_tlb(0, current_cpu_data.tlbsize - 1); 145 } 146