Skip to content

Commit

Permalink
qlge: Fix chip reset process.
Browse files Browse the repository at this point in the history
Add wait for NIC fifo and MGMNT fifo to empty before applying reset.
Otherwise broken frames can be processed by management processor and
cause it to hang.

Signed-off-by: Ron Mercer <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Ron Mercer authored and davem330 committed Oct 9, 2009
1 parent 76b2669 commit 84087f4
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 0 deletions.
8 changes: 8 additions & 0 deletions drivers/net/qlge/qlge.h
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,12 @@ enum {
MB_CMD_SET_PORT_CFG = 0x00000122,
MB_CMD_GET_PORT_CFG = 0x00000123,
MB_CMD_GET_LINK_STS = 0x00000124,
MB_CMD_SET_MGMNT_TFK_CTL = 0x00000160, /* Set Mgmnt Traffic Control */
MB_SET_MPI_TFK_STOP = (1 << 0),
MB_SET_MPI_TFK_RESUME = (1 << 1),
MB_CMD_GET_MGMNT_TFK_CTL = 0x00000161, /* Get Mgmnt Traffic Control */
MB_GET_MPI_TFK_STOPPED = (1 << 0),
MB_GET_MPI_TFK_FIFO_EMPTY = (1 << 1),

/* Mailbox Command Status. */
MB_CMD_STS_GOOD = 0x00004000, /* Success. */
Expand Down Expand Up @@ -1606,6 +1612,8 @@ int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
int ql_mb_about_fw(struct ql_adapter *qdev);
void ql_link_on(struct ql_adapter *qdev);
void ql_link_off(struct ql_adapter *qdev);
int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 control);
int ql_wait_fifo_empty(struct ql_adapter *qdev);

#if 1
#define QL_ALL_DUMP
Expand Down
9 changes: 9 additions & 0 deletions drivers/net/qlge/qlge_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3349,6 +3349,13 @@ static int ql_adapter_reset(struct ql_adapter *qdev)

end_jiffies = jiffies +
max((unsigned long)1, usecs_to_jiffies(30));

/* Stop management traffic. */
ql_mb_set_mgmnt_traffic_ctl(qdev, MB_SET_MPI_TFK_STOP);

/* Wait for the NIC and MGMNT FIFOs to empty. */
ql_wait_fifo_empty(qdev);

ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR);

do {
Expand All @@ -3364,6 +3371,8 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
status = -ETIMEDOUT;
}

/* Resume management traffic. */
ql_mb_set_mgmnt_traffic_ctl(qdev, MB_SET_MPI_TFK_RESUME);
return status;
}

Expand Down
89 changes: 89 additions & 0 deletions drivers/net/qlge/qlge_mpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,95 @@ static int ql_idc_wait(struct ql_adapter *qdev)
return status;
}

int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 control)
{
struct mbox_params mbc;
struct mbox_params *mbcp = &mbc;
int status;

memset(mbcp, 0, sizeof(struct mbox_params));

mbcp->in_count = 1;
mbcp->out_count = 2;

mbcp->mbox_in[0] = MB_CMD_SET_MGMNT_TFK_CTL;
mbcp->mbox_in[1] = control;

status = ql_mailbox_command(qdev, mbcp);
if (status)
return status;

if (mbcp->mbox_out[0] == MB_CMD_STS_GOOD)
return status;

if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) {
QPRINTK(qdev, DRV, ERR,
"Command not supported by firmware.\n");
status = -EINVAL;
} else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) {
/* This indicates that the firmware is
* already in the state we are trying to
* change it to.
*/
QPRINTK(qdev, DRV, ERR,
"Command parameters make no change.\n");
}
return status;
}

/* Returns a negative error code or the mailbox command status. */
static int ql_mb_get_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 *control)
{
struct mbox_params mbc;
struct mbox_params *mbcp = &mbc;
int status;

memset(mbcp, 0, sizeof(struct mbox_params));
*control = 0;

mbcp->in_count = 1;
mbcp->out_count = 1;

mbcp->mbox_in[0] = MB_CMD_GET_MGMNT_TFK_CTL;

status = ql_mailbox_command(qdev, mbcp);
if (status)
return status;

if (mbcp->mbox_out[0] == MB_CMD_STS_GOOD) {
*control = mbcp->mbox_in[1];
return status;
}

if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) {
QPRINTK(qdev, DRV, ERR,
"Command not supported by firmware.\n");
status = -EINVAL;
} else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) {
QPRINTK(qdev, DRV, ERR,
"Failed to get MPI traffic control.\n");
status = -EIO;
}
return status;
}

int ql_wait_fifo_empty(struct ql_adapter *qdev)
{
int count = 5;
u32 mgmnt_fifo_empty;
u32 nic_fifo_empty;

do {
nic_fifo_empty = ql_read32(qdev, STS) & STS_NFE;
ql_mb_get_mgmnt_traffic_ctl(qdev, &mgmnt_fifo_empty);
mgmnt_fifo_empty &= MB_GET_MPI_TFK_FIFO_EMPTY;
if (nic_fifo_empty && mgmnt_fifo_empty)
return 0;
msleep(100);
} while (count-- > 0);
return -ETIMEDOUT;
}

/* API called in work thread context to set new TX/RX
* maximum frame size values to match MTU.
*/
Expand Down

0 comments on commit 84087f4

Please sign in to comment.