From 823e1d90797552687d2dfab2299464e5b663a8a9 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Mon, 14 Jan 2013 05:11:47 +0000 Subject: [PATCH] bnx2x: improve stop-on-error Get better control over interrupts during panic, and allow FW to test outgoing Tx packets when stop-on-error is allowed. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 6 +- .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 4 + .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 2 +- .../ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 4 - .../net/ethernet/broadcom/bnx2x/bnx2x_main.c | 139 +++++++++--------- 5 files changed, 79 insertions(+), 76 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 309bbb70cf7f..757fe2c843d8 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -123,20 +123,18 @@ do { \ } while (0) #ifdef BNX2X_STOP_ON_ERROR -void bnx2x_int_disable(struct bnx2x *bp); #define bnx2x_panic() \ do { \ bp->panic = 1; \ BNX2X_ERR("driver assert\n"); \ - bnx2x_int_disable(bp); \ - bnx2x_panic_dump(bp); \ + bnx2x_panic_dump(bp, true); \ } while (0) #else #define bnx2x_panic() \ do { \ bp->panic = 1; \ BNX2X_ERR("driver assert\n"); \ - bnx2x_panic_dump(bp); \ + bnx2x_panic_dump(bp, false); \ } while (0) #endif diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 6312e636e37b..5409b303a69b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3535,13 +3535,17 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* when transmitting in a vf, start bd must hold the ethertype * for fw to enforce it */ +#ifndef BNX2X_STOP_ON_ERROR if (IS_VF(bp)) { +#endif tx_start_bd->vlan_or_ethertype = cpu_to_le16(ntohs(eth->h_proto)); +#ifndef BNX2X_STOP_ON_ERROR } else { /* used by FW for packet accounting */ tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod); } +#endif } /* turn on parsing and get a BD */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index a2583f2c935d..8104b986037b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -479,7 +479,7 @@ int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state); */ void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value); /* Error handling */ -void bnx2x_panic_dump(struct bnx2x *bp); +void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int); void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 9c9fe0e49117..d3b0429d62a0 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -2720,10 +2720,6 @@ static void bnx2x_self_test(struct net_device *dev, buf[2] = 1; etest->flags |= ETH_TEST_FL_FAILED; } - -#ifdef BNX2X_EXTRA_DEBUG - bnx2x_panic_dump(bp); -#endif } #define IS_PORT_STAT(i) \ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index f4d4896d71f3..b4838510f3da 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -802,7 +802,71 @@ static void bnx2x_fw_dump(struct bnx2x *bp) bnx2x_fw_dump_lvl(bp, KERN_ERR); } -void bnx2x_panic_dump(struct bnx2x *bp) +static void bnx2x_hc_int_disable(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0; + u32 val = REG_RD(bp, addr); + + /* in E1 we must use only PCI configuration space to disable + * MSI/MSIX capablility + * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block + */ + if (CHIP_IS_E1(bp)) { + /* Since IGU_PF_CONF_MSI_MSIX_EN still always on + * Use mask register to prevent from HC sending interrupts + * after we exit the function + */ + REG_WR(bp, HC_REG_INT_MASK + port*4, 0); + + val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 | + HC_CONFIG_0_REG_INT_LINE_EN_0 | + HC_CONFIG_0_REG_ATTN_BIT_EN_0); + } else + val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 | + HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 | + HC_CONFIG_0_REG_INT_LINE_EN_0 | + HC_CONFIG_0_REG_ATTN_BIT_EN_0); + + DP(NETIF_MSG_IFDOWN, + "write %x to HC %d (addr 0x%x)\n", + val, port, addr); + + /* flush all outstanding writes */ + mmiowb(); + + REG_WR(bp, addr, val); + if (REG_RD(bp, addr) != val) + BNX2X_ERR("BUG! proper val not read from IGU!\n"); +} + +static void bnx2x_igu_int_disable(struct bnx2x *bp) +{ + u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION); + + val &= ~(IGU_PF_CONF_MSI_MSIX_EN | + IGU_PF_CONF_INT_LINE_EN | + IGU_PF_CONF_ATTN_BIT_EN); + + DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val); + + /* flush all outstanding writes */ + mmiowb(); + + REG_WR(bp, IGU_REG_PF_CONFIGURATION, val); + if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val) + BNX2X_ERR("BUG! proper val not read from IGU!\n"); +} + +static void bnx2x_int_disable(struct bnx2x *bp) +{ + if (bp->common.int_block == INT_BLOCK_HC) + bnx2x_hc_int_disable(bp); + else + bnx2x_igu_int_disable(bp); +} + +void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int) { int i; u16 j; @@ -812,6 +876,8 @@ void bnx2x_panic_dump(struct bnx2x *bp) u16 start = 0, end = 0; u8 cos; #endif + if (disable_int) + bnx2x_int_disable(bp); bp->stats_state = STATS_STATE_DISABLED; bp->eth_stats.unrecoverable_error++; @@ -1527,71 +1593,6 @@ void bnx2x_int_enable(struct bnx2x *bp) bnx2x_igu_int_enable(bp); } -static void bnx2x_hc_int_disable(struct bnx2x *bp) -{ - int port = BP_PORT(bp); - u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0; - u32 val = REG_RD(bp, addr); - - /* - * in E1 we must use only PCI configuration space to disable - * MSI/MSIX capablility - * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block - */ - if (CHIP_IS_E1(bp)) { - /* Since IGU_PF_CONF_MSI_MSIX_EN still always on - * Use mask register to prevent from HC sending interrupts - * after we exit the function - */ - REG_WR(bp, HC_REG_INT_MASK + port*4, 0); - - val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 | - HC_CONFIG_0_REG_INT_LINE_EN_0 | - HC_CONFIG_0_REG_ATTN_BIT_EN_0); - } else - val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 | - HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 | - HC_CONFIG_0_REG_INT_LINE_EN_0 | - HC_CONFIG_0_REG_ATTN_BIT_EN_0); - - DP(NETIF_MSG_IFDOWN, - "write %x to HC %d (addr 0x%x)\n", - val, port, addr); - - /* flush all outstanding writes */ - mmiowb(); - - REG_WR(bp, addr, val); - if (REG_RD(bp, addr) != val) - BNX2X_ERR("BUG! proper val not read from IGU!\n"); -} - -static void bnx2x_igu_int_disable(struct bnx2x *bp) -{ - u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION); - - val &= ~(IGU_PF_CONF_MSI_MSIX_EN | - IGU_PF_CONF_INT_LINE_EN | - IGU_PF_CONF_ATTN_BIT_EN); - - DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val); - - /* flush all outstanding writes */ - mmiowb(); - - REG_WR(bp, IGU_REG_PF_CONFIGURATION, val); - if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val) - BNX2X_ERR("BUG! proper val not read from IGU!\n"); -} - -static void bnx2x_int_disable(struct bnx2x *bp) -{ - if (bp->common.int_block == INT_BLOCK_HC) - bnx2x_hc_int_disable(bp); - else - bnx2x_igu_int_disable(bp); -} - void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw) { int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; @@ -2945,6 +2946,10 @@ static unsigned long bnx2x_get_common_flags(struct bnx2x *bp, __set_bit(BNX2X_Q_FLG_ZERO_STATS, &flags); +#ifdef BNX2X_STOP_ON_ERROR + __set_bit(BNX2X_Q_FLG_TX_SEC, &flags); +#endif + return flags; } @@ -4765,7 +4770,7 @@ static int bnx2x_cnic_handle_cfc_del(struct bnx2x *bp, u32 cid, BNX2X_ERR("got delete ramrod for CNIC CID %d with error!\n", cid); - bnx2x_panic_dump(bp); + bnx2x_panic_dump(bp, false); } bnx2x_cnic_cfc_comp(bp, cid, err); return 0; -- 2.30.2