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