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