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; 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; 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; 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 struct bnad_debug_info *debug = file->private_data; 234 235 if (!debug) 236 return -EINVAL; 237 238 return fixed_size_llseek(file, offset, orig, debug->buffer_len); 239 } 240 241 static ssize_t 242 bnad_debugfs_read(struct file *file, char __user *buf, 243 size_t nbytes, loff_t *pos) 244 { 245 struct bnad_debug_info *debug = file->private_data; 246 247 if (!debug || !debug->debug_buffer) 248 return 0; 249 250 return simple_read_from_buffer(buf, nbytes, pos, 251 debug->debug_buffer, debug->buffer_len); 252 } 253 254 #define BFA_REG_CT_ADDRSZ (0x40000) 255 #define BFA_REG_CB_ADDRSZ (0x20000) 256 #define BFA_REG_ADDRSZ(__ioc) \ 257 ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \ 258 BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ)) 259 #define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1) 260 261 /* 262 * Function to check if the register offset passed is valid. 263 */ 264 static int 265 bna_reg_offset_check(struct bfa_ioc *ioc, u32 offset, u32 len) 266 { 267 u8 area; 268 269 /* check [16:15] */ 270 area = (offset >> 15) & 0x7; 271 if (area == 0) { 272 /* PCIe core register */ 273 if ((offset + (len<<2)) > 0x8000) /* 8k dwords or 32KB */ 274 return BFA_STATUS_EINVAL; 275 } else if (area == 0x1) { 276 /* CB 32 KB memory page */ 277 if ((offset + (len<<2)) > 0x10000) /* 8k dwords or 32KB */ 278 return BFA_STATUS_EINVAL; 279 } else { 280 /* CB register space 64KB */ 281 if ((offset + (len<<2)) > BFA_REG_ADDRMSK(ioc)) 282 return BFA_STATUS_EINVAL; 283 } 284 return BFA_STATUS_OK; 285 } 286 287 static ssize_t 288 bnad_debugfs_read_regrd(struct file *file, char __user *buf, 289 size_t nbytes, loff_t *pos) 290 { 291 struct bnad_debug_info *regrd_debug = file->private_data; 292 struct bnad *bnad = (struct bnad *)regrd_debug->i_private; 293 ssize_t rc; 294 295 if (!bnad->regdata) 296 return 0; 297 298 rc = simple_read_from_buffer(buf, nbytes, pos, 299 bnad->regdata, bnad->reglen); 300 301 if ((*pos + nbytes) >= bnad->reglen) { 302 kfree(bnad->regdata); 303 bnad->regdata = NULL; 304 bnad->reglen = 0; 305 } 306 307 return rc; 308 } 309 310 static ssize_t 311 bnad_debugfs_write_regrd(struct file *file, const char __user *buf, 312 size_t nbytes, loff_t *ppos) 313 { 314 struct bnad_debug_info *regrd_debug = file->private_data; 315 struct bnad *bnad = (struct bnad *)regrd_debug->i_private; 316 struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc; 317 int addr, len, rc, i; 318 u32 *regbuf; 319 void __iomem *rb, *reg_addr; 320 unsigned long flags; 321 void *kern_buf; 322 323 /* Allocate memory to store the user space buf */ 324 kern_buf = kzalloc(nbytes, GFP_KERNEL); 325 if (!kern_buf) 326 return -ENOMEM; 327 328 if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) { 329 kfree(kern_buf); 330 return -ENOMEM; 331 } 332 333 rc = sscanf(kern_buf, "%x:%x", &addr, &len); 334 if (rc < 2) { 335 pr_warn("bna %s: Failed to read user buffer\n", 336 pci_name(bnad->pcidev)); 337 kfree(kern_buf); 338 return -EINVAL; 339 } 340 341 kfree(kern_buf); 342 kfree(bnad->regdata); 343 bnad->regdata = NULL; 344 bnad->reglen = 0; 345 346 bnad->regdata = kzalloc(len << 2, GFP_KERNEL); 347 if (!bnad->regdata) 348 return -ENOMEM; 349 350 bnad->reglen = len << 2; 351 rb = bfa_ioc_bar0(ioc); 352 addr &= BFA_REG_ADDRMSK(ioc); 353 354 /* offset and len sanity check */ 355 rc = bna_reg_offset_check(ioc, addr, len); 356 if (rc) { 357 pr_warn("bna %s: Failed reg offset check\n", 358 pci_name(bnad->pcidev)); 359 kfree(bnad->regdata); 360 bnad->regdata = NULL; 361 bnad->reglen = 0; 362 return -EINVAL; 363 } 364 365 reg_addr = rb + addr; 366 regbuf = (u32 *)bnad->regdata; 367 spin_lock_irqsave(&bnad->bna_lock, flags); 368 for (i = 0; i < len; i++) { 369 *regbuf = readl(reg_addr); 370 regbuf++; 371 reg_addr += sizeof(u32); 372 } 373 spin_unlock_irqrestore(&bnad->bna_lock, flags); 374 375 return nbytes; 376 } 377 378 static ssize_t 379 bnad_debugfs_write_regwr(struct file *file, const char __user *buf, 380 size_t nbytes, loff_t *ppos) 381 { 382 struct bnad_debug_info *debug = file->private_data; 383 struct bnad *bnad = (struct bnad *)debug->i_private; 384 struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc; 385 int addr, val, rc; 386 void __iomem *reg_addr; 387 unsigned long flags; 388 void *kern_buf; 389 390 /* Allocate memory to store the user space buf */ 391 kern_buf = kzalloc(nbytes, GFP_KERNEL); 392 if (!kern_buf) 393 return -ENOMEM; 394 395 if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) { 396 kfree(kern_buf); 397 return -ENOMEM; 398 } 399 400 rc = sscanf(kern_buf, "%x:%x", &addr, &val); 401 if (rc < 2) { 402 pr_warn("bna %s: Failed to read user buffer\n", 403 pci_name(bnad->pcidev)); 404 kfree(kern_buf); 405 return -EINVAL; 406 } 407 kfree(kern_buf); 408 409 addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */ 410 411 /* offset and len sanity check */ 412 rc = bna_reg_offset_check(ioc, addr, 1); 413 if (rc) { 414 pr_warn("bna %s: Failed reg offset check\n", 415 pci_name(bnad->pcidev)); 416 return -EINVAL; 417 } 418 419 reg_addr = (bfa_ioc_bar0(ioc)) + addr; 420 spin_lock_irqsave(&bnad->bna_lock, flags); 421 writel(val, reg_addr); 422 spin_unlock_irqrestore(&bnad->bna_lock, flags); 423 424 return nbytes; 425 } 426 427 static int 428 bnad_debugfs_release(struct inode *inode, struct file *file) 429 { 430 struct bnad_debug_info *debug = file->private_data; 431 432 if (!debug) 433 return 0; 434 435 file->private_data = NULL; 436 kfree(debug); 437 return 0; 438 } 439 440 static int 441 bnad_debugfs_buffer_release(struct inode *inode, struct file *file) 442 { 443 struct bnad_debug_info *debug = file->private_data; 444 445 if (!debug) 446 return 0; 447 448 kfree(debug->debug_buffer); 449 450 file->private_data = NULL; 451 kfree(debug); 452 debug = NULL; 453 return 0; 454 } 455 456 static const struct file_operations bnad_debugfs_op_fwtrc = { 457 .owner = THIS_MODULE, 458 .open = bnad_debugfs_open_fwtrc, 459 .llseek = bnad_debugfs_lseek, 460 .read = bnad_debugfs_read, 461 .release = bnad_debugfs_buffer_release, 462 }; 463 464 static const struct file_operations bnad_debugfs_op_fwsave = { 465 .owner = THIS_MODULE, 466 .open = bnad_debugfs_open_fwsave, 467 .llseek = bnad_debugfs_lseek, 468 .read = bnad_debugfs_read, 469 .release = bnad_debugfs_buffer_release, 470 }; 471 472 static const struct file_operations bnad_debugfs_op_regrd = { 473 .owner = THIS_MODULE, 474 .open = bnad_debugfs_open_reg, 475 .llseek = bnad_debugfs_lseek, 476 .read = bnad_debugfs_read_regrd, 477 .write = bnad_debugfs_write_regrd, 478 .release = bnad_debugfs_release, 479 }; 480 481 static const struct file_operations bnad_debugfs_op_regwr = { 482 .owner = THIS_MODULE, 483 .open = bnad_debugfs_open_reg, 484 .llseek = bnad_debugfs_lseek, 485 .write = bnad_debugfs_write_regwr, 486 .release = bnad_debugfs_release, 487 }; 488 489 static const struct file_operations bnad_debugfs_op_drvinfo = { 490 .owner = THIS_MODULE, 491 .open = bnad_debugfs_open_drvinfo, 492 .llseek = bnad_debugfs_lseek, 493 .read = bnad_debugfs_read, 494 .release = bnad_debugfs_buffer_release, 495 }; 496 497 struct bnad_debugfs_entry { 498 const char *name; 499 umode_t mode; 500 const struct file_operations *fops; 501 }; 502 503 static const struct bnad_debugfs_entry bnad_debugfs_files[] = { 504 { "fwtrc", S_IFREG|S_IRUGO, &bnad_debugfs_op_fwtrc, }, 505 { "fwsave", S_IFREG|S_IRUGO, &bnad_debugfs_op_fwsave, }, 506 { "regrd", S_IFREG|S_IRUGO|S_IWUSR, &bnad_debugfs_op_regrd, }, 507 { "regwr", S_IFREG|S_IWUSR, &bnad_debugfs_op_regwr, }, 508 { "drvinfo", S_IFREG|S_IRUGO, &bnad_debugfs_op_drvinfo, }, 509 }; 510 511 static struct dentry *bna_debugfs_root; 512 static atomic_t bna_debugfs_port_count; 513 514 /* Initialize debugfs interface for BNA */ 515 void 516 bnad_debugfs_init(struct bnad *bnad) 517 { 518 const struct bnad_debugfs_entry *file; 519 char name[64]; 520 int i; 521 522 /* Setup the BNA debugfs root directory*/ 523 if (!bna_debugfs_root) { 524 bna_debugfs_root = debugfs_create_dir("bna", NULL); 525 atomic_set(&bna_debugfs_port_count, 0); 526 if (!bna_debugfs_root) { 527 pr_warn("BNA: debugfs root dir creation failed\n"); 528 return; 529 } 530 } 531 532 /* Setup the pci_dev debugfs directory for the port */ 533 snprintf(name, sizeof(name), "pci_dev:%s", pci_name(bnad->pcidev)); 534 if (!bnad->port_debugfs_root) { 535 bnad->port_debugfs_root = 536 debugfs_create_dir(name, bna_debugfs_root); 537 if (!bnad->port_debugfs_root) { 538 pr_warn("bna pci_dev %s: root dir creation failed\n", 539 pci_name(bnad->pcidev)); 540 return; 541 } 542 543 atomic_inc(&bna_debugfs_port_count); 544 545 for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) { 546 file = &bnad_debugfs_files[i]; 547 bnad->bnad_dentry_files[i] = 548 debugfs_create_file(file->name, 549 file->mode, 550 bnad->port_debugfs_root, 551 bnad, 552 file->fops); 553 if (!bnad->bnad_dentry_files[i]) { 554 pr_warn( 555 "BNA pci_dev:%s: create %s entry failed\n", 556 pci_name(bnad->pcidev), file->name); 557 return; 558 } 559 } 560 } 561 } 562 563 /* Uninitialize debugfs interface for BNA */ 564 void 565 bnad_debugfs_uninit(struct bnad *bnad) 566 { 567 int i; 568 569 for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) { 570 if (bnad->bnad_dentry_files[i]) { 571 debugfs_remove(bnad->bnad_dentry_files[i]); 572 bnad->bnad_dentry_files[i] = NULL; 573 } 574 } 575 576 /* Remove the pci_dev debugfs directory for the port */ 577 if (bnad->port_debugfs_root) { 578 debugfs_remove(bnad->port_debugfs_root); 579 bnad->port_debugfs_root = NULL; 580 atomic_dec(&bna_debugfs_port_count); 581 } 582 583 /* Remove the BNA debugfs root directory */ 584 if (atomic_read(&bna_debugfs_port_count) == 0) { 585 debugfs_remove(bna_debugfs_root); 586 bna_debugfs_root = NULL; 587 } 588 } 589