Skip to content

Commit

Permalink
[BNX2X]: fix HW attentions and error handling
Browse files Browse the repository at this point in the history
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: Eliezer Tamir <eliezert@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Eliezer Tamir authored and David S. Miller committed Feb 28, 2008
1 parent 615f8fd commit 877e9aa
Showing 1 changed file with 150 additions and 79 deletions.
229 changes: 150 additions & 79 deletions drivers/net/bnx2x.c
Original file line number Diff line number Diff line change
Expand Up @@ -4089,8 +4089,8 @@ 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 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
MISC_REG_AEU_MASK_ATTN_FUNC_0;
u32 nig_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
NIG_REG_MASK_INTERRUPT_PORT0;
u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
NIG_REG_MASK_INTERRUPT_PORT0;

if (~bp->aeu_mask & (asserted & 0xff))
BNX2X_ERR("IGU ERROR\n");
Expand All @@ -4108,15 +4108,11 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)

if (asserted & ATTN_HARD_WIRED_MASK) {
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);
REG_WR(bp, nig_mask_addr, 0);
/* save nig interrupt mask */
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);

/* handle unicore attn? */
Expand Down Expand Up @@ -4169,15 +4165,132 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)

/* now set back the mask */
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 index;
int reg_offset;
u32 val;

if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) {

reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);

val = REG_RD(bp, reg_offset);
val &= ~AEU_INPUTS_ATTN_BITS_SPIO5;
REG_WR(bp, reg_offset, val);

BNX2X_ERR("SPIO5 hw attention\n");

switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) {
case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G:
/* Fan failure attention */

/* The PHY reset is controled by GPIO 1 */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW);
/* 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;

default:
break;
}
}
}

static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn)
{
u32 val;

if (attn & BNX2X_DOORQ_ASSERT) {

val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR);
BNX2X_ERR("DB hw attention 0x%x\n", val);
/* DORQ discard attention */
if (val & 0x2)
BNX2X_ERR("FATAL error from DORQ\n");
}
}

static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn)
{
u32 val;

if (attn & AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {

val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR);
BNX2X_ERR("CFC hw attention 0x%x\n", val);
/* CFC error attention */
if (val & 0x2)
BNX2X_ERR("FATAL error from CFC\n");
}

if (attn & AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {

val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0);
BNX2X_ERR("PXP hw attention 0x%x\n", val);
/* RQ_USDMDP_FIFO_OVERFLOW */
if (val & 0x18000)
BNX2X_ERR("FATAL error from PXP\n");
}
}

static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
{
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);
}

if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) {

REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff);
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;

Expand All @@ -4198,80 +4311,38 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
DP(NETIF_MSG_HW, "group[%d]: %llx\n", index,
(unsigned long long)group_mask.sig[0]);

if (attn.sig[3] & group_mask.sig[3] &
EVEREST_GEN_ATTN_IN_USE_MASK) {

if (attn.sig[3] & BNX2X_MC_ASSERT_BITS) {

BNX2X_ERR("MC assert!\n");
bnx2x_panic();

} else if (attn.sig[3] & 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("UNKOWEN HW ASSERT!\n");
}
}

if (attn.sig[1] & group_mask.sig[1] &
BNX2X_DOORQ_ASSERT) {

val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR);
BNX2X_ERR("DB hw attention 0x%x\n", val);
/* DORQ discard attention */
if (val & 0x2)
BNX2X_ERR("FATAL error from DORQ\n");
}

if (attn.sig[2] & group_mask.sig[2] &
AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {

val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR);
BNX2X_ERR("CFC hw attention 0x%x\n", val);
/* CFC error attention */
if (val & 0x2)
BNX2X_ERR("FATAL error from CFC\n");
}

if (attn.sig[2] & group_mask.sig[2] &
AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {

val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0);
BNX2X_ERR("PXP hw attention 0x%x\n", val);
/* RQ_USDMDP_FIFO_OVERFLOW */
if (val & 0x18000)
BNX2X_ERR("FATAL error from PXP\n");
}

if (attn.sig[3] & group_mask.sig[3] &
EVEREST_LATCHED_ATTN_IN_USE_MASK) {

REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL,
0x7ff);
DP(NETIF_MSG_HW, "got latched bits 0x%x\n",
attn.sig[3]);
}
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] &
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))
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] &
HW_PRTY_ASSERT_SET_0) ||
(attn.sig[1] & group_mask.sig[1] &
HW_PRTY_ASSERT_SET_1) ||
(attn.sig[2] & group_mask.sig[2] &
HW_PRTY_ASSERT_SET_2))
BNX2X_ERR("FATAL HW block parity attention\n");
BNX2X_ERR("FATAL HW block parity attention\n");
}
}

Expand Down Expand Up @@ -4336,7 +4407,7 @@ static void bnx2x_sp_task(struct work_struct *work)

/* Return here if interrupt is disabled */
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;
}

Expand All @@ -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);

if (status & 0x1) {
/* HW attentions */
/* HW attentions */
if (status & 0x1)
bnx2x_attn_int(bp);
}

/* CStorm events: query_stats, cfc delete ramrods */
/* CStorm events: query_stats, port delete ramrod */
if (status & 0x2)
bp->stat_pending = 0;

Expand All @@ -4365,6 +4435,7 @@ static void bnx2x_sp_task(struct work_struct *work)
IGU_INT_NOP, 1);
bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx),
IGU_INT_ENABLE, 1);

}

static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
Expand All @@ -4374,11 +4445,11 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)

/* Return here if interrupt is disabled */
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;
}

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
if (unlikely(bp->panic))
Expand Down

0 comments on commit 877e9aa

Please sign in to comment.