sh: tlb debugfs support.
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / sh / mm / tlb-debugfs.c
1 /*
2  * arch/sh/mm/tlb-debugfs.c
3  *
4  * debugfs ops for SH-4 ITLB/UTLBs.
5  *
6  * Copyright (C) 2010  Matt Fleming
7  *
8  * This file is subject to the terms and conditions of the GNU General Public
9  * License.  See the file "COPYING" in the main directory of this archive
10  * for more details.
11  */
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/debugfs.h>
15 #include <linux/seq_file.h>
16 #include <asm/processor.h>
17 #include <asm/mmu_context.h>
18 #include <asm/tlbflush.h>
19
20 enum tlb_type {
21         TLB_TYPE_ITLB,
22         TLB_TYPE_UTLB,
23 };
24
25 static struct {
26         int bits;
27         const char *size;
28 } tlb_sizes[] = {
29         { 0x0, "  1KB" },
30         { 0x1, "  4KB" },
31         { 0x2, "  8KB" },
32         { 0x4, " 64KB" },
33         { 0x5, "256KB" },
34         { 0x7, "  1MB" },
35         { 0x8, "  4MB" },
36         { 0xc, " 64MB" },
37 };
38
39 static int tlb_seq_show(struct seq_file *file, void *iter)
40 {
41         unsigned int tlb_type = (unsigned int)file->private;
42         unsigned long addr1, addr2, data1, data2;
43         unsigned long flags;
44         unsigned long mmucr;
45         unsigned int nentries, entry;
46         unsigned int urb;
47
48         mmucr = __raw_readl(MMUCR);
49         if ((mmucr & 0x1) == 0) {
50                 seq_printf(file, "address translation disabled\n");
51                 return 0;
52         }
53
54         if (tlb_type == TLB_TYPE_ITLB) {
55                 addr1 = MMU_ITLB_ADDRESS_ARRAY;
56                 addr2 = MMU_ITLB_ADDRESS_ARRAY2;
57                 data1 = MMU_ITLB_DATA_ARRAY;
58                 data2 = MMU_ITLB_DATA_ARRAY2;
59                 nentries = 4;
60         } else {
61                 addr1 = MMU_UTLB_ADDRESS_ARRAY;
62                 addr2 = MMU_UTLB_ADDRESS_ARRAY2;
63                 data1 = MMU_UTLB_DATA_ARRAY;
64                 data2 = MMU_UTLB_DATA_ARRAY2;
65                 nentries = 64;
66         }
67
68         local_irq_save(flags);
69         jump_to_uncached();
70
71         urb = (mmucr & MMUCR_URB) >> MMUCR_URB_SHIFT;
72
73         /* Make the "entry >= urb" test fail. */
74         if (urb == 0)
75                 urb = MMUCR_URB_NENTRIES + 1;
76
77         if (tlb_type == TLB_TYPE_ITLB) {
78                 addr1 = MMU_ITLB_ADDRESS_ARRAY;
79                 addr2 = MMU_ITLB_ADDRESS_ARRAY2;
80                 data1 = MMU_ITLB_DATA_ARRAY;
81                 data2 = MMU_ITLB_DATA_ARRAY2;
82                 nentries = 4;
83         } else {
84                 addr1 = MMU_UTLB_ADDRESS_ARRAY;
85                 addr2 = MMU_UTLB_ADDRESS_ARRAY2;
86                 data1 = MMU_UTLB_DATA_ARRAY;
87                 data2 = MMU_UTLB_DATA_ARRAY2;
88                 nentries = 64;
89         }
90
91         seq_printf(file, "entry:     vpn        ppn     asid  size valid wired\n");
92
93         for (entry = 0; entry < nentries; entry++) {
94                 unsigned long vpn, ppn, asid, size;
95                 unsigned long valid;
96                 unsigned long val;
97                 const char *sz = "    ?";
98                 int i;
99
100                 val = __raw_readl(addr1 | (entry << MMU_TLB_ENTRY_SHIFT));
101                 ctrl_barrier();
102                 vpn = val & 0xfffffc00;
103                 valid = val & 0x100;
104
105                 val = __raw_readl(addr2 | (entry << MMU_TLB_ENTRY_SHIFT));
106                 ctrl_barrier();
107                 asid = val & MMU_CONTEXT_ASID_MASK;
108
109                 val = __raw_readl(data1 | (entry << MMU_TLB_ENTRY_SHIFT));
110                 ctrl_barrier();
111                 ppn = (val & 0x0ffffc00) << 4;
112
113                 val = __raw_readl(data2 | (entry << MMU_TLB_ENTRY_SHIFT));
114                 ctrl_barrier();
115                 size = (val & 0xf0) >> 4;
116
117                 for (i = 0; i < ARRAY_SIZE(tlb_sizes); i++) {
118                         if (tlb_sizes[i].bits == size)
119                                 break;
120                 }
121
122                 if (i != ARRAY_SIZE(tlb_sizes))
123                         sz = tlb_sizes[i].size;
124
125                 seq_printf(file, "%2d:    0x%08lx 0x%08lx %5lu %s   %s     %s\n",
126                            entry, vpn, ppn, asid,
127                            sz, valid ? "V" : "-",
128                            (urb <= entry) ? "W" : "-");
129         }
130
131         back_to_cached();
132         local_irq_restore(flags);
133
134         return 0;
135 }
136
137 static int tlb_debugfs_open(struct inode *inode, struct file *file)
138 {
139         return single_open(file, tlb_seq_show, inode->i_private);
140 }
141
142 static const struct file_operations tlb_debugfs_fops = {
143         .owner          = THIS_MODULE,
144         .open           = tlb_debugfs_open,
145         .read           = seq_read,
146         .llseek         = seq_lseek,
147         .release        = single_release,
148 };
149
150 static int __init tlb_debugfs_init(void)
151 {
152         struct dentry *itlb, *utlb;
153
154         itlb = debugfs_create_file("itlb", S_IRUSR, sh_debugfs_root,
155                                    (unsigned int *)TLB_TYPE_ITLB,
156                                    &tlb_debugfs_fops);
157         if (unlikely(!itlb))
158                 return -ENOMEM;
159         if (IS_ERR(itlb))
160                 return PTR_ERR(itlb);
161
162         utlb = debugfs_create_file("utlb", S_IRUSR, sh_debugfs_root,
163                                    (unsigned int *)TLB_TYPE_UTLB,
164                                    &tlb_debugfs_fops);
165         if (unlikely(!utlb)) {
166                 debugfs_remove(itlb);
167                 return -ENOMEM;
168         }
169
170         if (IS_ERR(utlb)) {
171                 debugfs_remove(itlb);
172                 return PTR_ERR(utlb);
173         }
174
175         return 0;
176 }
177 module_init(tlb_debugfs_init);
178
179 MODULE_LICENSE("GPL v2");