Skip to content

Commit

Permalink
bnx2x: Prevent NULL pointer dereference in kdump
Browse files Browse the repository at this point in the history
In scenarios in which a previous driver was removed without proper cleanup
(e.g., kdump), it is possible for the chip to generate an interrupt without
any apparent reason once interrupts are requested.

Due to an erroneous initialization of resources, some of the bnx2x structs
which are required for interrupt handling are initialized only after an
interface's interrupt is requested from the OS.

As a result, once such a spurious interrupt occurs, it will cause a NULL
pointer dereference - the driver will access those structs in its interrupt
handling routine.

This patch change the interrupt request scheme so that bnx2x would only
request interrupts from the kernel after it has finished initializing
all the inner structs required for interrupt handling.

Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Ariel Elior <ariele@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Yuval Mintz authored and David S. Miller committed Apr 25, 2013
1 parent e56db27 commit ecf01c2
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 23 deletions.
11 changes: 7 additions & 4 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,7 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
DP(NETIF_MSG_INTR,
"got an MSI-X interrupt on IDX:SB [fp %d fw_sd %d igusb %d]\n",
fp->index, fp->fw_sb_id, fp->igu_sb_id);

bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0);

#ifdef BNX2X_STOP_ON_ERROR
Expand Down Expand Up @@ -1718,7 +1719,7 @@ static int bnx2x_req_irq(struct bnx2x *bp)
return request_irq(irq, bnx2x_interrupt, flags, bp->dev->name, bp->dev);
}

static int bnx2x_setup_irqs(struct bnx2x *bp)
int bnx2x_setup_irqs(struct bnx2x *bp)
{
int rc = 0;
if (bp->flags & USING_MSIX_FLAG &&
Expand Down Expand Up @@ -2574,6 +2575,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
}
}

bnx2x_pre_irq_nic_init(bp);

/* Connect to IRQs */
rc = bnx2x_setup_irqs(bp);
if (rc) {
Expand All @@ -2583,11 +2586,11 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
LOAD_ERROR_EXIT(bp, load_error2);
}

/* Setup NIC internals and enable interrupts */
bnx2x_nic_init(bp, load_code);

/* Init per-function objects */
if (IS_PF(bp)) {
/* Setup NIC internals and enable interrupts */
bnx2x_post_irq_nic_init(bp, load_code);

bnx2x_init_bp_objs(bp);
bnx2x_iov_nic_init(bp);

Expand Down
19 changes: 16 additions & 3 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,16 +295,29 @@ void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw);
void bnx2x_nic_init_cnic(struct bnx2x *bp);

/**
* bnx2x_nic_init - init driver internals.
* bnx2x_preirq_nic_init - init driver internals.
*
* @bp: driver handle
*
* Initializes:
* - rings
* - fastpath object
* - fastpath rings
* etc.
*/
void bnx2x_pre_irq_nic_init(struct bnx2x *bp);

/**
* bnx2x_postirq_nic_init - init driver internals.
*
* @bp: driver handle
* @load_code: COMMON, PORT or FUNCTION
*
* Initializes:
* - status blocks
* - slowpath rings
* - etc.
*/
void bnx2x_nic_init(struct bnx2x *bp, u32 load_code);
void bnx2x_post_irq_nic_init(struct bnx2x *bp, u32 load_code);
/**
* bnx2x_alloc_mem_cnic - allocate driver's memory for cnic.
*
Expand Down
32 changes: 16 additions & 16 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6018,10 +6018,11 @@ void bnx2x_nic_init_cnic(struct bnx2x *bp)
mmiowb();
}

void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
void bnx2x_pre_irq_nic_init(struct bnx2x *bp)
{
int i;

/* Setup NIC internals and enable interrupts */
for_each_eth_queue(bp, i)
bnx2x_init_eth_fp(bp, i);

Expand All @@ -6030,17 +6031,21 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
bnx2x_init_rx_rings(bp);
bnx2x_init_tx_rings(bp);

if (IS_VF(bp))
return;
if (IS_PF(bp)) {
/* Initialize MOD_ABS interrupts */
bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id,
bp->common.shmem_base,
bp->common.shmem2_base, BP_PORT(bp));

/* Initialize MOD_ABS interrupts */
bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id,
bp->common.shmem_base, bp->common.shmem2_base,
BP_PORT(bp));
/* initialize the default status block and sp ring */
bnx2x_init_def_sb(bp);
bnx2x_update_dsb_idx(bp);
bnx2x_init_sp_ring(bp);
}
}

bnx2x_init_def_sb(bp);
bnx2x_update_dsb_idx(bp);
bnx2x_init_sp_ring(bp);
void bnx2x_post_irq_nic_init(struct bnx2x *bp, u32 load_code)
{
bnx2x_init_eq_ring(bp);
bnx2x_init_internal(bp, load_code);
bnx2x_pf_init(bp);
Expand All @@ -6058,12 +6063,7 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
AEU_INPUTS_ATTN_BITS_SPIO5);
}

/* end of nic init */

/*
* gzip service functions
*/

/* gzip service functions */
static int bnx2x_gunzip_init(struct bnx2x *bp)
{
bp->gunzip_buf = dma_alloc_coherent(&bp->pdev->dev, FW_BUF_SIZE,
Expand Down

0 comments on commit ecf01c2

Please sign in to comment.