diff options
author | Federico Vaga <federico.vaga@cern.ch> | 2017-07-18 02:33:03 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-08-28 10:24:21 -0400 |
commit | 2071a3e94abd34d65bd40f1ff845f9cea300dfa6 (patch) | |
tree | 7b115bbaf53ff854af74bc6b907bdd39688adc28 /drivers/fmc | |
parent | 9f757f415210a7c85e2784e4a1733ea78b2e4e88 (diff) |
drivers/fmc: The only way to dump the SDB is from debugfs
Driver should not call fmc_sdb_dump() anymore. (actually they can but the
operation is not supported, so it will print an error message)
Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
Tested-by: Pat Riehecky <riehecky@fnal.gov>
Acked-by: Alessandro Rubini <rubini@gnudd.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/fmc')
-rw-r--r-- | drivers/fmc/Makefile | 1 | ||||
-rw-r--r-- | drivers/fmc/fmc-core.c | 7 | ||||
-rw-r--r-- | drivers/fmc/fmc-debug.c | 173 | ||||
-rw-r--r-- | drivers/fmc/fmc-dump.c | 41 | ||||
-rw-r--r-- | drivers/fmc/fmc-private.h | 9 | ||||
-rw-r--r-- | drivers/fmc/fmc-sdb.c | 99 |
6 files changed, 192 insertions, 138 deletions
diff --git a/drivers/fmc/Makefile b/drivers/fmc/Makefile index b9452919739f..e809322e1bac 100644 --- a/drivers/fmc/Makefile +++ b/drivers/fmc/Makefile | |||
@@ -6,6 +6,7 @@ fmc-y += fmc-match.o | |||
6 | fmc-y += fmc-sdb.o | 6 | fmc-y += fmc-sdb.o |
7 | fmc-y += fru-parse.o | 7 | fmc-y += fru-parse.o |
8 | fmc-y += fmc-dump.o | 8 | fmc-y += fmc-dump.o |
9 | fmc-y += fmc-debug.o | ||
9 | 10 | ||
10 | obj-$(CONFIG_FMC_FAKEDEV) += fmc-fakedev.o | 11 | obj-$(CONFIG_FMC_FAKEDEV) += fmc-fakedev.o |
11 | obj-$(CONFIG_FMC_TRIVIAL) += fmc-trivial.o | 12 | obj-$(CONFIG_FMC_TRIVIAL) += fmc-trivial.o |
diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c index 5263d0607b64..ef6d8acb0a81 100644 --- a/drivers/fmc/fmc-core.c +++ b/drivers/fmc/fmc-core.c | |||
@@ -13,6 +13,9 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
15 | #include <linux/fmc.h> | 15 | #include <linux/fmc.h> |
16 | #include <linux/fmc-sdb.h> | ||
17 | |||
18 | #include "fmc-private.h" | ||
16 | 19 | ||
17 | static int fmc_check_version(unsigned long version, const char *name) | 20 | static int fmc_check_version(unsigned long version, const char *name) |
18 | { | 21 | { |
@@ -289,7 +292,7 @@ int fmc_device_register_n(struct fmc_device **devs, int n) | |||
289 | } | 292 | } |
290 | /* This device went well, give information to the user */ | 293 | /* This device went well, give information to the user */ |
291 | fmc_dump_eeprom(fmc); | 294 | fmc_dump_eeprom(fmc); |
292 | fmc_dump_sdb(fmc); | 295 | fmc_debug_init(fmc); |
293 | } | 296 | } |
294 | return 0; | 297 | return 0; |
295 | 298 | ||
@@ -301,6 +304,7 @@ out: | |||
301 | 304 | ||
302 | kfree(devarray); | 305 | kfree(devarray); |
303 | for (i--; i >= 0; i--) { | 306 | for (i--; i >= 0; i--) { |
307 | fmc_debug_exit(devs[i]); | ||
304 | sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); | 308 | sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); |
305 | device_del(&devs[i]->dev); | 309 | device_del(&devs[i]->dev); |
306 | fmc_free_id_info(devs[i]); | 310 | fmc_free_id_info(devs[i]); |
@@ -328,6 +332,7 @@ void fmc_device_unregister_n(struct fmc_device **devs, int n) | |||
328 | kfree(devs[0]->devarray); | 332 | kfree(devs[0]->devarray); |
329 | 333 | ||
330 | for (i = 0; i < n; i++) { | 334 | for (i = 0; i < n; i++) { |
335 | fmc_debug_exit(devs[i]); | ||
331 | sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); | 336 | sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); |
332 | device_del(&devs[i]->dev); | 337 | device_del(&devs[i]->dev); |
333 | fmc_free_id_info(devs[i]); | 338 | fmc_free_id_info(devs[i]); |
diff --git a/drivers/fmc/fmc-debug.c b/drivers/fmc/fmc-debug.c new file mode 100644 index 000000000000..32930722770c --- /dev/null +++ b/drivers/fmc/fmc-debug.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 CERN (www.cern.ch) | ||
3 | * Author: Federico Vaga <federico.vaga@cern.ch> | ||
4 | * | ||
5 | * Released according to the GNU GPL, version 2 or any later version. | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/device.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/debugfs.h> | ||
13 | #include <linux/seq_file.h> | ||
14 | #include <asm/byteorder.h> | ||
15 | |||
16 | #include <linux/fmc.h> | ||
17 | #include <linux/sdb.h> | ||
18 | #include <linux/fmc-sdb.h> | ||
19 | |||
20 | #define FMC_DBG_SDB_DUMP "dump_sdb" | ||
21 | |||
22 | static char *__strip_trailing_space(char *buf, char *str, int len) | ||
23 | { | ||
24 | int i = len - 1; | ||
25 | |||
26 | memcpy(buf, str, len); | ||
27 | buf[len] = '\0'; | ||
28 | while (i >= 0 && buf[i] == ' ') | ||
29 | buf[i--] = '\0'; | ||
30 | return buf; | ||
31 | } | ||
32 | |||
33 | #define __sdb_string(buf, field) ({ \ | ||
34 | BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \ | ||
35 | __strip_trailing_space(buf, (void *)(field), sizeof(field)); \ | ||
36 | }) | ||
37 | |||
38 | /** | ||
39 | * We do not check seq_printf() errors because we want to see things in any case | ||
40 | */ | ||
41 | static void fmc_sdb_dump_recursive(struct fmc_device *fmc, struct seq_file *s, | ||
42 | const struct sdb_array *arr) | ||
43 | { | ||
44 | unsigned long base = arr->baseaddr; | ||
45 | int i, j, n = arr->len, level = arr->level; | ||
46 | char tmp[64]; | ||
47 | |||
48 | for (i = 0; i < n; i++) { | ||
49 | union sdb_record *r; | ||
50 | struct sdb_product *p; | ||
51 | struct sdb_component *c; | ||
52 | |||
53 | r = &arr->record[i]; | ||
54 | c = &r->dev.sdb_component; | ||
55 | p = &c->product; | ||
56 | |||
57 | for (j = 0; j < level; j++) | ||
58 | seq_printf(s, " "); | ||
59 | switch (r->empty.record_type) { | ||
60 | case sdb_type_interconnect: | ||
61 | seq_printf(s, "%08llx:%08x %.19s\n", | ||
62 | __be64_to_cpu(p->vendor_id), | ||
63 | __be32_to_cpu(p->device_id), | ||
64 | p->name); | ||
65 | break; | ||
66 | case sdb_type_device: | ||
67 | seq_printf(s, "%08llx:%08x %.19s (%08llx-%08llx)\n", | ||
68 | __be64_to_cpu(p->vendor_id), | ||
69 | __be32_to_cpu(p->device_id), | ||
70 | p->name, | ||
71 | __be64_to_cpu(c->addr_first) + base, | ||
72 | __be64_to_cpu(c->addr_last) + base); | ||
73 | break; | ||
74 | case sdb_type_bridge: | ||
75 | seq_printf(s, "%08llx:%08x %.19s (bridge: %08llx)\n", | ||
76 | __be64_to_cpu(p->vendor_id), | ||
77 | __be32_to_cpu(p->device_id), | ||
78 | p->name, | ||
79 | __be64_to_cpu(c->addr_first) + base); | ||
80 | if (IS_ERR(arr->subtree[i])) { | ||
81 | seq_printf(s, "SDB: (bridge error %li)\n", | ||
82 | PTR_ERR(arr->subtree[i])); | ||
83 | break; | ||
84 | } | ||
85 | fmc_sdb_dump_recursive(fmc, s, arr->subtree[i]); | ||
86 | break; | ||
87 | case sdb_type_integration: | ||
88 | seq_printf(s, "integration\n"); | ||
89 | break; | ||
90 | case sdb_type_repo_url: | ||
91 | seq_printf(s, "Synthesis repository: %s\n", | ||
92 | __sdb_string(tmp, r->repo_url.repo_url)); | ||
93 | break; | ||
94 | case sdb_type_synthesis: | ||
95 | seq_printf(s, "Bitstream '%s' ", | ||
96 | __sdb_string(tmp, r->synthesis.syn_name)); | ||
97 | seq_printf(s, "synthesized %08x by %s ", | ||
98 | __be32_to_cpu(r->synthesis.date), | ||
99 | __sdb_string(tmp, r->synthesis.user_name)); | ||
100 | seq_printf(s, "(%s version %x), ", | ||
101 | __sdb_string(tmp, r->synthesis.tool_name), | ||
102 | __be32_to_cpu(r->synthesis.tool_version)); | ||
103 | seq_printf(s, "commit %pm\n", | ||
104 | r->synthesis.commit_id); | ||
105 | break; | ||
106 | case sdb_type_empty: | ||
107 | seq_printf(s, "empty\n"); | ||
108 | break; | ||
109 | default: | ||
110 | seq_printf(s, "UNKNOWN TYPE 0x%02x\n", | ||
111 | r->empty.record_type); | ||
112 | break; | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | |||
117 | static int fmc_sdb_dump(struct seq_file *s, void *offset) | ||
118 | { | ||
119 | struct fmc_device *fmc = s->private; | ||
120 | |||
121 | if (!fmc->sdb) { | ||
122 | seq_printf(s, "no SDB information\n"); | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | seq_printf(s, "FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev), | ||
127 | fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev)); | ||
128 | /* Dump SDB information */ | ||
129 | fmc_sdb_dump_recursive(fmc, s, fmc->sdb); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | |||
135 | static int fmc_sdb_dump_open(struct inode *inode, struct file *file) | ||
136 | { | ||
137 | struct fmc_device *fmc = inode->i_private; | ||
138 | |||
139 | return single_open(file, fmc_sdb_dump, fmc); | ||
140 | } | ||
141 | |||
142 | |||
143 | const struct file_operations fmc_dbgfs_sdb_dump = { | ||
144 | .owner = THIS_MODULE, | ||
145 | .open = fmc_sdb_dump_open, | ||
146 | .read = seq_read, | ||
147 | .llseek = seq_lseek, | ||
148 | .release = single_release, | ||
149 | }; | ||
150 | |||
151 | int fmc_debug_init(struct fmc_device *fmc) | ||
152 | { | ||
153 | fmc->dbg_dir = debugfs_create_dir(dev_name(&fmc->dev), NULL); | ||
154 | if (IS_ERR_OR_NULL(fmc->dbg_dir)) { | ||
155 | pr_err("FMC: Cannot create debugfs\n"); | ||
156 | return PTR_ERR(fmc->dbg_dir); | ||
157 | } | ||
158 | |||
159 | fmc->dbg_sdb_dump = debugfs_create_file(FMC_DBG_SDB_DUMP, 0444, | ||
160 | fmc->dbg_dir, fmc, | ||
161 | &fmc_dbgfs_sdb_dump); | ||
162 | if (IS_ERR_OR_NULL(fmc->dbg_sdb_dump)) | ||
163 | pr_err("FMC: Cannot create debugfs file %s\n", | ||
164 | FMC_DBG_SDB_DUMP); | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | void fmc_debug_exit(struct fmc_device *fmc) | ||
170 | { | ||
171 | if (fmc->dbg_dir) | ||
172 | debugfs_remove_recursive(fmc->dbg_dir); | ||
173 | } | ||
diff --git a/drivers/fmc/fmc-dump.c b/drivers/fmc/fmc-dump.c index c91afd6388f6..cd1df475b254 100644 --- a/drivers/fmc/fmc-dump.c +++ b/drivers/fmc/fmc-dump.c | |||
@@ -15,8 +15,6 @@ | |||
15 | 15 | ||
16 | static int fmc_must_dump_eeprom; | 16 | static int fmc_must_dump_eeprom; |
17 | module_param_named(dump_eeprom, fmc_must_dump_eeprom, int, 0644); | 17 | module_param_named(dump_eeprom, fmc_must_dump_eeprom, int, 0644); |
18 | static int fmc_must_dump_sdb; | ||
19 | module_param_named(dump_sdb, fmc_must_dump_sdb, int, 0644); | ||
20 | 18 | ||
21 | #define LINELEN 16 | 19 | #define LINELEN 16 |
22 | 20 | ||
@@ -59,42 +57,3 @@ void fmc_dump_eeprom(const struct fmc_device *fmc) | |||
59 | for (i = 0; i < fmc->eeprom_len; i += LINELEN, line += LINELEN) | 57 | for (i = 0; i < fmc->eeprom_len; i += LINELEN, line += LINELEN) |
60 | prev = dump_line(i, line, prev); | 58 | prev = dump_line(i, line, prev); |
61 | } | 59 | } |
62 | |||
63 | void fmc_dump_sdb(const struct fmc_device *fmc) | ||
64 | { | ||
65 | const uint8_t *line, *prev; | ||
66 | int i, len; | ||
67 | |||
68 | if (!fmc->sdb) | ||
69 | return; | ||
70 | if (!fmc_must_dump_sdb) | ||
71 | return; | ||
72 | |||
73 | /* If the argument is not-zero, do simple dump (== show) */ | ||
74 | if (fmc_must_dump_sdb > 0) | ||
75 | fmc_show_sdb_tree(fmc); | ||
76 | |||
77 | if (fmc_must_dump_sdb == 1) | ||
78 | return; | ||
79 | |||
80 | /* If bigger than 1, dump it seriously, to help debugging */ | ||
81 | |||
82 | /* | ||
83 | * Here we should really use libsdbfs (which is designed to | ||
84 | * work in kernel space as well) , but it doesn't support | ||
85 | * directories yet, and it requires better intergration (it | ||
86 | * should be used instead of fmc-specific code). | ||
87 | * | ||
88 | * So, lazily, just dump the top-level array | ||
89 | */ | ||
90 | pr_info("FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev), | ||
91 | fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev)); | ||
92 | pr_info("FMC: poor dump of sdb first level:\n"); | ||
93 | |||
94 | len = fmc->sdb->len * sizeof(union sdb_record); | ||
95 | line = (void *)fmc->sdb->record; | ||
96 | prev = NULL; | ||
97 | for (i = 0; i < len; i += LINELEN, line += LINELEN) | ||
98 | prev = dump_line(i, line, prev); | ||
99 | return; | ||
100 | } | ||
diff --git a/drivers/fmc/fmc-private.h b/drivers/fmc/fmc-private.h new file mode 100644 index 000000000000..1e5136643bdc --- /dev/null +++ b/drivers/fmc/fmc-private.h | |||
@@ -0,0 +1,9 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 CERN (www.cern.ch) | ||
3 | * Author: Federico Vaga <federico.vaga@cern.ch> | ||
4 | * | ||
5 | * Released according to the GNU GPL, version 2 or any later version. | ||
6 | */ | ||
7 | |||
8 | extern int fmc_debug_init(struct fmc_device *fmc); | ||
9 | extern void fmc_debug_exit(struct fmc_device *fmc); | ||
diff --git a/drivers/fmc/fmc-sdb.c b/drivers/fmc/fmc-sdb.c index 4603fdb74465..89e37a6cfc66 100644 --- a/drivers/fmc/fmc-sdb.c +++ b/drivers/fmc/fmc-sdb.c | |||
@@ -145,108 +145,15 @@ int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw, | |||
145 | sdb_entry); | 145 | sdb_entry); |
146 | return -ENODEV; | 146 | return -ENODEV; |
147 | } | 147 | } |
148 | fmc_dump_sdb(fmc); | 148 | |
149 | return 0; | 149 | return 0; |
150 | } | 150 | } |
151 | EXPORT_SYMBOL(fmc_reprogram); | 151 | EXPORT_SYMBOL(fmc_reprogram); |
152 | 152 | ||
153 | static char *__strip_trailing_space(char *buf, char *str, int len) | ||
154 | { | ||
155 | int i = len - 1; | ||
156 | |||
157 | memcpy(buf, str, len); | ||
158 | while(i >= 0 && buf[i] == ' ') | ||
159 | buf[i--] = '\0'; | ||
160 | return buf; | ||
161 | } | ||
162 | |||
163 | #define __sdb_string(buf, field) ({ \ | ||
164 | BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \ | ||
165 | __strip_trailing_space(buf, (void *)(field), sizeof(field)); \ | ||
166 | }) | ||
167 | |||
168 | static void __fmc_show_sdb_tree(const struct fmc_device *fmc, | ||
169 | const struct sdb_array *arr) | ||
170 | { | ||
171 | unsigned long base = arr->baseaddr; | ||
172 | int i, j, n = arr->len, level = arr->level; | ||
173 | char buf[64]; | ||
174 | |||
175 | for (i = 0; i < n; i++) { | ||
176 | union sdb_record *r; | ||
177 | struct sdb_product *p; | ||
178 | struct sdb_component *c; | ||
179 | r = &arr->record[i]; | ||
180 | c = &r->dev.sdb_component; | ||
181 | p = &c->product; | ||
182 | |||
183 | dev_info(&fmc->dev, "SDB: "); | ||
184 | |||
185 | for (j = 0; j < level; j++) | ||
186 | printk(KERN_CONT " "); | ||
187 | switch (r->empty.record_type) { | ||
188 | case sdb_type_interconnect: | ||
189 | printk(KERN_CONT "%08llx:%08x %.19s\n", | ||
190 | __be64_to_cpu(p->vendor_id), | ||
191 | __be32_to_cpu(p->device_id), | ||
192 | p->name); | ||
193 | break; | ||
194 | case sdb_type_device: | ||
195 | printk(KERN_CONT "%08llx:%08x %.19s (%08llx-%08llx)\n", | ||
196 | __be64_to_cpu(p->vendor_id), | ||
197 | __be32_to_cpu(p->device_id), | ||
198 | p->name, | ||
199 | __be64_to_cpu(c->addr_first) + base, | ||
200 | __be64_to_cpu(c->addr_last) + base); | ||
201 | break; | ||
202 | case sdb_type_bridge: | ||
203 | printk(KERN_CONT "%08llx:%08x %.19s (bridge: %08llx)\n", | ||
204 | __be64_to_cpu(p->vendor_id), | ||
205 | __be32_to_cpu(p->device_id), | ||
206 | p->name, | ||
207 | __be64_to_cpu(c->addr_first) + base); | ||
208 | if (IS_ERR(arr->subtree[i])) { | ||
209 | dev_info(&fmc->dev, "SDB: (bridge error %li)\n", | ||
210 | PTR_ERR(arr->subtree[i])); | ||
211 | break; | ||
212 | } | ||
213 | __fmc_show_sdb_tree(fmc, arr->subtree[i]); | ||
214 | break; | ||
215 | case sdb_type_integration: | ||
216 | printk(KERN_CONT "integration\n"); | ||
217 | break; | ||
218 | case sdb_type_repo_url: | ||
219 | printk(KERN_CONT "Synthesis repository: %s\n", | ||
220 | __sdb_string(buf, r->repo_url.repo_url)); | ||
221 | break; | ||
222 | case sdb_type_synthesis: | ||
223 | printk(KERN_CONT "Bitstream '%s' ", | ||
224 | __sdb_string(buf, r->synthesis.syn_name)); | ||
225 | printk(KERN_CONT "synthesized %08x by %s ", | ||
226 | __be32_to_cpu(r->synthesis.date), | ||
227 | __sdb_string(buf, r->synthesis.user_name)); | ||
228 | printk(KERN_CONT "(%s version %x), ", | ||
229 | __sdb_string(buf, r->synthesis.tool_name), | ||
230 | __be32_to_cpu(r->synthesis.tool_version)); | ||
231 | printk(KERN_CONT "commit %pm\n", | ||
232 | r->synthesis.commit_id); | ||
233 | break; | ||
234 | case sdb_type_empty: | ||
235 | printk(KERN_CONT "empty\n"); | ||
236 | break; | ||
237 | default: | ||
238 | printk(KERN_CONT "UNKNOWN TYPE 0x%02x\n", | ||
239 | r->empty.record_type); | ||
240 | break; | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | |||
245 | void fmc_show_sdb_tree(const struct fmc_device *fmc) | 153 | void fmc_show_sdb_tree(const struct fmc_device *fmc) |
246 | { | 154 | { |
247 | if (!fmc->sdb) | 155 | pr_err("%s: not supported anymore, use debugfs to dump SDB\n", |
248 | return; | 156 | __func__); |
249 | __fmc_show_sdb_tree(fmc, fmc->sdb); | ||
250 | } | 157 | } |
251 | EXPORT_SYMBOL(fmc_show_sdb_tree); | 158 | EXPORT_SYMBOL(fmc_show_sdb_tree); |
252 | 159 | ||