Skip to content

Commit

Permalink
bnx2x: Revert UNDI flushing mechanism
Browse files Browse the repository at this point in the history
Commit 91ebb92 ("bnx2x: Add support for Multi-Function UNDI") [which was
later supposedly fixed by de68294 ("bnx2x: Fix UNDI driver unload")]
introduced a bug in which in some [yet-to-be-determined] scenarios the
alternative flushing mechanism which was to guarantee the Rx buffers are
empty before resetting them during device probe will fail.
If this happens, when device will be loaded once more a fatal attention will
occur; Since this most likely happens in boot from SAN scenarios, the machine
will fail to load.

Notice this may occur not only in the 'Multi-Function' scenario but in the
regular scenario as well, i.e., this introduced a regression in the driver's
ability to perform boot from SAN.

The patch reverts the mechanism and applies the old scheme to multi-function
devices as well as to single-function devices.

Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: Ariel Elior <Ariel.Elior@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Yuval Mintz authored and David S. Miller committed Aug 22, 2014
1 parent 9a6d33c commit 7c3afd8
Showing 1 changed file with 17 additions and 75 deletions.
92 changes: 17 additions & 75 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -10052,15 +10052,15 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
}

#define BNX2X_PREV_UNDI_PROD_ADDR(p) (BAR_TSTRORM_INTMEM + 0x1508 + ((p) << 4))
#define BNX2X_PREV_UNDI_PROD_ADDR_H(f) (BAR_TSTRORM_INTMEM + \
0x1848 + ((f) << 4))
#define BNX2X_PREV_UNDI_RCQ(val) ((val) & 0xffff)
#define BNX2X_PREV_UNDI_BD(val) ((val) >> 16 & 0xffff)
#define BNX2X_PREV_UNDI_PROD(rcq, bd) ((bd) << 16 | (rcq))

#define BCM_5710_UNDI_FW_MF_MAJOR (0x07)
#define BCM_5710_UNDI_FW_MF_MINOR (0x08)
#define BCM_5710_UNDI_FW_MF_VERS (0x05)
#define BNX2X_PREV_UNDI_MF_PORT(p) (BAR_TSTRORM_INTMEM + 0x150c + ((p) << 4))
#define BNX2X_PREV_UNDI_MF_FUNC(f) (BAR_TSTRORM_INTMEM + 0x184c + ((f) << 4))

static bool bnx2x_prev_is_after_undi(struct bnx2x *bp)
{
Expand All @@ -10079,72 +10079,25 @@ static bool bnx2x_prev_is_after_undi(struct bnx2x *bp)
return false;
}

static bool bnx2x_prev_unload_undi_fw_supports_mf(struct bnx2x *bp)
{
u8 major, minor, version;
u32 fw;

/* Must check that FW is loaded */
if (!(REG_RD(bp, MISC_REG_RESET_REG_1) &
MISC_REGISTERS_RESET_REG_1_RST_XSEM)) {
BNX2X_DEV_INFO("XSEM is reset - UNDI MF FW is not loaded\n");
return false;
}

/* Read Currently loaded FW version */
fw = REG_RD(bp, XSEM_REG_PRAM);
major = fw & 0xff;
minor = (fw >> 0x8) & 0xff;
version = (fw >> 0x10) & 0xff;
BNX2X_DEV_INFO("Loaded FW: 0x%08x: Major 0x%02x Minor 0x%02x Version 0x%02x\n",
fw, major, minor, version);

if (major > BCM_5710_UNDI_FW_MF_MAJOR)
return true;

if ((major == BCM_5710_UNDI_FW_MF_MAJOR) &&
(minor > BCM_5710_UNDI_FW_MF_MINOR))
return true;

if ((major == BCM_5710_UNDI_FW_MF_MAJOR) &&
(minor == BCM_5710_UNDI_FW_MF_MINOR) &&
(version >= BCM_5710_UNDI_FW_MF_VERS))
return true;

return false;
}

static void bnx2x_prev_unload_undi_mf(struct bnx2x *bp)
{
int i;

/* Due to legacy (FW) code, the first function on each engine has a
* different offset macro from the rest of the functions.
* Setting this for all 8 functions is harmless regardless of whether
* this is actually a multi-function device.
*/
for (i = 0; i < 2; i++)
REG_WR(bp, BNX2X_PREV_UNDI_MF_PORT(i), 1);

for (i = 2; i < 8; i++)
REG_WR(bp, BNX2X_PREV_UNDI_MF_FUNC(i - 2), 1);

BNX2X_DEV_INFO("UNDI FW (MF) set to discard\n");
}

static void bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 port, u8 inc)
static void bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 inc)
{
u16 rcq, bd;
u32 tmp_reg = REG_RD(bp, BNX2X_PREV_UNDI_PROD_ADDR(port));
u32 addr, tmp_reg;

if (BP_FUNC(bp) < 2)
addr = BNX2X_PREV_UNDI_PROD_ADDR(BP_PORT(bp));
else
addr = BNX2X_PREV_UNDI_PROD_ADDR_H(BP_FUNC(bp) - 2);

tmp_reg = REG_RD(bp, addr);
rcq = BNX2X_PREV_UNDI_RCQ(tmp_reg) + inc;
bd = BNX2X_PREV_UNDI_BD(tmp_reg) + inc;

tmp_reg = BNX2X_PREV_UNDI_PROD(rcq, bd);
REG_WR(bp, BNX2X_PREV_UNDI_PROD_ADDR(port), tmp_reg);
REG_WR(bp, addr, tmp_reg);

BNX2X_DEV_INFO("UNDI producer [%d] rings bd -> 0x%04x, rcq -> 0x%04x\n",
port, bd, rcq);
BNX2X_DEV_INFO("UNDI producer [%d/%d][%08x] rings bd -> 0x%04x, rcq -> 0x%04x\n",
BP_PORT(bp), BP_FUNC(bp), addr, bd, rcq);
}

static int bnx2x_prev_mcp_done(struct bnx2x *bp)
Expand Down Expand Up @@ -10383,7 +10336,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
/* Reset should be performed after BRB is emptied */
if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_BRB1) {
u32 timer_count = 1000;
bool need_write = true;

/* Close the MAC Rx to prevent BRB from filling up */
bnx2x_prev_unload_close_mac(bp, &mac_vals);
Expand Down Expand Up @@ -10420,20 +10372,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
else
timer_count--;

/* New UNDI FW supports MF and contains better
* cleaning methods - might be redundant but harmless.
*/
if (bnx2x_prev_unload_undi_fw_supports_mf(bp)) {
if (need_write) {
bnx2x_prev_unload_undi_mf(bp);
need_write = false;
}
} else if (prev_undi) {
/* If UNDI resides in memory,
* manually increment it
*/
bnx2x_prev_unload_undi_inc(bp, BP_PORT(bp), 1);
}
/* If UNDI resides in memory, manually increment it */
if (prev_undi)
bnx2x_prev_unload_undi_inc(bp, 1);

udelay(10);
}

Expand Down

0 comments on commit 7c3afd8

Please sign in to comment.