Commit ad5afc89 authored by Ariel Elior's avatar Ariel Elior Committed by David S. Miller

bnx2x: Separate VF and PF logic

Generally, the VF driver cannot access the chip, except by the
narrow window its BAR allows. Care had to be taken so the VF driver
will not reach code which accesses the chip elsewhere.
Refactor the nic_load flow into parts so it would be
easier to separate the VF-only logic from the PF-only logic.
Signed-off-by: default avatarAriel Elior <ariele@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4513f925
......@@ -2221,6 +2221,7 @@ int bnx2x_get_vf_id(struct bnx2x *bp, u32 *vf_id);
int bnx2x_send_msg2pf(struct bnx2x *bp, u8 *done, dma_addr_t msg_mapping);
int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count);
int bnx2x_vfpf_release(struct bnx2x *bp);
int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code);
/* Congestion management fairness mode */
#define CMNG_FNS_NONE 0
#define CMNG_FNS_MINMAX 1
......
......@@ -1064,7 +1064,7 @@ void __bnx2x_link_report(struct bnx2x *bp)
struct bnx2x_link_report_data cur_data;
/* reread mf_cfg */
if (!CHIP_IS_E1(bp))
if (IS_PF(bp) && !CHIP_IS_E1(bp))
bnx2x_read_mf_cfg(bp);
/* Read the current link report info */
......@@ -1406,10 +1406,14 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp, int nvecs)
if (nvecs == offset)
return;
free_irq(bp->msix_table[offset].vector, bp->dev);
DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
bp->msix_table[offset].vector);
offset++;
/* VFs don't have a default SB */
if (IS_PF(bp)) {
free_irq(bp->msix_table[offset].vector, bp->dev);
DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
bp->msix_table[offset].vector);
offset++;
}
if (CNIC_SUPPORT(bp)) {
if (nvecs == offset)
......@@ -1430,11 +1434,17 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp, int nvecs)
void bnx2x_free_irq(struct bnx2x *bp)
{
if (bp->flags & USING_MSIX_FLAG &&
!(bp->flags & USING_SINGLE_MSIX_FLAG))
bnx2x_free_msix_irqs(bp, BNX2X_NUM_ETH_QUEUES(bp) +
CNIC_SUPPORT(bp) + 1);
else
!(bp->flags & USING_SINGLE_MSIX_FLAG)) {
int nvecs = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_SUPPORT(bp);
/* vfs don't have a default status block */
if (IS_PF(bp))
nvecs++;
bnx2x_free_msix_irqs(bp, nvecs);
} else {
free_irq(bp->dev->irq, bp->dev);
}
}
int bnx2x_enable_msix(struct bnx2x *bp)
......@@ -1530,12 +1540,15 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
{
int i, rc, offset = 0;
rc = request_irq(bp->msix_table[offset++].vector,
bnx2x_msix_sp_int, 0,
bp->dev->name, bp->dev);
if (rc) {
BNX2X_ERR("request sp irq failed\n");
return -EBUSY;
/* no default status block for vf */
if (IS_PF(bp)) {
rc = request_irq(bp->msix_table[offset++].vector,
bnx2x_msix_sp_int, 0,
bp->dev->name, bp->dev);
if (rc) {
BNX2X_ERR("request sp irq failed\n");
return -EBUSY;
}
}
if (CNIC_SUPPORT(bp))
......@@ -1559,12 +1572,20 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
}
i = BNX2X_NUM_ETH_QUEUES(bp);
offset = 1 + CNIC_SUPPORT(bp);
netdev_info(bp->dev, "using MSI-X IRQs: sp %d fp[%d] %d ... fp[%d] %d\n",
bp->msix_table[0].vector,
0, bp->msix_table[offset].vector,
i - 1, bp->msix_table[offset + i - 1].vector);
if (IS_PF(bp)) {
offset = 1 + CNIC_SUPPORT(bp);
netdev_info(bp->dev,
"using MSI-X IRQs: sp %d fp[%d] %d ... fp[%d] %d\n",
bp->msix_table[0].vector,
0, bp->msix_table[offset].vector,
i - 1, bp->msix_table[offset + i - 1].vector);
} else {
offset = CNIC_SUPPORT(bp);
netdev_info(bp->dev,
"using MSI-X IRQs: fp[%d] %d ... fp[%d] %d\n",
0, bp->msix_table[offset].vector,
i - 1, bp->msix_table[offset + i - 1].vector);
}
return 0;
}
......@@ -1972,27 +1993,204 @@ static void bnx2x_squeeze_objects(struct bnx2x *bp)
} while (0)
#endif /*BNX2X_STOP_ON_ERROR*/
bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err)
static void bnx2x_free_fw_stats_mem(struct bnx2x *bp)
{
BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
bp->fw_stats_data_sz + bp->fw_stats_req_sz);
return;
}
static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
{
/* build FW version dword */
u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
(BCM_5710_FW_MINOR_VERSION << 8) +
(BCM_5710_FW_REVISION_VERSION << 16) +
(BCM_5710_FW_ENGINEERING_VERSION << 24);
int num_groups;
int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1;
/* read loaded FW from chip */
u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
/* number of queues for statistics is number of eth queues + FCoE */
u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats;
DP(NETIF_MSG_IFUP, "loaded fw %x, my fw %x\n", loaded_fw, my_fw);
/* Total number of FW statistics requests =
* 1 for port stats + 1 for PF stats + potential 2 for FCoE (fcoe proper
* and fcoe l2 queue) stats + num of queues (which includes another 1
* for fcoe l2 queue if applicable)
*/
bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats;
if (loaded_fw != my_fw) {
if (is_err)
BNX2X_ERR("bnx2x with FW %x was already loaded, which mismatches my %x FW. aborting\n",
/* Request is built from stats_query_header and an array of
* stats_query_cmd_group each of which contains
* STATS_QUERY_CMD_COUNT rules. The real number or requests is
* configured in the stats_query_header.
*/
num_groups =
(((bp->fw_stats_num) / STATS_QUERY_CMD_COUNT) +
(((bp->fw_stats_num) % STATS_QUERY_CMD_COUNT) ?
1 : 0));
DP(BNX2X_MSG_SP, "stats fw_stats_num %d, num_groups %d\n",
bp->fw_stats_num, num_groups);
bp->fw_stats_req_sz = sizeof(struct stats_query_header) +
num_groups * sizeof(struct stats_query_cmd_group);
/* Data for statistics requests + stats_counter
* stats_counter holds per-STORM counters that are incremented
* when STORM has finished with the current request.
* memory for FCoE offloaded statistics are counted anyway,
* even if they will not be sent.
* VF stats are not accounted for here as the data of VF stats is stored
* in memory allocated by the VF, not here.
*/
bp->fw_stats_data_sz = sizeof(struct per_port_stats) +
sizeof(struct per_pf_stats) +
sizeof(struct fcoe_statistics_params) +
sizeof(struct per_queue_stats) * num_queue_stats +
sizeof(struct stats_counter);
BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping,
bp->fw_stats_data_sz + bp->fw_stats_req_sz);
/* Set shortcuts */
bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
bp->fw_stats_req_mapping = bp->fw_stats_mapping;
bp->fw_stats_data = (struct bnx2x_fw_stats_data *)
((u8 *)bp->fw_stats + bp->fw_stats_req_sz);
bp->fw_stats_data_mapping = bp->fw_stats_mapping +
bp->fw_stats_req_sz;
DP(BNX2X_MSG_SP, "statistics request base address set to %x %x",
U64_HI(bp->fw_stats_req_mapping),
U64_LO(bp->fw_stats_req_mapping));
DP(BNX2X_MSG_SP, "statistics data base address set to %x %x",
U64_HI(bp->fw_stats_data_mapping),
U64_LO(bp->fw_stats_data_mapping));
return 0;
alloc_mem_err:
bnx2x_free_fw_stats_mem(bp);
BNX2X_ERR("Can't allocate FW stats memory\n");
return -ENOMEM;
}
/* send load request to mcp and analyze response */
static int bnx2x_nic_load_request(struct bnx2x *bp, u32 *load_code)
{
/* init fw_seq */
bp->fw_seq =
(SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
DRV_MSG_SEQ_NUMBER_MASK);
BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
/* Get current FW pulse sequence */
bp->fw_drv_pulse_wr_seq =
(SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) &
DRV_PULSE_SEQ_MASK);
BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
/* load request */
(*load_code) = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ,
DRV_MSG_CODE_LOAD_REQ_WITH_LFA);
/* if mcp fails to respond we must abort */
if (!(*load_code)) {
BNX2X_ERR("MCP response failure, aborting\n");
return -EBUSY;
}
/* If mcp refused (e.g. other port is in diagnostic mode) we
* must abort
*/
if ((*load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED) {
BNX2X_ERR("MCP refused load request, aborting\n");
return -EBUSY;
}
return 0;
}
/* check whether another PF has already loaded FW to chip. In
* 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)
{
/* is another pf loaded on this engine? */
if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
/* build my FW version dword */
u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
(BCM_5710_FW_MINOR_VERSION << 8) +
(BCM_5710_FW_REVISION_VERSION << 16) +
(BCM_5710_FW_ENGINEERING_VERSION << 24);
/* read loaded FW from chip */
u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
DP(BNX2X_MSG_SP, "loaded fw %x, my fw %x\n",
loaded_fw, my_fw);
/* 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);
return false;
return -EBUSY;
}
}
return 0;
}
/* returns the "mcp load_code" according to global load_count array */
static int bnx2x_nic_load_no_mcp(struct bnx2x *bp, int port)
{
int path = BP_PATH(bp);
DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d] %d, %d, %d\n",
path, load_count[path][0], load_count[path][1],
load_count[path][2]);
load_count[path][0]++;
load_count[path][1 + port]++;
DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d] %d, %d, %d\n",
path, load_count[path][0], load_count[path][1],
load_count[path][2]);
if (load_count[path][0] == 1)
return FW_MSG_CODE_DRV_LOAD_COMMON;
else if (load_count[path][1 + port] == 1)
return FW_MSG_CODE_DRV_LOAD_PORT;
else
return FW_MSG_CODE_DRV_LOAD_FUNCTION;
}
/* mark PMF if applicable */
static void bnx2x_nic_load_pmf(struct bnx2x *bp, u32 load_code)
{
if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
(load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
(load_code == FW_MSG_CODE_DRV_LOAD_PORT)) {
bp->port.pmf = 1;
/* We need the barrier to ensure the ordering between the
* writing to bp->port.pmf here and reading it from the
* bnx2x_periodic_task().
*/
smp_mb();
} else {
bp->port.pmf = 0;
}
return true;
DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
}
static void bnx2x_nic_load_afex_dcc(struct bnx2x *bp, int load_code)
{
if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
(load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
(bp->common.shmem2_base)) {
if (SHMEM2_HAS(bp, dcc_support))
SHMEM2_WR(bp, dcc_support,
(SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
if (SHMEM2_HAS(bp, afex_driver_support))
SHMEM2_WR(bp, afex_driver_support,
SHMEM_AFEX_SUPPORTED_VERSION_ONE);
}
/* Set AFEX default VLAN tag to an invalid value */
bp->afex_def_vlan_tag = -1;
}
/**
......@@ -2095,10 +2293,12 @@ int bnx2x_load_cnic(struct bnx2x *bp)
mutex_init(&bp->cnic_mutex);
rc = bnx2x_alloc_mem_cnic(bp);
if (rc) {
BNX2X_ERR("Unable to allocate bp memory for cnic\n");
LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
if (IS_PF(bp)) {
rc = bnx2x_alloc_mem_cnic(bp);
if (rc) {
BNX2X_ERR("Unable to allocate bp memory for cnic\n");
LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
}
}
rc = bnx2x_alloc_fp_mem_cnic(bp);
......@@ -2125,14 +2325,17 @@ int bnx2x_load_cnic(struct bnx2x *bp)
bnx2x_nic_init_cnic(bp);
/* Enable Timer scan */
REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1);
for_each_cnic_queue(bp, i) {
rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
if (rc) {
BNX2X_ERR("Queue setup failed\n");
LOAD_ERROR_EXIT(bp, load_error_cnic2);
if (IS_PF(bp)) {
/* Enable Timer scan */
REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1);
/* setup cnic queues */
for_each_cnic_queue(bp, i) {
rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
if (rc) {
BNX2X_ERR("Queue setup failed\n");
LOAD_ERROR_EXIT(bp, load_error_cnic2);
}
}
}
......@@ -2178,8 +2381,7 @@ int bnx2x_load_cnic(struct bnx2x *bp)
int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
{
int port = BP_PORT(bp);
u32 load_code;
int i, rc;
int i, rc = 0, load_code = 0;
DP(NETIF_MSG_IFUP, "Starting NIC load\n");
DP(NETIF_MSG_IFUP,
......@@ -2201,8 +2403,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
&bp->last_reported_link.link_report_flags);
bnx2x_release_phy_lock(bp);
/* must be called before memory allocation and HW init */
bnx2x_ilt_set_info(bp);
if (IS_PF(bp))
/* must be called before memory allocation and HW init */
bnx2x_ilt_set_info(bp);
/*
* Zero fastpath structures preserving invariants like napi, which are
......@@ -2221,8 +2424,26 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
/* Set the receive queues buffer size */
bnx2x_set_rx_buf_size(bp);
if (bnx2x_alloc_mem(bp))
return -ENOMEM;
if (IS_PF(bp)) {
rc = bnx2x_alloc_mem(bp);
if (rc) {
BNX2X_ERR("Unable to allocate bp memory\n");
return rc;
}
}
/* Allocated memory for FW statistics */
if (bnx2x_alloc_fw_stats_mem(bp))
LOAD_ERROR_EXIT(bp, load_error0);
/* need to be done after alloc mem, since it's self adjusting to amount
* of memory available for RSS queues
*/
rc = bnx2x_alloc_fp_mem(bp);
if (rc) {
BNX2X_ERR("Unable to allocate memory for fps\n");
LOAD_ERROR_EXIT(bp, load_error0);
}
/* As long as bnx2x_alloc_mem() may possibly update
* bp->num_queues, bnx2x_set_real_num_queues() should always
......@@ -2245,98 +2466,48 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
DP(NETIF_MSG_IFUP, "napi added\n");
bnx2x_napi_enable(bp);
/* set pf load just before approaching the MCP */
bnx2x_set_pf_load(bp);
/* Send LOAD_REQUEST command to MCP
* Returns the type of LOAD command:
* if it is the first port to be initialized
* common blocks should be initialized, otherwise - not
*/
if (!BP_NOMCP(bp)) {
/* init fw_seq */
bp->fw_seq =
(SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
DRV_MSG_SEQ_NUMBER_MASK);
BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
/* Get current FW pulse sequence */
bp->fw_drv_pulse_wr_seq =
(SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) &
DRV_PULSE_SEQ_MASK);
BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ,
DRV_MSG_CODE_LOAD_REQ_WITH_LFA);
if (!load_code) {
BNX2X_ERR("MCP response failure, aborting\n");
rc = -EBUSY;
LOAD_ERROR_EXIT(bp, load_error1);
}
if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
BNX2X_ERR("Driver load refused\n");
rc = -EBUSY; /* other port in diagnostic mode */
LOAD_ERROR_EXIT(bp, load_error1);
}
if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
/* abort nic load if version mismatch */
if (!bnx2x_test_firmware_version(bp, true)) {
rc = -EBUSY;
if (IS_PF(bp)) {
/* set pf load just before approaching the MCP */
bnx2x_set_pf_load(bp);
/* if mcp exists send load request and analyze response */
if (!BP_NOMCP(bp)) {
/* attempt to load pf */
rc = bnx2x_nic_load_request(bp, &load_code);
if (rc)
LOAD_ERROR_EXIT(bp, load_error1);
/* what did mcp say? */
rc = bnx2x_nic_load_analyze_req(bp, load_code);
if (rc) {
bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
LOAD_ERROR_EXIT(bp, load_error2);
}
} else {
load_code = bnx2x_nic_load_no_mcp(bp, port);
}
} else {
int path = BP_PATH(bp);
DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d] %d, %d, %d\n",
path, load_count[path][0], load_count[path][1],
load_count[path][2]);
load_count[path][0]++;
load_count[path][1 + port]++;
DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d] %d, %d, %d\n",
path, load_count[path][0], load_count[path][1],
load_count[path][2]);
if (load_count[path][0] == 1)
load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
else if (load_count[path][1 + port] == 1)
load_code = FW_MSG_CODE_DRV_LOAD_PORT;
else
load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
}
/* mark pmf if applicable */
bnx2x_nic_load_pmf(bp, load_code);
if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
(load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
(load_code == FW_MSG_CODE_DRV_LOAD_PORT)) {
bp->port.pmf = 1;
/*
* We need the barrier to ensure the ordering between the
* writing to bp->port.pmf here and reading it from the
* bnx2x_periodic_task().
*/
smp_mb();
} else
bp->port.pmf = 0;
DP(NETIF_MSG_IFUP, "pmf %d\n", bp->port.pmf);
/* Init Function state controlling object */
bnx2x__init_func_obj(bp);
/* Init Function state controlling object */
bnx2x__init_func_obj(bp);
/* Initialize HW */
rc = bnx2x_init_hw(bp, load_code);
if (rc) {
BNX2X_ERR("HW init failed, aborting\n");
bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
LOAD_ERROR_EXIT(bp, load_error2);
/* Initialize HW */
rc = bnx2x_init_hw(bp, load_code);
if (rc) {
BNX2X_ERR("HW init failed, aborting\n");
bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
LOAD_ERROR_EXIT(bp, load_error2);
}
}
/* Connect to IRQs */
rc = bnx2x_setup_irqs(bp);
if (rc) {
BNX2X_ERR("IRQs setup failed\n");
bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
BNX2X_ERR("setup irqs failed\n");
if (IS_PF(bp))
bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
LOAD_ERROR_EXIT(bp, load_error2);
}
......@@ -2344,78 +2515,78 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
bnx2x_nic_init(bp, load_code);
/* Init per-function objects */
bnx2x_init_bp_objs(bp);
if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
(load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
(bp->common.shmem2_base)) {
if (SHMEM2_HAS(bp, dcc_support))
SHMEM2_WR(bp, dcc_support,
(SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
if (SHMEM2_HAS(bp, afex_driver_support))
SHMEM2_WR(bp, afex_driver_support,
SHMEM_AFEX_SUPPORTED_VERSION_ONE);
}
if (IS_PF(bp)) {
bnx2x_init_bp_objs(bp);
/* Set AFEX default VLAN tag to an invalid value */
bp->afex_def_vlan_tag = -1;
bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
rc = bnx2x_func_start(bp);
if (rc) {
BNX2X_ERR("Function start failed!\n");
bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
LOAD_ERROR_EXIT(bp, load_error3);
}
/* Set AFEX default VLAN tag to an invalid value */
bp->afex_def_vlan_tag = -1;
bnx2x_nic_load_afex_dcc(bp, load_code);
bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
rc = bnx2x_func_start(bp);
if (rc) {
BNX2X_ERR("Function start failed!\n");
bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
/* Send LOAD_DONE command to MCP */
if (!BP_NOMCP(bp)) {
load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
if (!load_code) {
BNX2X_ERR("MCP response failure, aborting\n");
rc = -EBUSY;
LOAD_ERROR_EXIT(bp, load_error3);
}
}
rc = bnx2x_setup_leading(bp);
if (rc) {
BNX2X_ERR("Setup leading failed!\n");
LOAD_ERROR_EXIT(bp, load_error3);
}
/* Send LOAD_DONE command to MCP */
if (!BP_NOMCP(bp)) {
load_code = bnx2x_fw_command(bp,
DRV_MSG_CODE_LOAD_DONE, 0);
if (!load_code) {
BNX2X_ERR("MCP response failure, aborting\n");
rc = -EBUSY;
LOAD_ERROR_EXIT(bp, load_error3);
}
}
for_each_nondefault_eth_queue(bp, i) {
rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
/* setup the leading queue */
rc = bnx2x_setup_leading(bp);
if (rc) {
BNX2X_ERR("Queue setup failed\n");
BNX2X_ERR("Setup leading failed!\n");
LOAD_ERROR_EXIT(bp, load_error3);
}
}
rc = bnx2x_init_rss_pf(bp);
if (rc) {
BNX2X_ERR("PF RSS init failed\n");
LOAD_ERROR_EXIT(bp, load_error3);
/* set up the rest of the queues */
for_each_nondefault_eth_queue(bp, i) {
rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
if (rc) {
BNX2X_ERR("Queue setup failed\n");
LOAD_ERROR_EXIT(bp, load_error3);
}
}
/* setup rss */
rc = bnx2x_init_rss_pf(bp);
if (rc) {
BNX2X_ERR("PF RSS init failed\n");
LOAD_ERROR_EXIT(bp, load_error3);
}
}
/* Now when Clients are configured we are ready to work */
bp->state = BNX2X_STATE_OPEN;
/* Configure a ucast MAC */
rc = bnx2x_set_eth_mac(bp, true);
if (IS_PF(bp))
rc = bnx2x_set_eth_mac(bp, true);
if (rc) {
BNX2X_ERR("Setting Ethernet MAC failed\n");
LOAD_ERROR_EXIT(bp, load_error3);
}
if (bp->pending_max) {
if (IS_PF(bp) && bp->pending_max) {
bnx2x_update_max_mf_config(bp, bp->pending_max);
bp->pending_max = 0;
}
if (bp->port.pmf)
bnx2x_initial_phy_init(bp, load_mode);
if (bp->port.pmf) {
rc = bnx2x_initial_phy_init(bp, load_mode);
if (rc)
LOAD_ERROR_EXIT(bp, load_error3);
}
bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_BOOT_FROM_SAN;
/* Start fast path */
......@@ -2457,8 +2628,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
if (CNIC_ENABLED(bp))
bnx2x_load_cnic(bp);
/* mark driver is loaded in shmem2 */
if (SHMEM2_HAS(bp, drv_capabilities_flag)) {
if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
/* mark driver is loaded in shmem2 */
u32 val;
val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
......@@ -2467,7 +2638,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
}
/* Wait for all pending SP commands to complete */
if (!bnx2x_wait_sp_comp(bp, ~0x0UL)) {
if (IS_PF(bp) && !bnx2x_wait_sp_comp(bp, ~0x0UL)) {
BNX2X_ERR("Timeout waiting for SP elements to complete\n");
bnx2x_nic_unload(bp, UNLOAD_CLOSE, false);
return -EBUSY;
......@@ -2483,10 +2654,12 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
#ifndef BNX2X_STOP_ON_ERROR
load_error3:
bnx2x_int_disable_sync(bp, 1);
if (IS_PF(bp)) {
bnx2x_int_disable_sync(bp, 1);
/* Clean queueable objects */
bnx2x_squeeze_objects(bp);
/* Clean queueable objects */
bnx2x_squeeze_objects(bp);
}
/* Free SKBs, SGEs, TPA pool and driver internals */
bnx2x_free_skbs(bp);
......@@ -2496,7 +2669,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
/* Release IRQs */
bnx2x_free_irq(bp);
load_error2:
if (!BP_NOMCP(bp)) {
if (IS_PF(bp) && !BP_NOMCP(bp)) {
bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0);
bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
}
......@@ -2504,15 +2677,35 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
bp->port.pmf = 0;
load_error1:
bnx2x_napi_disable(bp);
/* clear pf_load status, as it was already set */
bnx2x_clear_pf_load(bp);
if (IS_PF(bp))
bnx2x_clear_pf_load(bp);
load_error0:
bnx2x_free_fp_mem(bp);
bnx2x_free_fw_stats_mem(bp);
bnx2x_free_mem(bp);
return rc;
#endif /* ! BNX2X_STOP_ON_ERROR */
}
static int bnx2x_drain_tx_queues(struct bnx2x *bp)
{
u8 rc = 0, cos, i;
/* Wait until tx fastpath tasks complete */
for_each_tx_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
for_each_cos_in_tx_queue(fp, cos)
rc = bnx2x_clean_tx_queue(bp, fp->txdata_ptr[cos]);
if (rc)
return rc;
}
return 0;
}
/* must be called with rtnl_lock */
int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
{
......@@ -2522,15 +2715,16 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
DP(NETIF_MSG_IFUP, "Starting NIC unload\n");
/* mark driver is unloaded in shmem2 */
if (SHMEM2_HAS(bp, drv_capabilities_flag)) {
if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
u32 val;
val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
val & ~DRV_FLAGS_CAPABILITIES_LOADED_L2);
}
if ((bp->state == BNX2X_STATE_CLOSED) ||
(bp->state == BNX2X_STATE_ERROR)) {
if (IS_PF(bp) &&
(bp->state == BNX2X_STATE_CLOSED ||
bp->state == BNX2X_STATE_ERROR)) {
/* We can get here if the driver has been unloaded
* during parity error recovery and is either waiting for a
* leader to complete or for other functions to unload and
......@@ -2567,13 +2761,16 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
del_timer_sync(&bp->timer);
/* Set ALWAYS_ALIVE bit in shmem */
bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
bnx2x_drv_pulse(bp);
if (IS_PF(bp)) {
/* Set ALWAYS_ALIVE bit in shmem */
bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
bnx2x_drv_pulse(bp);
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
bnx2x_save_statistics(bp);
}
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
bnx2x_save_statistics(bp);
/* wait till consumers catch up with producers in all queues */
bnx2x_drain_tx_queues(bp);
/* Cleanup the chip if needed */
if (unload_mode != UNLOAD_RECOVERY)
......@@ -2609,7 +2806,8 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
* At this stage no more interrupts will arrive so we may safly clean
* the queueable objects here in case they failed to get cleaned so far.
*/
bnx2x_squeeze_objects(bp);
if (IS_PF(bp))
bnx2x_squeeze_objects(bp);
/* There should be no more pending SP commands at this stage */
bp->sp_state = 0;
......@@ -2623,19 +2821,22 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
for_each_rx_queue(bp, i)
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
if (CNIC_LOADED(bp)) {
bnx2x_free_fp_mem(bp);
if (CNIC_LOADED(bp))
bnx2x_free_fp_mem_cnic(bp);
bnx2x_free_mem_cnic(bp);
}
bnx2x_free_mem(bp);
if (IS_PF(bp)) {
bnx2x_free_mem(bp);
if (CNIC_LOADED(bp))
bnx2x_free_mem_cnic(bp);
}
bp->state = BNX2X_STATE_CLOSED;
bp->cnic_loaded = false;
/* Check if there are pending parity attentions. If there are - set
* RECOVERY_IN_PROGRESS.
*/
if (bnx2x_chk_parity_attn(bp, &global, false)) {
if (IS_PF(bp) && bnx2x_chk_parity_attn(bp, &global, false)) {
bnx2x_set_reset_in_progress(bp);
/* Set RESET_IS_GLOBAL if needed */
......@@ -2647,7 +2848,9 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
/* The last driver must disable a "close the gate" if there is no
* parity attention or "process kill" pending.
*/
if (!bnx2x_clear_pf_load(bp) && bnx2x_reset_is_done(bp, BP_PATH(bp)))
if (IS_PF(bp) &&
!bnx2x_clear_pf_load(bp) &&
bnx2x_reset_is_done(bp, BP_PATH(bp)))
bnx2x_disable_close_the_gate(bp);
DP(NETIF_MSG_IFUP, "Ending NIC unload\n");
......
......@@ -1128,11 +1128,18 @@ static inline u8 bnx2x_fp_qzone_id(struct bnx2x_fastpath *fp)
static inline u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
{
struct bnx2x *bp = fp->bp;
if (!CHIP_IS_E1x(bp))
return USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id);
u32 offset = BAR_USTRORM_INTMEM;
if (IS_VF(bp))
return PXP_VF_ADDR_USDM_QUEUES_START +
bp->acquire_resp.resc.hw_qid[fp->index] *
sizeof(struct ustorm_queue_zone_data);
else if (!CHIP_IS_E1x(bp))
offset += USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id);
else
return USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
offset += USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
return offset;
}
static inline void bnx2x_init_txdata(struct bnx2x *bp,
......
......@@ -890,7 +890,7 @@ static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
if (capable(CAP_NET_ADMIN)) {
/* dump MCP trace */
if (level & BNX2X_MSG_MCP)
if (IS_PF(bp) && (level & BNX2X_MSG_MCP))
bnx2x_fw_dump_lvl(bp, KERN_INFO);
bp->msg_enable = level;
}
......
......@@ -2460,17 +2460,49 @@ void bnx2x__link_status_update(struct bnx2x *bp)
return;
/* read updated dcb configuration */
bnx2x_dcbx_pmf_update(bp);
bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
if (IS_PF(bp)) {
bnx2x_dcbx_pmf_update(bp);
bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
if (bp->link_vars.link_up)
bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
else
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
/* indicate link status */
bnx2x_link_report(bp);
if (bp->link_vars.link_up)
} else { /* VF */
bp->port.supported[0] |= (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_2500baseX_Full |
SUPPORTED_10000baseT_Full |
SUPPORTED_TP |
SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
bp->port.advertising[0] = bp->port.supported[0];
bp->link_params.bp = bp;
bp->link_params.port = BP_PORT(bp);
bp->link_params.req_duplex[0] = DUPLEX_FULL;
bp->link_params.req_flow_ctrl[0] = BNX2X_FLOW_CTRL_NONE;
bp->link_params.req_line_speed[0] = SPEED_10000;
bp->link_params.speed_cap_mask[0] = 0x7f0000;
bp->link_params.switch_cfg = SWITCH_CFG_10G;
bp->link_vars.mac_type = MAC_TYPE_BMAC;
bp->link_vars.line_speed = SPEED_10000;
bp->link_vars.link_status =
(LINK_STATUS_LINK_UP |
LINK_STATUS_SPEED_AND_DUPLEX_10GTFD);
bp->link_vars.link_up = 1;
bp->link_vars.duplex = DUPLEX_FULL;
bp->link_vars.flow_ctrl = BNX2X_FLOW_CTRL_NONE;
__bnx2x_link_report(bp);
bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
else
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
/* indicate link status */
bnx2x_link_report(bp);
}
}
static int bnx2x_afex_func_update(struct bnx2x *bp, u16 vifid,
......@@ -5700,6 +5732,13 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
cids[cos] = fp->txdata_ptr[cos]->cid;
}
/* nothing more for vf to do here */
if (IS_VF(bp))
return;
bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false,
fp->fw_sb_id, fp->igu_sb_id);
bnx2x_update_fpsb_idx(fp);
bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id, cids,
fp->max_cos, BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
bnx2x_sp_mapping(bp, q_rdata), q_type);
......@@ -5709,13 +5748,10 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
*/
bnx2x_init_vlan_mac_fp_objs(fp, BNX2X_OBJ_TYPE_RX_TX);
DP(NETIF_MSG_IFUP, "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d fw_sb %d igu_sb %d\n",
fp_idx, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
fp->igu_sb_id);
bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false,
fp->fw_sb_id, fp->igu_sb_id);
bnx2x_update_fpsb_idx(fp);
DP(NETIF_MSG_IFUP,
"queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d fw_sb %d igu_sb %d\n",
fp_idx, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
fp->igu_sb_id);
}
static void bnx2x_init_tx_ring_one(struct bnx2x_fp_txdata *txdata)
......@@ -5787,17 +5823,22 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
for_each_eth_queue(bp, i)
bnx2x_init_eth_fp(bp, i);
/* ensure status block indices were read */
rmb();
bnx2x_init_rx_rings(bp);
bnx2x_init_tx_rings(bp);
if (IS_VF(bp))
return;
/* 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));
/* ensure status block indices were read */
rmb();
bnx2x_init_def_sb(bp);
bnx2x_update_dsb_idx(bp);
bnx2x_init_rx_rings(bp);
bnx2x_init_tx_rings(bp);
bnx2x_init_sp_ring(bp);
bnx2x_init_eq_ring(bp);
bnx2x_init_internal(bp, load_code);
......@@ -9656,7 +9697,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_test_firmware_version(bp, false);
rc = bnx2x_nic_load_analyze_req(bp, FW_MSG_CODE_DRV_LOAD_FUNCTION);
if (!rc) {
/* fw version is good */
......@@ -11236,50 +11277,51 @@ static int bnx2x_open(struct net_device *dev)
bnx2x_set_power_state(bp, PCI_D0);
other_load_status = bnx2x_get_load_status(bp, other_engine);
load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
/*
* If parity had happen during the unload, then attentions
/* If parity had happen during the unload, then attentions
* and/or RECOVERY_IN_PROGRES may still be set. In this case we
* want the first function loaded on the current engine to
* complete the recovery.
* Parity recovery is only relevant for PF driver.
*/
if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
bnx2x_chk_parity_attn(bp, &global, true))
do {
/*
* If there are attentions and they are in a global
* blocks, set the GLOBAL_RESET bit regardless whether
* it will be this function that will complete the
* recovery or not.
*/
if (global)
bnx2x_set_reset_global(bp);
if (IS_PF(bp)) {
other_load_status = bnx2x_get_load_status(bp, other_engine);
load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
bnx2x_chk_parity_attn(bp, &global, true)) {
do {
/* If there are attentions and they are in a
* global blocks, set the GLOBAL_RESET bit
* regardless whether it will be this function
* that will complete the recovery or not.
*/
if (global)
bnx2x_set_reset_global(bp);
/*
* Only the first function on the current engine should
* try to recover in open. In case of attentions in
* global blocks only the first in the chip should try
* to recover.
*/
if ((!load_status &&
(!global || !other_load_status)) &&
bnx2x_trylock_leader_lock(bp) &&
!bnx2x_leader_reset(bp)) {
netdev_info(bp->dev, "Recovered in open\n");
break;
}
/* Only the first function on the current
* engine should try to recover in open. In case
* of attentions in global blocks only the first
* in the chip should try to recover.
*/
if ((!load_status &&
(!global || !other_load_status)) &&
bnx2x_trylock_leader_lock(bp) &&
!bnx2x_leader_reset(bp)) {
netdev_info(bp->dev,
"Recovered in open\n");
break;
}
/* recovery has failed... */
bnx2x_set_power_state(bp, PCI_D3hot);
bp->recovery_state = BNX2X_RECOVERY_FAILED;
/* recovery has failed... */
bnx2x_set_power_state(bp, PCI_D3hot);
bp->recovery_state = BNX2X_RECOVERY_FAILED;
BNX2X_ERR("Recovery flow hasn't been properly completed yet. Try again later.\n"
"If you still see this message after a few retries then power cycle is required.\n");
BNX2X_ERR("Recovery flow hasn't been properly completed yet. Try again later.\n"
"If you still see this message after a few retries then power cycle is required.\n");
return -EAGAIN;
} while (0);
return -EAGAIN;
} while (0);
}
}
bp->recovery_state = BNX2X_RECOVERY_DONE;
return bnx2x_nic_load(bp, LOAD_OPEN);
......
......@@ -6559,6 +6559,12 @@
#define PXP_VF_ADDR_IGU_END\
((PXP_VF_ADDR_IGU_START) + (PXP_VF_ADDR_IGU_SIZE) - 1)
#define PXP_VF_ADDR_USDM_QUEUES_START 0x3000
#define PXP_VF_ADDR_USDM_QUEUES_SIZE\
(PXP_VF_ADRR_NUM_QUEUES * PXP_ADDR_QUEUE_SIZE)
#define PXP_VF_ADDR_USDM_QUEUES_END\
((PXP_VF_ADDR_USDM_QUEUES_START) + (PXP_VF_ADDR_USDM_QUEUES_SIZE) - 1)
#define PXP_VF_ADDR_CSDM_GLOBAL_START 0x7600
#define PXP_VF_ADDR_CSDM_GLOBAL_SIZE (PXP_ADDR_REG_SIZE)
#define PXP_VF_ADDR_CSDM_GLOBAL_END\
......
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