Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 823e1d90 authored by Yuval Mintz's avatar Yuval Mintz Committed by David S. Miller
Browse files

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: default avatarYuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: default avatarAriel Elior <ariele@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 07ba6af4
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -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

+4 −0
Original line number Diff line number Diff line
@@ -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 */
+1 −1
Original line number Diff line number Diff line
@@ -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);

+0 −4
Original line number Diff line number Diff line
@@ -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) \
+72 −67
Original line number Diff line number Diff line
@@ -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;