17afc5dbdSKrishna Gudipati /* 27afc5dbdSKrishna Gudipati * Linux network driver for Brocade 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 /* 147afc5dbdSKrishna Gudipati * Copyright (c) 2005-2011 Brocade Communications Systems, Inc. 157afc5dbdSKrishna Gudipati * All rights reserved 167afc5dbdSKrishna Gudipati * www.brocade.com 177afc5dbdSKrishna Gudipati */ 187afc5dbdSKrishna Gudipati 197afc5dbdSKrishna Gudipati #include <linux/debugfs.h> 207afc5dbdSKrishna Gudipati #include <linux/module.h> 217afc5dbdSKrishna Gudipati #include "bnad.h" 227afc5dbdSKrishna Gudipati 237afc5dbdSKrishna Gudipati /* 247afc5dbdSKrishna Gudipati * BNA debufs interface 257afc5dbdSKrishna Gudipati * 267afc5dbdSKrishna Gudipati * To access the interface, debugfs file system should be mounted 277afc5dbdSKrishna Gudipati * if not already mounted using: 287afc5dbdSKrishna Gudipati * mount -t debugfs none /sys/kernel/debug 297afc5dbdSKrishna Gudipati * 307afc5dbdSKrishna Gudipati * BNA Hierarchy: 317afc5dbdSKrishna Gudipati * - bna/pci_dev:<pci_name> 327afc5dbdSKrishna Gudipati * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bna 337afc5dbdSKrishna Gudipati * 347afc5dbdSKrishna Gudipati * Debugging service available per pci_dev: 357afc5dbdSKrishna Gudipati * fwtrc: To collect current firmware trace. 367afc5dbdSKrishna Gudipati * fwsave: To collect last saved fw trace as a result of firmware crash. 377afc5dbdSKrishna Gudipati * regwr: To write one word to chip register 387afc5dbdSKrishna Gudipati * regrd: To read one or more words from chip register. 397afc5dbdSKrishna Gudipati */ 407afc5dbdSKrishna Gudipati 417afc5dbdSKrishna Gudipati struct bnad_debug_info { 427afc5dbdSKrishna Gudipati char *debug_buffer; 437afc5dbdSKrishna Gudipati void *i_private; 447afc5dbdSKrishna Gudipati int buffer_len; 457afc5dbdSKrishna Gudipati }; 467afc5dbdSKrishna Gudipati 477afc5dbdSKrishna Gudipati static int 487afc5dbdSKrishna Gudipati bnad_debugfs_open_fwtrc(struct inode *inode, struct file *file) 497afc5dbdSKrishna Gudipati { 507afc5dbdSKrishna Gudipati struct bnad *bnad = inode->i_private; 517afc5dbdSKrishna Gudipati struct bnad_debug_info *fw_debug; 527afc5dbdSKrishna Gudipati unsigned long flags; 537afc5dbdSKrishna Gudipati int rc; 547afc5dbdSKrishna Gudipati 557afc5dbdSKrishna Gudipati fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); 567afc5dbdSKrishna Gudipati if (!fw_debug) 577afc5dbdSKrishna Gudipati return -ENOMEM; 587afc5dbdSKrishna Gudipati 597afc5dbdSKrishna Gudipati fw_debug->buffer_len = BNA_DBG_FWTRC_LEN; 607afc5dbdSKrishna Gudipati 617afc5dbdSKrishna Gudipati fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL); 627afc5dbdSKrishna Gudipati if (!fw_debug->debug_buffer) { 637afc5dbdSKrishna Gudipati kfree(fw_debug); 647afc5dbdSKrishna Gudipati fw_debug = NULL; 657afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed to allocate fwtrc buffer\n", 667afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 677afc5dbdSKrishna Gudipati return -ENOMEM; 687afc5dbdSKrishna Gudipati } 697afc5dbdSKrishna Gudipati 707afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 717afc5dbdSKrishna Gudipati rc = bfa_nw_ioc_debug_fwtrc(&bnad->bna.ioceth.ioc, 727afc5dbdSKrishna Gudipati fw_debug->debug_buffer, 737afc5dbdSKrishna Gudipati &fw_debug->buffer_len); 747afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 757afc5dbdSKrishna Gudipati if (rc != BFA_STATUS_OK) { 767afc5dbdSKrishna Gudipati kfree(fw_debug->debug_buffer); 777afc5dbdSKrishna Gudipati fw_debug->debug_buffer = NULL; 787afc5dbdSKrishna Gudipati kfree(fw_debug); 797afc5dbdSKrishna Gudipati fw_debug = NULL; 807afc5dbdSKrishna Gudipati pr_warn("bnad %s: Failed to collect fwtrc\n", 817afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 827afc5dbdSKrishna Gudipati return -ENOMEM; 837afc5dbdSKrishna Gudipati } 847afc5dbdSKrishna Gudipati 857afc5dbdSKrishna Gudipati file->private_data = fw_debug; 867afc5dbdSKrishna Gudipati 877afc5dbdSKrishna Gudipati return 0; 887afc5dbdSKrishna Gudipati } 897afc5dbdSKrishna Gudipati 907afc5dbdSKrishna Gudipati static int 917afc5dbdSKrishna Gudipati bnad_debugfs_open_fwsave(struct inode *inode, struct file *file) 927afc5dbdSKrishna Gudipati { 937afc5dbdSKrishna Gudipati struct bnad *bnad = inode->i_private; 947afc5dbdSKrishna Gudipati struct bnad_debug_info *fw_debug; 957afc5dbdSKrishna Gudipati unsigned long flags; 967afc5dbdSKrishna Gudipati int rc; 977afc5dbdSKrishna Gudipati 987afc5dbdSKrishna Gudipati fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); 997afc5dbdSKrishna Gudipati if (!fw_debug) 1007afc5dbdSKrishna Gudipati return -ENOMEM; 1017afc5dbdSKrishna Gudipati 1027afc5dbdSKrishna Gudipati fw_debug->buffer_len = BNA_DBG_FWTRC_LEN; 1037afc5dbdSKrishna Gudipati 1047afc5dbdSKrishna Gudipati fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL); 1057afc5dbdSKrishna Gudipati if (!fw_debug->debug_buffer) { 1067afc5dbdSKrishna Gudipati kfree(fw_debug); 1077afc5dbdSKrishna Gudipati fw_debug = NULL; 1087afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed to allocate fwsave buffer\n", 1097afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 1107afc5dbdSKrishna Gudipati return -ENOMEM; 1117afc5dbdSKrishna Gudipati } 1127afc5dbdSKrishna Gudipati 1137afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 1147afc5dbdSKrishna Gudipati rc = bfa_nw_ioc_debug_fwsave(&bnad->bna.ioceth.ioc, 1157afc5dbdSKrishna Gudipati fw_debug->debug_buffer, 1167afc5dbdSKrishna Gudipati &fw_debug->buffer_len); 1177afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1187afc5dbdSKrishna Gudipati if (rc != BFA_STATUS_OK && rc != BFA_STATUS_ENOFSAVE) { 1197afc5dbdSKrishna Gudipati kfree(fw_debug->debug_buffer); 1207afc5dbdSKrishna Gudipati fw_debug->debug_buffer = NULL; 1217afc5dbdSKrishna Gudipati kfree(fw_debug); 1227afc5dbdSKrishna Gudipati fw_debug = NULL; 1237afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed to collect fwsave\n", 1247afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 1257afc5dbdSKrishna Gudipati return -ENOMEM; 1267afc5dbdSKrishna Gudipati } 1277afc5dbdSKrishna Gudipati 1287afc5dbdSKrishna Gudipati file->private_data = fw_debug; 1297afc5dbdSKrishna Gudipati 1307afc5dbdSKrishna Gudipati return 0; 1317afc5dbdSKrishna Gudipati } 1327afc5dbdSKrishna Gudipati 1337afc5dbdSKrishna Gudipati static int 1347afc5dbdSKrishna Gudipati bnad_debugfs_open_reg(struct inode *inode, struct file *file) 1357afc5dbdSKrishna Gudipati { 1367afc5dbdSKrishna Gudipati struct bnad_debug_info *reg_debug; 1377afc5dbdSKrishna Gudipati 1387afc5dbdSKrishna Gudipati reg_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); 1397afc5dbdSKrishna Gudipati if (!reg_debug) 1407afc5dbdSKrishna Gudipati return -ENOMEM; 1417afc5dbdSKrishna Gudipati 1427afc5dbdSKrishna Gudipati reg_debug->i_private = inode->i_private; 1437afc5dbdSKrishna Gudipati 1447afc5dbdSKrishna Gudipati file->private_data = reg_debug; 1457afc5dbdSKrishna Gudipati 1467afc5dbdSKrishna Gudipati return 0; 1477afc5dbdSKrishna Gudipati } 1487afc5dbdSKrishna Gudipati 1497afc5dbdSKrishna Gudipati static int 1507afc5dbdSKrishna Gudipati bnad_get_debug_drvinfo(struct bnad *bnad, void *buffer, u32 len) 1517afc5dbdSKrishna Gudipati { 1527afc5dbdSKrishna Gudipati struct bnad_drvinfo *drvinfo = (struct bnad_drvinfo *) buffer; 1537afc5dbdSKrishna Gudipati struct bnad_iocmd_comp fcomp; 1547afc5dbdSKrishna Gudipati unsigned long flags = 0; 1557afc5dbdSKrishna Gudipati int ret = BFA_STATUS_FAILED; 1567afc5dbdSKrishna Gudipati 1577afc5dbdSKrishna Gudipati /* Get IOC info */ 1587afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 1597afc5dbdSKrishna Gudipati bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, &drvinfo->ioc_attr); 1607afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1617afc5dbdSKrishna Gudipati 1627afc5dbdSKrishna Gudipati /* Retrieve CEE related info */ 1637afc5dbdSKrishna Gudipati fcomp.bnad = bnad; 1647afc5dbdSKrishna Gudipati fcomp.comp_status = 0; 1657afc5dbdSKrishna Gudipati init_completion(&fcomp.comp); 1667afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 1677afc5dbdSKrishna Gudipati ret = bfa_nw_cee_get_attr(&bnad->bna.cee, &drvinfo->cee_attr, 1687afc5dbdSKrishna Gudipati bnad_cb_completion, &fcomp); 1697afc5dbdSKrishna Gudipati if (ret != BFA_STATUS_OK) { 1707afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1717afc5dbdSKrishna Gudipati goto out; 1727afc5dbdSKrishna Gudipati } 1737afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1747afc5dbdSKrishna Gudipati wait_for_completion(&fcomp.comp); 1757afc5dbdSKrishna Gudipati drvinfo->cee_status = fcomp.comp_status; 1767afc5dbdSKrishna Gudipati 1777afc5dbdSKrishna Gudipati /* Retrieve flash partition info */ 1787afc5dbdSKrishna Gudipati fcomp.comp_status = 0; 1797afc5dbdSKrishna Gudipati init_completion(&fcomp.comp); 1807afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 1817afc5dbdSKrishna Gudipati ret = bfa_nw_flash_get_attr(&bnad->bna.flash, &drvinfo->flash_attr, 1827afc5dbdSKrishna Gudipati bnad_cb_completion, &fcomp); 1837afc5dbdSKrishna Gudipati if (ret != BFA_STATUS_OK) { 1847afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1857afc5dbdSKrishna Gudipati goto out; 1867afc5dbdSKrishna Gudipati } 1877afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 1887afc5dbdSKrishna Gudipati wait_for_completion(&fcomp.comp); 1897afc5dbdSKrishna Gudipati drvinfo->flash_status = fcomp.comp_status; 1907afc5dbdSKrishna Gudipati out: 1917afc5dbdSKrishna Gudipati return ret; 1927afc5dbdSKrishna Gudipati } 1937afc5dbdSKrishna Gudipati 1947afc5dbdSKrishna Gudipati static int 1957afc5dbdSKrishna Gudipati bnad_debugfs_open_drvinfo(struct inode *inode, struct file *file) 1967afc5dbdSKrishna Gudipati { 1977afc5dbdSKrishna Gudipati struct bnad *bnad = inode->i_private; 1987afc5dbdSKrishna Gudipati struct bnad_debug_info *drv_info; 1997afc5dbdSKrishna Gudipati int rc; 2007afc5dbdSKrishna Gudipati 2017afc5dbdSKrishna Gudipati drv_info = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL); 2027afc5dbdSKrishna Gudipati if (!drv_info) 2037afc5dbdSKrishna Gudipati return -ENOMEM; 2047afc5dbdSKrishna Gudipati 2057afc5dbdSKrishna Gudipati drv_info->buffer_len = sizeof(struct bnad_drvinfo); 2067afc5dbdSKrishna Gudipati 2077afc5dbdSKrishna Gudipati drv_info->debug_buffer = kzalloc(drv_info->buffer_len, GFP_KERNEL); 2087afc5dbdSKrishna Gudipati if (!drv_info->debug_buffer) { 2097afc5dbdSKrishna Gudipati kfree(drv_info); 2107afc5dbdSKrishna Gudipati drv_info = NULL; 2117afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed to allocate drv info buffer\n", 2127afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 2137afc5dbdSKrishna Gudipati return -ENOMEM; 2147afc5dbdSKrishna Gudipati } 2157afc5dbdSKrishna Gudipati 2167afc5dbdSKrishna Gudipati mutex_lock(&bnad->conf_mutex); 2177afc5dbdSKrishna Gudipati rc = bnad_get_debug_drvinfo(bnad, drv_info->debug_buffer, 2187afc5dbdSKrishna Gudipati drv_info->buffer_len); 2197afc5dbdSKrishna Gudipati mutex_unlock(&bnad->conf_mutex); 2207afc5dbdSKrishna Gudipati if (rc != BFA_STATUS_OK) { 2217afc5dbdSKrishna Gudipati kfree(drv_info->debug_buffer); 2227afc5dbdSKrishna Gudipati drv_info->debug_buffer = NULL; 2237afc5dbdSKrishna Gudipati kfree(drv_info); 2247afc5dbdSKrishna Gudipati drv_info = NULL; 2257afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed to collect drvinfo\n", 2267afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 2277afc5dbdSKrishna Gudipati return -ENOMEM; 2287afc5dbdSKrishna Gudipati } 2297afc5dbdSKrishna Gudipati 2307afc5dbdSKrishna Gudipati file->private_data = drv_info; 2317afc5dbdSKrishna Gudipati 2327afc5dbdSKrishna Gudipati return 0; 2337afc5dbdSKrishna Gudipati } 2347afc5dbdSKrishna Gudipati 2357afc5dbdSKrishna Gudipati /* Changes the current file position */ 2367afc5dbdSKrishna Gudipati static loff_t 2377afc5dbdSKrishna Gudipati bnad_debugfs_lseek(struct file *file, loff_t offset, int orig) 2387afc5dbdSKrishna Gudipati { 2397afc5dbdSKrishna Gudipati loff_t pos = file->f_pos; 2407afc5dbdSKrishna Gudipati struct bnad_debug_info *debug = file->private_data; 2417afc5dbdSKrishna Gudipati 2427afc5dbdSKrishna Gudipati if (!debug) 2437afc5dbdSKrishna Gudipati return -EINVAL; 2447afc5dbdSKrishna Gudipati 2457afc5dbdSKrishna Gudipati switch (orig) { 2467afc5dbdSKrishna Gudipati case 0: 2477afc5dbdSKrishna Gudipati file->f_pos = offset; 2487afc5dbdSKrishna Gudipati break; 2497afc5dbdSKrishna Gudipati case 1: 2507afc5dbdSKrishna Gudipati file->f_pos += offset; 2517afc5dbdSKrishna Gudipati break; 2527afc5dbdSKrishna Gudipati case 2: 2537afc5dbdSKrishna Gudipati file->f_pos = debug->buffer_len - offset; 2547afc5dbdSKrishna Gudipati break; 2557afc5dbdSKrishna Gudipati default: 2567afc5dbdSKrishna Gudipati return -EINVAL; 2577afc5dbdSKrishna Gudipati } 2587afc5dbdSKrishna Gudipati 2597afc5dbdSKrishna Gudipati if (file->f_pos < 0 || file->f_pos > debug->buffer_len) { 2607afc5dbdSKrishna Gudipati file->f_pos = pos; 2617afc5dbdSKrishna Gudipati return -EINVAL; 2627afc5dbdSKrishna Gudipati } 2637afc5dbdSKrishna Gudipati 2647afc5dbdSKrishna Gudipati return file->f_pos; 2657afc5dbdSKrishna Gudipati } 2667afc5dbdSKrishna Gudipati 2677afc5dbdSKrishna Gudipati static ssize_t 2687afc5dbdSKrishna Gudipati bnad_debugfs_read(struct file *file, char __user *buf, 2697afc5dbdSKrishna Gudipati size_t nbytes, loff_t *pos) 2707afc5dbdSKrishna Gudipati { 2717afc5dbdSKrishna Gudipati struct bnad_debug_info *debug = file->private_data; 2727afc5dbdSKrishna Gudipati 2737afc5dbdSKrishna Gudipati if (!debug || !debug->debug_buffer) 2747afc5dbdSKrishna Gudipati return 0; 2757afc5dbdSKrishna Gudipati 2767afc5dbdSKrishna Gudipati return simple_read_from_buffer(buf, nbytes, pos, 2777afc5dbdSKrishna Gudipati debug->debug_buffer, debug->buffer_len); 2787afc5dbdSKrishna Gudipati } 2797afc5dbdSKrishna Gudipati 2807afc5dbdSKrishna Gudipati #define BFA_REG_CT_ADDRSZ (0x40000) 2817afc5dbdSKrishna Gudipati #define BFA_REG_CB_ADDRSZ (0x20000) 2827afc5dbdSKrishna Gudipati #define BFA_REG_ADDRSZ(__ioc) \ 2837afc5dbdSKrishna Gudipati ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \ 2847afc5dbdSKrishna Gudipati BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ)) 2857afc5dbdSKrishna Gudipati #define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1) 2867afc5dbdSKrishna Gudipati 2877afc5dbdSKrishna Gudipati /* 2887afc5dbdSKrishna Gudipati * Function to check if the register offset passed is valid. 2897afc5dbdSKrishna Gudipati */ 2907afc5dbdSKrishna Gudipati static int 2917afc5dbdSKrishna Gudipati bna_reg_offset_check(struct bfa_ioc *ioc, u32 offset, u32 len) 2927afc5dbdSKrishna Gudipati { 2937afc5dbdSKrishna Gudipati u8 area; 2947afc5dbdSKrishna Gudipati 2957afc5dbdSKrishna Gudipati /* check [16:15] */ 2967afc5dbdSKrishna Gudipati area = (offset >> 15) & 0x7; 2977afc5dbdSKrishna Gudipati if (area == 0) { 2987afc5dbdSKrishna Gudipati /* PCIe core register */ 2997afc5dbdSKrishna Gudipati if ((offset + (len<<2)) > 0x8000) /* 8k dwords or 32KB */ 3007afc5dbdSKrishna Gudipati return BFA_STATUS_EINVAL; 3017afc5dbdSKrishna Gudipati } else if (area == 0x1) { 3027afc5dbdSKrishna Gudipati /* CB 32 KB memory page */ 3037afc5dbdSKrishna Gudipati if ((offset + (len<<2)) > 0x10000) /* 8k dwords or 32KB */ 3047afc5dbdSKrishna Gudipati return BFA_STATUS_EINVAL; 3057afc5dbdSKrishna Gudipati } else { 3067afc5dbdSKrishna Gudipati /* CB register space 64KB */ 3077afc5dbdSKrishna Gudipati if ((offset + (len<<2)) > BFA_REG_ADDRMSK(ioc)) 3087afc5dbdSKrishna Gudipati return BFA_STATUS_EINVAL; 3097afc5dbdSKrishna Gudipati } 3107afc5dbdSKrishna Gudipati return BFA_STATUS_OK; 3117afc5dbdSKrishna Gudipati } 3127afc5dbdSKrishna Gudipati 3137afc5dbdSKrishna Gudipati static ssize_t 3147afc5dbdSKrishna Gudipati bnad_debugfs_read_regrd(struct file *file, char __user *buf, 3157afc5dbdSKrishna Gudipati size_t nbytes, loff_t *pos) 3167afc5dbdSKrishna Gudipati { 3177afc5dbdSKrishna Gudipati struct bnad_debug_info *regrd_debug = file->private_data; 3187afc5dbdSKrishna Gudipati struct bnad *bnad = (struct bnad *)regrd_debug->i_private; 3197afc5dbdSKrishna Gudipati ssize_t rc; 3207afc5dbdSKrishna Gudipati 3217afc5dbdSKrishna Gudipati if (!bnad->regdata) 3227afc5dbdSKrishna Gudipati return 0; 3237afc5dbdSKrishna Gudipati 3247afc5dbdSKrishna Gudipati rc = simple_read_from_buffer(buf, nbytes, pos, 3257afc5dbdSKrishna Gudipati bnad->regdata, bnad->reglen); 3267afc5dbdSKrishna Gudipati 3277afc5dbdSKrishna Gudipati if ((*pos + nbytes) >= bnad->reglen) { 3287afc5dbdSKrishna Gudipati kfree(bnad->regdata); 3297afc5dbdSKrishna Gudipati bnad->regdata = NULL; 3307afc5dbdSKrishna Gudipati bnad->reglen = 0; 3317afc5dbdSKrishna Gudipati } 3327afc5dbdSKrishna Gudipati 3337afc5dbdSKrishna Gudipati return rc; 3347afc5dbdSKrishna Gudipati } 3357afc5dbdSKrishna Gudipati 3367afc5dbdSKrishna Gudipati static ssize_t 3377afc5dbdSKrishna Gudipati bnad_debugfs_write_regrd(struct file *file, const char __user *buf, 3387afc5dbdSKrishna Gudipati size_t nbytes, loff_t *ppos) 3397afc5dbdSKrishna Gudipati { 3407afc5dbdSKrishna Gudipati struct bnad_debug_info *regrd_debug = file->private_data; 3417afc5dbdSKrishna Gudipati struct bnad *bnad = (struct bnad *)regrd_debug->i_private; 3427afc5dbdSKrishna Gudipati struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc; 3437afc5dbdSKrishna Gudipati int addr, len, rc, i; 3447afc5dbdSKrishna Gudipati u32 *regbuf; 3457afc5dbdSKrishna Gudipati void __iomem *rb, *reg_addr; 3467afc5dbdSKrishna Gudipati unsigned long flags; 3477afc5dbdSKrishna Gudipati void *kern_buf; 3487afc5dbdSKrishna Gudipati 3497afc5dbdSKrishna Gudipati /* Allocate memory to store the user space buf */ 3507afc5dbdSKrishna Gudipati kern_buf = kzalloc(nbytes, GFP_KERNEL); 3517afc5dbdSKrishna Gudipati if (!kern_buf) { 3527afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed to allocate user buffer\n", 3537afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 3547afc5dbdSKrishna Gudipati return -ENOMEM; 3557afc5dbdSKrishna Gudipati } 3567afc5dbdSKrishna Gudipati 3577afc5dbdSKrishna Gudipati if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) { 3587afc5dbdSKrishna Gudipati kfree(kern_buf); 3597afc5dbdSKrishna Gudipati return -ENOMEM; 3607afc5dbdSKrishna Gudipati } 3617afc5dbdSKrishna Gudipati 3627afc5dbdSKrishna Gudipati rc = sscanf(kern_buf, "%x:%x", &addr, &len); 3637afc5dbdSKrishna Gudipati if (rc < 2) { 3647afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed to read user buffer\n", 3657afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 3667afc5dbdSKrishna Gudipati kfree(kern_buf); 3677afc5dbdSKrishna Gudipati return -EINVAL; 3687afc5dbdSKrishna Gudipati } 3697afc5dbdSKrishna Gudipati 3707afc5dbdSKrishna Gudipati kfree(kern_buf); 3717afc5dbdSKrishna Gudipati kfree(bnad->regdata); 3727afc5dbdSKrishna Gudipati bnad->regdata = NULL; 3737afc5dbdSKrishna Gudipati bnad->reglen = 0; 3747afc5dbdSKrishna Gudipati 3757afc5dbdSKrishna Gudipati bnad->regdata = kzalloc(len << 2, GFP_KERNEL); 3767afc5dbdSKrishna Gudipati if (!bnad->regdata) { 3777afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed to allocate regrd buffer\n", 3787afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 3797afc5dbdSKrishna Gudipati return -ENOMEM; 3807afc5dbdSKrishna Gudipati } 3817afc5dbdSKrishna Gudipati 3827afc5dbdSKrishna Gudipati bnad->reglen = len << 2; 3837afc5dbdSKrishna Gudipati rb = bfa_ioc_bar0(ioc); 3847afc5dbdSKrishna Gudipati addr &= BFA_REG_ADDRMSK(ioc); 3857afc5dbdSKrishna Gudipati 3867afc5dbdSKrishna Gudipati /* offset and len sanity check */ 3877afc5dbdSKrishna Gudipati rc = bna_reg_offset_check(ioc, addr, len); 3887afc5dbdSKrishna Gudipati if (rc) { 3897afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed reg offset check\n", 3907afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 3917afc5dbdSKrishna Gudipati kfree(bnad->regdata); 3927afc5dbdSKrishna Gudipati bnad->regdata = NULL; 3937afc5dbdSKrishna Gudipati bnad->reglen = 0; 3947afc5dbdSKrishna Gudipati return -EINVAL; 3957afc5dbdSKrishna Gudipati } 3967afc5dbdSKrishna Gudipati 3977afc5dbdSKrishna Gudipati reg_addr = rb + addr; 3987afc5dbdSKrishna Gudipati regbuf = (u32 *)bnad->regdata; 3997afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 4007afc5dbdSKrishna Gudipati for (i = 0; i < len; i++) { 4017afc5dbdSKrishna Gudipati *regbuf = readl(reg_addr); 4027afc5dbdSKrishna Gudipati regbuf++; 4037afc5dbdSKrishna Gudipati reg_addr += sizeof(u32); 4047afc5dbdSKrishna Gudipati } 4057afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 4067afc5dbdSKrishna Gudipati 4077afc5dbdSKrishna Gudipati return nbytes; 4087afc5dbdSKrishna Gudipati } 4097afc5dbdSKrishna Gudipati 4107afc5dbdSKrishna Gudipati static ssize_t 4117afc5dbdSKrishna Gudipati bnad_debugfs_write_regwr(struct file *file, const char __user *buf, 4127afc5dbdSKrishna Gudipati size_t nbytes, loff_t *ppos) 4137afc5dbdSKrishna Gudipati { 4147afc5dbdSKrishna Gudipati struct bnad_debug_info *debug = file->private_data; 4157afc5dbdSKrishna Gudipati struct bnad *bnad = (struct bnad *)debug->i_private; 4167afc5dbdSKrishna Gudipati struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc; 4177afc5dbdSKrishna Gudipati int addr, val, rc; 4187afc5dbdSKrishna Gudipati void __iomem *reg_addr; 4197afc5dbdSKrishna Gudipati unsigned long flags; 4207afc5dbdSKrishna Gudipati void *kern_buf; 4217afc5dbdSKrishna Gudipati 4227afc5dbdSKrishna Gudipati /* Allocate memory to store the user space buf */ 4237afc5dbdSKrishna Gudipati kern_buf = kzalloc(nbytes, GFP_KERNEL); 4247afc5dbdSKrishna Gudipati if (!kern_buf) { 4257afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed to allocate user buffer\n", 4267afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 4277afc5dbdSKrishna Gudipati return -ENOMEM; 4287afc5dbdSKrishna Gudipati } 4297afc5dbdSKrishna Gudipati 4307afc5dbdSKrishna Gudipati if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) { 4317afc5dbdSKrishna Gudipati kfree(kern_buf); 4327afc5dbdSKrishna Gudipati return -ENOMEM; 4337afc5dbdSKrishna Gudipati } 4347afc5dbdSKrishna Gudipati 4357afc5dbdSKrishna Gudipati rc = sscanf(kern_buf, "%x:%x", &addr, &val); 4367afc5dbdSKrishna Gudipati if (rc < 2) { 4377afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed to read user buffer\n", 4387afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 4397afc5dbdSKrishna Gudipati kfree(kern_buf); 4407afc5dbdSKrishna Gudipati return -EINVAL; 4417afc5dbdSKrishna Gudipati } 4427afc5dbdSKrishna Gudipati kfree(kern_buf); 4437afc5dbdSKrishna Gudipati 4447afc5dbdSKrishna Gudipati addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */ 4457afc5dbdSKrishna Gudipati 4467afc5dbdSKrishna Gudipati /* offset and len sanity check */ 4477afc5dbdSKrishna Gudipati rc = bna_reg_offset_check(ioc, addr, 1); 4487afc5dbdSKrishna Gudipati if (rc) { 4497afc5dbdSKrishna Gudipati pr_warn("bna %s: Failed reg offset check\n", 4507afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 4517afc5dbdSKrishna Gudipati return -EINVAL; 4527afc5dbdSKrishna Gudipati } 4537afc5dbdSKrishna Gudipati 4547afc5dbdSKrishna Gudipati reg_addr = (bfa_ioc_bar0(ioc)) + addr; 4557afc5dbdSKrishna Gudipati spin_lock_irqsave(&bnad->bna_lock, flags); 4567afc5dbdSKrishna Gudipati writel(val, reg_addr); 4577afc5dbdSKrishna Gudipati spin_unlock_irqrestore(&bnad->bna_lock, flags); 4587afc5dbdSKrishna Gudipati 4597afc5dbdSKrishna Gudipati return nbytes; 4607afc5dbdSKrishna Gudipati } 4617afc5dbdSKrishna Gudipati 4627afc5dbdSKrishna Gudipati static int 4637afc5dbdSKrishna Gudipati bnad_debugfs_release(struct inode *inode, struct file *file) 4647afc5dbdSKrishna Gudipati { 4657afc5dbdSKrishna Gudipati struct bnad_debug_info *debug = file->private_data; 4667afc5dbdSKrishna Gudipati 4677afc5dbdSKrishna Gudipati if (!debug) 4687afc5dbdSKrishna Gudipati return 0; 4697afc5dbdSKrishna Gudipati 4707afc5dbdSKrishna Gudipati file->private_data = NULL; 4717afc5dbdSKrishna Gudipati kfree(debug); 4727afc5dbdSKrishna Gudipati return 0; 4737afc5dbdSKrishna Gudipati } 4747afc5dbdSKrishna Gudipati 4757afc5dbdSKrishna Gudipati static int 4767afc5dbdSKrishna Gudipati bnad_debugfs_buffer_release(struct inode *inode, struct file *file) 4777afc5dbdSKrishna Gudipati { 4787afc5dbdSKrishna Gudipati struct bnad_debug_info *debug = file->private_data; 4797afc5dbdSKrishna Gudipati 4807afc5dbdSKrishna Gudipati if (!debug) 4817afc5dbdSKrishna Gudipati return 0; 4827afc5dbdSKrishna Gudipati 4837afc5dbdSKrishna Gudipati kfree(debug->debug_buffer); 4847afc5dbdSKrishna Gudipati 4857afc5dbdSKrishna Gudipati file->private_data = NULL; 4867afc5dbdSKrishna Gudipati kfree(debug); 4877afc5dbdSKrishna Gudipati debug = NULL; 4887afc5dbdSKrishna Gudipati return 0; 4897afc5dbdSKrishna Gudipati } 4907afc5dbdSKrishna Gudipati 4917afc5dbdSKrishna Gudipati static const struct file_operations bnad_debugfs_op_fwtrc = { 4927afc5dbdSKrishna Gudipati .owner = THIS_MODULE, 4937afc5dbdSKrishna Gudipati .open = bnad_debugfs_open_fwtrc, 4947afc5dbdSKrishna Gudipati .llseek = bnad_debugfs_lseek, 4957afc5dbdSKrishna Gudipati .read = bnad_debugfs_read, 4967afc5dbdSKrishna Gudipati .release = bnad_debugfs_buffer_release, 4977afc5dbdSKrishna Gudipati }; 4987afc5dbdSKrishna Gudipati 4997afc5dbdSKrishna Gudipati static const struct file_operations bnad_debugfs_op_fwsave = { 5007afc5dbdSKrishna Gudipati .owner = THIS_MODULE, 5017afc5dbdSKrishna Gudipati .open = bnad_debugfs_open_fwsave, 5027afc5dbdSKrishna Gudipati .llseek = bnad_debugfs_lseek, 5037afc5dbdSKrishna Gudipati .read = bnad_debugfs_read, 5047afc5dbdSKrishna Gudipati .release = bnad_debugfs_buffer_release, 5057afc5dbdSKrishna Gudipati }; 5067afc5dbdSKrishna Gudipati 5077afc5dbdSKrishna Gudipati static const struct file_operations bnad_debugfs_op_regrd = { 5087afc5dbdSKrishna Gudipati .owner = THIS_MODULE, 5097afc5dbdSKrishna Gudipati .open = bnad_debugfs_open_reg, 5107afc5dbdSKrishna Gudipati .llseek = bnad_debugfs_lseek, 5117afc5dbdSKrishna Gudipati .read = bnad_debugfs_read_regrd, 5127afc5dbdSKrishna Gudipati .write = bnad_debugfs_write_regrd, 5137afc5dbdSKrishna Gudipati .release = bnad_debugfs_release, 5147afc5dbdSKrishna Gudipati }; 5157afc5dbdSKrishna Gudipati 5167afc5dbdSKrishna Gudipati static const struct file_operations bnad_debugfs_op_regwr = { 5177afc5dbdSKrishna Gudipati .owner = THIS_MODULE, 5187afc5dbdSKrishna Gudipati .open = bnad_debugfs_open_reg, 5197afc5dbdSKrishna Gudipati .llseek = bnad_debugfs_lseek, 5207afc5dbdSKrishna Gudipati .write = bnad_debugfs_write_regwr, 5217afc5dbdSKrishna Gudipati .release = bnad_debugfs_release, 5227afc5dbdSKrishna Gudipati }; 5237afc5dbdSKrishna Gudipati 5247afc5dbdSKrishna Gudipati static const struct file_operations bnad_debugfs_op_drvinfo = { 5257afc5dbdSKrishna Gudipati .owner = THIS_MODULE, 5267afc5dbdSKrishna Gudipati .open = bnad_debugfs_open_drvinfo, 5277afc5dbdSKrishna Gudipati .llseek = bnad_debugfs_lseek, 5287afc5dbdSKrishna Gudipati .read = bnad_debugfs_read, 5297afc5dbdSKrishna Gudipati .release = bnad_debugfs_buffer_release, 5307afc5dbdSKrishna Gudipati }; 5317afc5dbdSKrishna Gudipati 5327afc5dbdSKrishna Gudipati struct bnad_debugfs_entry { 5337afc5dbdSKrishna Gudipati const char *name; 5347afc5dbdSKrishna Gudipati mode_t mode; 5357afc5dbdSKrishna Gudipati const struct file_operations *fops; 5367afc5dbdSKrishna Gudipati }; 5377afc5dbdSKrishna Gudipati 5387afc5dbdSKrishna Gudipati static const struct bnad_debugfs_entry bnad_debugfs_files[] = { 5397afc5dbdSKrishna Gudipati { "fwtrc", S_IFREG|S_IRUGO, &bnad_debugfs_op_fwtrc, }, 5407afc5dbdSKrishna Gudipati { "fwsave", S_IFREG|S_IRUGO, &bnad_debugfs_op_fwsave, }, 5417afc5dbdSKrishna Gudipati { "regrd", S_IFREG|S_IRUGO|S_IWUSR, &bnad_debugfs_op_regrd, }, 5427afc5dbdSKrishna Gudipati { "regwr", S_IFREG|S_IWUSR, &bnad_debugfs_op_regwr, }, 5437afc5dbdSKrishna Gudipati { "drvinfo", S_IFREG|S_IRUGO, &bnad_debugfs_op_drvinfo, }, 5447afc5dbdSKrishna Gudipati }; 5457afc5dbdSKrishna Gudipati 5467afc5dbdSKrishna Gudipati static struct dentry *bna_debugfs_root; 5477afc5dbdSKrishna Gudipati static atomic_t bna_debugfs_port_count; 5487afc5dbdSKrishna Gudipati 5497afc5dbdSKrishna Gudipati /* Initialize debugfs interface for BNA */ 5507afc5dbdSKrishna Gudipati void 5517afc5dbdSKrishna Gudipati bnad_debugfs_init(struct bnad *bnad) 5527afc5dbdSKrishna Gudipati { 5537afc5dbdSKrishna Gudipati const struct bnad_debugfs_entry *file; 5547afc5dbdSKrishna Gudipati char name[64]; 5557afc5dbdSKrishna Gudipati int i; 5567afc5dbdSKrishna Gudipati 5577afc5dbdSKrishna Gudipati /* Setup the BNA debugfs root directory*/ 5587afc5dbdSKrishna Gudipati if (!bna_debugfs_root) { 5597afc5dbdSKrishna Gudipati bna_debugfs_root = debugfs_create_dir("bna", NULL); 5607afc5dbdSKrishna Gudipati atomic_set(&bna_debugfs_port_count, 0); 5617afc5dbdSKrishna Gudipati if (!bna_debugfs_root) { 5627afc5dbdSKrishna Gudipati pr_warn("BNA: debugfs root dir creation failed\n"); 5637afc5dbdSKrishna Gudipati return; 5647afc5dbdSKrishna Gudipati } 5657afc5dbdSKrishna Gudipati } 5667afc5dbdSKrishna Gudipati 5677afc5dbdSKrishna Gudipati /* Setup the pci_dev debugfs directory for the port */ 5687afc5dbdSKrishna Gudipati snprintf(name, sizeof(name), "pci_dev:%s", pci_name(bnad->pcidev)); 5697afc5dbdSKrishna Gudipati if (!bnad->port_debugfs_root) { 5707afc5dbdSKrishna Gudipati bnad->port_debugfs_root = 5717afc5dbdSKrishna Gudipati debugfs_create_dir(name, bna_debugfs_root); 5727afc5dbdSKrishna Gudipati if (!bnad->port_debugfs_root) { 5737afc5dbdSKrishna Gudipati pr_warn("bna pci_dev %s: root dir creation failed\n", 5747afc5dbdSKrishna Gudipati pci_name(bnad->pcidev)); 5757afc5dbdSKrishna Gudipati return; 5767afc5dbdSKrishna Gudipati } 5777afc5dbdSKrishna Gudipati 5787afc5dbdSKrishna Gudipati atomic_inc(&bna_debugfs_port_count); 5797afc5dbdSKrishna Gudipati 5807afc5dbdSKrishna Gudipati for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) { 5817afc5dbdSKrishna Gudipati file = &bnad_debugfs_files[i]; 5827afc5dbdSKrishna Gudipati bnad->bnad_dentry_files[i] = 5837afc5dbdSKrishna Gudipati debugfs_create_file(file->name, 5847afc5dbdSKrishna Gudipati file->mode, 5857afc5dbdSKrishna Gudipati bnad->port_debugfs_root, 5867afc5dbdSKrishna Gudipati bnad, 5877afc5dbdSKrishna Gudipati file->fops); 5887afc5dbdSKrishna Gudipati if (!bnad->bnad_dentry_files[i]) { 5897afc5dbdSKrishna Gudipati pr_warn( 5907afc5dbdSKrishna Gudipati "BNA pci_dev:%s: create %s entry failed\n", 5917afc5dbdSKrishna Gudipati pci_name(bnad->pcidev), file->name); 5927afc5dbdSKrishna Gudipati return; 5937afc5dbdSKrishna Gudipati } 5947afc5dbdSKrishna Gudipati } 5957afc5dbdSKrishna Gudipati } 5967afc5dbdSKrishna Gudipati } 5977afc5dbdSKrishna Gudipati 5987afc5dbdSKrishna Gudipati /* Uninitialize debugfs interface for BNA */ 5997afc5dbdSKrishna Gudipati void 6007afc5dbdSKrishna Gudipati bnad_debugfs_uninit(struct bnad *bnad) 6017afc5dbdSKrishna Gudipati { 6027afc5dbdSKrishna Gudipati int i; 6037afc5dbdSKrishna Gudipati 6047afc5dbdSKrishna Gudipati for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) { 6057afc5dbdSKrishna Gudipati if (bnad->bnad_dentry_files[i]) { 6067afc5dbdSKrishna Gudipati debugfs_remove(bnad->bnad_dentry_files[i]); 6077afc5dbdSKrishna Gudipati bnad->bnad_dentry_files[i] = NULL; 6087afc5dbdSKrishna Gudipati } 6097afc5dbdSKrishna Gudipati } 6107afc5dbdSKrishna Gudipati 6117afc5dbdSKrishna Gudipati /* Remove the pci_dev debugfs directory for the port */ 6127afc5dbdSKrishna Gudipati if (bnad->port_debugfs_root) { 6137afc5dbdSKrishna Gudipati debugfs_remove(bnad->port_debugfs_root); 6147afc5dbdSKrishna Gudipati bnad->port_debugfs_root = NULL; 6157afc5dbdSKrishna Gudipati atomic_dec(&bna_debugfs_port_count); 6167afc5dbdSKrishna Gudipati } 6177afc5dbdSKrishna Gudipati 6187afc5dbdSKrishna Gudipati /* Remove the BNA debugfs root directory */ 6197afc5dbdSKrishna Gudipati if (atomic_read(&bna_debugfs_port_count) == 0) { 6207afc5dbdSKrishna Gudipati debugfs_remove(bna_debugfs_root); 6217afc5dbdSKrishna Gudipati bna_debugfs_root = NULL; 6227afc5dbdSKrishna Gudipati } 6237afc5dbdSKrishna Gudipati } 624