aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrishna Gudipati <kgudipat@brocade.com>2011-12-22 08:30:19 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-23 16:50:58 -0500
commit7afc5dbde09104b023ce04465ba71aaba0fc4346 (patch)
tree03109d7dfed9afb5c0e4d1f1c86d307f577f0b6d
parent72a9730b3f556e18912f3e1b494a7aee7ae3dd91 (diff)
bna: Add debugfs interface.
Change details: - Add debugfs support to obtain firmware trace, saved firmware trace on an IOC crash, driver info and read/write to registers. - debugfs hierarchy: bna/pci_dev:<pci_name> where the pci_name corresponds to the one under /sys/bus/pci/drivers/bna - Following are the new debugfs entries added: fwtrc: collect current firmware trace. fwsave: collect last saved fw trace as a result of firmware crash. regwr: write one word to chip register regrd: read one or more words from chip register. drvinfo: collect the driver information. Signed-off-by: Krishna Gudipati <kgudipat@brocade.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/brocade/bna/Makefile2
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cee.c35
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cee.h4
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.c121
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.h6
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi.h2
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_enet.c5
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c15
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.h18
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_debugfs.c623
10 files changed, 827 insertions, 4 deletions
diff --git a/drivers/net/ethernet/brocade/bna/Makefile b/drivers/net/ethernet/brocade/bna/Makefile
index 74d3abca1960..6027302ae73a 100644
--- a/drivers/net/ethernet/brocade/bna/Makefile
+++ b/drivers/net/ethernet/brocade/bna/Makefile
@@ -5,7 +5,7 @@
5 5
6obj-$(CONFIG_BNA) += bna.o 6obj-$(CONFIG_BNA) += bna.o
7 7
8bna-objs := bnad.o bnad_ethtool.o bna_enet.o bna_tx_rx.o 8bna-objs := bnad.o bnad_ethtool.o bnad_debugfs.o bna_enet.o bna_tx_rx.o
9bna-objs += bfa_msgq.o bfa_ioc.o bfa_ioc_ct.o bfa_cee.o 9bna-objs += bfa_msgq.o bfa_ioc.o bfa_ioc_ct.o bfa_cee.o
10bna-objs += cna_fwimg.o 10bna-objs += cna_fwimg.o
11 11
diff --git a/drivers/net/ethernet/brocade/bna/bfa_cee.c b/drivers/net/ethernet/brocade/bna/bfa_cee.c
index 8e627186507c..29f284f79e02 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_cee.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_cee.c
@@ -185,6 +185,41 @@ bfa_nw_cee_mem_claim(struct bfa_cee *cee, u8 *dma_kva, u64 dma_pa)
185} 185}
186 186
187/** 187/**
188 * bfa_cee_get_attr()
189 *
190 * @brief Send the request to the f/w to fetch CEE attributes.
191 *
192 * @param[in] Pointer to the CEE module data structure.
193 *
194 * @return Status
195 */
196enum bfa_status
197bfa_nw_cee_get_attr(struct bfa_cee *cee, struct bfa_cee_attr *attr,
198 bfa_cee_get_attr_cbfn_t cbfn, void *cbarg)
199{
200 struct bfi_cee_get_req *cmd;
201
202 BUG_ON(!((cee != NULL) && (cee->ioc != NULL)));
203 if (!bfa_nw_ioc_is_operational(cee->ioc))
204 return BFA_STATUS_IOC_FAILURE;
205
206 if (cee->get_attr_pending == true)
207 return BFA_STATUS_DEVBUSY;
208
209 cee->get_attr_pending = true;
210 cmd = (struct bfi_cee_get_req *) cee->get_cfg_mb.msg;
211 cee->attr = attr;
212 cee->cbfn.get_attr_cbfn = cbfn;
213 cee->cbfn.get_attr_cbarg = cbarg;
214 bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ,
215 bfa_ioc_portid(cee->ioc));
216 bfa_dma_be_addr_set(cmd->dma_addr, cee->attr_dma.pa);
217 bfa_nw_ioc_mbox_queue(cee->ioc, &cee->get_cfg_mb, NULL, NULL);
218
219 return BFA_STATUS_OK;
220}
221
222/**
188 * bfa_cee_isrs() 223 * bfa_cee_isrs()
189 * 224 *
190 * @brief Handles Mail-box interrupts for CEE module. 225 * @brief Handles Mail-box interrupts for CEE module.
diff --git a/drivers/net/ethernet/brocade/bna/bfa_cee.h b/drivers/net/ethernet/brocade/bna/bfa_cee.h
index 58d54e98d595..93fde633d6f3 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_cee.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_cee.h
@@ -59,5 +59,7 @@ u32 bfa_nw_cee_meminfo(void);
59void bfa_nw_cee_mem_claim(struct bfa_cee *cee, u8 *dma_kva, 59void bfa_nw_cee_mem_claim(struct bfa_cee *cee, u8 *dma_kva,
60 u64 dma_pa); 60 u64 dma_pa);
61void bfa_nw_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc, void *dev); 61void bfa_nw_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc, void *dev);
62 62enum bfa_status bfa_nw_cee_get_attr(struct bfa_cee *cee,
63 struct bfa_cee_attr *attr,
64 bfa_cee_get_attr_cbfn_t cbfn, void *cbarg);
63#endif /* __BFA_CEE_H__ */ 65#endif /* __BFA_CEE_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
index 1d130445efbc..abfad275b5f3 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -74,6 +74,7 @@ static void bfa_ioc_check_attr_wwns(struct bfa_ioc *ioc);
74static void bfa_ioc_event_notify(struct bfa_ioc *, enum bfa_ioc_event); 74static void bfa_ioc_event_notify(struct bfa_ioc *, enum bfa_ioc_event);
75static void bfa_ioc_disable_comp(struct bfa_ioc *ioc); 75static void bfa_ioc_disable_comp(struct bfa_ioc *ioc);
76static void bfa_ioc_lpu_stop(struct bfa_ioc *ioc); 76static void bfa_ioc_lpu_stop(struct bfa_ioc *ioc);
77static void bfa_nw_ioc_debug_save_ftrc(struct bfa_ioc *ioc);
77static void bfa_ioc_fail_notify(struct bfa_ioc *ioc); 78static void bfa_ioc_fail_notify(struct bfa_ioc *ioc);
78static void bfa_ioc_pf_enabled(struct bfa_ioc *ioc); 79static void bfa_ioc_pf_enabled(struct bfa_ioc *ioc);
79static void bfa_ioc_pf_disabled(struct bfa_ioc *ioc); 80static void bfa_ioc_pf_disabled(struct bfa_ioc *ioc);
@@ -997,6 +998,7 @@ bfa_iocpf_sm_disabled(struct bfa_iocpf *iocpf, enum iocpf_event event)
997static void 998static void
998bfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf *iocpf) 999bfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf *iocpf)
999{ 1000{
1001 bfa_nw_ioc_debug_save_ftrc(iocpf->ioc);
1000 bfa_ioc_hw_sem_get(iocpf->ioc); 1002 bfa_ioc_hw_sem_get(iocpf->ioc);
1001} 1003}
1002 1004
@@ -1743,6 +1745,114 @@ bfa_ioc_mbox_flush(struct bfa_ioc *ioc)
1743 bfa_q_deq(&mod->cmd_q, &cmd); 1745 bfa_q_deq(&mod->cmd_q, &cmd);
1744} 1746}
1745 1747
1748/**
1749 * Read data from SMEM to host through PCI memmap
1750 *
1751 * @param[in] ioc memory for IOC
1752 * @param[in] tbuf app memory to store data from smem
1753 * @param[in] soff smem offset
1754 * @param[in] sz size of smem in bytes
1755 */
1756static int
1757bfa_nw_ioc_smem_read(struct bfa_ioc *ioc, void *tbuf, u32 soff, u32 sz)
1758{
1759 u32 pgnum, loff, r32;
1760 int i, len;
1761 u32 *buf = tbuf;
1762
1763 pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, soff);
1764 loff = PSS_SMEM_PGOFF(soff);
1765
1766 /*
1767 * Hold semaphore to serialize pll init and fwtrc.
1768 */
1769 if (bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg) == 0)
1770 return 1;
1771
1772 writel(pgnum, ioc->ioc_regs.host_page_num_fn);
1773
1774 len = sz/sizeof(u32);
1775 for (i = 0; i < len; i++) {
1776 r32 = swab32(readl((loff) + (ioc->ioc_regs.smem_page_start)));
1777 buf[i] = be32_to_cpu(r32);
1778 loff += sizeof(u32);
1779
1780 /**
1781 * handle page offset wrap around
1782 */
1783 loff = PSS_SMEM_PGOFF(loff);
1784 if (loff == 0) {
1785 pgnum++;
1786 writel(pgnum, ioc->ioc_regs.host_page_num_fn);
1787 }
1788 }
1789
1790 writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),
1791 ioc->ioc_regs.host_page_num_fn);
1792
1793 /*
1794 * release semaphore
1795 */
1796 readl(ioc->ioc_regs.ioc_init_sem_reg);
1797 writel(1, ioc->ioc_regs.ioc_init_sem_reg);
1798 return 0;
1799}
1800
1801/**
1802 * Retrieve saved firmware trace from a prior IOC failure.
1803 */
1804int
1805bfa_nw_ioc_debug_fwtrc(struct bfa_ioc *ioc, void *trcdata, int *trclen)
1806{
1807 u32 loff = BFI_IOC_TRC_OFF + BNA_DBG_FWTRC_LEN * ioc->port_id;
1808 int tlen, status = 0;
1809
1810 tlen = *trclen;
1811 if (tlen > BNA_DBG_FWTRC_LEN)
1812 tlen = BNA_DBG_FWTRC_LEN;
1813
1814 status = bfa_nw_ioc_smem_read(ioc, trcdata, loff, tlen);
1815 *trclen = tlen;
1816 return status;
1817}
1818
1819/**
1820 * Save firmware trace if configured.
1821 */
1822static void
1823bfa_nw_ioc_debug_save_ftrc(struct bfa_ioc *ioc)
1824{
1825 int tlen;
1826
1827 if (ioc->dbg_fwsave_once) {
1828 ioc->dbg_fwsave_once = 0;
1829 if (ioc->dbg_fwsave_len) {
1830 tlen = ioc->dbg_fwsave_len;
1831 bfa_nw_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
1832 }
1833 }
1834}
1835
1836/**
1837 * Retrieve saved firmware trace from a prior IOC failure.
1838 */
1839int
1840bfa_nw_ioc_debug_fwsave(struct bfa_ioc *ioc, void *trcdata, int *trclen)
1841{
1842 int tlen;
1843
1844 if (ioc->dbg_fwsave_len == 0)
1845 return BFA_STATUS_ENOFSAVE;
1846
1847 tlen = *trclen;
1848 if (tlen > ioc->dbg_fwsave_len)
1849 tlen = ioc->dbg_fwsave_len;
1850
1851 memcpy(trcdata, ioc->dbg_fwsave, tlen);
1852 *trclen = tlen;
1853 return BFA_STATUS_OK;
1854}
1855
1746static void 1856static void
1747bfa_ioc_fail_notify(struct bfa_ioc *ioc) 1857bfa_ioc_fail_notify(struct bfa_ioc *ioc)
1748{ 1858{
@@ -1751,6 +1861,7 @@ bfa_ioc_fail_notify(struct bfa_ioc *ioc)
1751 */ 1861 */
1752 ioc->cbfn->hbfail_cbfn(ioc->bfa); 1862 ioc->cbfn->hbfail_cbfn(ioc->bfa);
1753 bfa_ioc_event_notify(ioc, BFA_IOC_E_FAILED); 1863 bfa_ioc_event_notify(ioc, BFA_IOC_E_FAILED);
1864 bfa_nw_ioc_debug_save_ftrc(ioc);
1754} 1865}
1755 1866
1756/** 1867/**
@@ -2058,6 +2169,16 @@ bfa_nw_ioc_disable(struct bfa_ioc *ioc)
2058 bfa_fsm_send_event(ioc, IOC_E_DISABLE); 2169 bfa_fsm_send_event(ioc, IOC_E_DISABLE);
2059} 2170}
2060 2171
2172/**
2173 * Initialize memory for saving firmware trace.
2174 */
2175void
2176bfa_nw_ioc_debug_memclaim(struct bfa_ioc *ioc, void *dbg_fwsave)
2177{
2178 ioc->dbg_fwsave = dbg_fwsave;
2179 ioc->dbg_fwsave_len = ioc->iocpf.auto_recover ? BNA_DBG_FWTRC_LEN : 0;
2180}
2181
2061static u32 2182static u32
2062bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr) 2183bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr)
2063{ 2184{
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.h b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
index fc108c7a735e..3b4460fdc148 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
@@ -27,6 +27,8 @@
27#define BFA_IOC_HWSEM_TOV 500 /* msecs */ 27#define BFA_IOC_HWSEM_TOV 500 /* msecs */
28#define BFA_IOC_HB_TOV 500 /* msecs */ 28#define BFA_IOC_HB_TOV 500 /* msecs */
29#define BFA_IOC_POLL_TOV 200 /* msecs */ 29#define BFA_IOC_POLL_TOV 200 /* msecs */
30#define BNA_DBG_FWTRC_LEN (BFI_IOC_TRC_ENTS * BFI_IOC_TRC_ENT_SZ + \
31 BFI_IOC_TRC_HDR_SZ)
30 32
31/** 33/**
32 * PCI device information required by IOC 34 * PCI device information required by IOC
@@ -306,6 +308,7 @@ void bfa_nw_ioc_disable(struct bfa_ioc *ioc);
306 308
307void bfa_nw_ioc_error_isr(struct bfa_ioc *ioc); 309void bfa_nw_ioc_error_isr(struct bfa_ioc *ioc);
308bool bfa_nw_ioc_is_disabled(struct bfa_ioc *ioc); 310bool bfa_nw_ioc_is_disabled(struct bfa_ioc *ioc);
311bool bfa_nw_ioc_is_operational(struct bfa_ioc *ioc);
309void bfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr); 312void bfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr);
310void bfa_nw_ioc_notify_register(struct bfa_ioc *ioc, 313void bfa_nw_ioc_notify_register(struct bfa_ioc *ioc,
311 struct bfa_ioc_notify *notify); 314 struct bfa_ioc_notify *notify);
@@ -317,6 +320,9 @@ void bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc,
317bool bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, 320bool bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc,
318 struct bfi_ioc_image_hdr *fwhdr); 321 struct bfi_ioc_image_hdr *fwhdr);
319mac_t bfa_nw_ioc_get_mac(struct bfa_ioc *ioc); 322mac_t bfa_nw_ioc_get_mac(struct bfa_ioc *ioc);
323void bfa_nw_ioc_debug_memclaim(struct bfa_ioc *ioc, void *dbg_fwsave);
324int bfa_nw_ioc_debug_fwtrc(struct bfa_ioc *ioc, void *trcdata, int *trclen);
325int bfa_nw_ioc_debug_fwsave(struct bfa_ioc *ioc, void *trcdata, int *trclen);
320 326
321/* 327/*
322 * Timeout APIs 328 * Timeout APIs
diff --git a/drivers/net/ethernet/brocade/bna/bfi.h b/drivers/net/ethernet/brocade/bna/bfi.h
index 8230970ad2d3..0d9df695397a 100644
--- a/drivers/net/ethernet/brocade/bna/bfi.h
+++ b/drivers/net/ethernet/brocade/bna/bfi.h
@@ -257,6 +257,8 @@ struct bfi_ioc_getattr_reply {
257 */ 257 */
258#define BFI_IOC_TRC_OFF (0x4b00) 258#define BFI_IOC_TRC_OFF (0x4b00)
259#define BFI_IOC_TRC_ENTS 256 259#define BFI_IOC_TRC_ENTS 256
260#define BFI_IOC_TRC_ENT_SZ 16
261#define BFI_IOC_TRC_HDR_SZ 32
260 262
261#define BFI_IOC_FW_SIGNATURE (0xbfadbfad) 263#define BFI_IOC_FW_SIGNATURE (0xbfadbfad)
262#define BFI_IOC_MD5SUM_SZ 4 264#define BFI_IOC_MD5SUM_SZ 4
diff --git a/drivers/net/ethernet/brocade/bna/bna_enet.c b/drivers/net/ethernet/brocade/bna/bna_enet.c
index bcfe29676677..9ccc586e3767 100644
--- a/drivers/net/ethernet/brocade/bna/bna_enet.c
+++ b/drivers/net/ethernet/brocade/bna/bna_enet.c
@@ -1727,6 +1727,7 @@ bna_ioceth_init(struct bna_ioceth *ioceth, struct bna *bna,
1727 bfa_nw_ioc_mem_claim(&ioceth->ioc, kva, dma); 1727 bfa_nw_ioc_mem_claim(&ioceth->ioc, kva, dma);
1728 1728
1729 kva = res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mdl[0].kva; 1729 kva = res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mdl[0].kva;
1730 bfa_nw_ioc_debug_memclaim(&ioceth->ioc, kva);
1730 1731
1731 /** 1732 /**
1732 * Attach common modules (Diag, SFP, CEE, Port) and claim respective 1733 * Attach common modules (Diag, SFP, CEE, Port) and claim respective
@@ -1910,8 +1911,8 @@ bna_res_req(struct bna_res_info *res_info)
1910 /* Virtual memory for retreiving fw_trc */ 1911 /* Virtual memory for retreiving fw_trc */
1911 res_info[BNA_RES_MEM_T_FWTRC].res_type = BNA_RES_T_MEM; 1912 res_info[BNA_RES_MEM_T_FWTRC].res_type = BNA_RES_T_MEM;
1912 res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mem_type = BNA_MEM_T_KVA; 1913 res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mem_type = BNA_MEM_T_KVA;
1913 res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.num = 0; 1914 res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.num = 1;
1914 res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.len = 0; 1915 res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.len = BNA_DBG_FWTRC_LEN;
1915 1916
1916 /* DMA memory for retreiving stats */ 1917 /* DMA memory for retreiving stats */
1917 res_info[BNA_RES_MEM_T_STATS].res_type = BNA_RES_T_MEM; 1918 res_info[BNA_RES_MEM_T_STATS].res_type = BNA_RES_T_MEM;
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index 741f2e405006..2eddbaa5db47 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -44,6 +44,11 @@ static uint bnad_ioc_auto_recover = 1;
44module_param(bnad_ioc_auto_recover, uint, 0444); 44module_param(bnad_ioc_auto_recover, uint, 0444);
45MODULE_PARM_DESC(bnad_ioc_auto_recover, "Enable / Disable auto recovery"); 45MODULE_PARM_DESC(bnad_ioc_auto_recover, "Enable / Disable auto recovery");
46 46
47static uint bna_debugfs_enable = 1;
48module_param(bna_debugfs_enable, uint, S_IRUGO | S_IWUSR);
49MODULE_PARM_DESC(bna_debugfs_enable, "Enables debugfs feature, default=1,"
50 " Range[false:0|true:1]");
51
47/* 52/*
48 * Global variables 53 * Global variables
49 */ 54 */
@@ -3312,6 +3317,10 @@ bnad_pci_probe(struct pci_dev *pdev,
3312 /* Set link to down state */ 3317 /* Set link to down state */
3313 netif_carrier_off(netdev); 3318 netif_carrier_off(netdev);
3314 3319
3320 /* Setup the debugfs node for this bfad */
3321 if (bna_debugfs_enable)
3322 bnad_debugfs_init(bnad);
3323
3315 /* Get resource requirement form bna */ 3324 /* Get resource requirement form bna */
3316 spin_lock_irqsave(&bnad->bna_lock, flags); 3325 spin_lock_irqsave(&bnad->bna_lock, flags);
3317 bna_res_req(&bnad->res_info[0]); 3326 bna_res_req(&bnad->res_info[0]);
@@ -3433,6 +3442,9 @@ disable_ioceth:
3433res_free: 3442res_free:
3434 bnad_res_free(bnad, &bnad->res_info[0], BNA_RES_T_MAX); 3443 bnad_res_free(bnad, &bnad->res_info[0], BNA_RES_T_MAX);
3435drv_uninit: 3444drv_uninit:
3445 /* Remove the debugfs node for this bnad */
3446 kfree(bnad->regdata);
3447 bnad_debugfs_uninit(bnad);
3436 bnad_uninit(bnad); 3448 bnad_uninit(bnad);
3437pci_uninit: 3449pci_uninit:
3438 bnad_pci_uninit(pdev); 3450 bnad_pci_uninit(pdev);
@@ -3479,6 +3491,9 @@ bnad_pci_remove(struct pci_dev *pdev)
3479 mutex_unlock(&bnad->conf_mutex); 3491 mutex_unlock(&bnad->conf_mutex);
3480 bnad_remove_from_list(bnad); 3492 bnad_remove_from_list(bnad);
3481 bnad_lock_uninit(bnad); 3493 bnad_lock_uninit(bnad);
3494 /* Remove the debugfs node for this bnad */
3495 kfree(bnad->regdata);
3496 bnad_debugfs_uninit(bnad);
3482 bnad_uninit(bnad); 3497 bnad_uninit(bnad);
3483 free_netdev(netdev); 3498 free_netdev(netdev);
3484} 3499}
diff --git a/drivers/net/ethernet/brocade/bna/bnad.h b/drivers/net/ethernet/brocade/bna/bnad.h
index 459030c191c5..c975ce672f48 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.h
+++ b/drivers/net/ethernet/brocade/bna/bnad.h
@@ -328,6 +328,20 @@ struct bnad {
328 char adapter_name[BNAD_NAME_LEN]; 328 char adapter_name[BNAD_NAME_LEN];
329 char port_name[BNAD_NAME_LEN]; 329 char port_name[BNAD_NAME_LEN];
330 char mbox_irq_name[BNAD_NAME_LEN]; 330 char mbox_irq_name[BNAD_NAME_LEN];
331
332 /* debugfs specific data */
333 char *regdata;
334 u32 reglen;
335 struct dentry *bnad_dentry_files[5];
336 struct dentry *port_debugfs_root;
337};
338
339struct bnad_drvinfo {
340 struct bfa_ioc_attr ioc_attr;
341 struct bfa_cee_attr cee_attr;
342 struct bfa_flash_attr flash_attr;
343 u32 cee_status;
344 u32 flash_status;
331}; 345};
332 346
333/* 347/*
@@ -368,6 +382,10 @@ extern void bnad_netdev_qstats_fill(struct bnad *bnad,
368extern void bnad_netdev_hwstats_fill(struct bnad *bnad, 382extern void bnad_netdev_hwstats_fill(struct bnad *bnad,
369 struct rtnl_link_stats64 *stats); 383 struct rtnl_link_stats64 *stats);
370 384
385/* Debugfs */
386void bnad_debugfs_init(struct bnad *bnad);
387void bnad_debugfs_uninit(struct bnad *bnad);
388
371/** 389/**
372 * MACROS 390 * MACROS
373 */ 391 */
diff --git a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
new file mode 100644
index 000000000000..592ad3929f53
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
@@ -0,0 +1,623 @@
1/*
2 * Linux network driver for Brocade Converged Network Adapter.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License (GPL) Version 2 as
6 * published by the Free Software Foundation
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 */
13/*
14 * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
15 * All rights reserved
16 * www.brocade.com
17 */
18
19#include <linux/debugfs.h>
20#include <linux/module.h>
21#include "bnad.h"
22
23/*
24 * BNA debufs interface
25 *
26 * To access the interface, debugfs file system should be mounted
27 * if not already mounted using:
28 * mount -t debugfs none /sys/kernel/debug
29 *
30 * BNA Hierarchy:
31 * - bna/pci_dev:<pci_name>
32 * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bna
33 *
34 * Debugging service available per pci_dev:
35 * fwtrc: To collect current firmware trace.
36 * fwsave: To collect last saved fw trace as a result of firmware crash.
37 * regwr: To write one word to chip register
38 * regrd: To read one or more words from chip register.
39 */
40
41struct bnad_debug_info {
42 char *debug_buffer;
43 void *i_private;
44 int buffer_len;
45};
46
47static int
48bnad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
49{
50 struct bnad *bnad = inode->i_private;
51 struct bnad_debug_info *fw_debug;
52 unsigned long flags;
53 int rc;
54
55 fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
56 if (!fw_debug)
57 return -ENOMEM;
58
59 fw_debug->buffer_len = BNA_DBG_FWTRC_LEN;
60
61 fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL);
62 if (!fw_debug->debug_buffer) {
63 kfree(fw_debug);
64 fw_debug = NULL;
65 pr_warn("bna %s: Failed to allocate fwtrc buffer\n",
66 pci_name(bnad->pcidev));
67 return -ENOMEM;
68 }
69
70 spin_lock_irqsave(&bnad->bna_lock, flags);
71 rc = bfa_nw_ioc_debug_fwtrc(&bnad->bna.ioceth.ioc,
72 fw_debug->debug_buffer,
73 &fw_debug->buffer_len);
74 spin_unlock_irqrestore(&bnad->bna_lock, flags);
75 if (rc != BFA_STATUS_OK) {
76 kfree(fw_debug->debug_buffer);
77 fw_debug->debug_buffer = NULL;
78 kfree(fw_debug);
79 fw_debug = NULL;
80 pr_warn("bnad %s: Failed to collect fwtrc\n",
81 pci_name(bnad->pcidev));
82 return -ENOMEM;
83 }
84
85 file->private_data = fw_debug;
86
87 return 0;
88}
89
90static int
91bnad_debugfs_open_fwsave(struct inode *inode, struct file *file)
92{
93 struct bnad *bnad = inode->i_private;
94 struct bnad_debug_info *fw_debug;
95 unsigned long flags;
96 int rc;
97
98 fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
99 if (!fw_debug)
100 return -ENOMEM;
101
102 fw_debug->buffer_len = BNA_DBG_FWTRC_LEN;
103
104 fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL);
105 if (!fw_debug->debug_buffer) {
106 kfree(fw_debug);
107 fw_debug = NULL;
108 pr_warn("bna %s: Failed to allocate fwsave buffer\n",
109 pci_name(bnad->pcidev));
110 return -ENOMEM;
111 }
112
113 spin_lock_irqsave(&bnad->bna_lock, flags);
114 rc = bfa_nw_ioc_debug_fwsave(&bnad->bna.ioceth.ioc,
115 fw_debug->debug_buffer,
116 &fw_debug->buffer_len);
117 spin_unlock_irqrestore(&bnad->bna_lock, flags);
118 if (rc != BFA_STATUS_OK && rc != BFA_STATUS_ENOFSAVE) {
119 kfree(fw_debug->debug_buffer);
120 fw_debug->debug_buffer = NULL;
121 kfree(fw_debug);
122 fw_debug = NULL;
123 pr_warn("bna %s: Failed to collect fwsave\n",
124 pci_name(bnad->pcidev));
125 return -ENOMEM;
126 }
127
128 file->private_data = fw_debug;
129
130 return 0;
131}
132
133static int
134bnad_debugfs_open_reg(struct inode *inode, struct file *file)
135{
136 struct bnad_debug_info *reg_debug;
137
138 reg_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
139 if (!reg_debug)
140 return -ENOMEM;
141
142 reg_debug->i_private = inode->i_private;
143
144 file->private_data = reg_debug;
145
146 return 0;
147}
148
149static int
150bnad_get_debug_drvinfo(struct bnad *bnad, void *buffer, u32 len)
151{
152 struct bnad_drvinfo *drvinfo = (struct bnad_drvinfo *) buffer;
153 struct bnad_iocmd_comp fcomp;
154 unsigned long flags = 0;
155 int ret = BFA_STATUS_FAILED;
156
157 /* Get IOC info */
158 spin_lock_irqsave(&bnad->bna_lock, flags);
159 bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, &drvinfo->ioc_attr);
160 spin_unlock_irqrestore(&bnad->bna_lock, flags);
161
162 /* Retrieve CEE related info */
163 fcomp.bnad = bnad;
164 fcomp.comp_status = 0;
165 init_completion(&fcomp.comp);
166 spin_lock_irqsave(&bnad->bna_lock, flags);
167 ret = bfa_nw_cee_get_attr(&bnad->bna.cee, &drvinfo->cee_attr,
168 bnad_cb_completion, &fcomp);
169 if (ret != BFA_STATUS_OK) {
170 spin_unlock_irqrestore(&bnad->bna_lock, flags);
171 goto out;
172 }
173 spin_unlock_irqrestore(&bnad->bna_lock, flags);
174 wait_for_completion(&fcomp.comp);
175 drvinfo->cee_status = fcomp.comp_status;
176
177 /* Retrieve flash partition info */
178 fcomp.comp_status = 0;
179 init_completion(&fcomp.comp);
180 spin_lock_irqsave(&bnad->bna_lock, flags);
181 ret = bfa_nw_flash_get_attr(&bnad->bna.flash, &drvinfo->flash_attr,
182 bnad_cb_completion, &fcomp);
183 if (ret != BFA_STATUS_OK) {
184 spin_unlock_irqrestore(&bnad->bna_lock, flags);
185 goto out;
186 }
187 spin_unlock_irqrestore(&bnad->bna_lock, flags);
188 wait_for_completion(&fcomp.comp);
189 drvinfo->flash_status = fcomp.comp_status;
190out:
191 return ret;
192}
193
194static int
195bnad_debugfs_open_drvinfo(struct inode *inode, struct file *file)
196{
197 struct bnad *bnad = inode->i_private;
198 struct bnad_debug_info *drv_info;
199 int rc;
200
201 drv_info = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
202 if (!drv_info)
203 return -ENOMEM;
204
205 drv_info->buffer_len = sizeof(struct bnad_drvinfo);
206
207 drv_info->debug_buffer = kzalloc(drv_info->buffer_len, GFP_KERNEL);
208 if (!drv_info->debug_buffer) {
209 kfree(drv_info);
210 drv_info = NULL;
211 pr_warn("bna %s: Failed to allocate drv info buffer\n",
212 pci_name(bnad->pcidev));
213 return -ENOMEM;
214 }
215
216 mutex_lock(&bnad->conf_mutex);
217 rc = bnad_get_debug_drvinfo(bnad, drv_info->debug_buffer,
218 drv_info->buffer_len);
219 mutex_unlock(&bnad->conf_mutex);
220 if (rc != BFA_STATUS_OK) {
221 kfree(drv_info->debug_buffer);
222 drv_info->debug_buffer = NULL;
223 kfree(drv_info);
224 drv_info = NULL;
225 pr_warn("bna %s: Failed to collect drvinfo\n",
226 pci_name(bnad->pcidev));
227 return -ENOMEM;
228 }
229
230 file->private_data = drv_info;
231
232 return 0;
233}
234
235/* Changes the current file position */
236static loff_t
237bnad_debugfs_lseek(struct file *file, loff_t offset, int orig)
238{
239 loff_t pos = file->f_pos;
240 struct bnad_debug_info *debug = file->private_data;
241
242 if (!debug)
243 return -EINVAL;
244
245 switch (orig) {
246 case 0:
247 file->f_pos = offset;
248 break;
249 case 1:
250 file->f_pos += offset;
251 break;
252 case 2:
253 file->f_pos = debug->buffer_len - offset;
254 break;
255 default:
256 return -EINVAL;
257 }
258
259 if (file->f_pos < 0 || file->f_pos > debug->buffer_len) {
260 file->f_pos = pos;
261 return -EINVAL;
262 }
263
264 return file->f_pos;
265}
266
267static ssize_t
268bnad_debugfs_read(struct file *file, char __user *buf,
269 size_t nbytes, loff_t *pos)
270{
271 struct bnad_debug_info *debug = file->private_data;
272
273 if (!debug || !debug->debug_buffer)
274 return 0;
275
276 return simple_read_from_buffer(buf, nbytes, pos,
277 debug->debug_buffer, debug->buffer_len);
278}
279
280#define BFA_REG_CT_ADDRSZ (0x40000)
281#define BFA_REG_CB_ADDRSZ (0x20000)
282#define BFA_REG_ADDRSZ(__ioc) \
283 ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \
284 BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ))
285#define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1)
286
287/*
288 * Function to check if the register offset passed is valid.
289 */
290static int
291bna_reg_offset_check(struct bfa_ioc *ioc, u32 offset, u32 len)
292{
293 u8 area;
294
295 /* check [16:15] */
296 area = (offset >> 15) & 0x7;
297 if (area == 0) {
298 /* PCIe core register */
299 if ((offset + (len<<2)) > 0x8000) /* 8k dwords or 32KB */
300 return BFA_STATUS_EINVAL;
301 } else if (area == 0x1) {
302 /* CB 32 KB memory page */
303 if ((offset + (len<<2)) > 0x10000) /* 8k dwords or 32KB */
304 return BFA_STATUS_EINVAL;
305 } else {
306 /* CB register space 64KB */
307 if ((offset + (len<<2)) > BFA_REG_ADDRMSK(ioc))
308 return BFA_STATUS_EINVAL;
309 }
310 return BFA_STATUS_OK;
311}
312
313static ssize_t
314bnad_debugfs_read_regrd(struct file *file, char __user *buf,
315 size_t nbytes, loff_t *pos)
316{
317 struct bnad_debug_info *regrd_debug = file->private_data;
318 struct bnad *bnad = (struct bnad *)regrd_debug->i_private;
319 ssize_t rc;
320
321 if (!bnad->regdata)
322 return 0;
323
324 rc = simple_read_from_buffer(buf, nbytes, pos,
325 bnad->regdata, bnad->reglen);
326
327 if ((*pos + nbytes) >= bnad->reglen) {
328 kfree(bnad->regdata);
329 bnad->regdata = NULL;
330 bnad->reglen = 0;
331 }
332
333 return rc;
334}
335
336static ssize_t
337bnad_debugfs_write_regrd(struct file *file, const char __user *buf,
338 size_t nbytes, loff_t *ppos)
339{
340 struct bnad_debug_info *regrd_debug = file->private_data;
341 struct bnad *bnad = (struct bnad *)regrd_debug->i_private;
342 struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc;
343 int addr, len, rc, i;
344 u32 *regbuf;
345 void __iomem *rb, *reg_addr;
346 unsigned long flags;
347 void *kern_buf;
348
349 /* Allocate memory to store the user space buf */
350 kern_buf = kzalloc(nbytes, GFP_KERNEL);
351 if (!kern_buf) {
352 pr_warn("bna %s: Failed to allocate user buffer\n",
353 pci_name(bnad->pcidev));
354 return -ENOMEM;
355 }
356
357 if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
358 kfree(kern_buf);
359 return -ENOMEM;
360 }
361
362 rc = sscanf(kern_buf, "%x:%x", &addr, &len);
363 if (rc < 2) {
364 pr_warn("bna %s: Failed to read user buffer\n",
365 pci_name(bnad->pcidev));
366 kfree(kern_buf);
367 return -EINVAL;
368 }
369
370 kfree(kern_buf);
371 kfree(bnad->regdata);
372 bnad->regdata = NULL;
373 bnad->reglen = 0;
374
375 bnad->regdata = kzalloc(len << 2, GFP_KERNEL);
376 if (!bnad->regdata) {
377 pr_warn("bna %s: Failed to allocate regrd buffer\n",
378 pci_name(bnad->pcidev));
379 return -ENOMEM;
380 }
381
382 bnad->reglen = len << 2;
383 rb = bfa_ioc_bar0(ioc);
384 addr &= BFA_REG_ADDRMSK(ioc);
385
386 /* offset and len sanity check */
387 rc = bna_reg_offset_check(ioc, addr, len);
388 if (rc) {
389 pr_warn("bna %s: Failed reg offset check\n",
390 pci_name(bnad->pcidev));
391 kfree(bnad->regdata);
392 bnad->regdata = NULL;
393 bnad->reglen = 0;
394 return -EINVAL;
395 }
396
397 reg_addr = rb + addr;
398 regbuf = (u32 *)bnad->regdata;
399 spin_lock_irqsave(&bnad->bna_lock, flags);
400 for (i = 0; i < len; i++) {
401 *regbuf = readl(reg_addr);
402 regbuf++;
403 reg_addr += sizeof(u32);
404 }
405 spin_unlock_irqrestore(&bnad->bna_lock, flags);
406
407 return nbytes;
408}
409
410static ssize_t
411bnad_debugfs_write_regwr(struct file *file, const char __user *buf,
412 size_t nbytes, loff_t *ppos)
413{
414 struct bnad_debug_info *debug = file->private_data;
415 struct bnad *bnad = (struct bnad *)debug->i_private;
416 struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc;
417 int addr, val, rc;
418 void __iomem *reg_addr;
419 unsigned long flags;
420 void *kern_buf;
421
422 /* Allocate memory to store the user space buf */
423 kern_buf = kzalloc(nbytes, GFP_KERNEL);
424 if (!kern_buf) {
425 pr_warn("bna %s: Failed to allocate user buffer\n",
426 pci_name(bnad->pcidev));
427 return -ENOMEM;
428 }
429
430 if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
431 kfree(kern_buf);
432 return -ENOMEM;
433 }
434
435 rc = sscanf(kern_buf, "%x:%x", &addr, &val);
436 if (rc < 2) {
437 pr_warn("bna %s: Failed to read user buffer\n",
438 pci_name(bnad->pcidev));
439 kfree(kern_buf);
440 return -EINVAL;
441 }
442 kfree(kern_buf);
443
444 addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */
445
446 /* offset and len sanity check */
447 rc = bna_reg_offset_check(ioc, addr, 1);
448 if (rc) {
449 pr_warn("bna %s: Failed reg offset check\n",
450 pci_name(bnad->pcidev));
451 return -EINVAL;
452 }
453
454 reg_addr = (bfa_ioc_bar0(ioc)) + addr;
455 spin_lock_irqsave(&bnad->bna_lock, flags);
456 writel(val, reg_addr);
457 spin_unlock_irqrestore(&bnad->bna_lock, flags);
458
459 return nbytes;
460}
461
462static int
463bnad_debugfs_release(struct inode *inode, struct file *file)
464{
465 struct bnad_debug_info *debug = file->private_data;
466
467 if (!debug)
468 return 0;
469
470 file->private_data = NULL;
471 kfree(debug);
472 return 0;
473}
474
475static int
476bnad_debugfs_buffer_release(struct inode *inode, struct file *file)
477{
478 struct bnad_debug_info *debug = file->private_data;
479
480 if (!debug)
481 return 0;
482
483 kfree(debug->debug_buffer);
484
485 file->private_data = NULL;
486 kfree(debug);
487 debug = NULL;
488 return 0;
489}
490
491static const struct file_operations bnad_debugfs_op_fwtrc = {
492 .owner = THIS_MODULE,
493 .open = bnad_debugfs_open_fwtrc,
494 .llseek = bnad_debugfs_lseek,
495 .read = bnad_debugfs_read,
496 .release = bnad_debugfs_buffer_release,
497};
498
499static const struct file_operations bnad_debugfs_op_fwsave = {
500 .owner = THIS_MODULE,
501 .open = bnad_debugfs_open_fwsave,
502 .llseek = bnad_debugfs_lseek,
503 .read = bnad_debugfs_read,
504 .release = bnad_debugfs_buffer_release,
505};
506
507static const struct file_operations bnad_debugfs_op_regrd = {
508 .owner = THIS_MODULE,
509 .open = bnad_debugfs_open_reg,
510 .llseek = bnad_debugfs_lseek,
511 .read = bnad_debugfs_read_regrd,
512 .write = bnad_debugfs_write_regrd,
513 .release = bnad_debugfs_release,
514};
515
516static const struct file_operations bnad_debugfs_op_regwr = {
517 .owner = THIS_MODULE,
518 .open = bnad_debugfs_open_reg,
519 .llseek = bnad_debugfs_lseek,
520 .write = bnad_debugfs_write_regwr,
521 .release = bnad_debugfs_release,
522};
523
524static const struct file_operations bnad_debugfs_op_drvinfo = {
525 .owner = THIS_MODULE,
526 .open = bnad_debugfs_open_drvinfo,
527 .llseek = bnad_debugfs_lseek,
528 .read = bnad_debugfs_read,
529 .release = bnad_debugfs_buffer_release,
530};
531
532struct bnad_debugfs_entry {
533 const char *name;
534 mode_t mode;
535 const struct file_operations *fops;
536};
537
538static const struct bnad_debugfs_entry bnad_debugfs_files[] = {
539 { "fwtrc", S_IFREG|S_IRUGO, &bnad_debugfs_op_fwtrc, },
540 { "fwsave", S_IFREG|S_IRUGO, &bnad_debugfs_op_fwsave, },
541 { "regrd", S_IFREG|S_IRUGO|S_IWUSR, &bnad_debugfs_op_regrd, },
542 { "regwr", S_IFREG|S_IWUSR, &bnad_debugfs_op_regwr, },
543 { "drvinfo", S_IFREG|S_IRUGO, &bnad_debugfs_op_drvinfo, },
544};
545
546static struct dentry *bna_debugfs_root;
547static atomic_t bna_debugfs_port_count;
548
549/* Initialize debugfs interface for BNA */
550void
551bnad_debugfs_init(struct bnad *bnad)
552{
553 const struct bnad_debugfs_entry *file;
554 char name[64];
555 int i;
556
557 /* Setup the BNA debugfs root directory*/
558 if (!bna_debugfs_root) {
559 bna_debugfs_root = debugfs_create_dir("bna", NULL);
560 atomic_set(&bna_debugfs_port_count, 0);
561 if (!bna_debugfs_root) {
562 pr_warn("BNA: debugfs root dir creation failed\n");
563 return;
564 }
565 }
566
567 /* Setup the pci_dev debugfs directory for the port */
568 snprintf(name, sizeof(name), "pci_dev:%s", pci_name(bnad->pcidev));
569 if (!bnad->port_debugfs_root) {
570 bnad->port_debugfs_root =
571 debugfs_create_dir(name, bna_debugfs_root);
572 if (!bnad->port_debugfs_root) {
573 pr_warn("bna pci_dev %s: root dir creation failed\n",
574 pci_name(bnad->pcidev));
575 return;
576 }
577
578 atomic_inc(&bna_debugfs_port_count);
579
580 for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
581 file = &bnad_debugfs_files[i];
582 bnad->bnad_dentry_files[i] =
583 debugfs_create_file(file->name,
584 file->mode,
585 bnad->port_debugfs_root,
586 bnad,
587 file->fops);
588 if (!bnad->bnad_dentry_files[i]) {
589 pr_warn(
590 "BNA pci_dev:%s: create %s entry failed\n",
591 pci_name(bnad->pcidev), file->name);
592 return;
593 }
594 }
595 }
596}
597
598/* Uninitialize debugfs interface for BNA */
599void
600bnad_debugfs_uninit(struct bnad *bnad)
601{
602 int i;
603
604 for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
605 if (bnad->bnad_dentry_files[i]) {
606 debugfs_remove(bnad->bnad_dentry_files[i]);
607 bnad->bnad_dentry_files[i] = NULL;
608 }
609 }
610
611 /* Remove the pci_dev debugfs directory for the port */
612 if (bnad->port_debugfs_root) {
613 debugfs_remove(bnad->port_debugfs_root);
614 bnad->port_debugfs_root = NULL;
615 atomic_dec(&bna_debugfs_port_count);
616 }
617
618 /* Remove the BNA debugfs root directory */
619 if (atomic_read(&bna_debugfs_port_count) == 0) {
620 debugfs_remove(bna_debugfs_root);
621 bna_debugfs_root = NULL;
622 }
623}