Commit 877e9aa4 authored by Eliezer Tamir's avatar Eliezer Tamir Committed by David S. Miller

[BNX2X]: fix HW attentions and error handling

Some of the HW attentions, used to indicate an error were not properly
acked.

This will cause the driver to endlessly receive interrupts when such
an error happens.

Had to break the code into smaller chunks because it got too nested.
Signed-off-by: default avatarEliezer Tamir <eliezert@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 615f8fd9
...@@ -4089,7 +4089,7 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) ...@@ -4089,7 +4089,7 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
u32 igu_addr = (IGU_ADDR_ATTN_BITS_SET + IGU_PORT_BASE * port) * 8; u32 igu_addr = (IGU_ADDR_ATTN_BITS_SET + IGU_PORT_BASE * port) * 8;
u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
MISC_REG_AEU_MASK_ATTN_FUNC_0; MISC_REG_AEU_MASK_ATTN_FUNC_0;
u32 nig_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 : u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
NIG_REG_MASK_INTERRUPT_PORT0; NIG_REG_MASK_INTERRUPT_PORT0;
if (~bp->aeu_mask & (asserted & 0xff)) if (~bp->aeu_mask & (asserted & 0xff))
...@@ -4108,15 +4108,11 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) ...@@ -4108,15 +4108,11 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
if (asserted & ATTN_HARD_WIRED_MASK) { if (asserted & ATTN_HARD_WIRED_MASK) {
if (asserted & ATTN_NIG_FOR_FUNC) { if (asserted & ATTN_NIG_FOR_FUNC) {
u32 nig_status_port;
u32 nig_int_addr = port ?
NIG_REG_STATUS_INTERRUPT_PORT1 :
NIG_REG_STATUS_INTERRUPT_PORT0;
bp->nig_mask = REG_RD(bp, nig_mask_addr); /* save nig interrupt mask */
REG_WR(bp, nig_mask_addr, 0); bp->nig_mask = REG_RD(bp, nig_int_mask_addr);
REG_WR(bp, nig_int_mask_addr, 0);
nig_status_port = REG_RD(bp, nig_int_addr);
bnx2x_link_update(bp); bnx2x_link_update(bp);
/* handle unicore attn? */ /* handle unicore attn? */
...@@ -4169,57 +4165,64 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) ...@@ -4169,57 +4165,64 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
/* now set back the mask */ /* now set back the mask */
if (asserted & ATTN_NIG_FOR_FUNC) if (asserted & ATTN_NIG_FOR_FUNC)
REG_WR(bp, nig_mask_addr, bp->nig_mask); REG_WR(bp, nig_int_mask_addr, bp->nig_mask);
} }
static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
{ {
int port = bp->port; int port = bp->port;
int index; int reg_offset;
struct attn_route attn;
struct attn_route group_mask;
u32 reg_addr;
u32 val; u32 val;
/* need to take HW lock because MCP or other port might also if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) {
try to handle this event */
bnx2x_lock_alr(bp);
attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4);
attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4);
attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4);
attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4);
DP(NETIF_MSG_HW, "attn %llx\n", (unsigned long long)attn.sig[0]);
for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
if (deasserted & (1 << index)) {
group_mask = bp->attn_group[index];
DP(NETIF_MSG_HW, "group[%d]: %llx\n", index,
(unsigned long long)group_mask.sig[0]);
if (attn.sig[3] & group_mask.sig[3] & reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
EVEREST_GEN_ATTN_IN_USE_MASK) { MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
if (attn.sig[3] & BNX2X_MC_ASSERT_BITS) { val = REG_RD(bp, reg_offset);
val &= ~AEU_INPUTS_ATTN_BITS_SPIO5;
REG_WR(bp, reg_offset, val);
BNX2X_ERR("MC assert!\n"); BNX2X_ERR("SPIO5 hw attention\n");
bnx2x_panic();
} else if (attn.sig[3] & BNX2X_MCP_ASSERT) { switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) {
case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G:
/* Fan failure attention */
BNX2X_ERR("MCP assert!\n"); /* The PHY reset is controled by GPIO 1 */
REG_WR(bp, bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REG_AEU_GENERAL_ATTN_11, 0); MISC_REGISTERS_GPIO_OUTPUT_LOW);
bnx2x_mc_assert(bp); /* Low power mode is controled by GPIO 2 */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_LOW);
/* mark the failure */
bp->ext_phy_config &=
~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
bp->ext_phy_config |=
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
SHMEM_WR(bp,
dev_info.port_hw_config[port].
external_phy_config,
bp->ext_phy_config);
/* log the failure */
printk(KERN_ERR PFX "Fan Failure on Network"
" Controller %s has caused the driver to"
" shutdown the card to prevent permanent"
" damage. Please contact Dell Support for"
" assistance\n", bp->dev->name);
break;
} else { default:
BNX2X_ERR("UNKOWEN HW ASSERT!\n"); break;
} }
} }
}
static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn)
{
u32 val;
if (attn.sig[1] & group_mask.sig[1] & if (attn & BNX2X_DOORQ_ASSERT) {
BNX2X_DOORQ_ASSERT) {
val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR); val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR);
BNX2X_ERR("DB hw attention 0x%x\n", val); BNX2X_ERR("DB hw attention 0x%x\n", val);
...@@ -4227,9 +4230,13 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) ...@@ -4227,9 +4230,13 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
if (val & 0x2) if (val & 0x2)
BNX2X_ERR("FATAL error from DORQ\n"); BNX2X_ERR("FATAL error from DORQ\n");
} }
}
static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn)
{
u32 val;
if (attn.sig[2] & group_mask.sig[2] & if (attn & AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {
AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {
val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR); val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR);
BNX2X_ERR("CFC hw attention 0x%x\n", val); BNX2X_ERR("CFC hw attention 0x%x\n", val);
...@@ -4238,8 +4245,7 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) ...@@ -4238,8 +4245,7 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
BNX2X_ERR("FATAL error from CFC\n"); BNX2X_ERR("FATAL error from CFC\n");
} }
if (attn.sig[2] & group_mask.sig[2] & if (attn & AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {
AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {
val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0); val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0);
BNX2X_ERR("PXP hw attention 0x%x\n", val); BNX2X_ERR("PXP hw attention 0x%x\n", val);
...@@ -4247,15 +4253,72 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) ...@@ -4247,15 +4253,72 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
if (val & 0x18000) if (val & 0x18000)
BNX2X_ERR("FATAL error from PXP\n"); BNX2X_ERR("FATAL error from PXP\n");
} }
}
if (attn.sig[3] & group_mask.sig[3] & static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
EVEREST_LATCHED_ATTN_IN_USE_MASK) { {
if (attn & EVEREST_GEN_ATTN_IN_USE_MASK) {
if (attn & BNX2X_MC_ASSERT_BITS) {
BNX2X_ERR("MC assert!\n");
REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_10, 0);
REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_9, 0);
REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_8, 0);
REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_7, 0);
bnx2x_panic();
} else if (attn & BNX2X_MCP_ASSERT) {
BNX2X_ERR("MCP assert!\n");
REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_11, 0);
bnx2x_mc_assert(bp);
} else
BNX2X_ERR("Unknown HW assert! (attn 0x%x)\n", attn);
}
REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) {
0x7ff);
DP(NETIF_MSG_HW, "got latched bits 0x%x\n", REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff);
attn.sig[3]); BNX2X_ERR("LATCHED attention 0x%x (masked)\n", attn);
} }
}
static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
{
struct attn_route attn;
struct attn_route group_mask;
int port = bp->port;
int index;
u32 reg_addr;
u32 val;
/* need to take HW lock because MCP or other port might also
try to handle this event */
bnx2x_lock_alr(bp);
attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4);
attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4);
attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4);
attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4);
DP(NETIF_MSG_HW, "attn %llx\n", (unsigned long long)attn.sig[0]);
for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
if (deasserted & (1 << index)) {
group_mask = bp->attn_group[index];
DP(NETIF_MSG_HW, "group[%d]: %llx\n", index,
(unsigned long long)group_mask.sig[0]);
bnx2x_attn_int_deasserted3(bp,
attn.sig[3] & group_mask.sig[3]);
bnx2x_attn_int_deasserted1(bp,
attn.sig[1] & group_mask.sig[1]);
bnx2x_attn_int_deasserted2(bp,
attn.sig[2] & group_mask.sig[2]);
bnx2x_attn_int_deasserted0(bp,
attn.sig[0] & group_mask.sig[0]);
if ((attn.sig[0] & group_mask.sig[0] & if ((attn.sig[0] & group_mask.sig[0] &
HW_INTERRUT_ASSERT_SET_0) || HW_INTERRUT_ASSERT_SET_0) ||
...@@ -4263,7 +4326,15 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) ...@@ -4263,7 +4326,15 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
HW_INTERRUT_ASSERT_SET_1) || HW_INTERRUT_ASSERT_SET_1) ||
(attn.sig[2] & group_mask.sig[2] & (attn.sig[2] & group_mask.sig[2] &
HW_INTERRUT_ASSERT_SET_2)) HW_INTERRUT_ASSERT_SET_2))
BNX2X_ERR("FATAL HW block attention\n"); BNX2X_ERR("FATAL HW block attention"
" set0 0x%x set1 0x%x"
" set2 0x%x\n",
(attn.sig[0] & group_mask.sig[0] &
HW_INTERRUT_ASSERT_SET_0),
(attn.sig[1] & group_mask.sig[1] &
HW_INTERRUT_ASSERT_SET_1),
(attn.sig[2] & group_mask.sig[2] &
HW_INTERRUT_ASSERT_SET_2));
if ((attn.sig[0] & group_mask.sig[0] & if ((attn.sig[0] & group_mask.sig[0] &
HW_PRTY_ASSERT_SET_0) || HW_PRTY_ASSERT_SET_0) ||
...@@ -4336,7 +4407,7 @@ static void bnx2x_sp_task(struct work_struct *work) ...@@ -4336,7 +4407,7 @@ static void bnx2x_sp_task(struct work_struct *work)
/* Return here if interrupt is disabled */ /* Return here if interrupt is disabled */
if (unlikely(atomic_read(&bp->intr_sem) != 0)) { if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n"); DP(BNX2X_MSG_SP, "called but intr_sem not 0, returning\n");
return; return;
} }
...@@ -4346,12 +4417,11 @@ static void bnx2x_sp_task(struct work_struct *work) ...@@ -4346,12 +4417,11 @@ static void bnx2x_sp_task(struct work_struct *work)
DP(NETIF_MSG_INTR, "got a slowpath interrupt (updated %x)\n", status); DP(NETIF_MSG_INTR, "got a slowpath interrupt (updated %x)\n", status);
if (status & 0x1) {
/* HW attentions */ /* HW attentions */
if (status & 0x1)
bnx2x_attn_int(bp); bnx2x_attn_int(bp);
}
/* CStorm events: query_stats, cfc delete ramrods */ /* CStorm events: query_stats, port delete ramrod */
if (status & 0x2) if (status & 0x2)
bp->stat_pending = 0; bp->stat_pending = 0;
...@@ -4365,6 +4435,7 @@ static void bnx2x_sp_task(struct work_struct *work) ...@@ -4365,6 +4435,7 @@ static void bnx2x_sp_task(struct work_struct *work)
IGU_INT_NOP, 1); IGU_INT_NOP, 1);
bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx), bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx),
IGU_INT_ENABLE, 1); IGU_INT_ENABLE, 1);
} }
static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance) static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
...@@ -4374,11 +4445,11 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance) ...@@ -4374,11 +4445,11 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
/* Return here if interrupt is disabled */ /* Return here if interrupt is disabled */
if (unlikely(atomic_read(&bp->intr_sem) != 0)) { if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n"); DP(BNX2X_MSG_SP, "called but intr_sem not 0, returning\n");
return IRQ_HANDLED; return IRQ_HANDLED;
} }
bnx2x_ack_sb(bp, 16, XSTORM_ID, 0, IGU_INT_DISABLE, 0); bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, 0, IGU_INT_DISABLE, 0);
#ifdef BNX2X_STOP_ON_ERROR #ifdef BNX2X_STOP_ON_ERROR
if (unlikely(bp->panic)) if (unlikely(bp->panic))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment