root/drivers/net/ethernet/brocade/bna/bnad_debugfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bnad_debugfs_open_fwtrc
  2. bnad_debugfs_open_fwsave
  3. bnad_debugfs_open_reg
  4. bnad_get_debug_drvinfo
  5. bnad_debugfs_open_drvinfo
  6. bnad_debugfs_lseek
  7. bnad_debugfs_read
  8. bna_reg_offset_check
  9. bnad_debugfs_read_regrd
  10. bnad_debugfs_write_regrd
  11. bnad_debugfs_write_regwr
  12. bnad_debugfs_release
  13. bnad_debugfs_buffer_release
  14. bnad_debugfs_init
  15. bnad_debugfs_uninit

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

/* [<][>][^][v][top][bottom][index][help] */