Commit 39f5b1eb authored by Yuval Mintz's avatar Yuval Mintz Committed by Greg Kroah-Hartman

bnx2x: Revert UNDI flushing mechanism

[ Upstream commit 7c3afd85 ]

Commit 91ebb929 ("bnx2x: Add support for Multi-Function UNDI") [which was
later supposedly fixed by de682941 ("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: default avatarYuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: default avatarAriel Elior <Ariel.Elior@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 29c75569
...@@ -10044,6 +10044,8 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp, ...@@ -10044,6 +10044,8 @@ 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(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_RCQ(val) ((val) & 0xffff)
#define BNX2X_PREV_UNDI_BD(val) ((val) >> 16 & 0xffff) #define BNX2X_PREV_UNDI_BD(val) ((val) >> 16 & 0xffff)
#define BNX2X_PREV_UNDI_PROD(rcq, bd) ((bd) << 16 | (rcq)) #define BNX2X_PREV_UNDI_PROD(rcq, bd) ((bd) << 16 | (rcq))
...@@ -10051,8 +10053,6 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp, ...@@ -10051,8 +10053,6 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
#define BCM_5710_UNDI_FW_MF_MAJOR (0x07) #define BCM_5710_UNDI_FW_MF_MAJOR (0x07)
#define BCM_5710_UNDI_FW_MF_MINOR (0x08) #define BCM_5710_UNDI_FW_MF_MINOR (0x08)
#define BCM_5710_UNDI_FW_MF_VERS (0x05) #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) static bool bnx2x_prev_is_after_undi(struct bnx2x *bp)
{ {
...@@ -10071,72 +10071,25 @@ static bool bnx2x_prev_is_after_undi(struct bnx2x *bp) ...@@ -10071,72 +10071,25 @@ static bool bnx2x_prev_is_after_undi(struct bnx2x *bp)
return false; return false;
} }
static bool bnx2x_prev_unload_undi_fw_supports_mf(struct bnx2x *bp) static void bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 inc)
{
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)
{ {
u16 rcq, bd; 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; rcq = BNX2X_PREV_UNDI_RCQ(tmp_reg) + inc;
bd = BNX2X_PREV_UNDI_BD(tmp_reg) + inc; bd = BNX2X_PREV_UNDI_BD(tmp_reg) + inc;
tmp_reg = BNX2X_PREV_UNDI_PROD(rcq, bd); 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", BNX2X_DEV_INFO("UNDI producer [%d/%d][%08x] rings bd -> 0x%04x, rcq -> 0x%04x\n",
port, bd, rcq); BP_PORT(bp), BP_FUNC(bp), addr, bd, rcq);
} }
static int bnx2x_prev_mcp_done(struct bnx2x *bp) static int bnx2x_prev_mcp_done(struct bnx2x *bp)
...@@ -10375,7 +10328,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) ...@@ -10375,7 +10328,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
/* Reset should be performed after BRB is emptied */ /* Reset should be performed after BRB is emptied */
if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_BRB1) { if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_BRB1) {
u32 timer_count = 1000; u32 timer_count = 1000;
bool need_write = true;
/* Close the MAC Rx to prevent BRB from filling up */ /* Close the MAC Rx to prevent BRB from filling up */
bnx2x_prev_unload_close_mac(bp, &mac_vals); bnx2x_prev_unload_close_mac(bp, &mac_vals);
...@@ -10412,20 +10364,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) ...@@ -10412,20 +10364,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
else else
timer_count--; timer_count--;
/* New UNDI FW supports MF and contains better /* If UNDI resides in memory, manually increment it */
* cleaning methods - might be redundant but harmless. if (prev_undi)
*/ bnx2x_prev_unload_undi_inc(bp, 1);
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);
}
udelay(10); udelay(10);
} }
......
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