18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2020 Loongson Technology Corporation Limited
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#include <linux/kernel.h>
68c2ecf20Sopenharmony_ci#include <linux/mm.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <asm/loongarchregs.h>
98c2ecf20Sopenharmony_ci#include <asm/page.h>
108c2ecf20Sopenharmony_ci#include <asm/pgtable.h>
118c2ecf20Sopenharmony_ci#include <asm/tlb.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_civoid dump_tlb_regs(void)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	const int field = 2 * sizeof(unsigned long);
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci	pr_info("Index    : 0x%0x\n", read_csr_tlbidx());
188c2ecf20Sopenharmony_ci	pr_info("PageSize : 0x%0x\n", read_csr_pagesize());
198c2ecf20Sopenharmony_ci	pr_info("EntryHi  : 0x%0*lx\n", field, read_csr_entryhi());
208c2ecf20Sopenharmony_ci	pr_info("EntryLo0 : 0x%0*lx\n", field, read_csr_entrylo0());
218c2ecf20Sopenharmony_ci	pr_info("EntryLo1 : 0x%0*lx\n", field, read_csr_entrylo1());
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic void dump_tlb(int first, int last)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	unsigned long s_entryhi, entryhi, asid;
278c2ecf20Sopenharmony_ci	unsigned long long entrylo0, entrylo1, pa;
288c2ecf20Sopenharmony_ci	unsigned int index;
298c2ecf20Sopenharmony_ci	unsigned int s_index, s_asid;
308c2ecf20Sopenharmony_ci	unsigned int pagesize, c0, c1, i;
318c2ecf20Sopenharmony_ci	unsigned long asidmask = cpu_asid_mask(&current_cpu_data);
328c2ecf20Sopenharmony_ci	int pwidth = 16;
338c2ecf20Sopenharmony_ci	int vwidth = 16;
348c2ecf20Sopenharmony_ci	int asidwidth = DIV_ROUND_UP(ilog2(asidmask) + 1, 4);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	s_entryhi = read_csr_entryhi();
378c2ecf20Sopenharmony_ci	s_index = read_csr_tlbidx();
388c2ecf20Sopenharmony_ci	s_asid = read_csr_asid();
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	for (i = first; i <= last; i++) {
418c2ecf20Sopenharmony_ci		write_csr_index(i);
428c2ecf20Sopenharmony_ci		tlb_read();
438c2ecf20Sopenharmony_ci		pagesize = read_csr_pagesize();
448c2ecf20Sopenharmony_ci		entryhi	 = read_csr_entryhi();
458c2ecf20Sopenharmony_ci		entrylo0 = read_csr_entrylo0();
468c2ecf20Sopenharmony_ci		entrylo1 = read_csr_entrylo1();
478c2ecf20Sopenharmony_ci		index = read_csr_tlbidx();
488c2ecf20Sopenharmony_ci		asid = read_csr_asid();
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci		/* EHINV bit marks entire entry as invalid */
518c2ecf20Sopenharmony_ci		if (index & CSR_TLBIDX_EHINV)
528c2ecf20Sopenharmony_ci			continue;
538c2ecf20Sopenharmony_ci		/*
548c2ecf20Sopenharmony_ci		 * ASID takes effect in absence of G (global) bit.
558c2ecf20Sopenharmony_ci		 */
568c2ecf20Sopenharmony_ci		if (!((entrylo0 | entrylo1) & ENTRYLO_G) &&
578c2ecf20Sopenharmony_ci		    asid != s_asid)
588c2ecf20Sopenharmony_ci			continue;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		/*
618c2ecf20Sopenharmony_ci		 * Only print entries in use
628c2ecf20Sopenharmony_ci		 */
638c2ecf20Sopenharmony_ci		printk("Index: %4d pgsize=0x%x ", i, (1 << pagesize));
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci		c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
668c2ecf20Sopenharmony_ci		c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci		pr_cont("va=0x%0*lx asid=0x%0*lx",
698c2ecf20Sopenharmony_ci			vwidth, (entryhi & ~0x1fffUL), asidwidth, asid & asidmask);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci		/* NR/NX are in awkward places, so mask them off separately */
728c2ecf20Sopenharmony_ci		pa = entrylo0 & ~(ENTRYLO_NR | ENTRYLO_NX);
738c2ecf20Sopenharmony_ci		pa = pa & PAGE_MASK;
748c2ecf20Sopenharmony_ci		pr_cont("\n\t[");
758c2ecf20Sopenharmony_ci		pr_cont("nr=%d nx=%d ",
768c2ecf20Sopenharmony_ci			(entrylo0 & ENTRYLO_NR) ? 1 : 0,
778c2ecf20Sopenharmony_ci			(entrylo0 & ENTRYLO_NX) ? 1 : 0);
788c2ecf20Sopenharmony_ci		pr_cont("pa=0x%0*llx c=%d d=%d v=%d g=%d plv=%lld] [",
798c2ecf20Sopenharmony_ci			pwidth, pa, c0,
808c2ecf20Sopenharmony_ci			(entrylo0 & ENTRYLO_D) ? 1 : 0,
818c2ecf20Sopenharmony_ci			(entrylo0 & ENTRYLO_V) ? 1 : 0,
828c2ecf20Sopenharmony_ci			(entrylo0 & ENTRYLO_G) ? 1 : 0,
838c2ecf20Sopenharmony_ci			(entrylo0 & ENTRYLO_PLV) >> ENTRYLO_PLV_SHIFT);
848c2ecf20Sopenharmony_ci		/* NR/NX are in awkward places, so mask them off separately */
858c2ecf20Sopenharmony_ci		pa = entrylo1 & ~(ENTRYLO_NR | ENTRYLO_NX);
868c2ecf20Sopenharmony_ci		pa = pa & PAGE_MASK;
878c2ecf20Sopenharmony_ci		pr_cont("nr=%d nx=%d ",
888c2ecf20Sopenharmony_ci			(entrylo1 & ENTRYLO_NR) ? 1 : 0,
898c2ecf20Sopenharmony_ci			(entrylo1 & ENTRYLO_NX) ? 1 : 0);
908c2ecf20Sopenharmony_ci		pr_cont("pa=0x%0*llx c=%d d=%d v=%d g=%d plv=%lld]\n",
918c2ecf20Sopenharmony_ci			pwidth, pa, c1,
928c2ecf20Sopenharmony_ci			(entrylo1 & ENTRYLO_D) ? 1 : 0,
938c2ecf20Sopenharmony_ci			(entrylo1 & ENTRYLO_V) ? 1 : 0,
948c2ecf20Sopenharmony_ci			(entrylo1 & ENTRYLO_G) ? 1 : 0,
958c2ecf20Sopenharmony_ci			(entrylo1 & ENTRYLO_PLV) >> ENTRYLO_PLV_SHIFT);
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci	printk("\n");
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	write_csr_entryhi(s_entryhi);
1008c2ecf20Sopenharmony_ci	write_csr_tlbidx(s_index);
1018c2ecf20Sopenharmony_ci	write_csr_asid(s_asid);
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_civoid dump_tlb_all(void)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	dump_tlb(0, current_cpu_data.tlbsize - 1);
1078c2ecf20Sopenharmony_ci}
108