Merge branch 'bnx2x'

Yuval Mintz says:

====================
bnx2x: new features patch series

This patch series adds/fixes several new features in the bnx2x driver -
it adds support for loading the bnx2x over an UNDI running on a Multi-function
device, adds missing bits for PCIe AER support and enables VFs to properly
configure multicast filters
(In addition, it also contains some small improvements in driver behaviour).

Please consider applying these patches to `net-next'.

Changes from previous versions
------------------------------
  v2:
     - Fixed comment typo in patch 4 (propogate --> propagate)
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2013-12-26 13:38:26 -05:00
commit f55b0821b9
8 changed files with 172 additions and 35 deletions

View File

@ -1546,6 +1546,7 @@ struct bnx2x {
#define INTERRUPTS_ENABLED_FLAG (1 << 23)
#define BC_SUPPORTS_RMMOD_CMD (1 << 24)
#define HAS_PHYS_PORT_ID (1 << 25)
#define AER_ENABLED (1 << 26)
#define BP_NOMCP(bp) ((bp)->flags & NO_MCP_FLAG)
@ -2436,7 +2437,8 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
#define GOOD_ME_REG(me_reg) (((me_reg) & ME_REG_VF_VALID) && \
(!((me_reg) & ME_REG_VF_ERR)))
int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code);
int bnx2x_compare_fw_ver(struct bnx2x *bp, u32 load_code, bool print_err);
/* Congestion management fairness mode */
#define CMNG_FNS_NONE 0
#define CMNG_FNS_MINMAX 1

View File

@ -2265,7 +2265,7 @@ static int bnx2x_nic_load_request(struct bnx2x *bp, u32 *load_code)
* virtualized environments a pf from another VM may have already
* initialized the device including loading FW
*/
int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code)
int bnx2x_compare_fw_ver(struct bnx2x *bp, u32 load_code, bool print_err)
{
/* is another pf loaded on this engine? */
if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
@ -2284,8 +2284,12 @@ int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code)
/* abort nic load if version mismatch */
if (my_fw != loaded_fw) {
BNX2X_ERR("bnx2x with FW %x was already loaded which mismatches my %x FW. Aborting\n",
loaded_fw, my_fw);
if (print_err)
BNX2X_ERR("bnx2x with FW %x was already loaded which mismatches my %x FW. Aborting\n",
loaded_fw, my_fw);
else
BNX2X_DEV_INFO("bnx2x with FW %x was already loaded which mismatches my %x FW, possibly due to MF UNDI\n",
loaded_fw, my_fw);
return -EBUSY;
}
}
@ -2600,7 +2604,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
LOAD_ERROR_EXIT(bp, load_error1);
/* what did mcp say? */
rc = bnx2x_nic_load_analyze_req(bp, load_code);
rc = bnx2x_compare_fw_ver(bp, load_code, true);
if (rc) {
bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
LOAD_ERROR_EXIT(bp, load_error2);

View File

@ -1639,6 +1639,12 @@ static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf,
memcpy(&val, data_buf, 4);
/* Notice unlike bnx2x_nvram_read_dword() this will not
* change val using be32_to_cpu(), which causes data to flip
* if the eeprom is read and then written back. This is due
* to tools utilizing this functionality that would break
* if this would be resolved.
*/
rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags);
/* advance to the next dword */

View File

@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/aer.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@ -3297,6 +3298,8 @@ static void bnx2x_drv_info_ether_stat(struct bnx2x *bp)
ether_stat->txq_size = bp->tx_ring_size;
ether_stat->rxq_size = bp->rx_ring_size;
ether_stat->vf_cnt = IS_SRIOV(bp) ? bp->vfdb->sriov.nr_virtfn : 0;
}
static void bnx2x_drv_info_fcoe_stat(struct bnx2x *bp)
@ -9854,6 +9857,64 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
#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) (0x1a150c + ((p) << 4))
#define BNX2X_PREV_UNDI_MF_FUNC(f) (0x1a184c + ((f) << 4))
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)
{
u16 rcq, bd;
@ -10054,7 +10115,7 @@ static int bnx2x_prev_unload_uncommon(struct bnx2x *bp)
* the one required, then FLR will be sufficient to clean any residue
* left by previous driver
*/
rc = bnx2x_nic_load_analyze_req(bp, FW_MSG_CODE_DRV_LOAD_FUNCTION);
rc = bnx2x_compare_fw_ver(bp, FW_MSG_CODE_DRV_LOAD_FUNCTION, false);
if (!rc) {
/* fw version is good */
@ -10142,10 +10203,17 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
else
timer_count--;
/* If UNDI resides in memory, manually increment it */
if (prev_undi)
/* New UNDI FW supports MF and contains better
* cleaning methods - might be redundant but harmless.
*/
if (bnx2x_prev_unload_undi_fw_supports_mf(bp)) {
bnx2x_prev_unload_undi_mf(bp);
} else if (prev_undi) {
/* If UNDI resides in memory,
* manually increment it
*/
bnx2x_prev_unload_undi_inc(bp, BP_PORT(bp), 1);
}
udelay(10);
}
@ -10265,8 +10333,8 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
} while (--time_counter);
if (!time_counter || rc) {
BNX2X_ERR("Failed unloading previous driver, aborting\n");
rc = -EBUSY;
BNX2X_DEV_INFO("Unloading previous driver did not occur, Possibly due to MF UNDI\n");
rc = -EPROBE_DEFER;
}
/* Mark function if its port was used to boot from SAN */
@ -11636,7 +11704,11 @@ static int bnx2x_init_bp(struct bnx2x *bp)
DRV_MSG_SEQ_NUMBER_MASK;
BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
bnx2x_prev_unload(bp);
rc = bnx2x_prev_unload(bp);
if (rc) {
bnx2x_free_mem_bp(bp);
return rc;
}
}
if (CHIP_REV_IS_FPGA(bp))
@ -12156,6 +12228,14 @@ static int bnx2x_set_coherency_mask(struct bnx2x *bp)
return 0;
}
static void bnx2x_disable_pcie_error_reporting(struct bnx2x *bp)
{
if (bp->flags & AER_ENABLED) {
pci_disable_pcie_error_reporting(bp->pdev);
bp->flags &= ~AER_ENABLED;
}
}
static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
struct net_device *dev, unsigned long board_type)
{
@ -12262,6 +12342,14 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
/* clean indirect addresses */
pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
PCICFG_VENDOR_ID_OFFSET);
/* AER (Advanced Error reporting) configuration */
rc = pci_enable_pcie_error_reporting(pdev);
if (!rc)
bp->flags |= AER_ENABLED;
else
BNX2X_DEV_INFO("Failed To configure PCIe AER [%d]\n", rc);
/*
* Clean the following indirect addresses for all functions since it
* is not used by the driver.
@ -12869,6 +12957,8 @@ static int bnx2x_init_one(struct pci_dev *pdev,
return 0;
init_one_exit:
bnx2x_disable_pcie_error_reporting(bp);
if (bp->regview)
iounmap(bp->regview);
@ -12942,6 +13032,8 @@ static void __bnx2x_remove(struct pci_dev *pdev,
pci_set_power_state(pdev, PCI_D3hot);
}
bnx2x_disable_pcie_error_reporting(bp);
if (bp->regview)
iounmap(bp->regview);
@ -13119,6 +13211,14 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
rtnl_unlock();
/* If AER, perform cleanup of the PCIe registers */
if (bp->flags & AER_ENABLED) {
if (pci_cleanup_aer_uncorrect_error_status(pdev))
BNX2X_ERR("pci_cleanup_aer_uncorrect_error_status failed\n");
else
DP(NETIF_MSG_HW, "pci_cleanup_aer_uncorrect_error_status succeeded\n");
}
return PCI_ERS_RESULT_RECOVERED;
}

View File

@ -5932,6 +5932,7 @@
#define MISC_REGISTERS_RESET_REG_1_RST_NIG (0x1<<7)
#define MISC_REGISTERS_RESET_REG_1_RST_PXP (0x1<<26)
#define MISC_REGISTERS_RESET_REG_1_RST_PXPV (0x1<<27)
#define MISC_REGISTERS_RESET_REG_1_RST_XSEM (0x1<<22)
#define MISC_REGISTERS_RESET_REG_1_SET 0x584
#define MISC_REGISTERS_RESET_REG_2_CLEAR 0x598
#define MISC_REGISTERS_RESET_REG_2_MSTAT0 (0x1<<24)

View File

@ -166,6 +166,7 @@ enum bnx2x_vfop_qteardown_state {
BNX2X_VFOP_QTEARDOWN_RXMODE,
BNX2X_VFOP_QTEARDOWN_CLR_VLAN,
BNX2X_VFOP_QTEARDOWN_CLR_MAC,
BNX2X_VFOP_QTEARDOWN_CLR_MCAST,
BNX2X_VFOP_QTEARDOWN_QDTOR,
BNX2X_VFOP_QTEARDOWN_DONE
};
@ -1112,7 +1113,10 @@ static void bnx2x_vfop_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf)
switch (state) {
case BNX2X_VFOP_MCAST_DEL:
/* clear existing mcasts */
vfop->state = BNX2X_VFOP_MCAST_ADD;
vfop->state = (args->mc_num) ? BNX2X_VFOP_MCAST_ADD
: BNX2X_VFOP_MCAST_CHK_DONE;
mcast->mcast_list_len = vf->mcast_list_len;
vf->mcast_list_len = args->mc_num;
vfop->rc = bnx2x_config_mcast(bp, mcast, BNX2X_MCAST_CMD_DEL);
bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
@ -1120,17 +1124,17 @@ static void bnx2x_vfop_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf)
if (raw->check_pending(raw))
goto op_pending;
if (args->mc_num) {
/* update mcast list on the ramrod params */
INIT_LIST_HEAD(&mcast->mcast_list);
for (i = 0; i < args->mc_num; i++)
list_add_tail(&(args->mc[i].link),
&mcast->mcast_list);
/* add new mcasts */
vfop->state = BNX2X_VFOP_MCAST_CHK_DONE;
vfop->rc = bnx2x_config_mcast(bp, mcast,
BNX2X_MCAST_CMD_ADD);
}
/* update mcast list on the ramrod params */
INIT_LIST_HEAD(&mcast->mcast_list);
for (i = 0; i < args->mc_num; i++)
list_add_tail(&(args->mc[i].link),
&mcast->mcast_list);
mcast->mcast_list_len = args->mc_num;
/* add new mcasts */
vfop->state = BNX2X_VFOP_MCAST_CHK_DONE;
vfop->rc = bnx2x_config_mcast(bp, mcast,
BNX2X_MCAST_CMD_ADD);
bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
case BNX2X_VFOP_MCAST_CHK_DONE:
@ -1303,12 +1307,19 @@ static void bnx2x_vfop_qdown(struct bnx2x *bp, struct bnx2x_virtf *vf)
case BNX2X_VFOP_QTEARDOWN_CLR_MAC:
/* mac-clear-all: consume credit */
vfop->state = BNX2X_VFOP_QTEARDOWN_QDTOR;
vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_MCAST;
vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, qid, false);
if (vfop->rc)
goto op_err;
return;
case BNX2X_VFOP_QTEARDOWN_CLR_MCAST:
vfop->state = BNX2X_VFOP_QTEARDOWN_QDTOR;
vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL, 0, false);
if (vfop->rc)
goto op_err;
return;
case BNX2X_VFOP_QTEARDOWN_QDTOR:
/* run the queue destruction flow */
DP(BNX2X_MSG_IOV, "case: BNX2X_VFOP_QTEARDOWN_QDTOR\n");
@ -2188,6 +2199,7 @@ int bnx2x_iov_nic_init(struct bnx2x *bp)
* It needs to be initialized here so that it can be safely
* handled by a subsequent FLR flow.
*/
vf->mcast_list_len = 0;
bnx2x_init_mcast_obj(bp, &vf->mcast_obj, 0xFF,
0xFF, 0xFF, 0xFF,
bnx2x_vf_sp(bp, vf, mcast_rdata),
@ -2848,13 +2860,9 @@ static void bnx2x_vfop_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
goto op_err;
return;
}
/* remove multicasts */
vfop->state = BNX2X_VFOP_CLOSE_HW;
vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL, 0, false);
if (vfop->rc)
goto op_err;
return;
vfop->rc = 0;
bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
case BNX2X_VFOP_CLOSE_HW:
@ -2888,6 +2896,9 @@ static void bnx2x_vfop_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
DP(BNX2X_MSG_IOV, "set state to acquired\n");
bnx2x_vfop_end(bp, vf, vfop);
op_pending:
/* Not supported at the moment; Exists for macros only */
return;
}
int bnx2x_vfop_close_cmd(struct bnx2x *bp,

View File

@ -268,6 +268,7 @@ struct bnx2x_virtf {
int leading_rss;
/* MCAST object */
int mcast_list_len;
struct bnx2x_mcast_obj mcast_obj;
/* RSS configuration object */

View File

@ -800,14 +800,18 @@ int bnx2x_vfpf_config_rss(struct bnx2x *bp,
}
if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("failed to send rss message to PF over Vf PF channel %d\n",
resp->hdr.status);
rc = -EINVAL;
/* Since older drivers don't support this feature (and VF has
* no way of knowing other than failing this), don't propagate
* an error in this case.
*/
DP(BNX2X_MSG_IOV,
"Failed to send rss message to PF over VF-PF channel [%d]\n",
resp->hdr.status);
}
out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return 0;
return rc;
}
int bnx2x_vfpf_set_mcast(struct net_device *dev)
@ -1416,6 +1420,14 @@ static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
setup_q->rxq.cache_line_log;
rxq_params->sb_cq_index = setup_q->rxq.sb_index;
/* rx setup - multicast engine */
if (bnx2x_vfq_is_leading(q)) {
u8 mcast_id = FW_VF_HANDLE(vf->abs_vfid);
rxq_params->mcast_engine_id = mcast_id;
__set_bit(BNX2X_Q_FLG_MCAST, &setup_p->flags);
}
bnx2x_vfop_qctor_dump_rx(bp, vf, init_p, setup_p,
q->index, q->sb_idx);
}