xref: /openbmc/linux/arch/mips/lib/dump_tlb.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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(&current_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