1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
24becef1dSAtsushi Nemoto /*
34becef1dSAtsushi Nemoto * Dump R4x00 TLB for debugging purposes.
44becef1dSAtsushi Nemoto *
54becef1dSAtsushi Nemoto * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle.
64becef1dSAtsushi Nemoto * Copyright (C) 1999 by Silicon Graphics, Inc.
74becef1dSAtsushi Nemoto */
84becef1dSAtsushi Nemoto #include <linux/kernel.h>
94becef1dSAtsushi Nemoto #include <linux/mm.h>
104becef1dSAtsushi Nemoto
11137877e4SJames Hogan #include <asm/hazards.h>
124becef1dSAtsushi Nemoto #include <asm/mipsregs.h>
13c8790d65SPaul Burton #include <asm/mmu_context.h>
144becef1dSAtsushi Nemoto #include <asm/page.h>
1540df3831SAtsushi Nemoto #include <asm/tlbdebug.h>
164becef1dSAtsushi Nemoto
dump_tlb_regs(void)173c865dd9SJames Hogan void dump_tlb_regs(void)
183c865dd9SJames Hogan {
193c865dd9SJames Hogan const int field = 2 * sizeof(unsigned long);
203c865dd9SJames Hogan
213c865dd9SJames Hogan pr_info("Index : %0x\n", read_c0_index());
223c865dd9SJames Hogan pr_info("PageMask : %0x\n", read_c0_pagemask());
234b62fad5SJames Hogan if (cpu_has_guestid)
244b62fad5SJames Hogan pr_info("GuestCtl1: %0x\n", read_c0_guestctl1());
253c865dd9SJames Hogan pr_info("EntryHi : %0*lx\n", field, read_c0_entryhi());
263c865dd9SJames Hogan pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0());
273c865dd9SJames Hogan pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1());
283c865dd9SJames Hogan pr_info("Wired : %0x\n", read_c0_wired());
299bd860caSJames Hogan switch (current_cpu_type()) {
309bd860caSJames Hogan case CPU_R10000:
319bd860caSJames Hogan case CPU_R12000:
329bd860caSJames Hogan case CPU_R14000:
339bd860caSJames Hogan case CPU_R16000:
349bd860caSJames Hogan pr_info("FrameMask: %0x\n", read_c0_framemask());
359bd860caSJames Hogan break;
369bd860caSJames Hogan }
375d3c3c7dSJames Hogan if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa)
383c865dd9SJames Hogan pr_info("PageGrain: %0x\n", read_c0_pagegrain());
393c865dd9SJames Hogan if (cpu_has_htw) {
403c865dd9SJames Hogan pr_info("PWField : %0*lx\n", field, read_c0_pwfield());
413c865dd9SJames Hogan pr_info("PWSize : %0*lx\n", field, read_c0_pwsize());
423c865dd9SJames Hogan pr_info("PWCtl : %0x\n", read_c0_pwctl());
433c865dd9SJames Hogan }
443c865dd9SJames Hogan }
453c865dd9SJames Hogan
msk2str(unsigned int mask)464becef1dSAtsushi Nemoto static inline const char *msk2str(unsigned int mask)
474becef1dSAtsushi Nemoto {
484becef1dSAtsushi Nemoto switch (mask) {
494becef1dSAtsushi Nemoto case PM_4K: return "4kb";
504becef1dSAtsushi Nemoto case PM_16K: return "16kb";
514becef1dSAtsushi Nemoto case PM_64K: return "64kb";
524becef1dSAtsushi Nemoto case PM_256K: return "256kb";
53c52399beSRalf Baechle #ifdef CONFIG_CPU_CAVIUM_OCTEON
54c52399beSRalf Baechle case PM_8K: return "8kb";
55c52399beSRalf Baechle case PM_32K: return "32kb";
56c52399beSRalf Baechle case PM_128K: return "128kb";
57c52399beSRalf Baechle case PM_512K: return "512kb";
58c52399beSRalf Baechle case PM_2M: return "2Mb";
59c52399beSRalf Baechle case PM_8M: return "8Mb";
60c52399beSRalf Baechle case PM_32M: return "32Mb";
61c52399beSRalf Baechle #endif
624becef1dSAtsushi Nemoto }
634becef1dSAtsushi Nemoto return "";
644becef1dSAtsushi Nemoto }
654becef1dSAtsushi Nemoto
dump_tlb(int first,int last)6669ed25b8SAtsushi Nemoto static void dump_tlb(int first, int last)
674becef1dSAtsushi Nemoto {
68c8790d65SPaul Burton unsigned long s_entryhi, entryhi, asid, mmid;
69c2bc435eSJames Hogan unsigned long long entrylo0, entrylo1, pa;
70382208dcSJames Hogan unsigned int s_index, s_pagemask, s_guestctl1 = 0;
71382208dcSJames Hogan unsigned int pagemask, guestctl1 = 0, c0, c1, i;
724edf00a4SPaul Burton unsigned long asidmask = cpu_asid_mask(¤t_cpu_data);
734edf00a4SPaul Burton int asidwidth = DIV_ROUND_UP(ilog2(asidmask) + 1, 4);
74*3f649ab7SKees Cook unsigned long s_mmid;
75d1ce483eSJames Hogan #ifdef CONFIG_32BIT
7624ca1d98SJames Hogan bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA);
7724ca1d98SJames Hogan int pwidth = xpa ? 11 : 8;
7824ca1d98SJames Hogan int vwidth = 8;
79d1ce483eSJames Hogan #else
8024ca1d98SJames Hogan bool xpa = false;
8124ca1d98SJames Hogan int pwidth = 11;
8224ca1d98SJames Hogan int vwidth = 11;
83d1ce483eSJames Hogan #endif
844becef1dSAtsushi Nemoto
8501422ff4SRalf Baechle s_pagemask = read_c0_pagemask();
864becef1dSAtsushi Nemoto s_entryhi = read_c0_entryhi();
874becef1dSAtsushi Nemoto s_index = read_c0_index();
88c8790d65SPaul Burton
89c8790d65SPaul Burton if (cpu_has_mmid)
90c8790d65SPaul Burton asid = s_mmid = read_c0_memorymapid();
91c8790d65SPaul Burton else
924edf00a4SPaul Burton asid = s_entryhi & asidmask;
93c8790d65SPaul Burton
94382208dcSJames Hogan if (cpu_has_guestid)
95382208dcSJames Hogan s_guestctl1 = read_c0_guestctl1();
964becef1dSAtsushi Nemoto
974becef1dSAtsushi Nemoto for (i = first; i <= last; i++) {
984becef1dSAtsushi Nemoto write_c0_index(i);
99137877e4SJames Hogan mtc0_tlbr_hazard();
1004becef1dSAtsushi Nemoto tlb_read();
101137877e4SJames Hogan tlb_read_hazard();
1024becef1dSAtsushi Nemoto pagemask = read_c0_pagemask();
1034becef1dSAtsushi Nemoto entryhi = read_c0_entryhi();
1044becef1dSAtsushi Nemoto entrylo0 = read_c0_entrylo0();
1054becef1dSAtsushi Nemoto entrylo1 = read_c0_entrylo1();
106c8790d65SPaul Burton
107c8790d65SPaul Burton if (cpu_has_mmid)
108c8790d65SPaul Burton mmid = read_c0_memorymapid();
109c8790d65SPaul Burton else
110c8790d65SPaul Burton mmid = entryhi & asidmask;
111c8790d65SPaul Burton
112382208dcSJames Hogan if (cpu_has_guestid)
113382208dcSJames Hogan guestctl1 = read_c0_guestctl1();
1144becef1dSAtsushi Nemoto
115decebccdSJames Hogan /* EHINV bit marks entire entry as invalid */
116decebccdSJames Hogan if (cpu_has_tlbinv && entryhi & MIPS_ENTRYHI_EHINV)
117decebccdSJames Hogan continue;
118d1ce483eSJames Hogan /*
119d1ce483eSJames Hogan * Prior to tlbinv, unused entries have a virtual address of
120d1ce483eSJames Hogan * CKSEG0.
121d1ce483eSJames Hogan */
122d1ce483eSJames Hogan if ((entryhi & ~0x1ffffUL) == CKSEG0)
123d1ce483eSJames Hogan continue;
12448269c78SJames Hogan /*
12548269c78SJames Hogan * ASID takes effect in absence of G (global) bit.
12648269c78SJames Hogan * We check both G bits, even though architecturally they should
12748269c78SJames Hogan * match one another, because some revisions of the SB1 core may
12848269c78SJames Hogan * leave only a single G bit set after a machine check exception
12948269c78SJames Hogan * due to duplicate TLB entry.
13048269c78SJames Hogan */
131c8790d65SPaul Burton if (!((entrylo0 | entrylo1) & ENTRYLO_G) && (mmid != asid))
132d1ce483eSJames Hogan continue;
133d1ce483eSJames Hogan
1344becef1dSAtsushi Nemoto /*
1354becef1dSAtsushi Nemoto * Only print entries in use
1364becef1dSAtsushi Nemoto */
1374becef1dSAtsushi Nemoto printk("Index: %2d pgmask=%s ", i, msk2str(pagemask));
1384becef1dSAtsushi Nemoto
139bae637a2SJames Hogan c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
140bae637a2SJames Hogan c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
1414becef1dSAtsushi Nemoto
1428a98495cSJames Hogan pr_cont("va=%0*lx asid=%0*lx",
14324ca1d98SJames Hogan vwidth, (entryhi & ~0x1fffUL),
144c8790d65SPaul Burton asidwidth, mmid);
145382208dcSJames Hogan if (cpu_has_guestid)
1468a98495cSJames Hogan pr_cont(" gid=%02lx",
147382208dcSJames Hogan (guestctl1 & MIPS_GCTL1_RID)
148382208dcSJames Hogan >> MIPS_GCTL1_RID_SHIFT);
149c2bc435eSJames Hogan /* RI/XI are in awkward places, so mask them off separately */
150c2bc435eSJames Hogan pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
15124ca1d98SJames Hogan if (xpa)
15224ca1d98SJames Hogan pa |= (unsigned long long)readx_c0_entrylo0() << 30;
153c2bc435eSJames Hogan pa = (pa << 6) & PAGE_MASK;
1548a98495cSJames Hogan pr_cont("\n\t[");
155c2bc435eSJames Hogan if (cpu_has_rixi)
1568a98495cSJames Hogan pr_cont("ri=%d xi=%d ",
157c2bc435eSJames Hogan (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0,
158c2bc435eSJames Hogan (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0);
1598a98495cSJames Hogan pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d] [",
16024ca1d98SJames Hogan pwidth, pa, c0,
161bae637a2SJames Hogan (entrylo0 & ENTRYLO_D) ? 1 : 0,
162bae637a2SJames Hogan (entrylo0 & ENTRYLO_V) ? 1 : 0,
163bae637a2SJames Hogan (entrylo0 & ENTRYLO_G) ? 1 : 0);
164c2bc435eSJames Hogan /* RI/XI are in awkward places, so mask them off separately */
165c2bc435eSJames Hogan pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
16624ca1d98SJames Hogan if (xpa)
16724ca1d98SJames Hogan pa |= (unsigned long long)readx_c0_entrylo1() << 30;
168c2bc435eSJames Hogan pa = (pa << 6) & PAGE_MASK;
169c2bc435eSJames Hogan if (cpu_has_rixi)
1708a98495cSJames Hogan pr_cont("ri=%d xi=%d ",
171c2bc435eSJames Hogan (entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0,
172c2bc435eSJames Hogan (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0);
1738a98495cSJames Hogan pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d]\n",
17424ca1d98SJames Hogan pwidth, pa, c1,
175bae637a2SJames Hogan (entrylo1 & ENTRYLO_D) ? 1 : 0,
176bae637a2SJames Hogan (entrylo1 & ENTRYLO_V) ? 1 : 0,
177bae637a2SJames Hogan (entrylo1 & ENTRYLO_G) ? 1 : 0);
1784becef1dSAtsushi Nemoto }
1794becef1dSAtsushi Nemoto printk("\n");
1804becef1dSAtsushi Nemoto
1814becef1dSAtsushi Nemoto write_c0_entryhi(s_entryhi);
1824becef1dSAtsushi Nemoto write_c0_index(s_index);
18301422ff4SRalf Baechle write_c0_pagemask(s_pagemask);
184382208dcSJames Hogan if (cpu_has_guestid)
185382208dcSJames Hogan write_c0_guestctl1(s_guestctl1);
1864becef1dSAtsushi Nemoto }
1874becef1dSAtsushi Nemoto
dump_tlb_all(void)1884becef1dSAtsushi Nemoto void dump_tlb_all(void)
1894becef1dSAtsushi Nemoto {
1904becef1dSAtsushi Nemoto dump_tlb(0, current_cpu_data.tlbsize - 1);
1914becef1dSAtsushi Nemoto }
192