linux/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
<<
>>
Prefs
   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
  34struct bnad_debug_info {
  35        char *debug_buffer;
  36        void *i_private;
  37        int buffer_len;
  38};
  39
  40static int
  41bnad_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
  80static int
  81bnad_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
 120static int
 121bnad_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
 136static int
 137bnad_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;
 177out:
 178        return ret;
 179}
 180
 181static int
 182bnad_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 */
 220static loff_t
 221bnad_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
 231static ssize_t
 232bnad_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 */
 254static int
 255bna_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
 277static ssize_t
 278bnad_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
 300static ssize_t
 301bnad_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
 361static ssize_t
 362bnad_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
 404static int
 405bnad_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
 417static int
 418bnad_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
 433static 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
 441static 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
 449static 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
 458static 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
 466static 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
 474struct bnad_debugfs_entry {
 475        const char *name;
 476        umode_t  mode;
 477        const struct file_operations *fops;
 478};
 479
 480static 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
 488static struct dentry *bna_debugfs_root;
 489static atomic_t bna_debugfs_port_count;
 490
 491/* Initialize debugfs interface for BNA */
 492void
 493bnad_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 */
 542void
 543bnad_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}
 567