Merge ../linux-2.6-watchdog-mm
[sfrench/cifs-2.6.git] / arch / mips / lib-64 / 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
35         return "unknown";
36 }
37
38 #define BARRIER()                                       \
39         __asm__ __volatile__(                           \
40                 ".set\tnoreorder\n\t"                   \
41                 "nop;nop;nop;nop;nop;nop;nop\n\t"       \
42                 ".set\treorder");
43
44 void dump_tlb(int first, int last)
45 {
46         unsigned long s_entryhi, entryhi, entrylo0, entrylo1, asid;
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                         /*
67                          * Only print entries in use
68                          */
69                         printk("Index: %2d pgmask=%s ", i, msk2str(pagemask));
70
71                         c0 = (entrylo0 >> 3) & 7;
72                         c1 = (entrylo1 >> 3) & 7;
73
74                         printk("va=%011lx asid=%02lx\n",
75                                (entryhi & ~0x1fffUL),
76                                entryhi & 0xff);
77                         printk("\t[pa=%011lx c=%d d=%d v=%d g=%ld] ",
78                                (entrylo0 << 6) & PAGE_MASK, c0,
79                                (entrylo0 & 4) ? 1 : 0,
80                                (entrylo0 & 2) ? 1 : 0,
81                                (entrylo0 & 1));
82                         printk("[pa=%011lx c=%d d=%d v=%d g=%ld]\n",
83                                (entrylo1 << 6) & PAGE_MASK, c1,
84                                (entrylo1 & 4) ? 1 : 0,
85                                (entrylo1 & 2) ? 1 : 0,
86                                (entrylo1 & 1));
87                 }
88         }
89         printk("\n");
90
91         write_c0_entryhi(s_entryhi);
92         write_c0_index(s_index);
93 }
94
95 void dump_tlb_all(void)
96 {
97         dump_tlb(0, current_cpu_data.tlbsize - 1);
98 }
99
100 void dump_tlb_wired(void)
101 {
102         int     wired;
103
104         wired = read_c0_wired();
105         printk("Wired: %d", wired);
106         dump_tlb(0, read_c0_wired());
107 }
108
109 void dump_tlb_addr(unsigned long addr)
110 {
111         unsigned int flags, oldpid;
112         int index;
113
114         local_irq_save(flags);
115         oldpid = read_c0_entryhi() & 0xff;
116         BARRIER();
117         write_c0_entryhi((addr & PAGE_MASK) | oldpid);
118         BARRIER();
119         tlb_probe();
120         BARRIER();
121         index = read_c0_index();
122         write_c0_entryhi(oldpid);
123         local_irq_restore(flags);
124
125         if (index < 0) {
126                 printk("No entry for address 0x%08lx in TLB\n", addr);
127                 return;
128         }
129
130         printk("Entry %d maps address 0x%08lx\n", index, addr);
131         dump_tlb(index, index);
132 }
133
134 void dump_tlb_nonwired(void)
135 {
136         dump_tlb(read_c0_wired(), current_cpu_data.tlbsize - 1);
137 }
138
139 void dump_list_process(struct task_struct *t, void *address)
140 {
141         pgd_t   *page_dir, *pgd;
142         pud_t   *pud;
143         pmd_t   *pmd;
144         pte_t   *pte, page;
145         unsigned long addr, val;
146
147         addr = (unsigned long) address;
148
149         printk("Addr                 == %08lx\n", addr);
150         printk("tasks->mm.pgd        == %08lx\n", (unsigned long) t->mm->pgd);
151
152         page_dir = pgd_offset(t->mm, 0UL);
153         printk("page_dir == %016lx\n", (unsigned long) page_dir);
154
155         pgd = pgd_offset(t->mm, addr);
156         printk("pgd == %016lx\n", (unsigned long) pgd);
157
158         pud = pud_offset(pgd, addr);
159         printk("pud == %016lx\n", (unsigned long) pud);
160
161         pmd = pmd_offset(pud, addr);
162         printk("pmd == %016lx\n", (unsigned long) pmd);
163
164         pte = pte_offset(pmd, addr);
165         printk("pte == %016lx\n", (unsigned long) pte);
166
167         page = *pte;
168         printk("page == %08lx\n", pte_val(page));
169
170         val = pte_val(page);
171         if (val & _PAGE_PRESENT) printk("present ");
172         if (val & _PAGE_READ) printk("read ");
173         if (val & _PAGE_WRITE) printk("write ");
174         if (val & _PAGE_ACCESSED) printk("accessed ");
175         if (val & _PAGE_MODIFIED) printk("modified ");
176         if (val & _PAGE_R4KBUG) printk("r4kbug ");
177         if (val & _PAGE_GLOBAL) printk("global ");
178         if (val & _PAGE_VALID) printk("valid ");
179         printk("\n");
180 }
181
182 void dump_list_current(void *address)
183 {
184         dump_list_process(current, address);
185 }
186
187 unsigned long vtop(void *address)
188 {
189         pgd_t   *pgd;
190         pud_t   *pud;
191         pmd_t   *pmd;
192         pte_t   *pte;
193         unsigned long addr, paddr;
194
195         addr = (unsigned long) address;
196         pgd = pgd_offset(current->mm, addr);
197         pud = pud_offset(pgd, addr);
198         pmd = pmd_offset(pud, addr);
199         pte = pte_offset(pmd, addr);
200         paddr = (CKSEG1 | (unsigned int) pte_val(*pte)) & PAGE_MASK;
201         paddr |= (addr & ~PAGE_MASK);
202
203         return paddr;
204 }
205
206 void dump16(unsigned long *p)
207 {
208         int i;
209
210         for (i = 0; i < 8; i++) {
211                 printk("*%08lx == %08lx, ", (unsigned long)p, *p);
212                 p++;
213                 printk("*%08lx == %08lx\n", (unsigned long)p, *p);
214                 p++;
215         }
216 }