Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
0004  * Copyright (c) 2014- QLogic Corporation.
0005  * All rights reserved
0006  * www.qlogic.com
0007  *
0008  * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
0009  */
0010 
0011 #include <linux/debugfs.h>
0012 #include <linux/export.h>
0013 
0014 #include "bfad_drv.h"
0015 #include "bfad_im.h"
0016 
0017 /*
0018  * BFA debufs interface
0019  *
0020  * To access the interface, debugfs file system should be mounted
0021  * if not already mounted using:
0022  * mount -t debugfs none /sys/kernel/debug
0023  *
0024  * BFA Hierarchy:
0025  *  - bfa/pci_dev:<pci_name>
0026  * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bfa
0027  *
0028  * Debugging service available per pci_dev:
0029  * fwtrc:  To collect current firmware trace.
0030  * drvtrc: To collect current driver trace
0031  * fwsave: To collect last saved fw trace as a result of firmware crash.
0032  * regwr:  To write one word to chip register
0033  * regrd:  To read one or more words from chip register.
0034  */
0035 
0036 struct bfad_debug_info {
0037     char *debug_buffer;
0038     void *i_private;
0039     int buffer_len;
0040 };
0041 
0042 static int
0043 bfad_debugfs_open_drvtrc(struct inode *inode, struct file *file)
0044 {
0045     struct bfad_port_s *port = inode->i_private;
0046     struct bfad_s *bfad = port->bfad;
0047     struct bfad_debug_info *debug;
0048 
0049     debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
0050     if (!debug)
0051         return -ENOMEM;
0052 
0053     debug->debug_buffer = (void *) bfad->trcmod;
0054     debug->buffer_len = sizeof(struct bfa_trc_mod_s);
0055 
0056     file->private_data = debug;
0057 
0058     return 0;
0059 }
0060 
0061 static int
0062 bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
0063 {
0064     struct bfad_port_s *port = inode->i_private;
0065     struct bfad_s *bfad = port->bfad;
0066     struct bfad_debug_info *fw_debug;
0067     unsigned long flags;
0068     int rc;
0069 
0070     fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
0071     if (!fw_debug)
0072         return -ENOMEM;
0073 
0074     fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
0075 
0076     fw_debug->debug_buffer = vzalloc(fw_debug->buffer_len);
0077     if (!fw_debug->debug_buffer) {
0078         kfree(fw_debug);
0079         printk(KERN_INFO "bfad[%d]: Failed to allocate fwtrc buffer\n",
0080                 bfad->inst_no);
0081         return -ENOMEM;
0082     }
0083 
0084     spin_lock_irqsave(&bfad->bfad_lock, flags);
0085     rc = bfa_ioc_debug_fwtrc(&bfad->bfa.ioc,
0086             fw_debug->debug_buffer,
0087             &fw_debug->buffer_len);
0088     spin_unlock_irqrestore(&bfad->bfad_lock, flags);
0089     if (rc != BFA_STATUS_OK) {
0090         vfree(fw_debug->debug_buffer);
0091         fw_debug->debug_buffer = NULL;
0092         kfree(fw_debug);
0093         printk(KERN_INFO "bfad[%d]: Failed to collect fwtrc\n",
0094                 bfad->inst_no);
0095         return -ENOMEM;
0096     }
0097 
0098     file->private_data = fw_debug;
0099 
0100     return 0;
0101 }
0102 
0103 static int
0104 bfad_debugfs_open_fwsave(struct inode *inode, struct file *file)
0105 {
0106     struct bfad_port_s *port = inode->i_private;
0107     struct bfad_s *bfad = port->bfad;
0108     struct bfad_debug_info *fw_debug;
0109     unsigned long flags;
0110     int rc;
0111 
0112     fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
0113     if (!fw_debug)
0114         return -ENOMEM;
0115 
0116     fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
0117 
0118     fw_debug->debug_buffer = vzalloc(fw_debug->buffer_len);
0119     if (!fw_debug->debug_buffer) {
0120         kfree(fw_debug);
0121         printk(KERN_INFO "bfad[%d]: Failed to allocate fwsave buffer\n",
0122                 bfad->inst_no);
0123         return -ENOMEM;
0124     }
0125 
0126     spin_lock_irqsave(&bfad->bfad_lock, flags);
0127     rc = bfa_ioc_debug_fwsave(&bfad->bfa.ioc,
0128             fw_debug->debug_buffer,
0129             &fw_debug->buffer_len);
0130     spin_unlock_irqrestore(&bfad->bfad_lock, flags);
0131     if (rc != BFA_STATUS_OK) {
0132         vfree(fw_debug->debug_buffer);
0133         fw_debug->debug_buffer = NULL;
0134         kfree(fw_debug);
0135         printk(KERN_INFO "bfad[%d]: Failed to collect fwsave\n",
0136                 bfad->inst_no);
0137         return -ENOMEM;
0138     }
0139 
0140     file->private_data = fw_debug;
0141 
0142     return 0;
0143 }
0144 
0145 static int
0146 bfad_debugfs_open_reg(struct inode *inode, struct file *file)
0147 {
0148     struct bfad_debug_info *reg_debug;
0149 
0150     reg_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
0151     if (!reg_debug)
0152         return -ENOMEM;
0153 
0154     reg_debug->i_private = inode->i_private;
0155 
0156     file->private_data = reg_debug;
0157 
0158     return 0;
0159 }
0160 
0161 /* Changes the current file position */
0162 static loff_t
0163 bfad_debugfs_lseek(struct file *file, loff_t offset, int orig)
0164 {
0165     struct bfad_debug_info *debug = file->private_data;
0166     return fixed_size_llseek(file, offset, orig,
0167                 debug->buffer_len);
0168 }
0169 
0170 static ssize_t
0171 bfad_debugfs_read(struct file *file, char __user *buf,
0172             size_t nbytes, loff_t *pos)
0173 {
0174     struct bfad_debug_info *debug = file->private_data;
0175 
0176     if (!debug || !debug->debug_buffer)
0177         return 0;
0178 
0179     return simple_read_from_buffer(buf, nbytes, pos,
0180                 debug->debug_buffer, debug->buffer_len);
0181 }
0182 
0183 #define BFA_REG_CT_ADDRSZ   (0x40000)
0184 #define BFA_REG_CB_ADDRSZ   (0x20000)
0185 #define BFA_REG_ADDRSZ(__ioc)   \
0186     ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ?  \
0187      BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ))
0188 #define BFA_REG_ADDRMSK(__ioc)  (BFA_REG_ADDRSZ(__ioc) - 1)
0189 
0190 static bfa_status_t
0191 bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len)
0192 {
0193     u8  area;
0194 
0195     /* check [16:15] */
0196     area = (offset >> 15) & 0x7;
0197     if (area == 0) {
0198         /* PCIe core register */
0199         if ((offset + (len<<2)) > 0x8000)    /* 8k dwords or 32KB */
0200             return BFA_STATUS_EINVAL;
0201     } else if (area == 0x1) {
0202         /* CB 32 KB memory page */
0203         if ((offset + (len<<2)) > 0x10000)    /* 8k dwords or 32KB */
0204             return BFA_STATUS_EINVAL;
0205     } else {
0206         /* CB register space 64KB */
0207         if ((offset + (len<<2)) > BFA_REG_ADDRMSK(&bfa->ioc))
0208             return BFA_STATUS_EINVAL;
0209     }
0210     return BFA_STATUS_OK;
0211 }
0212 
0213 static ssize_t
0214 bfad_debugfs_read_regrd(struct file *file, char __user *buf,
0215         size_t nbytes, loff_t *pos)
0216 {
0217     struct bfad_debug_info *regrd_debug = file->private_data;
0218     struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
0219     struct bfad_s *bfad = port->bfad;
0220     ssize_t rc;
0221 
0222     if (!bfad->regdata)
0223         return 0;
0224 
0225     rc = simple_read_from_buffer(buf, nbytes, pos,
0226             bfad->regdata, bfad->reglen);
0227 
0228     if ((*pos + nbytes) >= bfad->reglen) {
0229         kfree(bfad->regdata);
0230         bfad->regdata = NULL;
0231         bfad->reglen = 0;
0232     }
0233 
0234     return rc;
0235 }
0236 
0237 static ssize_t
0238 bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
0239         size_t nbytes, loff_t *ppos)
0240 {
0241     struct bfad_debug_info *regrd_debug = file->private_data;
0242     struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
0243     struct bfad_s *bfad = port->bfad;
0244     struct bfa_s *bfa = &bfad->bfa;
0245     struct bfa_ioc_s *ioc = &bfa->ioc;
0246     int addr, rc, i;
0247     u32 len;
0248     u32 *regbuf;
0249     void __iomem *rb, *reg_addr;
0250     unsigned long flags;
0251     void *kern_buf;
0252 
0253     kern_buf = memdup_user(buf, nbytes);
0254     if (IS_ERR(kern_buf))
0255         return PTR_ERR(kern_buf);
0256 
0257     rc = sscanf(kern_buf, "%x:%x", &addr, &len);
0258     if (rc < 2 || len > (UINT_MAX >> 2)) {
0259         printk(KERN_INFO
0260             "bfad[%d]: %s failed to read user buf\n",
0261             bfad->inst_no, __func__);
0262         kfree(kern_buf);
0263         return -EINVAL;
0264     }
0265 
0266     kfree(kern_buf);
0267     kfree(bfad->regdata);
0268     bfad->regdata = NULL;
0269     bfad->reglen = 0;
0270 
0271     bfad->regdata = kzalloc(len << 2, GFP_KERNEL);
0272     if (!bfad->regdata) {
0273         printk(KERN_INFO "bfad[%d]: Failed to allocate regrd buffer\n",
0274                 bfad->inst_no);
0275         return -ENOMEM;
0276     }
0277 
0278     bfad->reglen = len << 2;
0279     rb = bfa_ioc_bar0(ioc);
0280     addr &= BFA_REG_ADDRMSK(ioc);
0281 
0282     /* offset and len sanity check */
0283     rc = bfad_reg_offset_check(bfa, addr, len);
0284     if (rc) {
0285         printk(KERN_INFO "bfad[%d]: Failed reg offset check\n",
0286                 bfad->inst_no);
0287         kfree(bfad->regdata);
0288         bfad->regdata = NULL;
0289         bfad->reglen = 0;
0290         return -EINVAL;
0291     }
0292 
0293     reg_addr = rb + addr;
0294     regbuf =  (u32 *)bfad->regdata;
0295     spin_lock_irqsave(&bfad->bfad_lock, flags);
0296     for (i = 0; i < len; i++) {
0297         *regbuf = readl(reg_addr);
0298         regbuf++;
0299         reg_addr += sizeof(u32);
0300     }
0301     spin_unlock_irqrestore(&bfad->bfad_lock, flags);
0302 
0303     return nbytes;
0304 }
0305 
0306 static ssize_t
0307 bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
0308         size_t nbytes, loff_t *ppos)
0309 {
0310     struct bfad_debug_info *debug = file->private_data;
0311     struct bfad_port_s *port = (struct bfad_port_s *)debug->i_private;
0312     struct bfad_s *bfad = port->bfad;
0313     struct bfa_s *bfa = &bfad->bfa;
0314     struct bfa_ioc_s *ioc = &bfa->ioc;
0315     int addr, val, rc;
0316     void __iomem *reg_addr;
0317     unsigned long flags;
0318     void *kern_buf;
0319 
0320     kern_buf = memdup_user(buf, nbytes);
0321     if (IS_ERR(kern_buf))
0322         return PTR_ERR(kern_buf);
0323 
0324     rc = sscanf(kern_buf, "%x:%x", &addr, &val);
0325     if (rc < 2) {
0326         printk(KERN_INFO
0327             "bfad[%d]: %s failed to read user buf\n",
0328             bfad->inst_no, __func__);
0329         kfree(kern_buf);
0330         return -EINVAL;
0331     }
0332     kfree(kern_buf);
0333 
0334     addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */
0335 
0336     /* offset and len sanity check */
0337     rc = bfad_reg_offset_check(bfa, addr, 1);
0338     if (rc) {
0339         printk(KERN_INFO
0340             "bfad[%d]: Failed reg offset check\n",
0341             bfad->inst_no);
0342         return -EINVAL;
0343     }
0344 
0345     reg_addr = (bfa_ioc_bar0(ioc)) + addr;
0346     spin_lock_irqsave(&bfad->bfad_lock, flags);
0347     writel(val, reg_addr);
0348     spin_unlock_irqrestore(&bfad->bfad_lock, flags);
0349 
0350     return nbytes;
0351 }
0352 
0353 static int
0354 bfad_debugfs_release(struct inode *inode, struct file *file)
0355 {
0356     struct bfad_debug_info *debug = file->private_data;
0357 
0358     if (!debug)
0359         return 0;
0360 
0361     file->private_data = NULL;
0362     kfree(debug);
0363     return 0;
0364 }
0365 
0366 static int
0367 bfad_debugfs_release_fwtrc(struct inode *inode, struct file *file)
0368 {
0369     struct bfad_debug_info *fw_debug = file->private_data;
0370 
0371     if (!fw_debug)
0372         return 0;
0373 
0374     vfree(fw_debug->debug_buffer);
0375 
0376     file->private_data = NULL;
0377     kfree(fw_debug);
0378     return 0;
0379 }
0380 
0381 static const struct file_operations bfad_debugfs_op_drvtrc = {
0382     .owner      =   THIS_MODULE,
0383     .open       =   bfad_debugfs_open_drvtrc,
0384     .llseek     =   bfad_debugfs_lseek,
0385     .read       =   bfad_debugfs_read,
0386     .release    =   bfad_debugfs_release,
0387 };
0388 
0389 static const struct file_operations bfad_debugfs_op_fwtrc = {
0390     .owner      =   THIS_MODULE,
0391     .open       =   bfad_debugfs_open_fwtrc,
0392     .llseek     =   bfad_debugfs_lseek,
0393     .read       =   bfad_debugfs_read,
0394     .release    =   bfad_debugfs_release_fwtrc,
0395 };
0396 
0397 static const struct file_operations bfad_debugfs_op_fwsave = {
0398     .owner      =   THIS_MODULE,
0399     .open       =   bfad_debugfs_open_fwsave,
0400     .llseek     =   bfad_debugfs_lseek,
0401     .read       =   bfad_debugfs_read,
0402     .release    =   bfad_debugfs_release_fwtrc,
0403 };
0404 
0405 static const struct file_operations bfad_debugfs_op_regrd = {
0406     .owner      =   THIS_MODULE,
0407     .open       =   bfad_debugfs_open_reg,
0408     .llseek     =   bfad_debugfs_lseek,
0409     .read       =   bfad_debugfs_read_regrd,
0410     .write      =   bfad_debugfs_write_regrd,
0411     .release    =   bfad_debugfs_release,
0412 };
0413 
0414 static const struct file_operations bfad_debugfs_op_regwr = {
0415     .owner      =   THIS_MODULE,
0416     .open       =   bfad_debugfs_open_reg,
0417     .llseek     =   bfad_debugfs_lseek,
0418     .write      =   bfad_debugfs_write_regwr,
0419     .release    =   bfad_debugfs_release,
0420 };
0421 
0422 struct bfad_debugfs_entry {
0423     const char *name;
0424     umode_t mode;
0425     const struct file_operations *fops;
0426 };
0427 
0428 static const struct bfad_debugfs_entry bfad_debugfs_files[] = {
0429     { "drvtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_drvtrc, },
0430     { "fwtrc",  S_IFREG|S_IRUGO, &bfad_debugfs_op_fwtrc,  },
0431     { "fwsave", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwsave, },
0432     { "regrd",  S_IFREG|S_IRUGO|S_IWUSR, &bfad_debugfs_op_regrd,  },
0433     { "regwr",  S_IFREG|S_IWUSR, &bfad_debugfs_op_regwr,  },
0434 };
0435 
0436 static struct dentry *bfa_debugfs_root;
0437 static atomic_t bfa_debugfs_port_count;
0438 
0439 inline void
0440 bfad_debugfs_init(struct bfad_port_s *port)
0441 {
0442     struct bfad_s *bfad = port->bfad;
0443     const struct bfad_debugfs_entry *file;
0444     char name[64];
0445     int i;
0446 
0447     if (!bfa_debugfs_enable)
0448         return;
0449 
0450     /* Setup the BFA debugfs root directory*/
0451     if (!bfa_debugfs_root) {
0452         bfa_debugfs_root = debugfs_create_dir("bfa", NULL);
0453         atomic_set(&bfa_debugfs_port_count, 0);
0454     }
0455 
0456     /* Setup the pci_dev debugfs directory for the port */
0457     snprintf(name, sizeof(name), "pci_dev:%s", bfad->pci_name);
0458     if (!port->port_debugfs_root) {
0459         port->port_debugfs_root =
0460             debugfs_create_dir(name, bfa_debugfs_root);
0461 
0462         atomic_inc(&bfa_debugfs_port_count);
0463 
0464         for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
0465             file = &bfad_debugfs_files[i];
0466             bfad->bfad_dentry_files[i] =
0467                     debugfs_create_file(file->name,
0468                             file->mode,
0469                             port->port_debugfs_root,
0470                             port,
0471                             file->fops);
0472         }
0473     }
0474 
0475     return;
0476 }
0477 
0478 inline void
0479 bfad_debugfs_exit(struct bfad_port_s *port)
0480 {
0481     struct bfad_s *bfad = port->bfad;
0482     int i;
0483 
0484     for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
0485         if (bfad->bfad_dentry_files[i]) {
0486             debugfs_remove(bfad->bfad_dentry_files[i]);
0487             bfad->bfad_dentry_files[i] = NULL;
0488         }
0489     }
0490 
0491     /* Remove the pci_dev debugfs directory for the port */
0492     if (port->port_debugfs_root) {
0493         debugfs_remove(port->port_debugfs_root);
0494         port->port_debugfs_root = NULL;
0495         atomic_dec(&bfa_debugfs_port_count);
0496     }
0497 
0498     /* Remove the BFA debugfs root directory */
0499     if (atomic_read(&bfa_debugfs_port_count) == 0) {
0500         debugfs_remove(bfa_debugfs_root);
0501         bfa_debugfs_root = NULL;
0502     }
0503 }