Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
bfad_debugfs.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
3  * All rights reserved
4  * www.brocade.com
5  *
6  * Linux driver for Brocade Fibre Channel Host Bus Adapter.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License (GPL) Version 2 as
10  * published by the Free Software Foundation
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  */
17 
18 #include <linux/debugfs.h>
19 #include <linux/export.h>
20 
21 #include "bfad_drv.h"
22 #include "bfad_im.h"
23 
24 /*
25  * BFA debufs interface
26  *
27  * To access the interface, debugfs file system should be mounted
28  * if not already mounted using:
29  * mount -t debugfs none /sys/kernel/debug
30  *
31  * BFA Hierarchy:
32  * - bfa/pci_dev:<pci_name>
33  * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bfa
34  *
35  * Debugging service available per pci_dev:
36  * fwtrc: To collect current firmware trace.
37  * drvtrc: To collect current driver trace
38  * fwsave: To collect last saved fw trace as a result of firmware crash.
39  * regwr: To write one word to chip register
40  * regrd: To read one or more words from chip register.
41  */
42 
44  char *debug_buffer;
45  void *i_private;
47 };
48 
49 static int
50 bfad_debugfs_open_drvtrc(struct inode *inode, struct file *file)
51 {
52  struct bfad_port_s *port = inode->i_private;
53  struct bfad_s *bfad = port->bfad;
54  struct bfad_debug_info *debug;
55 
56  debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
57  if (!debug)
58  return -ENOMEM;
59 
60  debug->debug_buffer = (void *) bfad->trcmod;
61  debug->buffer_len = sizeof(struct bfa_trc_mod_s);
62 
63  file->private_data = debug;
64 
65  return 0;
66 }
67 
68 static int
69 bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
70 {
71  struct bfad_port_s *port = inode->i_private;
72  struct bfad_s *bfad = port->bfad;
73  struct bfad_debug_info *fw_debug;
74  unsigned long flags;
75  int rc;
76 
77  fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
78  if (!fw_debug)
79  return -ENOMEM;
80 
81  fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
82 
83  fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len);
84  if (!fw_debug->debug_buffer) {
85  kfree(fw_debug);
86  printk(KERN_INFO "bfad[%d]: Failed to allocate fwtrc buffer\n",
87  bfad->inst_no);
88  return -ENOMEM;
89  }
90 
91  memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len);
92 
93  spin_lock_irqsave(&bfad->bfad_lock, flags);
94  rc = bfa_ioc_debug_fwtrc(&bfad->bfa.ioc,
95  fw_debug->debug_buffer,
96  &fw_debug->buffer_len);
97  spin_unlock_irqrestore(&bfad->bfad_lock, flags);
98  if (rc != BFA_STATUS_OK) {
99  vfree(fw_debug->debug_buffer);
100  fw_debug->debug_buffer = NULL;
101  kfree(fw_debug);
102  printk(KERN_INFO "bfad[%d]: Failed to collect fwtrc\n",
103  bfad->inst_no);
104  return -ENOMEM;
105  }
106 
107  file->private_data = fw_debug;
108 
109  return 0;
110 }
111 
112 static int
113 bfad_debugfs_open_fwsave(struct inode *inode, struct file *file)
114 {
115  struct bfad_port_s *port = inode->i_private;
116  struct bfad_s *bfad = port->bfad;
117  struct bfad_debug_info *fw_debug;
118  unsigned long flags;
119  int rc;
120 
121  fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
122  if (!fw_debug)
123  return -ENOMEM;
124 
125  fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
126 
127  fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len);
128  if (!fw_debug->debug_buffer) {
129  kfree(fw_debug);
130  printk(KERN_INFO "bfad[%d]: Failed to allocate fwsave buffer\n",
131  bfad->inst_no);
132  return -ENOMEM;
133  }
134 
135  memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len);
136 
137  spin_lock_irqsave(&bfad->bfad_lock, flags);
138  rc = bfa_ioc_debug_fwsave(&bfad->bfa.ioc,
139  fw_debug->debug_buffer,
140  &fw_debug->buffer_len);
141  spin_unlock_irqrestore(&bfad->bfad_lock, flags);
142  if (rc != BFA_STATUS_OK) {
143  vfree(fw_debug->debug_buffer);
144  fw_debug->debug_buffer = NULL;
145  kfree(fw_debug);
146  printk(KERN_INFO "bfad[%d]: Failed to collect fwsave\n",
147  bfad->inst_no);
148  return -ENOMEM;
149  }
150 
151  file->private_data = fw_debug;
152 
153  return 0;
154 }
155 
156 static int
157 bfad_debugfs_open_reg(struct inode *inode, struct file *file)
158 {
159  struct bfad_debug_info *reg_debug;
160 
161  reg_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
162  if (!reg_debug)
163  return -ENOMEM;
164 
165  reg_debug->i_private = inode->i_private;
166 
167  file->private_data = reg_debug;
168 
169  return 0;
170 }
171 
172 /* Changes the current file position */
173 static loff_t
174 bfad_debugfs_lseek(struct file *file, loff_t offset, int orig)
175 {
176  struct bfad_debug_info *debug;
177  loff_t pos = file->f_pos;
178 
179  debug = file->private_data;
180 
181  switch (orig) {
182  case 0:
183  file->f_pos = offset;
184  break;
185  case 1:
186  file->f_pos += offset;
187  break;
188  case 2:
189  file->f_pos = debug->buffer_len - offset;
190  break;
191  default:
192  return -EINVAL;
193  }
194 
195  if (file->f_pos < 0 || file->f_pos > debug->buffer_len) {
196  file->f_pos = pos;
197  return -EINVAL;
198  }
199 
200  return file->f_pos;
201 }
202 
203 static ssize_t
204 bfad_debugfs_read(struct file *file, char __user *buf,
205  size_t nbytes, loff_t *pos)
206 {
207  struct bfad_debug_info *debug = file->private_data;
208 
209  if (!debug || !debug->debug_buffer)
210  return 0;
211 
212  return simple_read_from_buffer(buf, nbytes, pos,
213  debug->debug_buffer, debug->buffer_len);
214 }
215 
216 #define BFA_REG_CT_ADDRSZ (0x40000)
217 #define BFA_REG_CB_ADDRSZ (0x20000)
218 #define BFA_REG_ADDRSZ(__ioc) \
219  ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \
220  BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ))
221 #define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1)
222 
223 static bfa_status_t
224 bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len)
225 {
226  u8 area;
227 
228  /* check [16:15] */
229  area = (offset >> 15) & 0x7;
230  if (area == 0) {
231  /* PCIe core register */
232  if ((offset + (len<<2)) > 0x8000) /* 8k dwords or 32KB */
233  return BFA_STATUS_EINVAL;
234  } else if (area == 0x1) {
235  /* CB 32 KB memory page */
236  if ((offset + (len<<2)) > 0x10000) /* 8k dwords or 32KB */
237  return BFA_STATUS_EINVAL;
238  } else {
239  /* CB register space 64KB */
240  if ((offset + (len<<2)) > BFA_REG_ADDRMSK(&bfa->ioc))
241  return BFA_STATUS_EINVAL;
242  }
243  return BFA_STATUS_OK;
244 }
245 
246 static ssize_t
247 bfad_debugfs_read_regrd(struct file *file, char __user *buf,
248  size_t nbytes, loff_t *pos)
249 {
250  struct bfad_debug_info *regrd_debug = file->private_data;
251  struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
252  struct bfad_s *bfad = port->bfad;
253  ssize_t rc;
254 
255  if (!bfad->regdata)
256  return 0;
257 
258  rc = simple_read_from_buffer(buf, nbytes, pos,
259  bfad->regdata, bfad->reglen);
260 
261  if ((*pos + nbytes) >= bfad->reglen) {
262  kfree(bfad->regdata);
263  bfad->regdata = NULL;
264  bfad->reglen = 0;
265  }
266 
267  return rc;
268 }
269 
270 static ssize_t
271 bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
272  size_t nbytes, loff_t *ppos)
273 {
274  struct bfad_debug_info *regrd_debug = file->private_data;
275  struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
276  struct bfad_s *bfad = port->bfad;
277  struct bfa_s *bfa = &bfad->bfa;
278  struct bfa_ioc_s *ioc = &bfa->ioc;
279  int addr, len, rc, i;
280  u32 *regbuf;
281  void __iomem *rb, *reg_addr;
282  unsigned long flags;
283  void *kern_buf;
284 
285  kern_buf = kzalloc(nbytes, GFP_KERNEL);
286 
287  if (!kern_buf) {
288  printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n",
289  bfad->inst_no);
290  return -ENOMEM;
291  }
292 
293  if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
294  kfree(kern_buf);
295  return -ENOMEM;
296  }
297 
298  rc = sscanf(kern_buf, "%x:%x", &addr, &len);
299  if (rc < 2) {
301  "bfad[%d]: %s failed to read user buf\n",
302  bfad->inst_no, __func__);
303  kfree(kern_buf);
304  return -EINVAL;
305  }
306 
307  kfree(kern_buf);
308  kfree(bfad->regdata);
309  bfad->regdata = NULL;
310  bfad->reglen = 0;
311 
312  bfad->regdata = kzalloc(len << 2, GFP_KERNEL);
313  if (!bfad->regdata) {
314  printk(KERN_INFO "bfad[%d]: Failed to allocate regrd buffer\n",
315  bfad->inst_no);
316  return -ENOMEM;
317  }
318 
319  bfad->reglen = len << 2;
320  rb = bfa_ioc_bar0(ioc);
321  addr &= BFA_REG_ADDRMSK(ioc);
322 
323  /* offset and len sanity check */
324  rc = bfad_reg_offset_check(bfa, addr, len);
325  if (rc) {
326  printk(KERN_INFO "bfad[%d]: Failed reg offset check\n",
327  bfad->inst_no);
328  kfree(bfad->regdata);
329  bfad->regdata = NULL;
330  bfad->reglen = 0;
331  return -EINVAL;
332  }
333 
334  reg_addr = rb + addr;
335  regbuf = (u32 *)bfad->regdata;
336  spin_lock_irqsave(&bfad->bfad_lock, flags);
337  for (i = 0; i < len; i++) {
338  *regbuf = readl(reg_addr);
339  regbuf++;
340  reg_addr += sizeof(u32);
341  }
342  spin_unlock_irqrestore(&bfad->bfad_lock, flags);
343 
344  return nbytes;
345 }
346 
347 static ssize_t
348 bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
349  size_t nbytes, loff_t *ppos)
350 {
351  struct bfad_debug_info *debug = file->private_data;
352  struct bfad_port_s *port = (struct bfad_port_s *)debug->i_private;
353  struct bfad_s *bfad = port->bfad;
354  struct bfa_s *bfa = &bfad->bfa;
355  struct bfa_ioc_s *ioc = &bfa->ioc;
356  int addr, val, rc;
357  void __iomem *reg_addr;
358  unsigned long flags;
359  void *kern_buf;
360 
361  kern_buf = kzalloc(nbytes, GFP_KERNEL);
362 
363  if (!kern_buf) {
364  printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n",
365  bfad->inst_no);
366  return -ENOMEM;
367  }
368 
369  if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
370  kfree(kern_buf);
371  return -ENOMEM;
372  }
373 
374  rc = sscanf(kern_buf, "%x:%x", &addr, &val);
375  if (rc < 2) {
377  "bfad[%d]: %s failed to read user buf\n",
378  bfad->inst_no, __func__);
379  kfree(kern_buf);
380  return -EINVAL;
381  }
382  kfree(kern_buf);
383 
384  addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */
385 
386  /* offset and len sanity check */
387  rc = bfad_reg_offset_check(bfa, addr, 1);
388  if (rc) {
390  "bfad[%d]: Failed reg offset check\n",
391  bfad->inst_no);
392  return -EINVAL;
393  }
394 
395  reg_addr = (bfa_ioc_bar0(ioc)) + addr;
396  spin_lock_irqsave(&bfad->bfad_lock, flags);
397  writel(val, reg_addr);
398  spin_unlock_irqrestore(&bfad->bfad_lock, flags);
399 
400  return nbytes;
401 }
402 
403 static int
404 bfad_debugfs_release(struct inode *inode, struct file *file)
405 {
406  struct bfad_debug_info *debug = file->private_data;
407 
408  if (!debug)
409  return 0;
410 
411  file->private_data = NULL;
412  kfree(debug);
413  return 0;
414 }
415 
416 static int
417 bfad_debugfs_release_fwtrc(struct inode *inode, struct file *file)
418 {
419  struct bfad_debug_info *fw_debug = file->private_data;
420 
421  if (!fw_debug)
422  return 0;
423 
424  if (fw_debug->debug_buffer)
425  vfree(fw_debug->debug_buffer);
426 
427  file->private_data = NULL;
428  kfree(fw_debug);
429  return 0;
430 }
431 
432 static const struct file_operations bfad_debugfs_op_drvtrc = {
433  .owner = THIS_MODULE,
434  .open = bfad_debugfs_open_drvtrc,
435  .llseek = bfad_debugfs_lseek,
436  .read = bfad_debugfs_read,
437  .release = bfad_debugfs_release,
438 };
439 
440 static const struct file_operations bfad_debugfs_op_fwtrc = {
441  .owner = THIS_MODULE,
442  .open = bfad_debugfs_open_fwtrc,
443  .llseek = bfad_debugfs_lseek,
444  .read = bfad_debugfs_read,
445  .release = bfad_debugfs_release_fwtrc,
446 };
447 
448 static const struct file_operations bfad_debugfs_op_fwsave = {
449  .owner = THIS_MODULE,
450  .open = bfad_debugfs_open_fwsave,
451  .llseek = bfad_debugfs_lseek,
452  .read = bfad_debugfs_read,
453  .release = bfad_debugfs_release_fwtrc,
454 };
455 
456 static const struct file_operations bfad_debugfs_op_regrd = {
457  .owner = THIS_MODULE,
458  .open = bfad_debugfs_open_reg,
459  .llseek = bfad_debugfs_lseek,
460  .read = bfad_debugfs_read_regrd,
461  .write = bfad_debugfs_write_regrd,
462  .release = bfad_debugfs_release,
463 };
464 
465 static const struct file_operations bfad_debugfs_op_regwr = {
466  .owner = THIS_MODULE,
467  .open = bfad_debugfs_open_reg,
468  .llseek = bfad_debugfs_lseek,
469  .write = bfad_debugfs_write_regwr,
470  .release = bfad_debugfs_release,
471 };
472 
474  const char *name;
476  const struct file_operations *fops;
477 };
478 
479 static const struct bfad_debugfs_entry bfad_debugfs_files[] = {
480  { "drvtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_drvtrc, },
481  { "fwtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwtrc, },
482  { "fwsave", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwsave, },
483  { "regrd", S_IFREG|S_IRUGO|S_IWUSR, &bfad_debugfs_op_regrd, },
484  { "regwr", S_IFREG|S_IWUSR, &bfad_debugfs_op_regwr, },
485 };
486 
487 static struct dentry *bfa_debugfs_root;
488 static atomic_t bfa_debugfs_port_count;
489 
490 inline void
492 {
493  struct bfad_s *bfad = port->bfad;
494  const struct bfad_debugfs_entry *file;
495  char name[64];
496  int i;
497 
498  if (!bfa_debugfs_enable)
499  return;
500 
501  /* Setup the BFA debugfs root directory*/
502  if (!bfa_debugfs_root) {
503  bfa_debugfs_root = debugfs_create_dir("bfa", NULL);
504  atomic_set(&bfa_debugfs_port_count, 0);
505  if (!bfa_debugfs_root) {
507  "BFA debugfs root dir creation failed\n");
508  goto err;
509  }
510  }
511 
512  /* Setup the pci_dev debugfs directory for the port */
513  snprintf(name, sizeof(name), "pci_dev:%s", bfad->pci_name);
514  if (!port->port_debugfs_root) {
515  port->port_debugfs_root =
516  debugfs_create_dir(name, bfa_debugfs_root);
517  if (!port->port_debugfs_root) {
519  "bfa %s: debugfs root creation failed\n",
520  bfad->pci_name);
521  goto err;
522  }
523 
524  atomic_inc(&bfa_debugfs_port_count);
525 
526  for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
527  file = &bfad_debugfs_files[i];
528  bfad->bfad_dentry_files[i] =
530  file->mode,
531  port->port_debugfs_root,
532  port,
533  file->fops);
534  if (!bfad->bfad_dentry_files[i]) {
536  "bfa %s: debugfs %s creation failed\n",
537  bfad->pci_name, file->name);
538  goto err;
539  }
540  }
541  }
542 
543 err:
544  return;
545 }
546 
547 inline void
549 {
550  struct bfad_s *bfad = port->bfad;
551  int i;
552 
553  for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
554  if (bfad->bfad_dentry_files[i]) {
556  bfad->bfad_dentry_files[i] = NULL;
557  }
558  }
559 
560  /* Remove the pci_dev debugfs directory for the port */
561  if (port->port_debugfs_root) {
563  port->port_debugfs_root = NULL;
564  atomic_dec(&bfa_debugfs_port_count);
565  }
566 
567  /* Remove the BFA debugfs root directory */
568  if (atomic_read(&bfa_debugfs_port_count) == 0) {
569  debugfs_remove(bfa_debugfs_root);
570  bfa_debugfs_root = NULL;
571  }
572 }