diff options
author | Mike Frysinger <vapier.adi@gmail.com> | 2008-11-18 04:48:22 -0500 |
---|---|---|
committer | Bryan Wu <cooloney@kernel.org> | 2008-11-18 04:48:22 -0500 |
commit | ff4c02e4be00dccfb4b7baa8e56300b6ab3e290a (patch) | |
tree | 75093ea97d661d59f5b7e882f05cb99dbad8fae7 /arch/blackfin/kernel/cplbinfo.c | |
parent | 4db557d4aeb6a9a6713e66e222949bc93b2bf2e9 (diff) |
Blackfin arch: unify cplbinfo files
Merge MPU and noMPU version of CPLB info code to one common version.
Signed-off-by: Mike Frysinger <vapier.adi@gmail.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Diffstat (limited to 'arch/blackfin/kernel/cplbinfo.c')
-rw-r--r-- | arch/blackfin/kernel/cplbinfo.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/arch/blackfin/kernel/cplbinfo.c b/arch/blackfin/kernel/cplbinfo.c new file mode 100644 index 000000000000..dc584fe18e5f --- /dev/null +++ b/arch/blackfin/kernel/cplbinfo.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * arch/blackfin/kernel/cplbinfo.c - display CPLB status | ||
3 | * | ||
4 | * Copyright 2004-2008 Analog Devices Inc. | ||
5 | * Licensed under the GPL-2 or later. | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/proc_fs.h> | ||
12 | #include <linux/uaccess.h> | ||
13 | |||
14 | #include <asm/cplbinit.h> | ||
15 | #include <asm/blackfin.h> | ||
16 | |||
17 | typedef enum { ICPLB, DCPLB } cplb_type; | ||
18 | |||
19 | static char page_strtbl[][3] = { "1K", "4K", "1M", "4M" }; | ||
20 | #define page(flags) (((flags) & 0x30000) >> 16) | ||
21 | #define strpage(flags) page_strtbl[page(flags)] | ||
22 | |||
23 | #ifdef CONFIG_MPU | ||
24 | |||
25 | static char *cplb_print_entry(char *buf, cplb_type type, unsigned int cpu) | ||
26 | { | ||
27 | struct cplb_entry *tbl; | ||
28 | int switched; | ||
29 | int i; | ||
30 | |||
31 | if (type == ICPLB) { | ||
32 | tbl = icplb_tbl[cpu]; | ||
33 | switched = first_switched_icplb; | ||
34 | } else { | ||
35 | tbl = dcplb_tbl[cpu]; | ||
36 | switched = first_switched_dcplb; | ||
37 | } | ||
38 | |||
39 | buf += sprintf(buf, "Index\tAddress\t\tData\tSize\tU/RD\tU/WR\tS/WR\tSwitch\n"); | ||
40 | for (i = 0; i < MAX_CPLBS; ++i) { | ||
41 | unsigned long data = tbl[i].data; | ||
42 | unsigned long addr = tbl[i].addr; | ||
43 | |||
44 | if (!(data & CPLB_VALID)) | ||
45 | continue; | ||
46 | |||
47 | buf += sprintf(buf, | ||
48 | "%d\t0x%08lx\t%05lx\t%s\t%c\t%c\t%c\t%c\n", | ||
49 | i, addr, data, strpage(data), | ||
50 | (data & CPLB_USER_RD) ? 'Y' : 'N', | ||
51 | (data & CPLB_USER_WR) ? 'Y' : 'N', | ||
52 | (data & CPLB_SUPV_WR) ? 'Y' : 'N', | ||
53 | i < switched ? 'N' : 'Y'); | ||
54 | } | ||
55 | buf += sprintf(buf, "\n"); | ||
56 | |||
57 | return buf; | ||
58 | } | ||
59 | |||
60 | #else | ||
61 | |||
62 | static int page_size_table[4] = { | ||
63 | 0x00000400, /* 1K */ | ||
64 | 0x00001000, /* 4K */ | ||
65 | 0x00100000, /* 1M */ | ||
66 | 0x00400000 /* 4M */ | ||
67 | }; | ||
68 | |||
69 | static int cplb_find_entry(unsigned long *cplb_addr, | ||
70 | unsigned long *cplb_data, unsigned long addr, | ||
71 | unsigned long data) | ||
72 | { | ||
73 | int i; | ||
74 | |||
75 | for (i = 0; i < 16; ++i) | ||
76 | if (addr >= cplb_addr[i] && | ||
77 | addr < cplb_addr[i] + page_size_table[page(cplb_data[i])] && | ||
78 | cplb_data[i] == data) | ||
79 | return i; | ||
80 | |||
81 | return -1; | ||
82 | } | ||
83 | |||
84 | static char *cplb_print_entry(char *buf, cplb_type type, unsigned int cpu) | ||
85 | { | ||
86 | unsigned long *p_addr, *p_data, *p_icount, *p_ocount; | ||
87 | unsigned long *cplb_addr, *cplb_data; | ||
88 | int entry = 0, used_cplb = 0; | ||
89 | |||
90 | if (type == ICPLB) { | ||
91 | p_addr = ipdt_tables[cpu]; | ||
92 | p_data = ipdt_tables[cpu] + 1; | ||
93 | p_icount = ipdt_swapcount_tables[cpu]; | ||
94 | p_ocount = ipdt_swapcount_tables[cpu] + 1; | ||
95 | cplb_addr = (unsigned long *)ICPLB_ADDR0; | ||
96 | cplb_data = (unsigned long *)ICPLB_DATA0; | ||
97 | } else { | ||
98 | p_addr = dpdt_tables[cpu]; | ||
99 | p_data = dpdt_tables[cpu] + 1; | ||
100 | p_icount = dpdt_swapcount_tables[cpu]; | ||
101 | p_ocount = dpdt_swapcount_tables[cpu] + 1; | ||
102 | cplb_addr = (unsigned long *)DCPLB_ADDR0; | ||
103 | cplb_data = (unsigned long *)DCPLB_DATA0; | ||
104 | } | ||
105 | |||
106 | buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\tiCount\toCount\n"); | ||
107 | |||
108 | while (*p_addr != 0xffffffff) { | ||
109 | entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data); | ||
110 | if (entry >= 0) | ||
111 | used_cplb |= 1 << entry; | ||
112 | |||
113 | buf += sprintf(buf, | ||
114 | "0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n", | ||
115 | *p_addr, *p_data, strpage(*p_data), | ||
116 | (*p_data & CPLB_VALID) ? 'Y' : 'N', | ||
117 | (*p_data & CPLB_LOCK) ? 'Y' : 'N', entry, *p_icount, | ||
118 | *p_ocount); | ||
119 | |||
120 | p_addr += 2; | ||
121 | p_data += 2; | ||
122 | p_icount += 2; | ||
123 | p_ocount += 2; | ||
124 | } | ||
125 | |||
126 | if (used_cplb != 0xffff) { | ||
127 | buf += sprintf(buf, "Unused/mismatched CPLBs:\n"); | ||
128 | |||
129 | for (entry = 0; entry < 16; ++entry) | ||
130 | if (0 == ((1 << entry) & used_cplb)) { | ||
131 | int flags = cplb_data[entry]; | ||
132 | buf += sprintf(buf, | ||
133 | "%2d: 0x%08lx\t0x%05x\t%s\t%c\t%c\n", | ||
134 | entry, cplb_addr[entry], flags, strpage(flags), | ||
135 | (flags & CPLB_VALID) ? 'Y' : 'N', | ||
136 | (flags & CPLB_LOCK) ? 'Y' : 'N'); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | buf += sprintf(buf, "\n"); | ||
141 | |||
142 | return buf; | ||
143 | } | ||
144 | |||
145 | #endif | ||
146 | |||
147 | static int cplbinfo_proc_output(char *buf, void *data) | ||
148 | { | ||
149 | unsigned int cpu = (unsigned int)data; | ||
150 | char *p = buf; | ||
151 | |||
152 | if (bfin_read_IMEM_CONTROL() & ENICPLB) { | ||
153 | p += sprintf(p, "Instruction CPLB entry:\n"); | ||
154 | p = cplb_print_entry(p, ICPLB, cpu); | ||
155 | } else | ||
156 | p += sprintf(p, "Instruction CPLB is disabled.\n\n"); | ||
157 | |||
158 | if (bfin_read_DMEM_CONTROL() & ENDCPLB) { | ||
159 | p += sprintf(p, "Data CPLB entry:\n"); | ||
160 | p = cplb_print_entry(p, DCPLB, cpu); | ||
161 | } else | ||
162 | p += sprintf(p, "Data CPLB is disabled.\n\n"); | ||
163 | |||
164 | return p - buf; | ||
165 | } | ||
166 | |||
167 | static int cplbinfo_read_proc(char *page, char **start, off_t off, | ||
168 | int count, int *eof, void *data) | ||
169 | { | ||
170 | int len = cplbinfo_proc_output(page, data); | ||
171 | if (len <= off + count) | ||
172 | *eof = 1; | ||
173 | *start = page + off; | ||
174 | len -= off; | ||
175 | return max(min(len, count), 0); | ||
176 | } | ||
177 | |||
178 | static int __init cplbinfo_init(void) | ||
179 | { | ||
180 | struct proc_dir_entry *parent, *entry; | ||
181 | unsigned int cpu; | ||
182 | unsigned char str[10]; | ||
183 | |||
184 | parent = proc_mkdir("cplbinfo", NULL); | ||
185 | if (!parent) | ||
186 | return -ENOMEM; | ||
187 | |||
188 | for_each_online_cpu(cpu) { | ||
189 | sprintf(str, "cpu%u", cpu); | ||
190 | entry = create_proc_entry(str, 0, parent); | ||
191 | if (!entry) | ||
192 | return -ENOMEM; | ||
193 | |||
194 | entry->read_proc = cplbinfo_read_proc; | ||
195 | entry->data = (void *)cpu; | ||
196 | } | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | late_initcall(cplbinfo_init); | ||