xref: /kernel/linux/linux-6.6/arch/mips/lib/dump_tlb.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Dump R4x00 TLB for debugging purposes.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle.
662306a36Sopenharmony_ci * Copyright (C) 1999 by Silicon Graphics, Inc.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#include <linux/kernel.h>
962306a36Sopenharmony_ci#include <linux/mm.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/hazards.h>
1262306a36Sopenharmony_ci#include <asm/mipsregs.h>
1362306a36Sopenharmony_ci#include <asm/mmu_context.h>
1462306a36Sopenharmony_ci#include <asm/page.h>
1562306a36Sopenharmony_ci#include <asm/tlbdebug.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_civoid dump_tlb_regs(void)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	const int field = 2 * sizeof(unsigned long);
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	pr_info("Index    : %0x\n", read_c0_index());
2262306a36Sopenharmony_ci	pr_info("PageMask : %0x\n", read_c0_pagemask());
2362306a36Sopenharmony_ci	if (cpu_has_guestid)
2462306a36Sopenharmony_ci		pr_info("GuestCtl1: %0x\n", read_c0_guestctl1());
2562306a36Sopenharmony_ci	pr_info("EntryHi  : %0*lx\n", field, read_c0_entryhi());
2662306a36Sopenharmony_ci	pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0());
2762306a36Sopenharmony_ci	pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1());
2862306a36Sopenharmony_ci	pr_info("Wired    : %0x\n", read_c0_wired());
2962306a36Sopenharmony_ci	switch (current_cpu_type()) {
3062306a36Sopenharmony_ci	case CPU_R10000:
3162306a36Sopenharmony_ci	case CPU_R12000:
3262306a36Sopenharmony_ci	case CPU_R14000:
3362306a36Sopenharmony_ci	case CPU_R16000:
3462306a36Sopenharmony_ci		pr_info("FrameMask: %0x\n", read_c0_framemask());
3562306a36Sopenharmony_ci		break;
3662306a36Sopenharmony_ci	}
3762306a36Sopenharmony_ci	if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa)
3862306a36Sopenharmony_ci		pr_info("PageGrain: %0x\n", read_c0_pagegrain());
3962306a36Sopenharmony_ci	if (cpu_has_htw) {
4062306a36Sopenharmony_ci		pr_info("PWField  : %0*lx\n", field, read_c0_pwfield());
4162306a36Sopenharmony_ci		pr_info("PWSize   : %0*lx\n", field, read_c0_pwsize());
4262306a36Sopenharmony_ci		pr_info("PWCtl    : %0x\n", read_c0_pwctl());
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic inline const char *msk2str(unsigned int mask)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	switch (mask) {
4962306a36Sopenharmony_ci	case PM_4K:	return "4kb";
5062306a36Sopenharmony_ci	case PM_16K:	return "16kb";
5162306a36Sopenharmony_ci	case PM_64K:	return "64kb";
5262306a36Sopenharmony_ci	case PM_256K:	return "256kb";
5362306a36Sopenharmony_ci#ifdef CONFIG_CPU_CAVIUM_OCTEON
5462306a36Sopenharmony_ci	case PM_8K:	return "8kb";
5562306a36Sopenharmony_ci	case PM_32K:	return "32kb";
5662306a36Sopenharmony_ci	case PM_128K:	return "128kb";
5762306a36Sopenharmony_ci	case PM_512K:	return "512kb";
5862306a36Sopenharmony_ci	case PM_2M:	return "2Mb";
5962306a36Sopenharmony_ci	case PM_8M:	return "8Mb";
6062306a36Sopenharmony_ci	case PM_32M:	return "32Mb";
6162306a36Sopenharmony_ci#endif
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci	return "";
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic void dump_tlb(int first, int last)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	unsigned long s_entryhi, entryhi, asid, mmid;
6962306a36Sopenharmony_ci	unsigned long long entrylo0, entrylo1, pa;
7062306a36Sopenharmony_ci	unsigned int s_index, s_pagemask, s_guestctl1 = 0;
7162306a36Sopenharmony_ci	unsigned int pagemask, guestctl1 = 0, c0, c1, i;
7262306a36Sopenharmony_ci	unsigned long asidmask = cpu_asid_mask(&current_cpu_data);
7362306a36Sopenharmony_ci	int asidwidth = DIV_ROUND_UP(ilog2(asidmask) + 1, 4);
7462306a36Sopenharmony_ci	unsigned long s_mmid;
7562306a36Sopenharmony_ci#ifdef CONFIG_32BIT
7662306a36Sopenharmony_ci	bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA);
7762306a36Sopenharmony_ci	int pwidth = xpa ? 11 : 8;
7862306a36Sopenharmony_ci	int vwidth = 8;
7962306a36Sopenharmony_ci#else
8062306a36Sopenharmony_ci	bool xpa = false;
8162306a36Sopenharmony_ci	int pwidth = 11;
8262306a36Sopenharmony_ci	int vwidth = 11;
8362306a36Sopenharmony_ci#endif
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	s_pagemask = read_c0_pagemask();
8662306a36Sopenharmony_ci	s_entryhi = read_c0_entryhi();
8762306a36Sopenharmony_ci	s_index = read_c0_index();
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (cpu_has_mmid)
9062306a36Sopenharmony_ci		asid = s_mmid = read_c0_memorymapid();
9162306a36Sopenharmony_ci	else
9262306a36Sopenharmony_ci		asid = s_entryhi & asidmask;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (cpu_has_guestid)
9562306a36Sopenharmony_ci		s_guestctl1 = read_c0_guestctl1();
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	for (i = first; i <= last; i++) {
9862306a36Sopenharmony_ci		write_c0_index(i);
9962306a36Sopenharmony_ci		mtc0_tlbr_hazard();
10062306a36Sopenharmony_ci		tlb_read();
10162306a36Sopenharmony_ci		tlb_read_hazard();
10262306a36Sopenharmony_ci		pagemask = read_c0_pagemask();
10362306a36Sopenharmony_ci		entryhi	 = read_c0_entryhi();
10462306a36Sopenharmony_ci		entrylo0 = read_c0_entrylo0();
10562306a36Sopenharmony_ci		entrylo1 = read_c0_entrylo1();
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci		if (cpu_has_mmid)
10862306a36Sopenharmony_ci			mmid = read_c0_memorymapid();
10962306a36Sopenharmony_ci		else
11062306a36Sopenharmony_ci			mmid = entryhi & asidmask;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		if (cpu_has_guestid)
11362306a36Sopenharmony_ci			guestctl1 = read_c0_guestctl1();
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		/* EHINV bit marks entire entry as invalid */
11662306a36Sopenharmony_ci		if (cpu_has_tlbinv && entryhi & MIPS_ENTRYHI_EHINV)
11762306a36Sopenharmony_ci			continue;
11862306a36Sopenharmony_ci		/*
11962306a36Sopenharmony_ci		 * Prior to tlbinv, unused entries have a virtual address of
12062306a36Sopenharmony_ci		 * CKSEG0.
12162306a36Sopenharmony_ci		 */
12262306a36Sopenharmony_ci		if ((entryhi & ~0x1ffffUL) == CKSEG0)
12362306a36Sopenharmony_ci			continue;
12462306a36Sopenharmony_ci		/*
12562306a36Sopenharmony_ci		 * ASID takes effect in absence of G (global) bit.
12662306a36Sopenharmony_ci		 * We check both G bits, even though architecturally they should
12762306a36Sopenharmony_ci		 * match one another, because some revisions of the SB1 core may
12862306a36Sopenharmony_ci		 * leave only a single G bit set after a machine check exception
12962306a36Sopenharmony_ci		 * due to duplicate TLB entry.
13062306a36Sopenharmony_ci		 */
13162306a36Sopenharmony_ci		if (!((entrylo0 | entrylo1) & ENTRYLO_G) && (mmid != asid))
13262306a36Sopenharmony_ci			continue;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci		/*
13562306a36Sopenharmony_ci		 * Only print entries in use
13662306a36Sopenharmony_ci		 */
13762306a36Sopenharmony_ci		printk("Index: %2d pgmask=%s ", i, msk2str(pagemask));
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
14062306a36Sopenharmony_ci		c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		pr_cont("va=%0*lx asid=%0*lx",
14362306a36Sopenharmony_ci			vwidth, (entryhi & ~0x1fffUL),
14462306a36Sopenharmony_ci			asidwidth, mmid);
14562306a36Sopenharmony_ci		if (cpu_has_guestid)
14662306a36Sopenharmony_ci			pr_cont(" gid=%02lx",
14762306a36Sopenharmony_ci				(guestctl1 & MIPS_GCTL1_RID)
14862306a36Sopenharmony_ci					>> MIPS_GCTL1_RID_SHIFT);
14962306a36Sopenharmony_ci		/* RI/XI are in awkward places, so mask them off separately */
15062306a36Sopenharmony_ci		pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
15162306a36Sopenharmony_ci		if (xpa)
15262306a36Sopenharmony_ci			pa |= (unsigned long long)readx_c0_entrylo0() << 30;
15362306a36Sopenharmony_ci		pa = (pa << 6) & PAGE_MASK;
15462306a36Sopenharmony_ci		pr_cont("\n\t[");
15562306a36Sopenharmony_ci		if (cpu_has_rixi)
15662306a36Sopenharmony_ci			pr_cont("ri=%d xi=%d ",
15762306a36Sopenharmony_ci				(entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0,
15862306a36Sopenharmony_ci				(entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0);
15962306a36Sopenharmony_ci		pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d] [",
16062306a36Sopenharmony_ci			pwidth, pa, c0,
16162306a36Sopenharmony_ci			(entrylo0 & ENTRYLO_D) ? 1 : 0,
16262306a36Sopenharmony_ci			(entrylo0 & ENTRYLO_V) ? 1 : 0,
16362306a36Sopenharmony_ci			(entrylo0 & ENTRYLO_G) ? 1 : 0);
16462306a36Sopenharmony_ci		/* RI/XI are in awkward places, so mask them off separately */
16562306a36Sopenharmony_ci		pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
16662306a36Sopenharmony_ci		if (xpa)
16762306a36Sopenharmony_ci			pa |= (unsigned long long)readx_c0_entrylo1() << 30;
16862306a36Sopenharmony_ci		pa = (pa << 6) & PAGE_MASK;
16962306a36Sopenharmony_ci		if (cpu_has_rixi)
17062306a36Sopenharmony_ci			pr_cont("ri=%d xi=%d ",
17162306a36Sopenharmony_ci				(entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0,
17262306a36Sopenharmony_ci				(entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0);
17362306a36Sopenharmony_ci		pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d]\n",
17462306a36Sopenharmony_ci			pwidth, pa, c1,
17562306a36Sopenharmony_ci			(entrylo1 & ENTRYLO_D) ? 1 : 0,
17662306a36Sopenharmony_ci			(entrylo1 & ENTRYLO_V) ? 1 : 0,
17762306a36Sopenharmony_ci			(entrylo1 & ENTRYLO_G) ? 1 : 0);
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci	printk("\n");
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	write_c0_entryhi(s_entryhi);
18262306a36Sopenharmony_ci	write_c0_index(s_index);
18362306a36Sopenharmony_ci	write_c0_pagemask(s_pagemask);
18462306a36Sopenharmony_ci	if (cpu_has_guestid)
18562306a36Sopenharmony_ci		write_c0_guestctl1(s_guestctl1);
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_civoid dump_tlb_all(void)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	dump_tlb(0, current_cpu_data.tlbsize - 1);
19162306a36Sopenharmony_ci}
192