1/*
2 * Dump R3000 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 * Copyright (C) 1999 by Harald Koerfgen
7 */
8#include <linux/kernel.h>
9#include <linux/mm.h>
10#include <linux/sched.h>
11#include <linux/string.h>
12
13#include <asm/bootinfo.h>
14#include <asm/cachectl.h>
15#include <asm/cpu.h>
16#include <asm/mipsregs.h>
17#include <asm/page.h>
18#include <asm/pgtable.h>
19
20extern int r3k_have_wired_reg;	/* defined in tlb-r3k.c */
21
22void
23dump_tlb(int first, int last)
24{
25	int	i;
26	unsigned int asid;
27	unsigned long entryhi, entrylo0;
28
29	asid = read_c0_entryhi() & 0xfc0;
30
31	for(i=first;i<=last;i++)
32	{
33		write_c0_index(i<<8);
34		__asm__ __volatile__(
35			".set\tnoreorder\n\t"
36			"tlbr\n\t"
37			"nop\n\t"
38			".set\treorder");
39		entryhi  = read_c0_entryhi();
40		entrylo0 = read_c0_entrylo0();
41
42		/* Unused entries have a virtual address of KSEG0.  */
43		if ((entryhi & 0xffffe000) != 0x80000000
44		    && (entryhi & 0xfc0) == asid) {
45			/*
46			 * Only print entries in use
47			 */
48			printk("Index: %2d ", i);
49
50			printk("va=%08lx asid=%08lx"
51			       "  [pa=%06lx n=%d d=%d v=%d g=%d]",
52			       (entryhi & 0xffffe000),
53			       entryhi & 0xfc0,
54			       entrylo0 & PAGE_MASK,
55			       (entrylo0 & (1 << 11)) ? 1 : 0,
56			       (entrylo0 & (1 << 10)) ? 1 : 0,
57			       (entrylo0 & (1 << 9)) ? 1 : 0,
58			       (entrylo0 & (1 << 8)) ? 1 : 0);
59		}
60	}
61	printk("\n");
62
63	write_c0_entryhi(asid);
64}
65
66void
67dump_tlb_all(void)
68{
69	dump_tlb(0, mips_cpu.tlbsize - 1);
70}
71
72void
73dump_tlb_wired(void)
74{
75	int wired = r3k_have_wired_reg ? read_c0_wired() : 8;
76
77	printk("Wired: %d", wired);
78	dump_tlb(0, wired - 1);
79}
80
81void
82dump_tlb_addr(unsigned long addr)
83{
84	unsigned int flags, oldpid;
85	int index;
86
87	__save_and_cli(flags);
88	oldpid = read_c0_entryhi() & 0xff;
89	write_c0_entryhi((addr & PAGE_MASK) | oldpid);
90	tlb_probe();
91	index = read_c0_index();
92	write_c0_entryhi(oldpid);
93	__restore_flags(flags);
94
95	if (index < 0) {
96		printk("No entry for address 0x%08lx in TLB\n", addr);
97		return;
98	}
99
100	printk("Entry %d maps address 0x%08lx\n", index, addr);
101	dump_tlb(index, index);
102}
103
104void
105dump_tlb_nonwired(void)
106{
107	int wired = r3k_have_wired_reg ? read_c0_wired() : 8;
108	dump_tlb(wired, mips_cpu.tlbsize - 1);
109}
110
111void
112dump_list_process(struct task_struct *t, void *address)
113{
114	pgd_t	*page_dir, *pgd;
115	pmd_t	*pmd;
116	pte_t	*pte, page;
117	unsigned int addr;
118	unsigned long val;
119
120	addr = (unsigned int) address;
121
122	printk("Addr                 == %08x\n", addr);
123	printk("tasks->mm.pgd        == %08x\n", (unsigned int) t->mm->pgd);
124
125	page_dir = pgd_offset(t->mm, 0);
126	printk("page_dir == %08x\n", (unsigned int) page_dir);
127
128	pgd = pgd_offset(t->mm, addr);
129	printk("pgd == %08x, ", (unsigned int) pgd);
130
131	pmd = pmd_offset(pgd, addr);
132	printk("pmd == %08x, ", (unsigned int) pmd);
133
134	pte = pte_offset(pmd, addr);
135	printk("pte == %08x, ", (unsigned int) pte);
136
137	page = *pte;
138	printk("page == %08x\n", (unsigned int) pte_val(page));
139
140	val = pte_val(page);
141	if (val & _PAGE_PRESENT) printk("present ");
142	if (val & _PAGE_READ) printk("read ");
143	if (val & _PAGE_WRITE) printk("write ");
144	if (val & _PAGE_ACCESSED) printk("accessed ");
145	if (val & _PAGE_MODIFIED) printk("modified ");
146	if (val & _PAGE_GLOBAL) printk("global ");
147	if (val & _PAGE_VALID) printk("valid ");
148	printk("\n");
149}
150
151void
152dump_list_current(void *address)
153{
154	dump_list_process(current, address);
155}
156
157unsigned int
158vtop(void *address)
159{
160	pgd_t	*pgd;
161	pmd_t	*pmd;
162	pte_t	*pte;
163	unsigned int addr, paddr;
164
165	addr = (unsigned long) address;
166	pgd = pgd_offset(current->mm, addr);
167	pmd = pmd_offset(pgd, addr);
168	pte = pte_offset(pmd, addr);
169	paddr = (KSEG1 | (unsigned int) pte_val(*pte)) & PAGE_MASK;
170	paddr |= (addr & ~PAGE_MASK);
171
172	return paddr;
173}
174
175void
176dump16(unsigned long *p)
177{
178	int i;
179
180	for(i=0;i<8;i++)
181	{
182		printk("*%08lx == %08lx, ",
183		       (unsigned long)p, (unsigned long)*p++);
184		printk("*%08lx == %08lx\n",
185		       (unsigned long)p, (unsigned long)*p++);
186	}
187}
188