17afc5dbdSKrishna Gudipati /* 22732ba56SRasesh Mody * Linux network driver for QLogic BR-series Converged Network Adapter. 37afc5dbdSKrishna Gudipati * 47afc5dbdSKrishna Gudipati * This program is free software; you can redistribute it and/or modify it 57afc5dbdSKrishna Gudipati * under the terms of the GNU General Public License (GPL) Version 2 as 67afc5dbdSKrishna Gudipati * published by the Free Software Foundation 77afc5dbdSKrishna Gudipati * 87afc5dbdSKrishna Gudipati * This program is distributed in the hope that it will be useful, but 97afc5dbdSKrishna Gudipati * WITHOUT ANY WARRANTY; without even the implied warranty of 107afc5dbdSKrishna Gudipati * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 117afc5dbdSKrishna Gudipati * General Public License for more details. 127afc5dbdSKrishna Gudipati */ 137afc5dbdSKrishna Gudipati /* 142732ba56SRasesh Mody * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. 152732ba56SRasesh Mody * Copyright (c) 2014-2015 QLogic Corporation 167afc5dbdSKrishna Gudipati * All rights reserved 172732ba56SRasesh Mody * www.qlogic.com 187afc5dbdSKrishna Gudipati */ 197afc5dbdSKrishna Gudipati 207afc5dbdSKrishna Gudipati #include <linux/debugfs.h> 217afc5dbdSKrishna Gudipati #include <linux/module.h> 227afc5dbdSKrishna Gudipati #include "bnad.h" 237afc5dbdSKrishna Gudipati 247afc5dbdSKrishna Gudipati /* 257afc5dbdSKrishna Gudipati * BNA debufs interface 267afc5dbdSKrishna Gudipati * 277afc5dbdSKrishna Gudipati * To access the interface, debugfs file system should be mounted 287afc5dbdSKrishna Gudipati * if not already mounted using: 297afc5dbdSKrishna Gudipati * mount -t debugfs none /sys/kernel/debug 307afc5dbdSKrishna Gudipati * 317afc5dbdSKrishna Gudipati * BNA Hierarchy: 327afc5dbdSKrishna Gudipati * - bna/pci_dev:<pci_name> 337afc5dbdSKrishna Gudipati * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bna 347afc5dbdSKrishna Gudipati * 357afc5dbdSKrishna Gudipati * Debugging service available per pci_dev: 367afc5dbdSKrishna Gudipati * fwtrc: To collect current firmware trace. 377afc5dbdSKrishna Gudipati * fwsave: To collect last saved fw trace as a result of firmware crash. 387afc5dbdSKrishna Gudipati * regwr: To write one word to chip register 397afc5dbdSKrishna Gudipati * regrd: To read one or more words from chip register. 407afc5dbdSKrishna Gudipati */ 417afc5dbdSKrishna Gudipati 427afc5dbdSKrishna Gudipati struct bnad_debug_info { 437afc5dbdSKrishna Gudipati char *debug_buffer; 447afc5dbdSKrishna Gudipati void *i_private; 457afc5dbdSKrishna Gudipati int buffer_len; 467afc5dbdSKrishna Gudipati }; 477afc5dbdSKrishna Gudipati 487afc5dbdSKrishna Gudipati static int 497afc5dbdSKrishna Gudipati bnad_debugfs_open_fwtrc(struct inode *inode, struct file *file) 507afc5dbdSKrishna Gudipati { 517afc5dbdSKrishna Gudipati struct bnad *bnad = inode->i_private; 527afc5dbdSKrishna Gudipati struct bnad_debug_info *fw_debug; 537afc5dbdSKrishna Gudipati unsigned long flags; 547afc5dbdSKrishna Gudipati int rc; 557afc5dbdSKrishna Gudipati 567afc5dbdSKrishna Gudipati fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); 577afc5dbdSKrishna Gudipati if (!fw_debug) 587afc5dbdSKrishna Gudipati return -ENOMEM; 597afc5dbdSKrishna Gudipati 607afc5dbdSKrishna Gudipati fw_debug->buffer_len = BNA_DBG_FWTRC_LEN; 617afc5dbdSKrishna Gudipati 627afc5dbdSKrishna Gudipati fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL); 637afc5dbdSKrishna Gudipati if (!fw_debug->debug_buffer) { 647afc5dbdSKrishna Gudipati kfree(fw_debug); 657afc5dbdSKrishna Gudipati fw_debug = NULL; 667afc5dbdSKrishna Gudipati return -ENOMEM; 677afc5dbdSKrishna Gudipati } 687afc5dbdSKrishna Gudipati 697afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 707afc5dbdSKrishna Gudipati rc = bfa_nw_ioc_debug_fwtrc(&bnad->bna.ioceth.ioc, 717afc5dbdSKrishna Gudipati fw_debug->debug_buffer, 727afc5dbdSKrishna Gudipati &fw_debug->buffer_len); 737afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 747afc5dbdSKrishna Gudipati if (rc != BFA_STATUS_OK) { 757afc5dbdSKrishna Gudipati kfree(fw_debug->debug_buffer); 767afc5dbdSKrishna Gudipati fw_debug->debug_buffer = NULL; 777afc5dbdSKrishna Gudipati kfree(fw_debug); 787afc5dbdSKrishna Gudipati fw_debug = NULL; 79ecc46789SIvan Vecera netdev_warn(bnad->netdev, "failed to collect fwtrc\n"); 807afc5dbdSKrishna Gudipati return -ENOMEM; 817afc5dbdSKrishna Gudipati } 827afc5dbdSKrishna Gudipati 837afc5dbdSKrishna Gudipati file->private_data = fw_debug; 847afc5dbdSKrishna Gudipati 857afc5dbdSKrishna Gudipati return 0; 867afc5dbdSKrishna Gudipati } 877afc5dbdSKrishna Gudipati 887afc5dbdSKrishna Gudipati static int 897afc5dbdSKrishna Gudipati bnad_debugfs_open_fwsave(struct inode *inode, struct file *file) 907afc5dbdSKrishna Gudipati { 917afc5dbdSKrishna Gudipati struct bnad *bnad = inode->i_private; 927afc5dbdSKrishna Gudipati struct bnad_debug_info *fw_debug; 937afc5dbdSKrishna Gudipati unsigned long flags; 947afc5dbdSKrishna Gudipati int rc; 957afc5dbdSKrishna Gudipati 967afc5dbdSKrishna Gudipati fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); 977afc5dbdSKrishna Gudipati if (!fw_debug) 987afc5dbdSKrishna Gudipati return -ENOMEM; 997afc5dbdSKrishna Gudipati 1007afc5dbdSKrishna Gudipati fw_debug->buffer_len = BNA_DBG_FWTRC_LEN; 1017afc5dbdSKrishna Gudipati 1027afc5dbdSKrishna Gudipati fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL); 1037afc5dbdSKrishna Gudipati if (!fw_debug->debug_buffer) { 1047afc5dbdSKrishna Gudipati kfree(fw_debug); 1057afc5dbdSKrishna Gudipati fw_debug = NULL; 1067afc5dbdSKrishna Gudipati return -ENOMEM; 1077afc5dbdSKrishna Gudipati } 1087afc5dbdSKrishna Gudipati 1097afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 1107afc5dbdSKrishna Gudipati rc = bfa_nw_ioc_debug_fwsave(&bnad->bna.ioceth.ioc, 1117afc5dbdSKrishna Gudipati fw_debug->debug_buffer, 1127afc5dbdSKrishna Gudipati &fw_debug->buffer_len); 1137afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1147afc5dbdSKrishna Gudipati if (rc != BFA_STATUS_OK && rc != BFA_STATUS_ENOFSAVE) { 1157afc5dbdSKrishna Gudipati kfree(fw_debug->debug_buffer); 1167afc5dbdSKrishna Gudipati fw_debug->debug_buffer = NULL; 1177afc5dbdSKrishna Gudipati kfree(fw_debug); 1187afc5dbdSKrishna Gudipati fw_debug = NULL; 119ecc46789SIvan Vecera netdev_warn(bnad->netdev, "failed to collect fwsave\n"); 1207afc5dbdSKrishna Gudipati return -ENOMEM; 1217afc5dbdSKrishna Gudipati } 1227afc5dbdSKrishna Gudipati 1237afc5dbdSKrishna Gudipati file->private_data = fw_debug; 1247afc5dbdSKrishna Gudipati 1257afc5dbdSKrishna Gudipati return 0; 1267afc5dbdSKrishna Gudipati } 1277afc5dbdSKrishna Gudipati 1287afc5dbdSKrishna Gudipati static int 1297afc5dbdSKrishna Gudipati bnad_debugfs_open_reg(struct inode *inode, struct file *file) 1307afc5dbdSKrishna Gudipati { 1317afc5dbdSKrishna Gudipati struct bnad_debug_info *reg_debug; 1327afc5dbdSKrishna Gudipati 1337afc5dbdSKrishna Gudipati reg_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); 1347afc5dbdSKrishna Gudipati if (!reg_debug) 1357afc5dbdSKrishna Gudipati return -ENOMEM; 1367afc5dbdSKrishna Gudipati 1377afc5dbdSKrishna Gudipati reg_debug->i_private = inode->i_private; 1387afc5dbdSKrishna Gudipati 1397afc5dbdSKrishna Gudipati file->private_data = reg_debug; 1407afc5dbdSKrishna Gudipati 1417afc5dbdSKrishna Gudipati return 0; 1427afc5dbdSKrishna Gudipati } 1437afc5dbdSKrishna Gudipati 1447afc5dbdSKrishna Gudipati static int 1457afc5dbdSKrishna Gudipati bnad_get_debug_drvinfo(struct bnad *bnad, void *buffer, u32 len) 1467afc5dbdSKrishna Gudipati { 1477afc5dbdSKrishna Gudipati struct bnad_drvinfo *drvinfo = (struct bnad_drvinfo *) buffer; 1487afc5dbdSKrishna Gudipati struct bnad_iocmd_comp fcomp; 1497afc5dbdSKrishna Gudipati unsigned long flags = 0; 1507afc5dbdSKrishna Gudipati int ret = BFA_STATUS_FAILED; 1517afc5dbdSKrishna Gudipati 1527afc5dbdSKrishna Gudipati /* Get IOC info */ 1537afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 1547afc5dbdSKrishna Gudipati bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, &drvinfo->ioc_attr); 1557afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1567afc5dbdSKrishna Gudipati 1577afc5dbdSKrishna Gudipati /* Retrieve CEE related info */ 1587afc5dbdSKrishna Gudipati fcomp.bnad = bnad; 1597afc5dbdSKrishna Gudipati fcomp.comp_status = 0; 1607afc5dbdSKrishna Gudipati init_completion(&fcomp.comp); 1617afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 1627afc5dbdSKrishna Gudipati ret = bfa_nw_cee_get_attr(&bnad->bna.cee, &drvinfo->cee_attr, 1637afc5dbdSKrishna Gudipati bnad_cb_completion, &fcomp); 1647afc5dbdSKrishna Gudipati if (ret != BFA_STATUS_OK) { 1657afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1667afc5dbdSKrishna Gudipati goto out; 1677afc5dbdSKrishna Gudipati } 1687afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1697afc5dbdSKrishna Gudipati wait_for_completion(&fcomp.comp); 1707afc5dbdSKrishna Gudipati drvinfo->cee_status = fcomp.comp_status; 1717afc5dbdSKrishna Gudipati 1727afc5dbdSKrishna Gudipati /* Retrieve flash partition info */ 1737afc5dbdSKrishna Gudipati fcomp.comp_status = 0; 1746e4ab361SNicholas Mc Guire reinit_completion(&fcomp.comp); 1757afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 1767afc5dbdSKrishna Gudipati ret = bfa_nw_flash_get_attr(&bnad->bna.flash, &drvinfo->flash_attr, 1777afc5dbdSKrishna Gudipati bnad_cb_completion, &fcomp); 1787afc5dbdSKrishna Gudipati if (ret != BFA_STATUS_OK) { 1797afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1807afc5dbdSKrishna Gudipati goto out; 1817afc5dbdSKrishna Gudipati } 1827afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1837afc5dbdSKrishna Gudipati wait_for_completion(&fcomp.comp); 1847afc5dbdSKrishna Gudipati drvinfo->flash_status = fcomp.comp_status; 1857afc5dbdSKrishna Gudipati out: 1867afc5dbdSKrishna Gudipati return ret; 1877afc5dbdSKrishna Gudipati } 1887afc5dbdSKrishna Gudipati 1897afc5dbdSKrishna Gudipati static int 1907afc5dbdSKrishna Gudipati bnad_debugfs_open_drvinfo(struct inode *inode, struct file *file) 1917afc5dbdSKrishna Gudipati { 1927afc5dbdSKrishna Gudipati struct bnad *bnad = inode->i_private; 1937afc5dbdSKrishna Gudipati struct bnad_debug_info *drv_info; 1947afc5dbdSKrishna Gudipati int rc; 1957afc5dbdSKrishna Gudipati 1967afc5dbdSKrishna Gudipati drv_info = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); 1977afc5dbdSKrishna Gudipati if (!drv_info) 1987afc5dbdSKrishna Gudipati return -ENOMEM; 1997afc5dbdSKrishna Gudipati 2007afc5dbdSKrishna Gudipati drv_info->buffer_len = sizeof(struct bnad_drvinfo); 2017afc5dbdSKrishna Gudipati 2027afc5dbdSKrishna Gudipati drv_info->debug_buffer = kzalloc(drv_info->buffer_len, GFP_KERNEL); 2037afc5dbdSKrishna Gudipati if (!drv_info->debug_buffer) { 2047afc5dbdSKrishna Gudipati kfree(drv_info); 2057afc5dbdSKrishna Gudipati drv_info = NULL; 2067afc5dbdSKrishna Gudipati return -ENOMEM; 2077afc5dbdSKrishna Gudipati } 2087afc5dbdSKrishna Gudipati 2097afc5dbdSKrishna Gudipati mutex_lock(&bnad->conf_mutex); 2107afc5dbdSKrishna Gudipati rc = bnad_get_debug_drvinfo(bnad, drv_info->debug_buffer, 2117afc5dbdSKrishna Gudipati drv_info->buffer_len); 2127afc5dbdSKrishna Gudipati mutex_unlock(&bnad->conf_mutex); 2137afc5dbdSKrishna Gudipati if (rc != BFA_STATUS_OK) { 2147afc5dbdSKrishna Gudipati kfree(drv_info->debug_buffer); 2157afc5dbdSKrishna Gudipati drv_info->debug_buffer = NULL; 2167afc5dbdSKrishna Gudipati kfree(drv_info); 2177afc5dbdSKrishna Gudipati drv_info = NULL; 218ecc46789SIvan Vecera netdev_warn(bnad->netdev, "failed to collect drvinfo\n"); 2197afc5dbdSKrishna Gudipati return -ENOMEM; 2207afc5dbdSKrishna Gudipati } 2217afc5dbdSKrishna Gudipati 2227afc5dbdSKrishna Gudipati file->private_data = drv_info; 2237afc5dbdSKrishna Gudipati 2247afc5dbdSKrishna Gudipati return 0; 2257afc5dbdSKrishna Gudipati } 2267afc5dbdSKrishna Gudipati 2277afc5dbdSKrishna Gudipati /* Changes the current file position */ 2287afc5dbdSKrishna Gudipati static loff_t 2297afc5dbdSKrishna Gudipati bnad_debugfs_lseek(struct file *file, loff_t offset, int orig) 2307afc5dbdSKrishna Gudipati { 2317afc5dbdSKrishna Gudipati struct bnad_debug_info *debug = file->private_data; 2327afc5dbdSKrishna Gudipati 2337afc5dbdSKrishna Gudipati if (!debug) 2347afc5dbdSKrishna Gudipati return -EINVAL; 2357afc5dbdSKrishna Gudipati 236c0caa07bSAl Viro return fixed_size_llseek(file, offset, orig, debug->buffer_len); 2377afc5dbdSKrishna Gudipati } 2387afc5dbdSKrishna Gudipati 2397afc5dbdSKrishna Gudipati static ssize_t 2407afc5dbdSKrishna Gudipati bnad_debugfs_read(struct file *file, char __user *buf, 2417afc5dbdSKrishna Gudipati size_t nbytes, loff_t *pos) 2427afc5dbdSKrishna Gudipati { 2437afc5dbdSKrishna Gudipati struct bnad_debug_info *debug = file->private_data; 2447afc5dbdSKrishna Gudipati 2457afc5dbdSKrishna Gudipati if (!debug || !debug->debug_buffer) 2467afc5dbdSKrishna Gudipati return 0; 2477afc5dbdSKrishna Gudipati 2487afc5dbdSKrishna Gudipati return simple_read_from_buffer(buf, nbytes, pos, 2497afc5dbdSKrishna Gudipati debug->debug_buffer, debug->buffer_len); 2507afc5dbdSKrishna Gudipati } 2517afc5dbdSKrishna Gudipati 2527afc5dbdSKrishna Gudipati #define BFA_REG_CT_ADDRSZ (0x40000) 2537afc5dbdSKrishna Gudipati #define BFA_REG_CB_ADDRSZ (0x20000) 2547afc5dbdSKrishna Gudipati #define BFA_REG_ADDRSZ(__ioc) \ 2557afc5dbdSKrishna Gudipati ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \ 2567afc5dbdSKrishna Gudipati BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ)) 2577afc5dbdSKrishna Gudipati #define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1) 2587afc5dbdSKrishna Gudipati 2597afc5dbdSKrishna Gudipati /* 2607afc5dbdSKrishna Gudipati * Function to check if the register offset passed is valid. 2617afc5dbdSKrishna Gudipati */ 2627afc5dbdSKrishna Gudipati static int 2637afc5dbdSKrishna Gudipati bna_reg_offset_check(struct bfa_ioc *ioc, u32 offset, u32 len) 2647afc5dbdSKrishna Gudipati { 2657afc5dbdSKrishna Gudipati u8 area; 2667afc5dbdSKrishna Gudipati 2677afc5dbdSKrishna Gudipati /* check [16:15] */ 2687afc5dbdSKrishna Gudipati area = (offset >> 15) & 0x7; 2697afc5dbdSKrishna Gudipati if (area == 0) { 2707afc5dbdSKrishna Gudipati /* PCIe core register */ 271ebb56d37SIvan Vecera if (offset + (len << 2) > 0x8000) /* 8k dwords or 32KB */ 2727afc5dbdSKrishna Gudipati return BFA_STATUS_EINVAL; 2737afc5dbdSKrishna Gudipati } else if (area == 0x1) { 2747afc5dbdSKrishna Gudipati /* CB 32 KB memory page */ 275ebb56d37SIvan Vecera if (offset + (len << 2) > 0x10000) /* 8k dwords or 32KB */ 2767afc5dbdSKrishna Gudipati return BFA_STATUS_EINVAL; 2777afc5dbdSKrishna Gudipati } else { 2787afc5dbdSKrishna Gudipati /* CB register space 64KB */ 279ebb56d37SIvan Vecera if (offset + (len << 2) > BFA_REG_ADDRMSK(ioc)) 2807afc5dbdSKrishna Gudipati return BFA_STATUS_EINVAL; 2817afc5dbdSKrishna Gudipati } 2827afc5dbdSKrishna Gudipati return BFA_STATUS_OK; 2837afc5dbdSKrishna Gudipati } 2847afc5dbdSKrishna Gudipati 2857afc5dbdSKrishna Gudipati static ssize_t 2867afc5dbdSKrishna Gudipati bnad_debugfs_read_regrd(struct file *file, char __user *buf, 2877afc5dbdSKrishna Gudipati size_t nbytes, loff_t *pos) 2887afc5dbdSKrishna Gudipati { 2897afc5dbdSKrishna Gudipati struct bnad_debug_info *regrd_debug = file->private_data; 2907afc5dbdSKrishna Gudipati struct bnad *bnad = (struct bnad *)regrd_debug->i_private; 2917afc5dbdSKrishna Gudipati ssize_t rc; 2927afc5dbdSKrishna Gudipati 2937afc5dbdSKrishna Gudipati if (!bnad->regdata) 2947afc5dbdSKrishna Gudipati return 0; 2957afc5dbdSKrishna Gudipati 2967afc5dbdSKrishna Gudipati rc = simple_read_from_buffer(buf, nbytes, pos, 2977afc5dbdSKrishna Gudipati bnad->regdata, bnad->reglen); 2987afc5dbdSKrishna Gudipati 2997afc5dbdSKrishna Gudipati if ((*pos + nbytes) >= bnad->reglen) { 3007afc5dbdSKrishna Gudipati kfree(bnad->regdata); 3017afc5dbdSKrishna Gudipati bnad->regdata = NULL; 3027afc5dbdSKrishna Gudipati bnad->reglen = 0; 3037afc5dbdSKrishna Gudipati } 3047afc5dbdSKrishna Gudipati 3057afc5dbdSKrishna Gudipati return rc; 3067afc5dbdSKrishna Gudipati } 3077afc5dbdSKrishna Gudipati 3087afc5dbdSKrishna Gudipati static ssize_t 3097afc5dbdSKrishna Gudipati bnad_debugfs_write_regrd(struct file *file, const char __user *buf, 3107afc5dbdSKrishna Gudipati size_t nbytes, loff_t *ppos) 3117afc5dbdSKrishna Gudipati { 3127afc5dbdSKrishna Gudipati struct bnad_debug_info *regrd_debug = file->private_data; 3137afc5dbdSKrishna Gudipati struct bnad *bnad = (struct bnad *)regrd_debug->i_private; 3147afc5dbdSKrishna Gudipati struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc; 315112b6b79Sxypron.glpk@gmx.de int rc, i; 316112b6b79Sxypron.glpk@gmx.de u32 addr, len; 3177afc5dbdSKrishna Gudipati u32 *regbuf; 3187afc5dbdSKrishna Gudipati void __iomem *rb, *reg_addr; 3197afc5dbdSKrishna Gudipati unsigned long flags; 3207afc5dbdSKrishna Gudipati void *kern_buf; 3217afc5dbdSKrishna Gudipati 322d0e6a806SIvan Vecera /* Copy the user space buf */ 323d0e6a806SIvan Vecera kern_buf = memdup_user(buf, nbytes); 324d0e6a806SIvan Vecera if (IS_ERR(kern_buf)) 325d0e6a806SIvan Vecera return PTR_ERR(kern_buf); 3267afc5dbdSKrishna Gudipati 3277afc5dbdSKrishna Gudipati rc = sscanf(kern_buf, "%x:%x", &addr, &len); 32813e2d518SDan Carpenter if (rc < 2 || len > UINT_MAX >> 2) { 329ecc46789SIvan Vecera netdev_warn(bnad->netdev, "failed to read user buffer\n"); 3307afc5dbdSKrishna Gudipati kfree(kern_buf); 3317afc5dbdSKrishna Gudipati return -EINVAL; 3327afc5dbdSKrishna Gudipati } 3337afc5dbdSKrishna Gudipati 3347afc5dbdSKrishna Gudipati kfree(kern_buf); 3357afc5dbdSKrishna Gudipati kfree(bnad->regdata); 3367afc5dbdSKrishna Gudipati bnad->reglen = 0; 3377afc5dbdSKrishna Gudipati 3387afc5dbdSKrishna Gudipati bnad->regdata = kzalloc(len << 2, GFP_KERNEL); 339e404decbSJoe Perches if (!bnad->regdata) 3407afc5dbdSKrishna Gudipati return -ENOMEM; 3417afc5dbdSKrishna Gudipati 3427afc5dbdSKrishna Gudipati bnad->reglen = len << 2; 3437afc5dbdSKrishna Gudipati rb = bfa_ioc_bar0(ioc); 3447afc5dbdSKrishna Gudipati addr &= BFA_REG_ADDRMSK(ioc); 3457afc5dbdSKrishna Gudipati 3467afc5dbdSKrishna Gudipati /* offset and len sanity check */ 3477afc5dbdSKrishna Gudipati rc = bna_reg_offset_check(ioc, addr, len); 3487afc5dbdSKrishna Gudipati if (rc) { 349ecc46789SIvan Vecera netdev_warn(bnad->netdev, "failed reg offset check\n"); 3507afc5dbdSKrishna Gudipati kfree(bnad->regdata); 3517afc5dbdSKrishna Gudipati bnad->regdata = NULL; 3527afc5dbdSKrishna Gudipati bnad->reglen = 0; 3537afc5dbdSKrishna Gudipati return -EINVAL; 3547afc5dbdSKrishna Gudipati } 3557afc5dbdSKrishna Gudipati 3567afc5dbdSKrishna Gudipati reg_addr = rb + addr; 3577afc5dbdSKrishna Gudipati regbuf = (u32 *)bnad->regdata; 3587afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 3597afc5dbdSKrishna Gudipati for (i = 0; i < len; i++) { 3607afc5dbdSKrishna Gudipati *regbuf = readl(reg_addr); 3617afc5dbdSKrishna Gudipati regbuf++; 3627afc5dbdSKrishna Gudipati reg_addr += sizeof(u32); 3637afc5dbdSKrishna Gudipati } 3647afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 3657afc5dbdSKrishna Gudipati 3667afc5dbdSKrishna Gudipati return nbytes; 3677afc5dbdSKrishna Gudipati } 3687afc5dbdSKrishna Gudipati 3697afc5dbdSKrishna Gudipati static ssize_t 3707afc5dbdSKrishna Gudipati bnad_debugfs_write_regwr(struct file *file, const char __user *buf, 3717afc5dbdSKrishna Gudipati size_t nbytes, loff_t *ppos) 3727afc5dbdSKrishna Gudipati { 3737afc5dbdSKrishna Gudipati struct bnad_debug_info *debug = file->private_data; 3747afc5dbdSKrishna Gudipati struct bnad *bnad = (struct bnad *)debug->i_private; 3757afc5dbdSKrishna Gudipati struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc; 3764c2e9e29Sxypron.glpk@gmx.de int rc; 3774c2e9e29Sxypron.glpk@gmx.de u32 addr, val; 3787afc5dbdSKrishna Gudipati void __iomem *reg_addr; 3797afc5dbdSKrishna Gudipati unsigned long flags; 3807afc5dbdSKrishna Gudipati void *kern_buf; 3817afc5dbdSKrishna Gudipati 382d0e6a806SIvan Vecera /* Copy the user space buf */ 383d0e6a806SIvan Vecera kern_buf = memdup_user(buf, nbytes); 384d0e6a806SIvan Vecera if (IS_ERR(kern_buf)) 385d0e6a806SIvan Vecera return PTR_ERR(kern_buf); 3867afc5dbdSKrishna Gudipati 3877afc5dbdSKrishna Gudipati rc = sscanf(kern_buf, "%x:%x", &addr, &val); 3887afc5dbdSKrishna Gudipati if (rc < 2) { 389ecc46789SIvan Vecera netdev_warn(bnad->netdev, "failed to read user buffer\n"); 3907afc5dbdSKrishna Gudipati kfree(kern_buf); 3917afc5dbdSKrishna Gudipati return -EINVAL; 3927afc5dbdSKrishna Gudipati } 3937afc5dbdSKrishna Gudipati kfree(kern_buf); 3947afc5dbdSKrishna Gudipati 3957afc5dbdSKrishna Gudipati addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */ 3967afc5dbdSKrishna Gudipati 3977afc5dbdSKrishna Gudipati /* offset and len sanity check */ 3987afc5dbdSKrishna Gudipati rc = bna_reg_offset_check(ioc, addr, 1); 3997afc5dbdSKrishna Gudipati if (rc) { 400ecc46789SIvan Vecera netdev_warn(bnad->netdev, "failed reg offset check\n"); 4017afc5dbdSKrishna Gudipati return -EINVAL; 4027afc5dbdSKrishna Gudipati } 4037afc5dbdSKrishna Gudipati 4047afc5dbdSKrishna Gudipati reg_addr = (bfa_ioc_bar0(ioc)) + addr; 4057afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 4067afc5dbdSKrishna Gudipati writel(val, reg_addr); 4077afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 4087afc5dbdSKrishna Gudipati 4097afc5dbdSKrishna Gudipati return nbytes; 4107afc5dbdSKrishna Gudipati } 4117afc5dbdSKrishna Gudipati 4127afc5dbdSKrishna Gudipati static int 4137afc5dbdSKrishna Gudipati bnad_debugfs_release(struct inode *inode, struct file *file) 4147afc5dbdSKrishna Gudipati { 4157afc5dbdSKrishna Gudipati struct bnad_debug_info *debug = file->private_data; 4167afc5dbdSKrishna Gudipati 4177afc5dbdSKrishna Gudipati if (!debug) 4187afc5dbdSKrishna Gudipati return 0; 4197afc5dbdSKrishna Gudipati 4207afc5dbdSKrishna Gudipati file->private_data = NULL; 4217afc5dbdSKrishna Gudipati kfree(debug); 4227afc5dbdSKrishna Gudipati return 0; 4237afc5dbdSKrishna Gudipati } 4247afc5dbdSKrishna Gudipati 4257afc5dbdSKrishna Gudipati static int 4267afc5dbdSKrishna Gudipati bnad_debugfs_buffer_release(struct inode *inode, struct file *file) 4277afc5dbdSKrishna Gudipati { 4287afc5dbdSKrishna Gudipati struct bnad_debug_info *debug = file->private_data; 4297afc5dbdSKrishna Gudipati 4307afc5dbdSKrishna Gudipati if (!debug) 4317afc5dbdSKrishna Gudipati return 0; 4327afc5dbdSKrishna Gudipati 4337afc5dbdSKrishna Gudipati kfree(debug->debug_buffer); 4347afc5dbdSKrishna Gudipati 4357afc5dbdSKrishna Gudipati file->private_data = NULL; 4367afc5dbdSKrishna Gudipati kfree(debug); 4377afc5dbdSKrishna Gudipati debug = NULL; 4387afc5dbdSKrishna Gudipati return 0; 4397afc5dbdSKrishna Gudipati } 4407afc5dbdSKrishna Gudipati 4417afc5dbdSKrishna Gudipati static const struct file_operations bnad_debugfs_op_fwtrc = { 4427afc5dbdSKrishna Gudipati .owner = THIS_MODULE, 4437afc5dbdSKrishna Gudipati .open = bnad_debugfs_open_fwtrc, 4447afc5dbdSKrishna Gudipati .llseek = bnad_debugfs_lseek, 4457afc5dbdSKrishna Gudipati .read = bnad_debugfs_read, 4467afc5dbdSKrishna Gudipati .release = bnad_debugfs_buffer_release, 4477afc5dbdSKrishna Gudipati }; 4487afc5dbdSKrishna Gudipati 4497afc5dbdSKrishna Gudipati static const struct file_operations bnad_debugfs_op_fwsave = { 4507afc5dbdSKrishna Gudipati .owner = THIS_MODULE, 4517afc5dbdSKrishna Gudipati .open = bnad_debugfs_open_fwsave, 4527afc5dbdSKrishna Gudipati .llseek = bnad_debugfs_lseek, 4537afc5dbdSKrishna Gudipati .read = bnad_debugfs_read, 4547afc5dbdSKrishna Gudipati .release = bnad_debugfs_buffer_release, 4557afc5dbdSKrishna Gudipati }; 4567afc5dbdSKrishna Gudipati 4577afc5dbdSKrishna Gudipati static const struct file_operations bnad_debugfs_op_regrd = { 4587afc5dbdSKrishna Gudipati .owner = THIS_MODULE, 4597afc5dbdSKrishna Gudipati .open = bnad_debugfs_open_reg, 4607afc5dbdSKrishna Gudipati .llseek = bnad_debugfs_lseek, 4617afc5dbdSKrishna Gudipati .read = bnad_debugfs_read_regrd, 4627afc5dbdSKrishna Gudipati .write = bnad_debugfs_write_regrd, 4637afc5dbdSKrishna Gudipati .release = bnad_debugfs_release, 4647afc5dbdSKrishna Gudipati }; 4657afc5dbdSKrishna Gudipati 4667afc5dbdSKrishna Gudipati static const struct file_operations bnad_debugfs_op_regwr = { 4677afc5dbdSKrishna Gudipati .owner = THIS_MODULE, 4687afc5dbdSKrishna Gudipati .open = bnad_debugfs_open_reg, 4697afc5dbdSKrishna Gudipati .llseek = bnad_debugfs_lseek, 4707afc5dbdSKrishna Gudipati .write = bnad_debugfs_write_regwr, 4717afc5dbdSKrishna Gudipati .release = bnad_debugfs_release, 4727afc5dbdSKrishna Gudipati }; 4737afc5dbdSKrishna Gudipati 4747afc5dbdSKrishna Gudipati static const struct file_operations bnad_debugfs_op_drvinfo = { 4757afc5dbdSKrishna Gudipati .owner = THIS_MODULE, 4767afc5dbdSKrishna Gudipati .open = bnad_debugfs_open_drvinfo, 4777afc5dbdSKrishna Gudipati .llseek = bnad_debugfs_lseek, 4787afc5dbdSKrishna Gudipati .read = bnad_debugfs_read, 4797afc5dbdSKrishna Gudipati .release = bnad_debugfs_buffer_release, 4807afc5dbdSKrishna Gudipati }; 4817afc5dbdSKrishna Gudipati 4827afc5dbdSKrishna Gudipati struct bnad_debugfs_entry { 4837afc5dbdSKrishna Gudipati const char *name; 48488187398SAl Viro umode_t mode; 4857afc5dbdSKrishna Gudipati const struct file_operations *fops; 4867afc5dbdSKrishna Gudipati }; 4877afc5dbdSKrishna Gudipati 4887afc5dbdSKrishna Gudipati static const struct bnad_debugfs_entry bnad_debugfs_files[] = { 489d3757ba4SJoe Perches { "fwtrc", S_IFREG | 0444, &bnad_debugfs_op_fwtrc, }, 490d3757ba4SJoe Perches { "fwsave", S_IFREG | 0444, &bnad_debugfs_op_fwsave, }, 491d3757ba4SJoe Perches { "regrd", S_IFREG | 0644, &bnad_debugfs_op_regrd, }, 492d3757ba4SJoe Perches { "regwr", S_IFREG | 0200, &bnad_debugfs_op_regwr, }, 493d3757ba4SJoe Perches { "drvinfo", S_IFREG | 0444, &bnad_debugfs_op_drvinfo, }, 4947afc5dbdSKrishna Gudipati }; 4957afc5dbdSKrishna Gudipati 4967afc5dbdSKrishna Gudipati static struct dentry *bna_debugfs_root; 4977afc5dbdSKrishna Gudipati static atomic_t bna_debugfs_port_count; 4987afc5dbdSKrishna Gudipati 4997afc5dbdSKrishna Gudipati /* Initialize debugfs interface for BNA */ 5007afc5dbdSKrishna Gudipati void 5017afc5dbdSKrishna Gudipati bnad_debugfs_init(struct bnad *bnad) 5027afc5dbdSKrishna Gudipati { 5037afc5dbdSKrishna Gudipati const struct bnad_debugfs_entry *file; 5047afc5dbdSKrishna Gudipati char name[64]; 5057afc5dbdSKrishna Gudipati int i; 5067afc5dbdSKrishna Gudipati 5077afc5dbdSKrishna Gudipati /* Setup the BNA debugfs root directory*/ 5087afc5dbdSKrishna Gudipati if (!bna_debugfs_root) { 5097afc5dbdSKrishna Gudipati bna_debugfs_root = debugfs_create_dir("bna", NULL); 5107afc5dbdSKrishna Gudipati atomic_set(&bna_debugfs_port_count, 0); 5117afc5dbdSKrishna Gudipati if (!bna_debugfs_root) { 512ecc46789SIvan Vecera netdev_warn(bnad->netdev, 513ecc46789SIvan Vecera "debugfs root dir creation failed\n"); 5147afc5dbdSKrishna Gudipati return; 5157afc5dbdSKrishna Gudipati } 5167afc5dbdSKrishna Gudipati } 5177afc5dbdSKrishna Gudipati 5187afc5dbdSKrishna Gudipati /* Setup the pci_dev debugfs directory for the port */ 5197afc5dbdSKrishna Gudipati snprintf(name, sizeof(name), "pci_dev:%s", pci_name(bnad->pcidev)); 5207afc5dbdSKrishna Gudipati if (!bnad->port_debugfs_root) { 5217afc5dbdSKrishna Gudipati bnad->port_debugfs_root = 5227afc5dbdSKrishna Gudipati debugfs_create_dir(name, bna_debugfs_root); 5237afc5dbdSKrishna Gudipati if (!bnad->port_debugfs_root) { 524ecc46789SIvan Vecera netdev_warn(bnad->netdev, 525ecc46789SIvan Vecera "debugfs root dir creation failed\n"); 5267afc5dbdSKrishna Gudipati return; 5277afc5dbdSKrishna Gudipati } 5287afc5dbdSKrishna Gudipati 5297afc5dbdSKrishna Gudipati atomic_inc(&bna_debugfs_port_count); 5307afc5dbdSKrishna Gudipati 5317afc5dbdSKrishna Gudipati for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) { 5327afc5dbdSKrishna Gudipati file = &bnad_debugfs_files[i]; 5337afc5dbdSKrishna Gudipati bnad->bnad_dentry_files[i] = 5347afc5dbdSKrishna Gudipati debugfs_create_file(file->name, 5357afc5dbdSKrishna Gudipati file->mode, 5367afc5dbdSKrishna Gudipati bnad->port_debugfs_root, 5377afc5dbdSKrishna Gudipati bnad, 5387afc5dbdSKrishna Gudipati file->fops); 5397afc5dbdSKrishna Gudipati if (!bnad->bnad_dentry_files[i]) { 540ecc46789SIvan Vecera netdev_warn(bnad->netdev, 541ecc46789SIvan Vecera "create %s entry failed\n", 542ecc46789SIvan Vecera file->name); 5437afc5dbdSKrishna Gudipati return; 5447afc5dbdSKrishna Gudipati } 5457afc5dbdSKrishna Gudipati } 5467afc5dbdSKrishna Gudipati } 5477afc5dbdSKrishna Gudipati } 5487afc5dbdSKrishna Gudipati 5497afc5dbdSKrishna Gudipati /* Uninitialize debugfs interface for BNA */ 5507afc5dbdSKrishna Gudipati void 5517afc5dbdSKrishna Gudipati bnad_debugfs_uninit(struct bnad *bnad) 5527afc5dbdSKrishna Gudipati { 5537afc5dbdSKrishna Gudipati int i; 5547afc5dbdSKrishna Gudipati 5557afc5dbdSKrishna Gudipati for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) { 5567afc5dbdSKrishna Gudipati if (bnad->bnad_dentry_files[i]) { 5577afc5dbdSKrishna Gudipati debugfs_remove(bnad->bnad_dentry_files[i]); 5587afc5dbdSKrishna Gudipati bnad->bnad_dentry_files[i] = NULL; 5597afc5dbdSKrishna Gudipati } 5607afc5dbdSKrishna Gudipati } 5617afc5dbdSKrishna Gudipati 5627afc5dbdSKrishna Gudipati /* Remove the pci_dev debugfs directory for the port */ 5637afc5dbdSKrishna Gudipati if (bnad->port_debugfs_root) { 5647afc5dbdSKrishna Gudipati debugfs_remove(bnad->port_debugfs_root); 5657afc5dbdSKrishna Gudipati bnad->port_debugfs_root = NULL; 5667afc5dbdSKrishna Gudipati atomic_dec(&bna_debugfs_port_count); 5677afc5dbdSKrishna Gudipati } 5687afc5dbdSKrishna Gudipati 5697afc5dbdSKrishna Gudipati /* Remove the BNA debugfs root directory */ 5707afc5dbdSKrishna Gudipati if (atomic_read(&bna_debugfs_port_count) == 0) { 5717afc5dbdSKrishna Gudipati debugfs_remove(bna_debugfs_root); 5727afc5dbdSKrishna Gudipati bna_debugfs_root = NULL; 5737afc5dbdSKrishna Gudipati } 5747afc5dbdSKrishna Gudipati } 575