Commit | Line | Data |
---|---|---|
7afc5dbd KG |
1 | /* |
2 | * Linux network driver for Brocade Converged Network Adapter. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License (GPL) Version 2 as | |
6 | * published by the Free Software Foundation | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, but | |
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
11 | * General Public License for more details. | |
12 | */ | |
13 | /* | |
14 | * Copyright (c) 2005-2011 Brocade Communications Systems, Inc. | |
15 | * All rights reserved | |
16 | * www.brocade.com | |
17 | */ | |
18 | ||
19 | #include <linux/debugfs.h> | |
20 | #include <linux/module.h> | |
21 | #include "bnad.h" | |
22 | ||
23 | /* | |
24 | * BNA debufs interface | |
25 | * | |
26 | * To access the interface, debugfs file system should be mounted | |
27 | * if not already mounted using: | |
28 | * mount -t debugfs none /sys/kernel/debug | |
29 | * | |
30 | * BNA Hierarchy: | |
31 | * - bna/pci_dev:<pci_name> | |
32 | * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bna | |
33 | * | |
34 | * Debugging service available per pci_dev: | |
35 | * fwtrc: To collect current firmware trace. | |
36 | * fwsave: To collect last saved fw trace as a result of firmware crash. | |
37 | * regwr: To write one word to chip register | |
38 | * regrd: To read one or more words from chip register. | |
39 | */ | |
40 | ||
41 | struct bnad_debug_info { | |
42 | char *debug_buffer; | |
43 | void *i_private; | |
44 | int buffer_len; | |
45 | }; | |
46 | ||
47 | static int | |
48 | bnad_debugfs_open_fwtrc(struct inode *inode, struct file *file) | |
49 | { | |
50 | struct bnad *bnad = inode->i_private; | |
51 | struct bnad_debug_info *fw_debug; | |
52 | unsigned long flags; | |
53 | int rc; | |
54 | ||
55 | fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); | |
56 | if (!fw_debug) | |
57 | return -ENOMEM; | |
58 | ||
59 | fw_debug->buffer_len = BNA_DBG_FWTRC_LEN; | |
60 | ||
61 | fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL); | |
62 | if (!fw_debug->debug_buffer) { | |
63 | kfree(fw_debug); | |
64 | fw_debug = NULL; | |
7afc5dbd KG |
65 | return -ENOMEM; |
66 | } | |
67 | ||
68 | spin_lock_irqsave(&bnad->bna_lock, flags); | |
69 | rc = bfa_nw_ioc_debug_fwtrc(&bnad->bna.ioceth.ioc, | |
70 | fw_debug->debug_buffer, | |
71 | &fw_debug->buffer_len); | |
72 | spin_unlock_irqrestore(&bnad->bna_lock, flags); | |
73 | if (rc != BFA_STATUS_OK) { | |
74 | kfree(fw_debug->debug_buffer); | |
75 | fw_debug->debug_buffer = NULL; | |
76 | kfree(fw_debug); | |
77 | fw_debug = NULL; | |
78 | pr_warn("bnad %s: Failed to collect fwtrc\n", | |
79 | pci_name(bnad->pcidev)); | |
80 | return -ENOMEM; | |
81 | } | |
82 | ||
83 | file->private_data = fw_debug; | |
84 | ||
85 | return 0; | |
86 | } | |
87 | ||
88 | static int | |
89 | bnad_debugfs_open_fwsave(struct inode *inode, struct file *file) | |
90 | { | |
91 | struct bnad *bnad = inode->i_private; | |
92 | struct bnad_debug_info *fw_debug; | |
93 | unsigned long flags; | |
94 | int rc; | |
95 | ||
96 | fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); | |
97 | if (!fw_debug) | |
98 | return -ENOMEM; | |
99 | ||
100 | fw_debug->buffer_len = BNA_DBG_FWTRC_LEN; | |
101 | ||
102 | fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL); | |
103 | if (!fw_debug->debug_buffer) { | |
104 | kfree(fw_debug); | |
105 | fw_debug = NULL; | |
7afc5dbd KG |
106 | return -ENOMEM; |
107 | } | |
108 | ||
109 | spin_lock_irqsave(&bnad->bna_lock, flags); | |
110 | rc = bfa_nw_ioc_debug_fwsave(&bnad->bna.ioceth.ioc, | |
111 | fw_debug->debug_buffer, | |
112 | &fw_debug->buffer_len); | |
113 | spin_unlock_irqrestore(&bnad->bna_lock, flags); | |
114 | if (rc != BFA_STATUS_OK && rc != BFA_STATUS_ENOFSAVE) { | |
115 | kfree(fw_debug->debug_buffer); | |
116 | fw_debug->debug_buffer = NULL; | |
117 | kfree(fw_debug); | |
118 | fw_debug = NULL; | |
119 | pr_warn("bna %s: Failed to collect fwsave\n", | |
120 | pci_name(bnad->pcidev)); | |
121 | return -ENOMEM; | |
122 | } | |
123 | ||
124 | file->private_data = fw_debug; | |
125 | ||
126 | return 0; | |
127 | } | |
128 | ||
129 | static int | |
130 | bnad_debugfs_open_reg(struct inode *inode, struct file *file) | |
131 | { | |
132 | struct bnad_debug_info *reg_debug; | |
133 | ||
134 | reg_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); | |
135 | if (!reg_debug) | |
136 | return -ENOMEM; | |
137 | ||
138 | reg_debug->i_private = inode->i_private; | |
139 | ||
140 | file->private_data = reg_debug; | |
141 | ||
142 | return 0; | |
143 | } | |
144 | ||
145 | static int | |
146 | bnad_get_debug_drvinfo(struct bnad *bnad, void *buffer, u32 len) | |
147 | { | |
148 | struct bnad_drvinfo *drvinfo = (struct bnad_drvinfo *) buffer; | |
149 | struct bnad_iocmd_comp fcomp; | |
150 | unsigned long flags = 0; | |
151 | int ret = BFA_STATUS_FAILED; | |
152 | ||
153 | /* Get IOC info */ | |
154 | spin_lock_irqsave(&bnad->bna_lock, flags); | |
155 | bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, &drvinfo->ioc_attr); | |
156 | spin_unlock_irqrestore(&bnad->bna_lock, flags); | |
157 | ||
158 | /* Retrieve CEE related info */ | |
159 | fcomp.bnad = bnad; | |
160 | fcomp.comp_status = 0; | |
161 | init_completion(&fcomp.comp); | |
162 | spin_lock_irqsave(&bnad->bna_lock, flags); | |
163 | ret = bfa_nw_cee_get_attr(&bnad->bna.cee, &drvinfo->cee_attr, | |
164 | bnad_cb_completion, &fcomp); | |
165 | if (ret != BFA_STATUS_OK) { | |
166 | spin_unlock_irqrestore(&bnad->bna_lock, flags); | |
167 | goto out; | |
168 | } | |
169 | spin_unlock_irqrestore(&bnad->bna_lock, flags); | |
170 | wait_for_completion(&fcomp.comp); | |
171 | drvinfo->cee_status = fcomp.comp_status; | |
172 | ||
173 | /* Retrieve flash partition info */ | |
174 | fcomp.comp_status = 0; | |
175 | init_completion(&fcomp.comp); | |
176 | spin_lock_irqsave(&bnad->bna_lock, flags); | |
177 | ret = bfa_nw_flash_get_attr(&bnad->bna.flash, &drvinfo->flash_attr, | |
178 | bnad_cb_completion, &fcomp); | |
179 | if (ret != BFA_STATUS_OK) { | |
180 | spin_unlock_irqrestore(&bnad->bna_lock, flags); | |
181 | goto out; | |
182 | } | |
183 | spin_unlock_irqrestore(&bnad->bna_lock, flags); | |
184 | wait_for_completion(&fcomp.comp); | |
185 | drvinfo->flash_status = fcomp.comp_status; | |
186 | out: | |
187 | return ret; | |
188 | } | |
189 | ||
190 | static int | |
191 | bnad_debugfs_open_drvinfo(struct inode *inode, struct file *file) | |
192 | { | |
193 | struct bnad *bnad = inode->i_private; | |
194 | struct bnad_debug_info *drv_info; | |
195 | int rc; | |
196 | ||
197 | drv_info = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); | |
198 | if (!drv_info) | |
199 | return -ENOMEM; | |
200 | ||
201 | drv_info->buffer_len = sizeof(struct bnad_drvinfo); | |
202 | ||
203 | drv_info->debug_buffer = kzalloc(drv_info->buffer_len, GFP_KERNEL); | |
204 | if (!drv_info->debug_buffer) { | |
205 | kfree(drv_info); | |
206 | drv_info = NULL; | |
7afc5dbd KG |
207 | return -ENOMEM; |
208 | } | |
209 | ||
210 | mutex_lock(&bnad->conf_mutex); | |
211 | rc = bnad_get_debug_drvinfo(bnad, drv_info->debug_buffer, | |
212 | drv_info->buffer_len); | |
213 | mutex_unlock(&bnad->conf_mutex); | |
214 | if (rc != BFA_STATUS_OK) { | |
215 | kfree(drv_info->debug_buffer); | |
216 | drv_info->debug_buffer = NULL; | |
217 | kfree(drv_info); | |
218 | drv_info = NULL; | |
219 | pr_warn("bna %s: Failed to collect drvinfo\n", | |
220 | pci_name(bnad->pcidev)); | |
221 | return -ENOMEM; | |
222 | } | |
223 | ||
224 | file->private_data = drv_info; | |
225 | ||
226 | return 0; | |
227 | } | |
228 | ||
229 | /* Changes the current file position */ | |
230 | static loff_t | |
231 | bnad_debugfs_lseek(struct file *file, loff_t offset, int orig) | |
232 | { | |
233 | loff_t pos = file->f_pos; | |
234 | struct bnad_debug_info *debug = file->private_data; | |
235 | ||
236 | if (!debug) | |
237 | return -EINVAL; | |
238 | ||
239 | switch (orig) { | |
240 | case 0: | |
241 | file->f_pos = offset; | |
242 | break; | |
243 | case 1: | |
244 | file->f_pos += offset; | |
245 | break; | |
246 | case 2: | |
8177a9d7 | 247 | file->f_pos = debug->buffer_len + offset; |
7afc5dbd KG |
248 | break; |
249 | default: | |
250 | return -EINVAL; | |
251 | } | |
252 | ||
253 | if (file->f_pos < 0 || file->f_pos > debug->buffer_len) { | |
254 | file->f_pos = pos; | |
255 | return -EINVAL; | |
256 | } | |
257 | ||
258 | return file->f_pos; | |
259 | } | |
260 | ||
261 | static ssize_t | |
262 | bnad_debugfs_read(struct file *file, char __user *buf, | |
263 | size_t nbytes, loff_t *pos) | |
264 | { | |
265 | struct bnad_debug_info *debug = file->private_data; | |
266 | ||
267 | if (!debug || !debug->debug_buffer) | |
268 | return 0; | |
269 | ||
270 | return simple_read_from_buffer(buf, nbytes, pos, | |
271 | debug->debug_buffer, debug->buffer_len); | |
272 | } | |
273 | ||
274 | #define BFA_REG_CT_ADDRSZ (0x40000) | |
275 | #define BFA_REG_CB_ADDRSZ (0x20000) | |
276 | #define BFA_REG_ADDRSZ(__ioc) \ | |
277 | ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \ | |
278 | BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ)) | |
279 | #define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1) | |
280 | ||
281 | /* | |
282 | * Function to check if the register offset passed is valid. | |
283 | */ | |
284 | static int | |
285 | bna_reg_offset_check(struct bfa_ioc *ioc, u32 offset, u32 len) | |
286 | { | |
287 | u8 area; | |
288 | ||
289 | /* check [16:15] */ | |
290 | area = (offset >> 15) & 0x7; | |
291 | if (area == 0) { | |
292 | /* PCIe core register */ | |
293 | if ((offset + (len<<2)) > 0x8000) /* 8k dwords or 32KB */ | |
294 | return BFA_STATUS_EINVAL; | |
295 | } else if (area == 0x1) { | |
296 | /* CB 32 KB memory page */ | |
297 | if ((offset + (len<<2)) > 0x10000) /* 8k dwords or 32KB */ | |
298 | return BFA_STATUS_EINVAL; | |
299 | } else { | |
300 | /* CB register space 64KB */ | |
301 | if ((offset + (len<<2)) > BFA_REG_ADDRMSK(ioc)) | |
302 | return BFA_STATUS_EINVAL; | |
303 | } | |
304 | return BFA_STATUS_OK; | |
305 | } | |
306 | ||
307 | static ssize_t | |
308 | bnad_debugfs_read_regrd(struct file *file, char __user *buf, | |
309 | size_t nbytes, loff_t *pos) | |
310 | { | |
311 | struct bnad_debug_info *regrd_debug = file->private_data; | |
312 | struct bnad *bnad = (struct bnad *)regrd_debug->i_private; | |
313 | ssize_t rc; | |
314 | ||
315 | if (!bnad->regdata) | |
316 | return 0; | |
317 | ||
318 | rc = simple_read_from_buffer(buf, nbytes, pos, | |
319 | bnad->regdata, bnad->reglen); | |
320 | ||
321 | if ((*pos + nbytes) >= bnad->reglen) { | |
322 | kfree(bnad->regdata); | |
323 | bnad->regdata = NULL; | |
324 | bnad->reglen = 0; | |
325 | } | |
326 | ||
327 | return rc; | |
328 | } | |
329 | ||
330 | static ssize_t | |
331 | bnad_debugfs_write_regrd(struct file *file, const char __user *buf, | |
332 | size_t nbytes, loff_t *ppos) | |
333 | { | |
334 | struct bnad_debug_info *regrd_debug = file->private_data; | |
335 | struct bnad *bnad = (struct bnad *)regrd_debug->i_private; | |
336 | struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc; | |
337 | int addr, len, rc, i; | |
338 | u32 *regbuf; | |
339 | void __iomem *rb, *reg_addr; | |
340 | unsigned long flags; | |
341 | void *kern_buf; | |
342 | ||
343 | /* Allocate memory to store the user space buf */ | |
344 | kern_buf = kzalloc(nbytes, GFP_KERNEL); | |
e404decb | 345 | if (!kern_buf) |
7afc5dbd | 346 | return -ENOMEM; |
7afc5dbd KG |
347 | |
348 | if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) { | |
349 | kfree(kern_buf); | |
350 | return -ENOMEM; | |
351 | } | |
352 | ||
353 | rc = sscanf(kern_buf, "%x:%x", &addr, &len); | |
354 | if (rc < 2) { | |
355 | pr_warn("bna %s: Failed to read user buffer\n", | |
356 | pci_name(bnad->pcidev)); | |
357 | kfree(kern_buf); | |
358 | return -EINVAL; | |
359 | } | |
360 | ||
361 | kfree(kern_buf); | |
362 | kfree(bnad->regdata); | |
363 | bnad->regdata = NULL; | |
364 | bnad->reglen = 0; | |
365 | ||
366 | bnad->regdata = kzalloc(len << 2, GFP_KERNEL); | |
e404decb | 367 | if (!bnad->regdata) |
7afc5dbd | 368 | return -ENOMEM; |
7afc5dbd KG |
369 | |
370 | bnad->reglen = len << 2; | |
371 | rb = bfa_ioc_bar0(ioc); | |
372 | addr &= BFA_REG_ADDRMSK(ioc); | |
373 | ||
374 | /* offset and len sanity check */ | |
375 | rc = bna_reg_offset_check(ioc, addr, len); | |
376 | if (rc) { | |
377 | pr_warn("bna %s: Failed reg offset check\n", | |
378 | pci_name(bnad->pcidev)); | |
379 | kfree(bnad->regdata); | |
380 | bnad->regdata = NULL; | |
381 | bnad->reglen = 0; | |
382 | return -EINVAL; | |
383 | } | |
384 | ||
385 | reg_addr = rb + addr; | |
386 | regbuf = (u32 *)bnad->regdata; | |
387 | spin_lock_irqsave(&bnad->bna_lock, flags); | |
388 | for (i = 0; i < len; i++) { | |
389 | *regbuf = readl(reg_addr); | |
390 | regbuf++; | |
391 | reg_addr += sizeof(u32); | |
392 | } | |
393 | spin_unlock_irqrestore(&bnad->bna_lock, flags); | |
394 | ||
395 | return nbytes; | |
396 | } | |
397 | ||
398 | static ssize_t | |
399 | bnad_debugfs_write_regwr(struct file *file, const char __user *buf, | |
400 | size_t nbytes, loff_t *ppos) | |
401 | { | |
402 | struct bnad_debug_info *debug = file->private_data; | |
403 | struct bnad *bnad = (struct bnad *)debug->i_private; | |
404 | struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc; | |
405 | int addr, val, rc; | |
406 | void __iomem *reg_addr; | |
407 | unsigned long flags; | |
408 | void *kern_buf; | |
409 | ||
410 | /* Allocate memory to store the user space buf */ | |
411 | kern_buf = kzalloc(nbytes, GFP_KERNEL); | |
e404decb | 412 | if (!kern_buf) |
7afc5dbd | 413 | return -ENOMEM; |
7afc5dbd KG |
414 | |
415 | if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) { | |
416 | kfree(kern_buf); | |
417 | return -ENOMEM; | |
418 | } | |
419 | ||
420 | rc = sscanf(kern_buf, "%x:%x", &addr, &val); | |
421 | if (rc < 2) { | |
422 | pr_warn("bna %s: Failed to read user buffer\n", | |
423 | pci_name(bnad->pcidev)); | |
424 | kfree(kern_buf); | |
425 | return -EINVAL; | |
426 | } | |
427 | kfree(kern_buf); | |
428 | ||
429 | addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */ | |
430 | ||
431 | /* offset and len sanity check */ | |
432 | rc = bna_reg_offset_check(ioc, addr, 1); | |
433 | if (rc) { | |
434 | pr_warn("bna %s: Failed reg offset check\n", | |
435 | pci_name(bnad->pcidev)); | |
436 | return -EINVAL; | |
437 | } | |
438 | ||
439 | reg_addr = (bfa_ioc_bar0(ioc)) + addr; | |
440 | spin_lock_irqsave(&bnad->bna_lock, flags); | |
441 | writel(val, reg_addr); | |
442 | spin_unlock_irqrestore(&bnad->bna_lock, flags); | |
443 | ||
444 | return nbytes; | |
445 | } | |
446 | ||
447 | static int | |
448 | bnad_debugfs_release(struct inode *inode, struct file *file) | |
449 | { | |
450 | struct bnad_debug_info *debug = file->private_data; | |
451 | ||
452 | if (!debug) | |
453 | return 0; | |
454 | ||
455 | file->private_data = NULL; | |
456 | kfree(debug); | |
457 | return 0; | |
458 | } | |
459 | ||
460 | static int | |
461 | bnad_debugfs_buffer_release(struct inode *inode, struct file *file) | |
462 | { | |
463 | struct bnad_debug_info *debug = file->private_data; | |
464 | ||
465 | if (!debug) | |
466 | return 0; | |
467 | ||
468 | kfree(debug->debug_buffer); | |
469 | ||
470 | file->private_data = NULL; | |
471 | kfree(debug); | |
472 | debug = NULL; | |
473 | return 0; | |
474 | } | |
475 | ||
476 | static const struct file_operations bnad_debugfs_op_fwtrc = { | |
477 | .owner = THIS_MODULE, | |
478 | .open = bnad_debugfs_open_fwtrc, | |
479 | .llseek = bnad_debugfs_lseek, | |
480 | .read = bnad_debugfs_read, | |
481 | .release = bnad_debugfs_buffer_release, | |
482 | }; | |
483 | ||
484 | static const struct file_operations bnad_debugfs_op_fwsave = { | |
485 | .owner = THIS_MODULE, | |
486 | .open = bnad_debugfs_open_fwsave, | |
487 | .llseek = bnad_debugfs_lseek, | |
488 | .read = bnad_debugfs_read, | |
489 | .release = bnad_debugfs_buffer_release, | |
490 | }; | |
491 | ||
492 | static const struct file_operations bnad_debugfs_op_regrd = { | |
493 | .owner = THIS_MODULE, | |
494 | .open = bnad_debugfs_open_reg, | |
495 | .llseek = bnad_debugfs_lseek, | |
496 | .read = bnad_debugfs_read_regrd, | |
497 | .write = bnad_debugfs_write_regrd, | |
498 | .release = bnad_debugfs_release, | |
499 | }; | |
500 | ||
501 | static const struct file_operations bnad_debugfs_op_regwr = { | |
502 | .owner = THIS_MODULE, | |
503 | .open = bnad_debugfs_open_reg, | |
504 | .llseek = bnad_debugfs_lseek, | |
505 | .write = bnad_debugfs_write_regwr, | |
506 | .release = bnad_debugfs_release, | |
507 | }; | |
508 | ||
509 | static const struct file_operations bnad_debugfs_op_drvinfo = { | |
510 | .owner = THIS_MODULE, | |
511 | .open = bnad_debugfs_open_drvinfo, | |
512 | .llseek = bnad_debugfs_lseek, | |
513 | .read = bnad_debugfs_read, | |
514 | .release = bnad_debugfs_buffer_release, | |
515 | }; | |
516 | ||
517 | struct bnad_debugfs_entry { | |
518 | const char *name; | |
88187398 | 519 | umode_t mode; |
7afc5dbd KG |
520 | const struct file_operations *fops; |
521 | }; | |
522 | ||
523 | static const struct bnad_debugfs_entry bnad_debugfs_files[] = { | |
524 | { "fwtrc", S_IFREG|S_IRUGO, &bnad_debugfs_op_fwtrc, }, | |
525 | { "fwsave", S_IFREG|S_IRUGO, &bnad_debugfs_op_fwsave, }, | |
526 | { "regrd", S_IFREG|S_IRUGO|S_IWUSR, &bnad_debugfs_op_regrd, }, | |
527 | { "regwr", S_IFREG|S_IWUSR, &bnad_debugfs_op_regwr, }, | |
528 | { "drvinfo", S_IFREG|S_IRUGO, &bnad_debugfs_op_drvinfo, }, | |
529 | }; | |
530 | ||
531 | static struct dentry *bna_debugfs_root; | |
532 | static atomic_t bna_debugfs_port_count; | |
533 | ||
534 | /* Initialize debugfs interface for BNA */ | |
535 | void | |
536 | bnad_debugfs_init(struct bnad *bnad) | |
537 | { | |
538 | const struct bnad_debugfs_entry *file; | |
539 | char name[64]; | |
540 | int i; | |
541 | ||
542 | /* Setup the BNA debugfs root directory*/ | |
543 | if (!bna_debugfs_root) { | |
544 | bna_debugfs_root = debugfs_create_dir("bna", NULL); | |
545 | atomic_set(&bna_debugfs_port_count, 0); | |
546 | if (!bna_debugfs_root) { | |
547 | pr_warn("BNA: debugfs root dir creation failed\n"); | |
548 | return; | |
549 | } | |
550 | } | |
551 | ||
552 | /* Setup the pci_dev debugfs directory for the port */ | |
553 | snprintf(name, sizeof(name), "pci_dev:%s", pci_name(bnad->pcidev)); | |
554 | if (!bnad->port_debugfs_root) { | |
555 | bnad->port_debugfs_root = | |
556 | debugfs_create_dir(name, bna_debugfs_root); | |
557 | if (!bnad->port_debugfs_root) { | |
558 | pr_warn("bna pci_dev %s: root dir creation failed\n", | |
559 | pci_name(bnad->pcidev)); | |
560 | return; | |
561 | } | |
562 | ||
563 | atomic_inc(&bna_debugfs_port_count); | |
564 | ||
565 | for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) { | |
566 | file = &bnad_debugfs_files[i]; | |
567 | bnad->bnad_dentry_files[i] = | |
568 | debugfs_create_file(file->name, | |
569 | file->mode, | |
570 | bnad->port_debugfs_root, | |
571 | bnad, | |
572 | file->fops); | |
573 | if (!bnad->bnad_dentry_files[i]) { | |
574 | pr_warn( | |
575 | "BNA pci_dev:%s: create %s entry failed\n", | |
576 | pci_name(bnad->pcidev), file->name); | |
577 | return; | |
578 | } | |
579 | } | |
580 | } | |
581 | } | |
582 | ||
583 | /* Uninitialize debugfs interface for BNA */ | |
584 | void | |
585 | bnad_debugfs_uninit(struct bnad *bnad) | |
586 | { | |
587 | int i; | |
588 | ||
589 | for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) { | |
590 | if (bnad->bnad_dentry_files[i]) { | |
591 | debugfs_remove(bnad->bnad_dentry_files[i]); | |
592 | bnad->bnad_dentry_files[i] = NULL; | |
593 | } | |
594 | } | |
595 | ||
596 | /* Remove the pci_dev debugfs directory for the port */ | |
597 | if (bnad->port_debugfs_root) { | |
598 | debugfs_remove(bnad->port_debugfs_root); | |
599 | bnad->port_debugfs_root = NULL; | |
600 | atomic_dec(&bna_debugfs_port_count); | |
601 | } | |
602 | ||
603 | /* Remove the BNA debugfs root directory */ | |
604 | if (atomic_read(&bna_debugfs_port_count) == 0) { | |
605 | debugfs_remove(bna_debugfs_root); | |
606 | bna_debugfs_root = NULL; | |
607 | } | |
608 | } |