diff options
author | Mike Frysinger <vapier.adi@gmail.com> | 2009-01-07 10:14:39 -0500 |
---|---|---|
committer | Bryan Wu <cooloney@kernel.org> | 2009-01-07 10:14:39 -0500 |
commit | a024d41bfeda183093c3e3af50e433d8de297f8b (patch) | |
tree | 5958659a8e83318e55ccab88e2d35f16de095695 /arch/blackfin/kernel/cplbinfo.c | |
parent | 73feb5c09dcf0d64beb67aa5e1f79e11a388e0ff (diff) |
Blackfin arch: rewrite cplbinfo to use seq files
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 | 316 |
1 files changed, 191 insertions, 125 deletions
diff --git a/arch/blackfin/kernel/cplbinfo.c b/arch/blackfin/kernel/cplbinfo.c index 723839da14a1..1d3bbec1a195 100644 --- a/arch/blackfin/kernel/cplbinfo.c +++ b/arch/blackfin/kernel/cplbinfo.c | |||
@@ -5,189 +5,255 @@ | |||
5 | * Licensed under the GPL-2 or later. | 5 | * Licensed under the GPL-2 or later. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/ctype.h> | ||
8 | #include <linux/module.h> | 9 | #include <linux/module.h> |
9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
10 | #include <linux/init.h> | 11 | #include <linux/init.h> |
11 | #include <linux/proc_fs.h> | 12 | #include <linux/proc_fs.h> |
13 | #include <linux/seq_file.h> | ||
12 | #include <linux/uaccess.h> | 14 | #include <linux/uaccess.h> |
13 | 15 | ||
14 | #include <asm/cplbinit.h> | 16 | #include <asm/cplbinit.h> |
15 | #include <asm/blackfin.h> | 17 | #include <asm/blackfin.h> |
16 | 18 | ||
17 | typedef enum { ICPLB, DCPLB } cplb_type; | 19 | static char const page_strtbl[][3] = { "1K", "4K", "1M", "4M" }; |
18 | |||
19 | static char page_strtbl[][3] = { "1K", "4K", "1M", "4M" }; | ||
20 | #define page(flags) (((flags) & 0x30000) >> 16) | 20 | #define page(flags) (((flags) & 0x30000) >> 16) |
21 | #define strpage(flags) page_strtbl[page(flags)] | 21 | #define strpage(flags) page_strtbl[page(flags)] |
22 | 22 | ||
23 | #ifdef CONFIG_MPU | 23 | #ifdef CONFIG_MPU |
24 | 24 | ||
25 | static char *cplb_print_entry(char *buf, cplb_type type, unsigned int cpu) | 25 | struct cplbinfo_data { |
26 | { | 26 | loff_t pos; |
27 | char cplb_type; | ||
28 | u32 mem_control; | ||
27 | struct cplb_entry *tbl; | 29 | struct cplb_entry *tbl; |
28 | int switched; | 30 | int switched; |
29 | int i; | 31 | }; |
30 | 32 | ||
31 | if (type == ICPLB) { | 33 | static void cplbinfo_print_header(struct seq_file *m) |
32 | tbl = icplb_tbl[cpu]; | 34 | { |
33 | switched = first_switched_icplb; | 35 | seq_printf(m, "Index\tAddress\t\tData\tSize\tU/RD\tU/WR\tS/WR\tSwitch\n"); |
34 | } else { | 36 | } |
35 | tbl = dcplb_tbl[cpu]; | ||
36 | switched = first_switched_dcplb; | ||
37 | } | ||
38 | 37 | ||
39 | buf += sprintf(buf, "Index\tAddress\t\tData\tSize\tU/RD\tU/WR\tS/WR\tSwitch\n"); | 38 | static int cplbinfo_nomore(struct cplbinfo_data *cdata) |
40 | for (i = 0; i < MAX_CPLBS; ++i) { | 39 | { |
41 | unsigned long data = tbl[i].data; | 40 | return cdata->pos >= MAX_CPLBS; |
42 | unsigned long addr = tbl[i].addr; | 41 | } |
43 | 42 | ||
44 | if (!(data & CPLB_VALID)) | 43 | static int cplbinfo_show(struct seq_file *m, void *p) |
45 | continue; | 44 | { |
46 | 45 | struct cplbinfo_data *cdata; | |
47 | buf += sprintf(buf, | 46 | unsigned long data, addr; |
48 | "%d\t0x%08lx\t%05lx\t%s\t%c\t%c\t%c\t%c\n", | 47 | loff_t pos; |
49 | i, addr, data, strpage(data), | 48 | |
50 | (data & CPLB_USER_RD) ? 'Y' : 'N', | 49 | cdata = p; |
51 | (data & CPLB_USER_WR) ? 'Y' : 'N', | 50 | pos = cdata->pos; |
52 | (data & CPLB_SUPV_WR) ? 'Y' : 'N', | 51 | addr = cdata->tbl[pos].addr; |
53 | i < switched ? 'N' : 'Y'); | 52 | data = cdata->tbl[pos].data; |
54 | } | 53 | |
55 | buf += sprintf(buf, "\n"); | 54 | seq_printf(m, |
55 | "%d\t0x%08lx\t%05lx\t%s\t%c\t%c\t%c\t%c\n", | ||
56 | (int)pos, addr, data, strpage(data), | ||
57 | (data & CPLB_USER_RD) ? 'Y' : 'N', | ||
58 | (data & CPLB_USER_WR) ? 'Y' : 'N', | ||
59 | (data & CPLB_SUPV_WR) ? 'Y' : 'N', | ||
60 | pos < cdata->switched ? 'N' : 'Y'); | ||
56 | 61 | ||
57 | return buf; | 62 | return 0; |
63 | } | ||
64 | |||
65 | static void cplbinfo_seq_init(struct cplbinfo_data *cdata, unsigned int cpu) | ||
66 | { | ||
67 | if (cdata->cplb_type == 'I') { | ||
68 | cdata->mem_control = bfin_read_IMEM_CONTROL(); | ||
69 | cdata->tbl = icplb_tbl[cpu]; | ||
70 | cdata->switched = first_switched_icplb; | ||
71 | } else { | ||
72 | cdata->mem_control = bfin_read_DMEM_CONTROL(); | ||
73 | cdata->tbl = dcplb_tbl[cpu]; | ||
74 | cdata->switched = first_switched_dcplb; | ||
75 | } | ||
58 | } | 76 | } |
59 | 77 | ||
60 | #else | 78 | #else |
61 | 79 | ||
80 | struct cplbinfo_data { | ||
81 | loff_t pos; | ||
82 | char cplb_type; | ||
83 | u32 mem_control; | ||
84 | unsigned long *pdt_tables, *pdt_swapcount; | ||
85 | unsigned long cplb_addr, cplb_data; | ||
86 | }; | ||
87 | |||
62 | extern int page_size_table[]; | 88 | extern int page_size_table[]; |
63 | 89 | ||
64 | static int cplb_find_entry(unsigned long *cplb_addr, | 90 | static int cplb_find_entry(unsigned long addr_tbl, unsigned long data_tbl, |
65 | unsigned long *cplb_data, unsigned long addr, | 91 | unsigned long addr_find, unsigned long data_find) |
66 | unsigned long data) | ||
67 | { | 92 | { |
68 | int i; | 93 | int i; |
69 | 94 | ||
70 | for (i = 0; i < 16; ++i) | 95 | for (i = 0; i < 16; ++i) { |
71 | if (addr >= cplb_addr[i] && | 96 | unsigned long cplb_addr = bfin_read32(addr_tbl + i * 4); |
72 | addr < cplb_addr[i] + page_size_table[page(cplb_data[i])] && | 97 | unsigned long cplb_data = bfin_read32(data_tbl + i * 4); |
73 | cplb_data[i] == data) | 98 | if (addr_find >= cplb_addr && |
99 | addr_find < cplb_addr + page_size_table[page(cplb_data)] && | ||
100 | cplb_data == data_find) | ||
74 | return i; | 101 | return i; |
102 | } | ||
75 | 103 | ||
76 | return -1; | 104 | return -1; |
77 | } | 105 | } |
78 | 106 | ||
79 | static char *cplb_print_entry(char *buf, cplb_type type, unsigned int cpu) | 107 | static void cplbinfo_print_header(struct seq_file *m) |
80 | { | 108 | { |
81 | unsigned long *p_addr, *p_data, *p_icount, *p_ocount; | 109 | seq_printf(m, "Address\t\tData\tSize\tValid\tLocked\tSwapin\tiCount\toCount\n"); |
82 | unsigned long *cplb_addr, *cplb_data; | 110 | } |
83 | int entry = 0, used_cplb = 0; | ||
84 | |||
85 | if (type == ICPLB) { | ||
86 | p_addr = ipdt_tables[cpu]; | ||
87 | p_data = ipdt_tables[cpu] + 1; | ||
88 | p_icount = ipdt_swapcount_tables[cpu]; | ||
89 | p_ocount = ipdt_swapcount_tables[cpu] + 1; | ||
90 | cplb_addr = (unsigned long *)ICPLB_ADDR0; | ||
91 | cplb_data = (unsigned long *)ICPLB_DATA0; | ||
92 | } else { | ||
93 | p_addr = dpdt_tables[cpu]; | ||
94 | p_data = dpdt_tables[cpu] + 1; | ||
95 | p_icount = dpdt_swapcount_tables[cpu]; | ||
96 | p_ocount = dpdt_swapcount_tables[cpu] + 1; | ||
97 | cplb_addr = (unsigned long *)DCPLB_ADDR0; | ||
98 | cplb_data = (unsigned long *)DCPLB_DATA0; | ||
99 | } | ||
100 | |||
101 | buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\tiCount\toCount\n"); | ||
102 | 111 | ||
103 | while (*p_addr != 0xffffffff) { | 112 | static int cplbinfo_nomore(struct cplbinfo_data *cdata) |
104 | entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data); | 113 | { |
105 | if (entry >= 0) | 114 | return cdata->pdt_tables[cdata->pos * 2] == 0xffffffff; |
106 | used_cplb |= 1 << entry; | 115 | } |
107 | 116 | ||
108 | buf += sprintf(buf, | 117 | static int cplbinfo_show(struct seq_file *m, void *p) |
109 | "0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n", | 118 | { |
110 | *p_addr, *p_data, strpage(*p_data), | 119 | struct cplbinfo_data *cdata; |
111 | (*p_data & CPLB_VALID) ? 'Y' : 'N', | 120 | unsigned long data, addr; |
112 | (*p_data & CPLB_LOCK) ? 'Y' : 'N', entry, *p_icount, | 121 | int entry; |
113 | *p_ocount); | 122 | loff_t pos; |
123 | |||
124 | cdata = p; | ||
125 | pos = cdata->pos * 2; | ||
126 | addr = cdata->pdt_tables[pos]; | ||
127 | data = cdata->pdt_tables[pos + 1]; | ||
128 | entry = cplb_find_entry(cdata->cplb_addr, cdata->cplb_data, addr, data); | ||
129 | |||
130 | seq_printf(m, | ||
131 | "0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n", | ||
132 | addr, data, strpage(data), | ||
133 | (data & CPLB_VALID) ? 'Y' : 'N', | ||
134 | (data & CPLB_LOCK) ? 'Y' : 'N', entry, | ||
135 | cdata->pdt_swapcount[pos], | ||
136 | cdata->pdt_swapcount[pos + 1]); | ||
114 | 137 | ||
115 | p_addr += 2; | 138 | return 0; |
116 | p_data += 2; | 139 | } |
117 | p_icount += 2; | ||
118 | p_ocount += 2; | ||
119 | } | ||
120 | 140 | ||
121 | if (used_cplb != 0xffff) { | 141 | static void cplbinfo_seq_init(struct cplbinfo_data *cdata, unsigned int cpu) |
122 | buf += sprintf(buf, "Unused/mismatched CPLBs:\n"); | 142 | { |
123 | 143 | if (cdata->cplb_type == 'I') { | |
124 | for (entry = 0; entry < 16; ++entry) | 144 | cdata->mem_control = bfin_read_IMEM_CONTROL(); |
125 | if (0 == ((1 << entry) & used_cplb)) { | 145 | cdata->pdt_tables = ipdt_tables[cpu]; |
126 | int flags = cplb_data[entry]; | 146 | cdata->pdt_swapcount = ipdt_swapcount_tables[cpu]; |
127 | buf += sprintf(buf, | 147 | cdata->cplb_addr = ICPLB_ADDR0; |
128 | "%2d: 0x%08lx\t0x%05x\t%s\t%c\t%c\n", | 148 | cdata->cplb_data = ICPLB_DATA0; |
129 | entry, cplb_addr[entry], flags, strpage(flags), | 149 | } else { |
130 | (flags & CPLB_VALID) ? 'Y' : 'N', | 150 | cdata->mem_control = bfin_read_DMEM_CONTROL(); |
131 | (flags & CPLB_LOCK) ? 'Y' : 'N'); | 151 | cdata->pdt_tables = dpdt_tables[cpu]; |
132 | } | 152 | cdata->pdt_swapcount = dpdt_swapcount_tables[cpu]; |
153 | cdata->cplb_addr = DCPLB_ADDR0; | ||
154 | cdata->cplb_data = DCPLB_DATA0; | ||
133 | } | 155 | } |
156 | } | ||
134 | 157 | ||
135 | buf += sprintf(buf, "\n"); | 158 | #endif |
136 | 159 | ||
137 | return buf; | 160 | static void *cplbinfo_start(struct seq_file *m, loff_t *pos) |
161 | { | ||
162 | struct cplbinfo_data *cdata = m->private; | ||
163 | |||
164 | if (!*pos) { | ||
165 | seq_printf(m, "%cCPLBs are %sabled: 0x%x\n", cdata->cplb_type, | ||
166 | (cdata->mem_control & ENDCPLB ? "en" : "dis"), | ||
167 | cdata->mem_control); | ||
168 | cplbinfo_print_header(m); | ||
169 | } else if (cplbinfo_nomore(cdata)) | ||
170 | return NULL; | ||
171 | |||
172 | get_cpu(); | ||
173 | return cdata; | ||
138 | } | 174 | } |
139 | 175 | ||
140 | #endif | 176 | static void *cplbinfo_next(struct seq_file *m, void *p, loff_t *pos) |
177 | { | ||
178 | struct cplbinfo_data *cdata = p; | ||
179 | cdata->pos = ++(*pos); | ||
180 | if (cplbinfo_nomore(cdata)) | ||
181 | return NULL; | ||
182 | else | ||
183 | return cdata; | ||
184 | } | ||
141 | 185 | ||
142 | static int cplbinfo_proc_output(char *buf, void *data) | 186 | static void cplbinfo_stop(struct seq_file *m, void *p) |
143 | { | 187 | { |
144 | unsigned int cpu = (unsigned int)data; | 188 | put_cpu(); |
145 | char *p = buf; | ||
146 | |||
147 | if (bfin_read_IMEM_CONTROL() & ENICPLB) { | ||
148 | p += sprintf(p, "Instruction CPLB entry:\n"); | ||
149 | p = cplb_print_entry(p, ICPLB, cpu); | ||
150 | } else | ||
151 | p += sprintf(p, "Instruction CPLB is disabled.\n\n"); | ||
152 | |||
153 | if (bfin_read_DMEM_CONTROL() & ENDCPLB) { | ||
154 | p += sprintf(p, "Data CPLB entry:\n"); | ||
155 | p = cplb_print_entry(p, DCPLB, cpu); | ||
156 | } else | ||
157 | p += sprintf(p, "Data CPLB is disabled.\n\n"); | ||
158 | |||
159 | return p - buf; | ||
160 | } | 189 | } |
161 | 190 | ||
162 | static int cplbinfo_read_proc(char *page, char **start, off_t off, | 191 | static const struct seq_operations cplbinfo_sops = { |
163 | int count, int *eof, void *data) | 192 | .start = cplbinfo_start, |
193 | .next = cplbinfo_next, | ||
194 | .stop = cplbinfo_stop, | ||
195 | .show = cplbinfo_show, | ||
196 | }; | ||
197 | |||
198 | static int cplbinfo_open(struct inode *inode, struct file *file) | ||
164 | { | 199 | { |
165 | int len = cplbinfo_proc_output(page, data); | 200 | char buf[256], *path, *p; |
166 | if (len <= off + count) | 201 | unsigned int cpu; |
167 | *eof = 1; | 202 | char *s_cpu, *s_cplb; |
168 | *start = page + off; | 203 | int ret; |
169 | len -= off; | 204 | struct seq_file *m; |
170 | return max(min(len, count), 0); | 205 | struct cplbinfo_data *cdata; |
206 | |||
207 | path = d_path(&file->f_path, buf, sizeof(buf)); | ||
208 | if (IS_ERR(path)) | ||
209 | return PTR_ERR(path); | ||
210 | s_cpu = strstr(path, "/cpu"); | ||
211 | s_cplb = strrchr(path, '/'); | ||
212 | if (!s_cpu || !s_cplb) | ||
213 | return -EINVAL; | ||
214 | |||
215 | cpu = simple_strtoul(s_cpu + 4, &p, 10); | ||
216 | if (!cpu_online(cpu)) | ||
217 | return -ENODEV; | ||
218 | |||
219 | ret = seq_open_private(file, &cplbinfo_sops, sizeof(*cdata)); | ||
220 | if (ret) | ||
221 | return ret; | ||
222 | m = file->private_data; | ||
223 | cdata = m->private; | ||
224 | |||
225 | cdata->pos = 0; | ||
226 | cdata->cplb_type = toupper(s_cplb[1]); | ||
227 | cplbinfo_seq_init(cdata, cpu); | ||
228 | |||
229 | return 0; | ||
171 | } | 230 | } |
172 | 231 | ||
232 | static const struct file_operations cplbinfo_fops = { | ||
233 | .open = cplbinfo_open, | ||
234 | .read = seq_read, | ||
235 | .llseek = seq_lseek, | ||
236 | .release = seq_release_private, | ||
237 | }; | ||
238 | |||
173 | static int __init cplbinfo_init(void) | 239 | static int __init cplbinfo_init(void) |
174 | { | 240 | { |
175 | struct proc_dir_entry *parent, *entry; | 241 | struct proc_dir_entry *cplb_dir, *cpu_dir; |
242 | char buf[10]; | ||
176 | unsigned int cpu; | 243 | unsigned int cpu; |
177 | unsigned char str[10]; | ||
178 | 244 | ||
179 | parent = proc_mkdir("cplbinfo", NULL); | 245 | cplb_dir = proc_mkdir("cplbinfo", NULL); |
180 | if (!parent) | 246 | if (!cplb_dir) |
181 | return -ENOMEM; | 247 | return -ENOMEM; |
182 | 248 | ||
183 | for_each_online_cpu(cpu) { | 249 | for_each_possible_cpu(cpu) { |
184 | sprintf(str, "cpu%u", cpu); | 250 | sprintf(buf, "cpu%i", cpu); |
185 | entry = create_proc_entry(str, 0, parent); | 251 | cpu_dir = proc_mkdir(buf, cplb_dir); |
186 | if (!entry) | 252 | if (!cpu_dir) |
187 | return -ENOMEM; | 253 | return -ENOMEM; |
188 | 254 | ||
189 | entry->read_proc = cplbinfo_read_proc; | 255 | proc_create("icplb", S_IRUGO, cpu_dir, &cplbinfo_fops); |
190 | entry->data = (void *)cpu; | 256 | proc_create("dcplb", S_IRUGO, cpu_dir, &cplbinfo_fops); |
191 | } | 257 | } |
192 | 258 | ||
193 | return 0; | 259 | return 0; |