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        loff_t pos = file->f_pos;
 234        struct bnad_debug_info *debug = file->private_data;
 235
 236        if (!debug)
 237                return -EINVAL;
 238
 239        switch (orig) {
 240        case 0:
 241                file->f_pos = offset;
 242                break;
 243        case 1:
 244                file->f_pos += offset;
 245                break;
 246        case 2:
 247                file->f_pos = debug->buffer_len + offset;
 248                break;
 249        default:
 250                return -EINVAL;
 251        }
 252
 253        if (file->f_pos < 0 || file->f_pos > debug->buffer_len) {
 254                file->f_pos = pos;
 255                return -EINVAL;
 256        }
 257
 258        return file->f_pos;
 259}
 260
 261static ssize_t
 262bnad_debugfs_read(struct file *file, char __user *buf,
 263                  size_t nbytes, loff_t *pos)
 264{
 265        struct bnad_debug_info *debug = file->private_data;
 266
 267        if (!debug || !debug->debug_buffer)
 268                return 0;
 269
 270        return simple_read_from_buffer(buf, nbytes, pos,
 271                                debug->debug_buffer, debug->buffer_len);
 272}
 273
 274#define BFA_REG_CT_ADDRSZ       (0x40000)
 275#define BFA_REG_CB_ADDRSZ       (0x20000)
 276#define BFA_REG_ADDRSZ(__ioc)   \
 277        ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ?  \
 278         BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ))
 279#define BFA_REG_ADDRMSK(__ioc)  (BFA_REG_ADDRSZ(__ioc) - 1)
 280
 281/*
 282 * Function to check if the register offset passed is valid.
 283 */
 284static int
 285bna_reg_offset_check(struct bfa_ioc *ioc, u32 offset, u32 len)
 286{
 287        u8 area;
 288
 289        /* check [16:15] */
 290        area = (offset >> 15) & 0x7;
 291        if (area == 0) {
 292                /* PCIe core register */
 293                if ((offset + (len<<2)) > 0x8000)       /* 8k dwords or 32KB */
 294                        return BFA_STATUS_EINVAL;
 295        } else if (area == 0x1) {
 296                /* CB 32 KB memory page */
 297                if ((offset + (len<<2)) > 0x10000)      /* 8k dwords or 32KB */
 298                        return BFA_STATUS_EINVAL;
 299        } else {
 300                /* CB register space 64KB */
 301                if ((offset + (len<<2)) > BFA_REG_ADDRMSK(ioc))
 302                        return BFA_STATUS_EINVAL;
 303        }
 304        return BFA_STATUS_OK;
 305}
 306
 307static ssize_t
 308bnad_debugfs_read_regrd(struct file *file, char __user *buf,
 309                        size_t nbytes, loff_t *pos)
 310{
 311        struct bnad_debug_info *regrd_debug = file->private_data;
 312        struct bnad *bnad = (struct bnad *)regrd_debug->i_private;
 313        ssize_t rc;
 314
 315        if (!bnad->regdata)
 316                return 0;
 317
 318        rc = simple_read_from_buffer(buf, nbytes, pos,
 319                        bnad->regdata, bnad->reglen);
 320
 321        if ((*pos + nbytes) >= bnad->reglen) {
 322                kfree(bnad->regdata);
 323                bnad->regdata = NULL;
 324                bnad->reglen = 0;
 325        }
 326
 327        return rc;
 328}
 329
 330static ssize_t
 331bnad_debugfs_write_regrd(struct file *file, const char __user *buf,
 332                size_t nbytes, loff_t *ppos)
 333{
 334        struct bnad_debug_info *regrd_debug = file->private_data;
 335        struct bnad *bnad = (struct bnad *)regrd_debug->i_private;
 336        struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc;
 337        int addr, len, rc, i;
 338        u32 *regbuf;
 339        void __iomem *rb, *reg_addr;
 340        unsigned long flags;
 341        void *kern_buf;
 342
 343        /* Allocate memory to store the user space buf */
 344        kern_buf = kzalloc(nbytes, GFP_KERNEL);
 345        if (!kern_buf)
 346                return -ENOMEM;
 347
 348        if (copy_from_user(kern_buf, (void  __user *)buf, nbytes)) {
 349                kfree(kern_buf);
 350                return -ENOMEM;
 351        }
 352
 353        rc = sscanf(kern_buf, "%x:%x", &addr, &len);
 354        if (rc < 2) {
 355                pr_warn("bna %s: Failed to read user buffer\n",
 356                        pci_name(bnad->pcidev));
 357                kfree(kern_buf);
 358                return -EINVAL;
 359        }
 360
 361        kfree(kern_buf);
 362        kfree(bnad->regdata);
 363        bnad->regdata = NULL;
 364        bnad->reglen = 0;
 365
 366        bnad->regdata = kzalloc(len << 2, GFP_KERNEL);
 367        if (!bnad->regdata)
 368                return -ENOMEM;
 369
 370        bnad->reglen = len << 2;
 371        rb = bfa_ioc_bar0(ioc);
 372        addr &= BFA_REG_ADDRMSK(ioc);
 373
 374        /* offset and len sanity check */
 375        rc = bna_reg_offset_check(ioc, addr, len);
 376        if (rc) {
 377                pr_warn("bna %s: Failed reg offset check\n",
 378                        pci_name(bnad->pcidev));
 379                kfree(bnad->regdata);
 380                bnad->regdata = NULL;
 381                bnad->reglen = 0;
 382                return -EINVAL;
 383        }
 384
 385        reg_addr = rb + addr;
 386        regbuf =  (u32 *)bnad->regdata;
 387        spin_lock_irqsave(&bnad->bna_lock, flags);
 388        for (i = 0; i < len; i++) {
 389                *regbuf = readl(reg_addr);
 390                regbuf++;
 391                reg_addr += sizeof(u32);
 392        }
 393        spin_unlock_irqrestore(&bnad->bna_lock, flags);
 394
 395        return nbytes;
 396}
 397
 398static ssize_t
 399bnad_debugfs_write_regwr(struct file *file, const char __user *buf,
 400                size_t nbytes, loff_t *ppos)
 401{
 402        struct bnad_debug_info *debug = file->private_data;
 403        struct bnad *bnad = (struct bnad *)debug->i_private;
 404        struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc;
 405        int addr, val, rc;
 406        void __iomem *reg_addr;
 407        unsigned long flags;
 408        void *kern_buf;
 409
 410        /* Allocate memory to store the user space buf */
 411        kern_buf = kzalloc(nbytes, GFP_KERNEL);
 412        if (!kern_buf)
 413                return -ENOMEM;
 414
 415        if (copy_from_user(kern_buf, (void  __user *)buf, nbytes)) {
 416                kfree(kern_buf);
 417                return -ENOMEM;
 418        }
 419
 420        rc = sscanf(kern_buf, "%x:%x", &addr, &val);
 421        if (rc < 2) {
 422                pr_warn("bna %s: Failed to read user buffer\n",
 423                        pci_name(bnad->pcidev));
 424                kfree(kern_buf);
 425                return -EINVAL;
 426        }
 427        kfree(kern_buf);
 428
 429        addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */
 430
 431        /* offset and len sanity check */
 432        rc = bna_reg_offset_check(ioc, addr, 1);
 433        if (rc) {
 434                pr_warn("bna %s: Failed reg offset check\n",
 435                        pci_name(bnad->pcidev));
 436                return -EINVAL;
 437        }
 438
 439        reg_addr = (bfa_ioc_bar0(ioc)) + addr;
 440        spin_lock_irqsave(&bnad->bna_lock, flags);
 441        writel(val, reg_addr);
 442        spin_unlock_irqrestore(&bnad->bna_lock, flags);
 443
 444        return nbytes;
 445}
 446
 447static int
 448bnad_debugfs_release(struct inode *inode, struct file *file)
 449{
 450        struct bnad_debug_info *debug = file->private_data;
 451
 452        if (!debug)
 453                return 0;
 454
 455        file->private_data = NULL;
 456        kfree(debug);
 457        return 0;
 458}
 459
 460static int
 461bnad_debugfs_buffer_release(struct inode *inode, struct file *file)
 462{
 463        struct bnad_debug_info *debug = file->private_data;
 464
 465        if (!debug)
 466                return 0;
 467
 468        kfree(debug->debug_buffer);
 469
 470        file->private_data = NULL;
 471        kfree(debug);
 472        debug = NULL;
 473        return 0;
 474}
 475
 476static const struct file_operations bnad_debugfs_op_fwtrc = {
 477        .owner          =       THIS_MODULE,
 478        .open           =       bnad_debugfs_open_fwtrc,
 479        .llseek         =       bnad_debugfs_lseek,
 480        .read           =       bnad_debugfs_read,
 481        .release        =       bnad_debugfs_buffer_release,
 482};
 483
 484static const struct file_operations bnad_debugfs_op_fwsave = {
 485        .owner          =       THIS_MODULE,
 486        .open           =       bnad_debugfs_open_fwsave,
 487        .llseek         =       bnad_debugfs_lseek,
 488        .read           =       bnad_debugfs_read,
 489        .release        =       bnad_debugfs_buffer_release,
 490};
 491
 492static const struct file_operations bnad_debugfs_op_regrd = {
 493        .owner          =       THIS_MODULE,
 494        .open           =       bnad_debugfs_open_reg,
 495        .llseek         =       bnad_debugfs_lseek,
 496        .read           =       bnad_debugfs_read_regrd,
 497        .write          =       bnad_debugfs_write_regrd,
 498        .release        =       bnad_debugfs_release,
 499};
 500
 501static const struct file_operations bnad_debugfs_op_regwr = {
 502        .owner          =       THIS_MODULE,
 503        .open           =       bnad_debugfs_open_reg,
 504        .llseek         =       bnad_debugfs_lseek,
 505        .write          =       bnad_debugfs_write_regwr,
 506        .release        =       bnad_debugfs_release,
 507};
 508
 509static const struct file_operations bnad_debugfs_op_drvinfo = {
 510        .owner          =       THIS_MODULE,
 511        .open           =       bnad_debugfs_open_drvinfo,
 512        .llseek         =       bnad_debugfs_lseek,
 513        .read           =       bnad_debugfs_read,
 514        .release        =       bnad_debugfs_buffer_release,
 515};
 516
 517struct bnad_debugfs_entry {
 518        const char *name;
 519        umode_t  mode;
 520        const struct file_operations *fops;
 521};
 522
 523static const struct bnad_debugfs_entry bnad_debugfs_files[] = {
 524        { "fwtrc",  S_IFREG|S_IRUGO, &bnad_debugfs_op_fwtrc, },
 525        { "fwsave", S_IFREG|S_IRUGO, &bnad_debugfs_op_fwsave, },
 526        { "regrd",  S_IFREG|S_IRUGO|S_IWUSR, &bnad_debugfs_op_regrd, },
 527        { "regwr",  S_IFREG|S_IWUSR, &bnad_debugfs_op_regwr, },
 528        { "drvinfo", S_IFREG|S_IRUGO, &bnad_debugfs_op_drvinfo, },
 529};
 530
 531static struct dentry *bna_debugfs_root;
 532static atomic_t bna_debugfs_port_count;
 533
 534/* Initialize debugfs interface for BNA */
 535void
 536bnad_debugfs_init(struct bnad *bnad)
 537{
 538        const struct bnad_debugfs_entry *file;
 539        char name[64];
 540        int i;
 541
 542        /* Setup the BNA debugfs root directory*/
 543        if (!bna_debugfs_root) {
 544                bna_debugfs_root = debugfs_create_dir("bna", NULL);
 545                atomic_set(&bna_debugfs_port_count, 0);
 546                if (!bna_debugfs_root) {
 547                        pr_warn("BNA: debugfs root dir creation failed\n");
 548                        return;
 549                }
 550        }
 551
 552        /* Setup the pci_dev debugfs directory for the port */
 553        snprintf(name, sizeof(name), "pci_dev:%s", pci_name(bnad->pcidev));
 554        if (!bnad->port_debugfs_root) {
 555                bnad->port_debugfs_root =
 556                        debugfs_create_dir(name, bna_debugfs_root);
 557                if (!bnad->port_debugfs_root) {
 558                        pr_warn("bna pci_dev %s: root dir creation failed\n",
 559                                pci_name(bnad->pcidev));
 560                        return;
 561                }
 562
 563                atomic_inc(&bna_debugfs_port_count);
 564
 565                for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
 566                        file = &bnad_debugfs_files[i];
 567                        bnad->bnad_dentry_files[i] =
 568                                        debugfs_create_file(file->name,
 569                                                        file->mode,
 570                                                        bnad->port_debugfs_root,
 571                                                        bnad,
 572                                                        file->fops);
 573                        if (!bnad->bnad_dentry_files[i]) {
 574                                pr_warn(
 575                                     "BNA pci_dev:%s: create %s entry failed\n",
 576                                     pci_name(bnad->pcidev), file->name);
 577                                return;
 578                        }
 579                }
 580        }
 581}
 582
 583/* Uninitialize debugfs interface for BNA */
 584void
 585bnad_debugfs_uninit(struct bnad *bnad)
 586{
 587        int i;
 588
 589        for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
 590                if (bnad->bnad_dentry_files[i]) {
 591                        debugfs_remove(bnad->bnad_dentry_files[i]);
 592                        bnad->bnad_dentry_files[i] = NULL;
 593                }
 594        }
 595
 596        /* Remove the pci_dev debugfs directory for the port */
 597        if (bnad->port_debugfs_root) {
 598                debugfs_remove(bnad->port_debugfs_root);
 599                bnad->port_debugfs_root = NULL;
 600                atomic_dec(&bna_debugfs_port_count);
 601        }
 602
 603        /* Remove the BNA debugfs root directory */
 604        if (atomic_read(&bna_debugfs_port_count) == 0) {
 605                debugfs_remove(bna_debugfs_root);
 606                bna_debugfs_root = NULL;
 607        }
 608}
 609