[MIPS] Unify dump_tlb
[linux-drm-fsl-dcu.git] / arch / mips / lib / dump_tlb.c
1 /*
2  * Dump R4x00 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  */
7 #include <linux/kernel.h>
8 #include <linux/mm.h>
9 #include <linux/sched.h>
10 #include <linux/string.h>
11
12 #include <asm/bootinfo.h>
13 #include <asm/cachectl.h>
14 #include <asm/cpu.h>
15 #include <asm/mipsregs.h>
16 #include <asm/page.h>
17 #include <asm/pgtable.h>
18
19 static inline const char *msk2str(unsigned int mask)
20 {
21         switch (mask) {
22         case PM_4K:     return "4kb";
23         case PM_16K:    return "16kb";
24         case PM_64K:    return "64kb";
25         case PM_256K:   return "256kb";
26 #ifndef CONFIG_CPU_VR41XX
27         case PM_1M:     return "1Mb";
28         case PM_4M:     return "4Mb";
29         case PM_16M:    return "16Mb";
30         case PM_64M:    return "64Mb";
31         case PM_256M:   return "256Mb";
32 #endif
33         }
34         return "";
35 }
36
37 #define BARRIER()                                       \
38         __asm__ __volatile__(                           \
39                 ".set\tnoreorder\n\t"                   \
40                 "nop;nop;nop;nop;nop;nop;nop\n\t"       \
41                 ".set\treorder");
42
43 void dump_tlb(int first, int last)
44 {
45         unsigned long s_entryhi, entryhi, asid;
46         unsigned long long entrylo0, entrylo1;
47         unsigned int s_index, pagemask, c0, c1, i;
48
49         s_entryhi = read_c0_entryhi();
50         s_index = read_c0_index();
51         asid = s_entryhi & 0xff;
52
53         for (i = first; i <= last; i++) {
54                 write_c0_index(i);
55                 BARRIER();
56                 tlb_read();
57                 BARRIER();
58                 pagemask = read_c0_pagemask();
59                 entryhi  = read_c0_entryhi();
60                 entrylo0 = read_c0_entrylo0();
61                 entrylo1 = read_c0_entrylo1();
62
63                 /* Unused entries have a virtual address of CKSEG0.  */
64                 if ((entryhi & ~0x1ffffUL) != CKSEG0
65                     && (entryhi & 0xff) == asid) {
66 #ifdef CONFIG_32BIT
67                         int width = 8;
68 #else
69                         int width = 11;
70 #endif
71                         /*
72                          * Only print entries in use
73                          */
74                         printk("Index: %2d pgmask=%s ", i, msk2str(pagemask));
75
76                         c0 = (entrylo0 >> 3) & 7;
77                         c1 = (entrylo1 >> 3) & 7;
78
79                         printk("va=%0*lx asid=%02lx\n",
80                                width, (entryhi & ~0x1fffUL),
81                                entryhi & 0xff);
82                         printk("\t[pa=%0*llx c=%d d=%d v=%d g=%d] ",
83                                width,
84                                (entrylo0 << 6) & PAGE_MASK, c0,
85                                (entrylo0 & 4) ? 1 : 0,
86                                (entrylo0 & 2) ? 1 : 0,
87                                (entrylo0 & 1) ? 1 : 0);
88                         printk("[pa=%0*llx c=%d d=%d v=%d g=%d]\n",
89                                width,
90                                (entrylo1 << 6) & PAGE_MASK, c1,
91                                (entrylo1 & 4) ? 1 : 0,
92                                (entrylo1 & 2) ? 1 : 0,
93                                (entrylo1 & 1) ? 1 : 0);
94                 }
95         }
96         printk("\n");
97
98         write_c0_entryhi(s_entryhi);
99         write_c0_index(s_index);
100 }
101
102 void dump_tlb_all(void)
103 {
104         dump_tlb(0, current_cpu_data.tlbsize - 1);
105 }
106
107 void dump_tlb_wired(void)
108 {
109         int     wired;
110
111         wired = read_c0_wired();
112         printk("Wired: %d", wired);
113         dump_tlb(0, read_c0_wired());
114 }
115
116 void dump_tlb_addr(unsigned long addr)
117 {
118         unsigned int flags, oldpid;
119         int index;
120
121         local_irq_save(flags);
122         oldpid = read_c0_entryhi() & 0xff;
123         BARRIER();
124         write_c0_entryhi((addr & PAGE_MASK) | oldpid);
125         BARRIER();
126         tlb_probe();
127         BARRIER();
128         index = read_c0_index();
129         write_c0_entryhi(oldpid);
130         local_irq_restore(flags);
131
132         if (index < 0) {
133                 printk("No entry for address 0x%08lx in TLB\n", addr);
134                 return;
135         }
136
137         printk("Entry %d maps address 0x%08lx\n", index, addr);
138         dump_tlb(index, index);
139 }
140
141 void dump_tlb_nonwired(void)
142 {
143         dump_tlb(read_c0_wired(), current_cpu_data.tlbsize - 1);
144 }
145
146 void dump_list_process(struct task_struct *t, void *address)
147 {
148         pgd_t   *page_dir, *pgd;
149         pud_t   *pud;
150         pmd_t   *pmd;
151         pte_t   *pte, page;
152         unsigned long addr, val;
153         int width = sizeof(long) * 2;
154
155         addr = (unsigned long) address;
156
157         printk("Addr                 == %08lx\n", addr);
158 #ifdef CONFIG_64BIT
159         printk("tasks->mm.pgd        == %08lx\n", (unsigned long) t->mm->pgd);
160 #endif
161
162 #ifdef CONFIG_64BIT
163         page_dir = pgd_offset(t->mm, 0UL);
164         pgd = pgd_offset(t->mm, addr);
165 #else
166         if (addr > KSEG0) {
167                 page_dir = pgd_offset_k(0);
168                 pgd = pgd_offset_k(addr);
169         } else if (t->mm) {
170                 page_dir = pgd_offset(t->mm, 0);
171                 pgd = pgd_offset(t->mm, addr);
172         } else {
173                 printk("Current thread has no mm\n");
174                 return;
175         }
176 #endif
177         printk("page_dir == %0*lx\n", width, (unsigned long) page_dir);
178         printk("pgd == %0*lx\n", width, (unsigned long) pgd);
179
180         pud = pud_offset(pgd, addr);
181         printk("pud == %0*lx\n", width, (unsigned long) pud);
182
183         pmd = pmd_offset(pud, addr);
184         printk("pmd == %0*lx\n", width, (unsigned long) pmd);
185
186         pte = pte_offset(pmd, addr);
187         printk("pte == %0*lx\n", width, (unsigned long) pte);
188
189         page = *pte;
190 #ifdef CONFIG_64BIT_PHYS_ADDR
191         printk("page == %08Lx\n", pte_val(page));
192 #else
193         printk("page == %0*lx\n", width, pte_val(page));
194 #endif
195
196         val = pte_val(page);
197         if (val & _PAGE_PRESENT) printk("present ");
198         if (val & _PAGE_READ) printk("read ");
199         if (val & _PAGE_WRITE) printk("write ");
200         if (val & _PAGE_ACCESSED) printk("accessed ");
201         if (val & _PAGE_MODIFIED) printk("modified ");
202         if (val & _PAGE_R4KBUG) printk("r4kbug ");
203         if (val & _PAGE_GLOBAL) printk("global ");
204         if (val & _PAGE_VALID) printk("valid ");
205         printk("\n");
206 }
207
208 void dump_list_current(void *address)
209 {
210         dump_list_process(current, address);
211 }
212
213 unsigned long vtop(void *address)
214 {
215         pgd_t   *pgd;
216         pud_t   *pud;
217         pmd_t   *pmd;
218         pte_t   *pte;
219         unsigned long addr, paddr;
220
221         addr = (unsigned long) address;
222         pgd = pgd_offset(current->mm, addr);
223         pud = pud_offset(pgd, addr);
224         pmd = pmd_offset(pud, addr);
225         pte = pte_offset(pmd, addr);
226         paddr = (CKSEG1 | (unsigned int) pte_val(*pte)) & PAGE_MASK;
227         paddr |= (addr & ~PAGE_MASK);
228
229         return paddr;
230 }
231
232 void dump16(unsigned long *p)
233 {
234         int i;
235
236         for (i = 0; i < 8; i++) {
237                 printk("*%08lx == %08lx, ", (unsigned long)p, *p);
238                 p++;
239                 printk("*%08lx == %08lx\n", (unsigned long)p, *p);
240                 p++;
241         }
242 }