Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Linux network driver for QLogic BR-series Converged Network Adapter.
0004  */
0005 /*
0006  * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
0007  * Copyright (c) 2014-2015 QLogic Corporation
0008  * All rights reserved
0009  * www.qlogic.com
0010  */
0011 
0012 #include <linux/debugfs.h>
0013 #include <linux/module.h>
0014 #include "bnad.h"
0015 
0016 /*
0017  * BNA debufs interface
0018  *
0019  * To access the interface, debugfs file system should be mounted
0020  * if not already mounted using:
0021  *  mount -t debugfs none /sys/kernel/debug
0022  *
0023  * BNA Hierarchy:
0024  *  - bna/pci_dev:<pci_name>
0025  * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bna
0026  *
0027  * Debugging service available per pci_dev:
0028  *  fwtrc:  To collect current firmware trace.
0029  *  fwsave: To collect last saved fw trace as a result of firmware crash.
0030  *  regwr:  To write one word to chip register
0031  *  regrd:  To read one or more words from chip register.
0032  */
0033 
0034 struct bnad_debug_info {
0035     char *debug_buffer;
0036     void *i_private;
0037     int buffer_len;
0038 };
0039 
0040 static int
0041 bnad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
0042 {
0043     struct bnad *bnad = inode->i_private;
0044     struct bnad_debug_info *fw_debug;
0045     unsigned long flags;
0046     int rc;
0047 
0048     fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
0049     if (!fw_debug)
0050         return -ENOMEM;
0051 
0052     fw_debug->buffer_len = BNA_DBG_FWTRC_LEN;
0053 
0054     fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL);
0055     if (!fw_debug->debug_buffer) {
0056         kfree(fw_debug);
0057         fw_debug = NULL;
0058         return -ENOMEM;
0059     }
0060 
0061     spin_lock_irqsave(&bnad->bna_lock, flags);
0062     rc = bfa_nw_ioc_debug_fwtrc(&bnad->bna.ioceth.ioc,
0063             fw_debug->debug_buffer,
0064             &fw_debug->buffer_len);
0065     spin_unlock_irqrestore(&bnad->bna_lock, flags);
0066     if (rc != BFA_STATUS_OK) {
0067         kfree(fw_debug->debug_buffer);
0068         fw_debug->debug_buffer = NULL;
0069         kfree(fw_debug);
0070         fw_debug = NULL;
0071         netdev_warn(bnad->netdev, "failed to collect fwtrc\n");
0072         return -ENOMEM;
0073     }
0074 
0075     file->private_data = fw_debug;
0076 
0077     return 0;
0078 }
0079 
0080 static int
0081 bnad_debugfs_open_fwsave(struct inode *inode, struct file *file)
0082 {
0083     struct bnad *bnad = inode->i_private;
0084     struct bnad_debug_info *fw_debug;
0085     unsigned long flags;
0086     int rc;
0087 
0088     fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
0089     if (!fw_debug)
0090         return -ENOMEM;
0091 
0092     fw_debug->buffer_len = BNA_DBG_FWTRC_LEN;
0093 
0094     fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL);
0095     if (!fw_debug->debug_buffer) {
0096         kfree(fw_debug);
0097         fw_debug = NULL;
0098         return -ENOMEM;
0099     }
0100 
0101     spin_lock_irqsave(&bnad->bna_lock, flags);
0102     rc = bfa_nw_ioc_debug_fwsave(&bnad->bna.ioceth.ioc,
0103             fw_debug->debug_buffer,
0104             &fw_debug->buffer_len);
0105     spin_unlock_irqrestore(&bnad->bna_lock, flags);
0106     if (rc != BFA_STATUS_OK && rc != BFA_STATUS_ENOFSAVE) {
0107         kfree(fw_debug->debug_buffer);
0108         fw_debug->debug_buffer = NULL;
0109         kfree(fw_debug);
0110         fw_debug = NULL;
0111         netdev_warn(bnad->netdev, "failed to collect fwsave\n");
0112         return -ENOMEM;
0113     }
0114 
0115     file->private_data = fw_debug;
0116 
0117     return 0;
0118 }
0119 
0120 static int
0121 bnad_debugfs_open_reg(struct inode *inode, struct file *file)
0122 {
0123     struct bnad_debug_info *reg_debug;
0124 
0125     reg_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
0126     if (!reg_debug)
0127         return -ENOMEM;
0128 
0129     reg_debug->i_private = inode->i_private;
0130 
0131     file->private_data = reg_debug;
0132 
0133     return 0;
0134 }
0135 
0136 static int
0137 bnad_get_debug_drvinfo(struct bnad *bnad, void *buffer, u32 len)
0138 {
0139     struct bnad_drvinfo *drvinfo = (struct bnad_drvinfo *) buffer;
0140     struct bnad_iocmd_comp fcomp;
0141     unsigned long flags = 0;
0142     int ret = BFA_STATUS_FAILED;
0143 
0144     /* Get IOC info */
0145     spin_lock_irqsave(&bnad->bna_lock, flags);
0146     bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, &drvinfo->ioc_attr);
0147     spin_unlock_irqrestore(&bnad->bna_lock, flags);
0148 
0149     /* Retrieve CEE related info */
0150     fcomp.bnad = bnad;
0151     fcomp.comp_status = 0;
0152     init_completion(&fcomp.comp);
0153     spin_lock_irqsave(&bnad->bna_lock, flags);
0154     ret = bfa_nw_cee_get_attr(&bnad->bna.cee, &drvinfo->cee_attr,
0155                 bnad_cb_completion, &fcomp);
0156     if (ret != BFA_STATUS_OK) {
0157         spin_unlock_irqrestore(&bnad->bna_lock, flags);
0158         goto out;
0159     }
0160     spin_unlock_irqrestore(&bnad->bna_lock, flags);
0161     wait_for_completion(&fcomp.comp);
0162     drvinfo->cee_status = fcomp.comp_status;
0163 
0164     /* Retrieve flash partition info */
0165     fcomp.comp_status = 0;
0166     reinit_completion(&fcomp.comp);
0167     spin_lock_irqsave(&bnad->bna_lock, flags);
0168     ret = bfa_nw_flash_get_attr(&bnad->bna.flash, &drvinfo->flash_attr,
0169                 bnad_cb_completion, &fcomp);
0170     if (ret != BFA_STATUS_OK) {
0171         spin_unlock_irqrestore(&bnad->bna_lock, flags);
0172         goto out;
0173     }
0174     spin_unlock_irqrestore(&bnad->bna_lock, flags);
0175     wait_for_completion(&fcomp.comp);
0176     drvinfo->flash_status = fcomp.comp_status;
0177 out:
0178     return ret;
0179 }
0180 
0181 static int
0182 bnad_debugfs_open_drvinfo(struct inode *inode, struct file *file)
0183 {
0184     struct bnad *bnad = inode->i_private;
0185     struct bnad_debug_info *drv_info;
0186     int rc;
0187 
0188     drv_info = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
0189     if (!drv_info)
0190         return -ENOMEM;
0191 
0192     drv_info->buffer_len = sizeof(struct bnad_drvinfo);
0193 
0194     drv_info->debug_buffer = kzalloc(drv_info->buffer_len, GFP_KERNEL);
0195     if (!drv_info->debug_buffer) {
0196         kfree(drv_info);
0197         drv_info = NULL;
0198         return -ENOMEM;
0199     }
0200 
0201     mutex_lock(&bnad->conf_mutex);
0202     rc = bnad_get_debug_drvinfo(bnad, drv_info->debug_buffer,
0203                 drv_info->buffer_len);
0204     mutex_unlock(&bnad->conf_mutex);
0205     if (rc != BFA_STATUS_OK) {
0206         kfree(drv_info->debug_buffer);
0207         drv_info->debug_buffer = NULL;
0208         kfree(drv_info);
0209         drv_info = NULL;
0210         netdev_warn(bnad->netdev, "failed to collect drvinfo\n");
0211         return -ENOMEM;
0212     }
0213 
0214     file->private_data = drv_info;
0215 
0216     return 0;
0217 }
0218 
0219 /* Changes the current file position */
0220 static loff_t
0221 bnad_debugfs_lseek(struct file *file, loff_t offset, int orig)
0222 {
0223     struct bnad_debug_info *debug = file->private_data;
0224 
0225     if (!debug)
0226         return -EINVAL;
0227 
0228     return fixed_size_llseek(file, offset, orig, debug->buffer_len);
0229 }
0230 
0231 static ssize_t
0232 bnad_debugfs_read(struct file *file, char __user *buf,
0233           size_t nbytes, loff_t *pos)
0234 {
0235     struct bnad_debug_info *debug = file->private_data;
0236 
0237     if (!debug || !debug->debug_buffer)
0238         return 0;
0239 
0240     return simple_read_from_buffer(buf, nbytes, pos,
0241                 debug->debug_buffer, debug->buffer_len);
0242 }
0243 
0244 #define BFA_REG_CT_ADDRSZ   (0x40000)
0245 #define BFA_REG_CB_ADDRSZ   (0x20000)
0246 #define BFA_REG_ADDRSZ(__ioc)   \
0247     ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ?  \
0248      BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ))
0249 #define BFA_REG_ADDRMSK(__ioc)  (BFA_REG_ADDRSZ(__ioc) - 1)
0250 
0251 /*
0252  * Function to check if the register offset passed is valid.
0253  */
0254 static int
0255 bna_reg_offset_check(struct bfa_ioc *ioc, u32 offset, u32 len)
0256 {
0257     u8 area;
0258 
0259     /* check [16:15] */
0260     area = (offset >> 15) & 0x7;
0261     if (area == 0) {
0262         /* PCIe core register */
0263         if (offset + (len << 2) > 0x8000)   /* 8k dwords or 32KB */
0264             return BFA_STATUS_EINVAL;
0265     } else if (area == 0x1) {
0266         /* CB 32 KB memory page */
0267         if (offset + (len << 2) > 0x10000)  /* 8k dwords or 32KB */
0268             return BFA_STATUS_EINVAL;
0269     } else {
0270         /* CB register space 64KB */
0271         if (offset + (len << 2) > BFA_REG_ADDRMSK(ioc))
0272             return BFA_STATUS_EINVAL;
0273     }
0274     return BFA_STATUS_OK;
0275 }
0276 
0277 static ssize_t
0278 bnad_debugfs_read_regrd(struct file *file, char __user *buf,
0279             size_t nbytes, loff_t *pos)
0280 {
0281     struct bnad_debug_info *regrd_debug = file->private_data;
0282     struct bnad *bnad = (struct bnad *)regrd_debug->i_private;
0283     ssize_t rc;
0284 
0285     if (!bnad->regdata)
0286         return 0;
0287 
0288     rc = simple_read_from_buffer(buf, nbytes, pos,
0289             bnad->regdata, bnad->reglen);
0290 
0291     if ((*pos + nbytes) >= bnad->reglen) {
0292         kfree(bnad->regdata);
0293         bnad->regdata = NULL;
0294         bnad->reglen = 0;
0295     }
0296 
0297     return rc;
0298 }
0299 
0300 static ssize_t
0301 bnad_debugfs_write_regrd(struct file *file, const char __user *buf,
0302         size_t nbytes, loff_t *ppos)
0303 {
0304     struct bnad_debug_info *regrd_debug = file->private_data;
0305     struct bnad *bnad = (struct bnad *)regrd_debug->i_private;
0306     struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc;
0307     int rc, i;
0308     u32 addr, len;
0309     u32 *regbuf;
0310     void __iomem *rb, *reg_addr;
0311     unsigned long flags;
0312     void *kern_buf;
0313 
0314     /* Copy the user space buf */
0315     kern_buf = memdup_user(buf, nbytes);
0316     if (IS_ERR(kern_buf))
0317         return PTR_ERR(kern_buf);
0318 
0319     rc = sscanf(kern_buf, "%x:%x", &addr, &len);
0320     if (rc < 2 || len > UINT_MAX >> 2) {
0321         netdev_warn(bnad->netdev, "failed to read user buffer\n");
0322         kfree(kern_buf);
0323         return -EINVAL;
0324     }
0325 
0326     kfree(kern_buf);
0327     kfree(bnad->regdata);
0328     bnad->reglen = 0;
0329 
0330     bnad->regdata = kzalloc(len << 2, GFP_KERNEL);
0331     if (!bnad->regdata)
0332         return -ENOMEM;
0333 
0334     bnad->reglen = len << 2;
0335     rb = bfa_ioc_bar0(ioc);
0336     addr &= BFA_REG_ADDRMSK(ioc);
0337 
0338     /* offset and len sanity check */
0339     rc = bna_reg_offset_check(ioc, addr, len);
0340     if (rc) {
0341         netdev_warn(bnad->netdev, "failed reg offset check\n");
0342         kfree(bnad->regdata);
0343         bnad->regdata = NULL;
0344         bnad->reglen = 0;
0345         return -EINVAL;
0346     }
0347 
0348     reg_addr = rb + addr;
0349     regbuf =  (u32 *)bnad->regdata;
0350     spin_lock_irqsave(&bnad->bna_lock, flags);
0351     for (i = 0; i < len; i++) {
0352         *regbuf = readl(reg_addr);
0353         regbuf++;
0354         reg_addr += sizeof(u32);
0355     }
0356     spin_unlock_irqrestore(&bnad->bna_lock, flags);
0357 
0358     return nbytes;
0359 }
0360 
0361 static ssize_t
0362 bnad_debugfs_write_regwr(struct file *file, const char __user *buf,
0363         size_t nbytes, loff_t *ppos)
0364 {
0365     struct bnad_debug_info *debug = file->private_data;
0366     struct bnad *bnad = (struct bnad *)debug->i_private;
0367     struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc;
0368     int rc;
0369     u32 addr, val;
0370     void __iomem *reg_addr;
0371     unsigned long flags;
0372     void *kern_buf;
0373 
0374     /* Copy the user space buf */
0375     kern_buf = memdup_user(buf, nbytes);
0376     if (IS_ERR(kern_buf))
0377         return PTR_ERR(kern_buf);
0378 
0379     rc = sscanf(kern_buf, "%x:%x", &addr, &val);
0380     if (rc < 2) {
0381         netdev_warn(bnad->netdev, "failed to read user buffer\n");
0382         kfree(kern_buf);
0383         return -EINVAL;
0384     }
0385     kfree(kern_buf);
0386 
0387     addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */
0388 
0389     /* offset and len sanity check */
0390     rc = bna_reg_offset_check(ioc, addr, 1);
0391     if (rc) {
0392         netdev_warn(bnad->netdev, "failed reg offset check\n");
0393         return -EINVAL;
0394     }
0395 
0396     reg_addr = (bfa_ioc_bar0(ioc)) + addr;
0397     spin_lock_irqsave(&bnad->bna_lock, flags);
0398     writel(val, reg_addr);
0399     spin_unlock_irqrestore(&bnad->bna_lock, flags);
0400 
0401     return nbytes;
0402 }
0403 
0404 static int
0405 bnad_debugfs_release(struct inode *inode, struct file *file)
0406 {
0407     struct bnad_debug_info *debug = file->private_data;
0408 
0409     if (!debug)
0410         return 0;
0411 
0412     file->private_data = NULL;
0413     kfree(debug);
0414     return 0;
0415 }
0416 
0417 static int
0418 bnad_debugfs_buffer_release(struct inode *inode, struct file *file)
0419 {
0420     struct bnad_debug_info *debug = file->private_data;
0421 
0422     if (!debug)
0423         return 0;
0424 
0425     kfree(debug->debug_buffer);
0426 
0427     file->private_data = NULL;
0428     kfree(debug);
0429     debug = NULL;
0430     return 0;
0431 }
0432 
0433 static const struct file_operations bnad_debugfs_op_fwtrc = {
0434     .owner      =   THIS_MODULE,
0435     .open       =   bnad_debugfs_open_fwtrc,
0436     .llseek     =   bnad_debugfs_lseek,
0437     .read       =   bnad_debugfs_read,
0438     .release    =   bnad_debugfs_buffer_release,
0439 };
0440 
0441 static const struct file_operations bnad_debugfs_op_fwsave = {
0442     .owner      =   THIS_MODULE,
0443     .open       =   bnad_debugfs_open_fwsave,
0444     .llseek     =   bnad_debugfs_lseek,
0445     .read       =   bnad_debugfs_read,
0446     .release    =   bnad_debugfs_buffer_release,
0447 };
0448 
0449 static const struct file_operations bnad_debugfs_op_regrd = {
0450     .owner      =       THIS_MODULE,
0451     .open       =   bnad_debugfs_open_reg,
0452     .llseek     =   bnad_debugfs_lseek,
0453     .read       =   bnad_debugfs_read_regrd,
0454     .write      =   bnad_debugfs_write_regrd,
0455     .release    =   bnad_debugfs_release,
0456 };
0457 
0458 static const struct file_operations bnad_debugfs_op_regwr = {
0459     .owner      =   THIS_MODULE,
0460     .open       =   bnad_debugfs_open_reg,
0461     .llseek     =   bnad_debugfs_lseek,
0462     .write      =   bnad_debugfs_write_regwr,
0463     .release    =   bnad_debugfs_release,
0464 };
0465 
0466 static const struct file_operations bnad_debugfs_op_drvinfo = {
0467     .owner      =   THIS_MODULE,
0468     .open       =   bnad_debugfs_open_drvinfo,
0469     .llseek     =   bnad_debugfs_lseek,
0470     .read       =   bnad_debugfs_read,
0471     .release    =   bnad_debugfs_buffer_release,
0472 };
0473 
0474 struct bnad_debugfs_entry {
0475     const char *name;
0476     umode_t  mode;
0477     const struct file_operations *fops;
0478 };
0479 
0480 static const struct bnad_debugfs_entry bnad_debugfs_files[] = {
0481     { "fwtrc",  S_IFREG | 0444, &bnad_debugfs_op_fwtrc, },
0482     { "fwsave", S_IFREG | 0444, &bnad_debugfs_op_fwsave, },
0483     { "regrd",  S_IFREG | 0644, &bnad_debugfs_op_regrd, },
0484     { "regwr",  S_IFREG | 0200, &bnad_debugfs_op_regwr, },
0485     { "drvinfo", S_IFREG | 0444, &bnad_debugfs_op_drvinfo, },
0486 };
0487 
0488 static struct dentry *bna_debugfs_root;
0489 static atomic_t bna_debugfs_port_count;
0490 
0491 /* Initialize debugfs interface for BNA */
0492 void
0493 bnad_debugfs_init(struct bnad *bnad)
0494 {
0495     const struct bnad_debugfs_entry *file;
0496     char name[64];
0497     int i;
0498 
0499     /* Setup the BNA debugfs root directory*/
0500     if (!bna_debugfs_root) {
0501         bna_debugfs_root = debugfs_create_dir("bna", NULL);
0502         atomic_set(&bna_debugfs_port_count, 0);
0503         if (!bna_debugfs_root) {
0504             netdev_warn(bnad->netdev,
0505                     "debugfs root dir creation failed\n");
0506             return;
0507         }
0508     }
0509 
0510     /* Setup the pci_dev debugfs directory for the port */
0511     snprintf(name, sizeof(name), "pci_dev:%s", pci_name(bnad->pcidev));
0512     if (!bnad->port_debugfs_root) {
0513         bnad->port_debugfs_root =
0514             debugfs_create_dir(name, bna_debugfs_root);
0515         if (!bnad->port_debugfs_root) {
0516             netdev_warn(bnad->netdev,
0517                     "debugfs root dir creation failed\n");
0518             return;
0519         }
0520 
0521         atomic_inc(&bna_debugfs_port_count);
0522 
0523         for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
0524             file = &bnad_debugfs_files[i];
0525             bnad->bnad_dentry_files[i] =
0526                     debugfs_create_file(file->name,
0527                             file->mode,
0528                             bnad->port_debugfs_root,
0529                             bnad,
0530                             file->fops);
0531             if (!bnad->bnad_dentry_files[i]) {
0532                 netdev_warn(bnad->netdev,
0533                         "create %s entry failed\n",
0534                         file->name);
0535                 return;
0536             }
0537         }
0538     }
0539 }
0540 
0541 /* Uninitialize debugfs interface for BNA */
0542 void
0543 bnad_debugfs_uninit(struct bnad *bnad)
0544 {
0545     int i;
0546 
0547     for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
0548         if (bnad->bnad_dentry_files[i]) {
0549             debugfs_remove(bnad->bnad_dentry_files[i]);
0550             bnad->bnad_dentry_files[i] = NULL;
0551         }
0552     }
0553 
0554     /* Remove the pci_dev debugfs directory for the port */
0555     if (bnad->port_debugfs_root) {
0556         debugfs_remove(bnad->port_debugfs_root);
0557         bnad->port_debugfs_root = NULL;
0558         atomic_dec(&bna_debugfs_port_count);
0559     }
0560 
0561     /* Remove the BNA debugfs root directory */
0562     if (atomic_read(&bna_debugfs_port_count) == 0) {
0563         debugfs_remove(bna_debugfs_root);
0564         bna_debugfs_root = NULL;
0565     }
0566 }