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