linux/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
<<
>>
Prefs
   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
  41struct bnad_debug_info {
  42        char *debug_buffer;
  43        void *i_private;
  44        int buffer_len;
  45};
  46
  47static int
  48bnad_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
  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                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
 129static int
 130bnad_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
 145static int
 146bnad_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;
 186out:
 187        return ret;
 188}
 189
 190static int
 191bnad_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 */
 230static loff_t
 231bnad_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
 241static ssize_t
 242bnad_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 */
 264static int
 265bna_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
 287static ssize_t
 288bnad_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
 310static ssize_t
 311bnad_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
 378static ssize_t
 379bnad_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
 427static int
 428bnad_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
 440static int
 441bnad_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
 456static 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
 464static 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
 472static 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
 481static 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
 489static 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
 497struct bnad_debugfs_entry {
 498        const char *name;
 499        umode_t  mode;
 500        const struct file_operations *fops;
 501};
 502
 503static 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
 511static struct dentry *bna_debugfs_root;
 512static atomic_t bna_debugfs_port_count;
 513
 514/* Initialize debugfs interface for BNA */
 515void
 516bnad_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 */
 564void
 565bnad_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