| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7 | #include <linux/kernel.h> | 
|  | 8 | #include <linux/mm.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 9 |  | 
| James Hogan | 137877e | 2015-05-19 09:50:32 +0100 | [diff] [blame] | 10 | #include <asm/hazards.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 11 | #include <asm/mipsregs.h> | 
|  | 12 | #include <asm/page.h> | 
|  | 13 | #include <asm/pgtable.h> | 
| Atsushi Nemoto | 40df383 | 2007-07-12 00:51:00 +0900 | [diff] [blame] | 14 | #include <asm/tlbdebug.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 |  | 
| James Hogan | 3c865dd | 2015-07-15 16:17:43 +0100 | [diff] [blame] | 16 | void dump_tlb_regs(void) | 
|  | 17 | { | 
|  | 18 | const int field = 2 * sizeof(unsigned long); | 
|  | 19 |  | 
|  | 20 | pr_info("Index    : %0x\n", read_c0_index()); | 
|  | 21 | pr_info("PageMask : %0x\n", read_c0_pagemask()); | 
|  | 22 | pr_info("EntryHi  : %0*lx\n", field, read_c0_entryhi()); | 
|  | 23 | pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0()); | 
|  | 24 | pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1()); | 
|  | 25 | pr_info("Wired    : %0x\n", read_c0_wired()); | 
| James Hogan | 9bd860c | 2015-07-15 16:17:46 +0100 | [diff] [blame] | 26 | switch (current_cpu_type()) { | 
|  | 27 | case CPU_R10000: | 
|  | 28 | case CPU_R12000: | 
|  | 29 | case CPU_R14000: | 
|  | 30 | case CPU_R16000: | 
|  | 31 | pr_info("FrameMask: %0x\n", read_c0_framemask()); | 
|  | 32 | break; | 
|  | 33 | } | 
| James Hogan | 5d3c3c7 | 2015-07-15 16:17:45 +0100 | [diff] [blame] | 34 | if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa) | 
|  | 35 | pr_info("PageGrain: %0x\n", read_c0_pagegrain()); | 
| James Hogan | 3c865dd | 2015-07-15 16:17:43 +0100 | [diff] [blame] | 36 | if (cpu_has_htw) { | 
|  | 37 | pr_info("PWField  : %0*lx\n", field, read_c0_pwfield()); | 
|  | 38 | pr_info("PWSize   : %0*lx\n", field, read_c0_pwsize()); | 
|  | 39 | pr_info("PWCtl    : %0x\n", read_c0_pwctl()); | 
|  | 40 | } | 
|  | 41 | } | 
|  | 42 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 43 | static inline const char *msk2str(unsigned int mask) | 
|  | 44 | { | 
|  | 45 | switch (mask) { | 
|  | 46 | case PM_4K:	return "4kb"; | 
|  | 47 | case PM_16K:	return "16kb"; | 
|  | 48 | case PM_64K:	return "64kb"; | 
|  | 49 | case PM_256K:	return "256kb"; | 
| Ralf Baechle | c52399b | 2009-04-02 14:07:10 +0200 | [diff] [blame] | 50 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | 
|  | 51 | case PM_8K:	return "8kb"; | 
|  | 52 | case PM_32K:	return "32kb"; | 
|  | 53 | case PM_128K:	return "128kb"; | 
|  | 54 | case PM_512K:	return "512kb"; | 
|  | 55 | case PM_2M:	return "2Mb"; | 
|  | 56 | case PM_8M:	return "8Mb"; | 
|  | 57 | case PM_32M:	return "32Mb"; | 
|  | 58 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 59 | #ifndef CONFIG_CPU_VR41XX | 
|  | 60 | case PM_1M:	return "1Mb"; | 
|  | 61 | case PM_4M:	return "4Mb"; | 
|  | 62 | case PM_16M:	return "16Mb"; | 
|  | 63 | case PM_64M:	return "64Mb"; | 
|  | 64 | case PM_256M:	return "256Mb"; | 
| Shinya Kuribayashi | 542c102 | 2008-10-24 01:27:57 +0900 | [diff] [blame] | 65 | case PM_1G:	return "1Gb"; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 66 | #endif | 
|  | 67 | } | 
| Atsushi Nemoto | 4becef1 | 2007-06-02 00:21:30 +0900 | [diff] [blame] | 68 | return ""; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 | } | 
|  | 70 |  | 
| Atsushi Nemoto | 69ed25b | 2007-06-02 00:30:25 +0900 | [diff] [blame] | 71 | static void dump_tlb(int first, int last) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 | { | 
| Atsushi Nemoto | 4becef1 | 2007-06-02 00:21:30 +0900 | [diff] [blame] | 73 | unsigned long s_entryhi, entryhi, asid; | 
| James Hogan | c2bc435 | 2015-05-19 09:50:37 +0100 | [diff] [blame] | 74 | unsigned long long entrylo0, entrylo1, pa; | 
| Ralf Baechle | 01422ff | 2012-10-17 01:01:20 +0200 | [diff] [blame] | 75 | unsigned int s_index, s_pagemask, pagemask, c0, c1, i; | 
| James Hogan | d1ce483e | 2015-05-19 09:50:33 +0100 | [diff] [blame] | 76 | #ifdef CONFIG_32BIT | 
| James Hogan | 24ca1d9 | 2015-05-19 09:50:38 +0100 | [diff] [blame] | 77 | bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA); | 
|  | 78 | int pwidth = xpa ? 11 : 8; | 
|  | 79 | int vwidth = 8; | 
| James Hogan | d1ce483e | 2015-05-19 09:50:33 +0100 | [diff] [blame] | 80 | #else | 
| James Hogan | 24ca1d9 | 2015-05-19 09:50:38 +0100 | [diff] [blame] | 81 | bool xpa = false; | 
|  | 82 | int pwidth = 11; | 
|  | 83 | int vwidth = 11; | 
| James Hogan | d1ce483e | 2015-05-19 09:50:33 +0100 | [diff] [blame] | 84 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 85 |  | 
| Ralf Baechle | 01422ff | 2012-10-17 01:01:20 +0200 | [diff] [blame] | 86 | s_pagemask = read_c0_pagemask(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | s_entryhi = read_c0_entryhi(); | 
|  | 88 | s_index = read_c0_index(); | 
| David Daney | 48c4ac9 | 2013-05-13 13:56:44 -0700 | [diff] [blame] | 89 | asid = s_entryhi & 0xff; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 90 |  | 
|  | 91 | for (i = first; i <= last; i++) { | 
|  | 92 | write_c0_index(i); | 
| James Hogan | 137877e | 2015-05-19 09:50:32 +0100 | [diff] [blame] | 93 | mtc0_tlbr_hazard(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 94 | tlb_read(); | 
| James Hogan | 137877e | 2015-05-19 09:50:32 +0100 | [diff] [blame] | 95 | tlb_read_hazard(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 | pagemask = read_c0_pagemask(); | 
| Ralf Baechle | 7034228 | 2013-01-22 12:59:30 +0100 | [diff] [blame] | 97 | entryhi	 = read_c0_entryhi(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 98 | entrylo0 = read_c0_entrylo0(); | 
|  | 99 | entrylo1 = read_c0_entrylo1(); | 
|  | 100 |  | 
| James Hogan | decebcc | 2015-05-19 09:50:36 +0100 | [diff] [blame] | 101 | /* EHINV bit marks entire entry as invalid */ | 
|  | 102 | if (cpu_has_tlbinv && entryhi & MIPS_ENTRYHI_EHINV) | 
|  | 103 | continue; | 
| James Hogan | d1ce483e | 2015-05-19 09:50:33 +0100 | [diff] [blame] | 104 | /* | 
|  | 105 | * Prior to tlbinv, unused entries have a virtual address of | 
|  | 106 | * CKSEG0. | 
|  | 107 | */ | 
|  | 108 | if ((entryhi & ~0x1ffffUL) == CKSEG0) | 
|  | 109 | continue; | 
| James Hogan | 48269c7 | 2015-05-19 09:50:35 +0100 | [diff] [blame] | 110 | /* | 
|  | 111 | * ASID takes effect in absence of G (global) bit. | 
|  | 112 | * We check both G bits, even though architecturally they should | 
|  | 113 | * match one another, because some revisions of the SB1 core may | 
|  | 114 | * leave only a single G bit set after a machine check exception | 
|  | 115 | * due to duplicate TLB entry. | 
|  | 116 | */ | 
| James Hogan | bae637a | 2015-07-15 16:17:47 +0100 | [diff] [blame] | 117 | if (!((entrylo0 | entrylo1) & ENTRYLO_G) && | 
| James Hogan | 48269c7 | 2015-05-19 09:50:35 +0100 | [diff] [blame] | 118 | (entryhi & 0xff) != asid) | 
| James Hogan | d1ce483e | 2015-05-19 09:50:33 +0100 | [diff] [blame] | 119 | continue; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 120 |  | 
| James Hogan | d1ce483e | 2015-05-19 09:50:33 +0100 | [diff] [blame] | 121 | /* | 
|  | 122 | * Only print entries in use | 
|  | 123 | */ | 
|  | 124 | printk("Index: %2d pgmask=%s ", i, msk2str(pagemask)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 |  | 
| James Hogan | bae637a | 2015-07-15 16:17:47 +0100 | [diff] [blame] | 126 | c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; | 
|  | 127 | c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; | 
| James Hogan | d1ce483e | 2015-05-19 09:50:33 +0100 | [diff] [blame] | 128 |  | 
|  | 129 | printk("va=%0*lx asid=%02lx\n", | 
| James Hogan | 24ca1d9 | 2015-05-19 09:50:38 +0100 | [diff] [blame] | 130 | vwidth, (entryhi & ~0x1fffUL), | 
| James Hogan | d1ce483e | 2015-05-19 09:50:33 +0100 | [diff] [blame] | 131 | entryhi & 0xff); | 
| James Hogan | c2bc435 | 2015-05-19 09:50:37 +0100 | [diff] [blame] | 132 | /* RI/XI are in awkward places, so mask them off separately */ | 
|  | 133 | pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); | 
| James Hogan | 24ca1d9 | 2015-05-19 09:50:38 +0100 | [diff] [blame] | 134 | if (xpa) | 
|  | 135 | pa |= (unsigned long long)readx_c0_entrylo0() << 30; | 
| James Hogan | c2bc435 | 2015-05-19 09:50:37 +0100 | [diff] [blame] | 136 | pa = (pa << 6) & PAGE_MASK; | 
|  | 137 | printk("\t["); | 
|  | 138 | if (cpu_has_rixi) | 
|  | 139 | printk("ri=%d xi=%d ", | 
|  | 140 | (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0, | 
|  | 141 | (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0); | 
|  | 142 | printk("pa=%0*llx c=%d d=%d v=%d g=%d] [", | 
| James Hogan | 24ca1d9 | 2015-05-19 09:50:38 +0100 | [diff] [blame] | 143 | pwidth, pa, c0, | 
| James Hogan | bae637a | 2015-07-15 16:17:47 +0100 | [diff] [blame] | 144 | (entrylo0 & ENTRYLO_D) ? 1 : 0, | 
|  | 145 | (entrylo0 & ENTRYLO_V) ? 1 : 0, | 
|  | 146 | (entrylo0 & ENTRYLO_G) ? 1 : 0); | 
| James Hogan | c2bc435 | 2015-05-19 09:50:37 +0100 | [diff] [blame] | 147 | /* RI/XI are in awkward places, so mask them off separately */ | 
|  | 148 | pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); | 
| James Hogan | 24ca1d9 | 2015-05-19 09:50:38 +0100 | [diff] [blame] | 149 | if (xpa) | 
|  | 150 | pa |= (unsigned long long)readx_c0_entrylo1() << 30; | 
| James Hogan | c2bc435 | 2015-05-19 09:50:37 +0100 | [diff] [blame] | 151 | pa = (pa << 6) & PAGE_MASK; | 
|  | 152 | if (cpu_has_rixi) | 
|  | 153 | printk("ri=%d xi=%d ", | 
|  | 154 | (entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0, | 
|  | 155 | (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0); | 
|  | 156 | printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n", | 
| James Hogan | 24ca1d9 | 2015-05-19 09:50:38 +0100 | [diff] [blame] | 157 | pwidth, pa, c1, | 
| James Hogan | bae637a | 2015-07-15 16:17:47 +0100 | [diff] [blame] | 158 | (entrylo1 & ENTRYLO_D) ? 1 : 0, | 
|  | 159 | (entrylo1 & ENTRYLO_V) ? 1 : 0, | 
|  | 160 | (entrylo1 & ENTRYLO_G) ? 1 : 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 161 | } | 
|  | 162 | printk("\n"); | 
|  | 163 |  | 
|  | 164 | write_c0_entryhi(s_entryhi); | 
|  | 165 | write_c0_index(s_index); | 
| Ralf Baechle | 01422ff | 2012-10-17 01:01:20 +0200 | [diff] [blame] | 166 | write_c0_pagemask(s_pagemask); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 | } | 
|  | 168 |  | 
|  | 169 | void dump_tlb_all(void) | 
|  | 170 | { | 
|  | 171 | dump_tlb(0, current_cpu_data.tlbsize - 1); | 
|  | 172 | } |