blob: 2cb10dba8838446ca96a2ccd9d7955ade08b4dbb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 Torvalds1da177e2005-04-16 15:20:36 -07007#include <linux/kernel.h>
8#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009
James Hogan137877e2015-05-19 09:50:32 +010010#include <asm/hazards.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <asm/mipsregs.h>
12#include <asm/page.h>
13#include <asm/pgtable.h>
Atsushi Nemoto40df3832007-07-12 00:51:00 +090014#include <asm/tlbdebug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015
James Hogan3c865dd2015-07-15 16:17:43 +010016void 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 Hogan9bd860c2015-07-15 16:17:46 +010026 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 Hogan5d3c3c72015-07-15 16:17:45 +010034 if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa)
35 pr_info("PageGrain: %0x\n", read_c0_pagegrain());
James Hogan3c865dd2015-07-15 16:17:43 +010036 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 Torvalds1da177e2005-04-16 15:20:36 -070043static 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 Baechlec52399b2009-04-02 14:07:10 +020050#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 Torvalds1da177e2005-04-16 15:20:36 -070059#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 Kuribayashi542c1022008-10-24 01:27:57 +090065 case PM_1G: return "1Gb";
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#endif
67 }
Atsushi Nemoto4becef12007-06-02 00:21:30 +090068 return "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070069}
70
Atsushi Nemoto69ed25b2007-06-02 00:30:25 +090071static void dump_tlb(int first, int last)
Linus Torvalds1da177e2005-04-16 15:20:36 -070072{
Atsushi Nemoto4becef12007-06-02 00:21:30 +090073 unsigned long s_entryhi, entryhi, asid;
James Hoganc2bc4352015-05-19 09:50:37 +010074 unsigned long long entrylo0, entrylo1, pa;
James Hogan382208dc2016-05-11 15:50:31 +010075 unsigned int s_index, s_pagemask, s_guestctl1 = 0;
76 unsigned int pagemask, guestctl1 = 0, c0, c1, i;
Paul Burton4edf00a2016-05-06 14:36:23 +010077 unsigned long asidmask = cpu_asid_mask(&current_cpu_data);
78 int asidwidth = DIV_ROUND_UP(ilog2(asidmask) + 1, 4);
James Hogand1ce483e2015-05-19 09:50:33 +010079#ifdef CONFIG_32BIT
James Hogan24ca1d92015-05-19 09:50:38 +010080 bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA);
81 int pwidth = xpa ? 11 : 8;
82 int vwidth = 8;
James Hogand1ce483e2015-05-19 09:50:33 +010083#else
James Hogan24ca1d92015-05-19 09:50:38 +010084 bool xpa = false;
85 int pwidth = 11;
86 int vwidth = 11;
James Hogand1ce483e2015-05-19 09:50:33 +010087#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
Ralf Baechle01422ff2012-10-17 01:01:20 +020089 s_pagemask = read_c0_pagemask();
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 s_entryhi = read_c0_entryhi();
91 s_index = read_c0_index();
Paul Burton4edf00a2016-05-06 14:36:23 +010092 asid = s_entryhi & asidmask;
James Hogan382208dc2016-05-11 15:50:31 +010093 if (cpu_has_guestid)
94 s_guestctl1 = read_c0_guestctl1();
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96 for (i = first; i <= last; i++) {
97 write_c0_index(i);
James Hogan137877e2015-05-19 09:50:32 +010098 mtc0_tlbr_hazard();
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 tlb_read();
James Hogan137877e2015-05-19 09:50:32 +0100100 tlb_read_hazard();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 pagemask = read_c0_pagemask();
Ralf Baechle70342282013-01-22 12:59:30 +0100102 entryhi = read_c0_entryhi();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 entrylo0 = read_c0_entrylo0();
104 entrylo1 = read_c0_entrylo1();
James Hogan382208dc2016-05-11 15:50:31 +0100105 if (cpu_has_guestid)
106 guestctl1 = read_c0_guestctl1();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
James Hogandecebcc2015-05-19 09:50:36 +0100108 /* EHINV bit marks entire entry as invalid */
109 if (cpu_has_tlbinv && entryhi & MIPS_ENTRYHI_EHINV)
110 continue;
James Hogand1ce483e2015-05-19 09:50:33 +0100111 /*
112 * Prior to tlbinv, unused entries have a virtual address of
113 * CKSEG0.
114 */
115 if ((entryhi & ~0x1ffffUL) == CKSEG0)
116 continue;
James Hogan48269c72015-05-19 09:50:35 +0100117 /*
118 * ASID takes effect in absence of G (global) bit.
119 * We check both G bits, even though architecturally they should
120 * match one another, because some revisions of the SB1 core may
121 * leave only a single G bit set after a machine check exception
122 * due to duplicate TLB entry.
123 */
James Hoganbae637a2015-07-15 16:17:47 +0100124 if (!((entrylo0 | entrylo1) & ENTRYLO_G) &&
Paul Burton4edf00a2016-05-06 14:36:23 +0100125 (entryhi & asidmask) != asid)
James Hogand1ce483e2015-05-19 09:50:33 +0100126 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
James Hogand1ce483e2015-05-19 09:50:33 +0100128 /*
129 * Only print entries in use
130 */
131 printk("Index: %2d pgmask=%s ", i, msk2str(pagemask));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
James Hoganbae637a2015-07-15 16:17:47 +0100133 c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
134 c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
James Hogand1ce483e2015-05-19 09:50:33 +0100135
James Hogan382208dc2016-05-11 15:50:31 +0100136 printk("va=%0*lx asid=%0*lx",
James Hogan24ca1d92015-05-19 09:50:38 +0100137 vwidth, (entryhi & ~0x1fffUL),
Paul Burton4edf00a2016-05-06 14:36:23 +0100138 asidwidth, entryhi & asidmask);
James Hogan382208dc2016-05-11 15:50:31 +0100139 if (cpu_has_guestid)
140 printk(" gid=%02lx",
141 (guestctl1 & MIPS_GCTL1_RID)
142 >> MIPS_GCTL1_RID_SHIFT);
James Hoganc2bc4352015-05-19 09:50:37 +0100143 /* RI/XI are in awkward places, so mask them off separately */
144 pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
James Hogan24ca1d92015-05-19 09:50:38 +0100145 if (xpa)
146 pa |= (unsigned long long)readx_c0_entrylo0() << 30;
James Hoganc2bc4352015-05-19 09:50:37 +0100147 pa = (pa << 6) & PAGE_MASK;
James Hogan382208dc2016-05-11 15:50:31 +0100148 printk("\n\t[");
James Hoganc2bc4352015-05-19 09:50:37 +0100149 if (cpu_has_rixi)
150 printk("ri=%d xi=%d ",
151 (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0,
152 (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0);
153 printk("pa=%0*llx c=%d d=%d v=%d g=%d] [",
James Hogan24ca1d92015-05-19 09:50:38 +0100154 pwidth, pa, c0,
James Hoganbae637a2015-07-15 16:17:47 +0100155 (entrylo0 & ENTRYLO_D) ? 1 : 0,
156 (entrylo0 & ENTRYLO_V) ? 1 : 0,
157 (entrylo0 & ENTRYLO_G) ? 1 : 0);
James Hoganc2bc4352015-05-19 09:50:37 +0100158 /* RI/XI are in awkward places, so mask them off separately */
159 pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
James Hogan24ca1d92015-05-19 09:50:38 +0100160 if (xpa)
161 pa |= (unsigned long long)readx_c0_entrylo1() << 30;
James Hoganc2bc4352015-05-19 09:50:37 +0100162 pa = (pa << 6) & PAGE_MASK;
163 if (cpu_has_rixi)
164 printk("ri=%d xi=%d ",
165 (entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0,
166 (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0);
167 printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n",
James Hogan24ca1d92015-05-19 09:50:38 +0100168 pwidth, pa, c1,
James Hoganbae637a2015-07-15 16:17:47 +0100169 (entrylo1 & ENTRYLO_D) ? 1 : 0,
170 (entrylo1 & ENTRYLO_V) ? 1 : 0,
171 (entrylo1 & ENTRYLO_G) ? 1 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 }
173 printk("\n");
174
175 write_c0_entryhi(s_entryhi);
176 write_c0_index(s_index);
Ralf Baechle01422ff2012-10-17 01:01:20 +0200177 write_c0_pagemask(s_pagemask);
James Hogan382208dc2016-05-11 15:50:31 +0100178 if (cpu_has_guestid)
179 write_c0_guestctl1(s_guestctl1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180}
181
182void dump_tlb_all(void)
183{
184 dump_tlb(0, current_cpu_data.tlbsize - 1);
185}