18c2ecf20Sopenharmony_ci/* bnx2x_sriov.c: QLogic Everest network driver.
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * Copyright 2009-2013 Broadcom Corporation
48c2ecf20Sopenharmony_ci * Copyright 2014 QLogic Corporation
58c2ecf20Sopenharmony_ci * All rights reserved
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Unless you and QLogic execute a separate written software license
88c2ecf20Sopenharmony_ci * agreement governing use of this software, this software is licensed to you
98c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License version 2, available
108c2ecf20Sopenharmony_ci * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Notwithstanding the above, under no circumstances may you combine this
138c2ecf20Sopenharmony_ci * software in any way with any other QLogic software provided under a
148c2ecf20Sopenharmony_ci * license other than the GPL, without QLogic's express prior written
158c2ecf20Sopenharmony_ci * consent.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * Maintained by: Ariel Elior <ariel.elior@qlogic.com>
188c2ecf20Sopenharmony_ci * Written by: Shmulik Ravid
198c2ecf20Sopenharmony_ci *	       Ariel Elior <ariel.elior@qlogic.com>
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci#include "bnx2x.h"
238c2ecf20Sopenharmony_ci#include "bnx2x_init.h"
248c2ecf20Sopenharmony_ci#include "bnx2x_cmn.h"
258c2ecf20Sopenharmony_ci#include "bnx2x_sp.h"
268c2ecf20Sopenharmony_ci#include <linux/crc32.h>
278c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic int bnx2x_vf_op_prep(struct bnx2x *bp, int vfidx,
308c2ecf20Sopenharmony_ci			    struct bnx2x_virtf **vf,
318c2ecf20Sopenharmony_ci			    struct pf_vf_bulletin_content **bulletin,
328c2ecf20Sopenharmony_ci			    bool test_queue);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* General service functions */
358c2ecf20Sopenharmony_cistatic void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
368c2ecf20Sopenharmony_ci					 u16 pf_id)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_VF_TO_PF_OFFSET(abs_fid),
398c2ecf20Sopenharmony_ci		pf_id);
408c2ecf20Sopenharmony_ci	REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_VF_TO_PF_OFFSET(abs_fid),
418c2ecf20Sopenharmony_ci		pf_id);
428c2ecf20Sopenharmony_ci	REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_VF_TO_PF_OFFSET(abs_fid),
438c2ecf20Sopenharmony_ci		pf_id);
448c2ecf20Sopenharmony_ci	REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_VF_TO_PF_OFFSET(abs_fid),
458c2ecf20Sopenharmony_ci		pf_id);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic void storm_memset_func_en(struct bnx2x *bp, u16 abs_fid,
498c2ecf20Sopenharmony_ci					u8 enable)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNC_EN_OFFSET(abs_fid),
528c2ecf20Sopenharmony_ci		enable);
538c2ecf20Sopenharmony_ci	REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNC_EN_OFFSET(abs_fid),
548c2ecf20Sopenharmony_ci		enable);
558c2ecf20Sopenharmony_ci	REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNC_EN_OFFSET(abs_fid),
568c2ecf20Sopenharmony_ci		enable);
578c2ecf20Sopenharmony_ci	REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(abs_fid),
588c2ecf20Sopenharmony_ci		enable);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ciint bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	int idx;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	for_each_vf(bp, idx)
668c2ecf20Sopenharmony_ci		if (bnx2x_vf(bp, idx, abs_vfid) == abs_vfid)
678c2ecf20Sopenharmony_ci			break;
688c2ecf20Sopenharmony_ci	return idx;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic
728c2ecf20Sopenharmony_cistruct bnx2x_virtf *bnx2x_vf_by_abs_fid(struct bnx2x *bp, u16 abs_vfid)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	u16 idx =  (u16)bnx2x_vf_idx_by_abs_fid(bp, abs_vfid);
758c2ecf20Sopenharmony_ci	return (idx < BNX2X_NR_VIRTFN(bp)) ? BP_VF(bp, idx) : NULL;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic void bnx2x_vf_igu_ack_sb(struct bnx2x *bp, struct bnx2x_virtf *vf,
798c2ecf20Sopenharmony_ci				u8 igu_sb_id, u8 segment, u16 index, u8 op,
808c2ecf20Sopenharmony_ci				u8 update)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	/* acking a VF sb through the PF - use the GRC */
838c2ecf20Sopenharmony_ci	u32 ctl;
848c2ecf20Sopenharmony_ci	u32 igu_addr_data = IGU_REG_COMMAND_REG_32LSB_DATA;
858c2ecf20Sopenharmony_ci	u32 igu_addr_ctl = IGU_REG_COMMAND_REG_CTRL;
868c2ecf20Sopenharmony_ci	u32 func_encode = vf->abs_vfid;
878c2ecf20Sopenharmony_ci	u32 addr_encode = IGU_CMD_E2_PROD_UPD_BASE + igu_sb_id;
888c2ecf20Sopenharmony_ci	struct igu_regular cmd_data = {0};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	cmd_data.sb_id_and_flags =
918c2ecf20Sopenharmony_ci			((index << IGU_REGULAR_SB_INDEX_SHIFT) |
928c2ecf20Sopenharmony_ci			 (segment << IGU_REGULAR_SEGMENT_ACCESS_SHIFT) |
938c2ecf20Sopenharmony_ci			 (update << IGU_REGULAR_BUPDATE_SHIFT) |
948c2ecf20Sopenharmony_ci			 (op << IGU_REGULAR_ENABLE_INT_SHIFT));
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	ctl = addr_encode << IGU_CTRL_REG_ADDRESS_SHIFT		|
978c2ecf20Sopenharmony_ci	      func_encode << IGU_CTRL_REG_FID_SHIFT		|
988c2ecf20Sopenharmony_ci	      IGU_CTRL_CMD_TYPE_WR << IGU_CTRL_REG_TYPE_SHIFT;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
1018c2ecf20Sopenharmony_ci	   cmd_data.sb_id_and_flags, igu_addr_data);
1028c2ecf20Sopenharmony_ci	REG_WR(bp, igu_addr_data, cmd_data.sb_id_and_flags);
1038c2ecf20Sopenharmony_ci	barrier();
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
1068c2ecf20Sopenharmony_ci	   ctl, igu_addr_ctl);
1078c2ecf20Sopenharmony_ci	REG_WR(bp, igu_addr_ctl, ctl);
1088c2ecf20Sopenharmony_ci	barrier();
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic bool bnx2x_validate_vf_sp_objs(struct bnx2x *bp,
1128c2ecf20Sopenharmony_ci				       struct bnx2x_virtf *vf,
1138c2ecf20Sopenharmony_ci				       bool print_err)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	if (!bnx2x_leading_vfq(vf, sp_initialized)) {
1168c2ecf20Sopenharmony_ci		if (print_err)
1178c2ecf20Sopenharmony_ci			BNX2X_ERR("Slowpath objects not yet initialized!\n");
1188c2ecf20Sopenharmony_ci		else
1198c2ecf20Sopenharmony_ci			DP(BNX2X_MSG_IOV, "Slowpath objects not yet initialized!\n");
1208c2ecf20Sopenharmony_ci		return false;
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci	return true;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci/* VFOP operations states */
1268c2ecf20Sopenharmony_civoid bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
1278c2ecf20Sopenharmony_ci			      struct bnx2x_queue_init_params *init_params,
1288c2ecf20Sopenharmony_ci			      struct bnx2x_queue_setup_params *setup_params,
1298c2ecf20Sopenharmony_ci			      u16 q_idx, u16 sb_idx)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV,
1328c2ecf20Sopenharmony_ci	   "VF[%d] Q_SETUP: txq[%d]-- vfsb=%d, sb-index=%d, hc-rate=%d, flags=0x%lx, traffic-type=%d",
1338c2ecf20Sopenharmony_ci	   vf->abs_vfid,
1348c2ecf20Sopenharmony_ci	   q_idx,
1358c2ecf20Sopenharmony_ci	   sb_idx,
1368c2ecf20Sopenharmony_ci	   init_params->tx.sb_cq_index,
1378c2ecf20Sopenharmony_ci	   init_params->tx.hc_rate,
1388c2ecf20Sopenharmony_ci	   setup_params->flags,
1398c2ecf20Sopenharmony_ci	   setup_params->txq_params.traffic_type);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_civoid bnx2x_vfop_qctor_dump_rx(struct bnx2x *bp, struct bnx2x_virtf *vf,
1438c2ecf20Sopenharmony_ci			    struct bnx2x_queue_init_params *init_params,
1448c2ecf20Sopenharmony_ci			    struct bnx2x_queue_setup_params *setup_params,
1458c2ecf20Sopenharmony_ci			    u16 q_idx, u16 sb_idx)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct bnx2x_rxq_setup_params *rxq_params = &setup_params->rxq_params;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "VF[%d] Q_SETUP: rxq[%d]-- vfsb=%d, sb-index=%d, hc-rate=%d, mtu=%d, buf-size=%d\n"
1508c2ecf20Sopenharmony_ci	   "sge-size=%d, max_sge_pkt=%d, tpa-agg-size=%d, flags=0x%lx, drop-flags=0x%x, cache-log=%d\n",
1518c2ecf20Sopenharmony_ci	   vf->abs_vfid,
1528c2ecf20Sopenharmony_ci	   q_idx,
1538c2ecf20Sopenharmony_ci	   sb_idx,
1548c2ecf20Sopenharmony_ci	   init_params->rx.sb_cq_index,
1558c2ecf20Sopenharmony_ci	   init_params->rx.hc_rate,
1568c2ecf20Sopenharmony_ci	   setup_params->gen_params.mtu,
1578c2ecf20Sopenharmony_ci	   rxq_params->buf_sz,
1588c2ecf20Sopenharmony_ci	   rxq_params->sge_buf_sz,
1598c2ecf20Sopenharmony_ci	   rxq_params->max_sges_pkt,
1608c2ecf20Sopenharmony_ci	   rxq_params->tpa_agg_sz,
1618c2ecf20Sopenharmony_ci	   setup_params->flags,
1628c2ecf20Sopenharmony_ci	   rxq_params->drop_flags,
1638c2ecf20Sopenharmony_ci	   rxq_params->cache_line_log);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_civoid bnx2x_vfop_qctor_prep(struct bnx2x *bp,
1678c2ecf20Sopenharmony_ci			   struct bnx2x_virtf *vf,
1688c2ecf20Sopenharmony_ci			   struct bnx2x_vf_queue *q,
1698c2ecf20Sopenharmony_ci			   struct bnx2x_vf_queue_construct_params *p,
1708c2ecf20Sopenharmony_ci			   unsigned long q_type)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	struct bnx2x_queue_init_params *init_p = &p->qstate.params.init;
1738c2ecf20Sopenharmony_ci	struct bnx2x_queue_setup_params *setup_p = &p->prep_qsetup;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	/* INIT */
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* Enable host coalescing in the transition to INIT state */
1788c2ecf20Sopenharmony_ci	if (test_bit(BNX2X_Q_FLG_HC, &init_p->rx.flags))
1798c2ecf20Sopenharmony_ci		__set_bit(BNX2X_Q_FLG_HC_EN, &init_p->rx.flags);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (test_bit(BNX2X_Q_FLG_HC, &init_p->tx.flags))
1828c2ecf20Sopenharmony_ci		__set_bit(BNX2X_Q_FLG_HC_EN, &init_p->tx.flags);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/* FW SB ID */
1858c2ecf20Sopenharmony_ci	init_p->rx.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
1868c2ecf20Sopenharmony_ci	init_p->tx.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	/* context */
1898c2ecf20Sopenharmony_ci	init_p->cxts[0] = q->cxt;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	/* SETUP */
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* Setup-op general parameters */
1948c2ecf20Sopenharmony_ci	setup_p->gen_params.spcl_id = vf->sp_cl_id;
1958c2ecf20Sopenharmony_ci	setup_p->gen_params.stat_id = vfq_stat_id(vf, q);
1968c2ecf20Sopenharmony_ci	setup_p->gen_params.fp_hsi = vf->fp_hsi;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	/* Setup-op flags:
1998c2ecf20Sopenharmony_ci	 * collect statistics, zero statistics, local-switching, security,
2008c2ecf20Sopenharmony_ci	 * OV for Flex10, RSS and MCAST for leading
2018c2ecf20Sopenharmony_ci	 */
2028c2ecf20Sopenharmony_ci	if (test_bit(BNX2X_Q_FLG_STATS, &setup_p->flags))
2038c2ecf20Sopenharmony_ci		__set_bit(BNX2X_Q_FLG_ZERO_STATS, &setup_p->flags);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/* for VFs, enable tx switching, bd coherency, and mac address
2068c2ecf20Sopenharmony_ci	 * anti-spoofing
2078c2ecf20Sopenharmony_ci	 */
2088c2ecf20Sopenharmony_ci	__set_bit(BNX2X_Q_FLG_TX_SWITCH, &setup_p->flags);
2098c2ecf20Sopenharmony_ci	__set_bit(BNX2X_Q_FLG_TX_SEC, &setup_p->flags);
2108c2ecf20Sopenharmony_ci	if (vf->spoofchk)
2118c2ecf20Sopenharmony_ci		__set_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags);
2128c2ecf20Sopenharmony_ci	else
2138c2ecf20Sopenharmony_ci		__clear_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/* Setup-op rx parameters */
2168c2ecf20Sopenharmony_ci	if (test_bit(BNX2X_Q_TYPE_HAS_RX, &q_type)) {
2178c2ecf20Sopenharmony_ci		struct bnx2x_rxq_setup_params *rxq_p = &setup_p->rxq_params;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		rxq_p->cl_qzone_id = vfq_qzone_id(vf, q);
2208c2ecf20Sopenharmony_ci		rxq_p->fw_sb_id = vf_igu_sb(vf, q->sb_idx);
2218c2ecf20Sopenharmony_ci		rxq_p->rss_engine_id = FW_VF_HANDLE(vf->abs_vfid);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		if (test_bit(BNX2X_Q_FLG_TPA, &setup_p->flags))
2248c2ecf20Sopenharmony_ci			rxq_p->max_tpa_queues = BNX2X_VF_MAX_TPA_AGG_QUEUES;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	/* Setup-op tx parameters */
2288c2ecf20Sopenharmony_ci	if (test_bit(BNX2X_Q_TYPE_HAS_TX, &q_type)) {
2298c2ecf20Sopenharmony_ci		setup_p->txq_params.tss_leading_cl_id = vf->leading_rss;
2308c2ecf20Sopenharmony_ci		setup_p->txq_params.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic int bnx2x_vf_queue_create(struct bnx2x *bp,
2358c2ecf20Sopenharmony_ci				 struct bnx2x_virtf *vf, int qid,
2368c2ecf20Sopenharmony_ci				 struct bnx2x_vf_queue_construct_params *qctor)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct bnx2x_queue_state_params *q_params;
2398c2ecf20Sopenharmony_ci	int rc = 0;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	/* Prepare ramrod information */
2448c2ecf20Sopenharmony_ci	q_params = &qctor->qstate;
2458c2ecf20Sopenharmony_ci	q_params->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
2468c2ecf20Sopenharmony_ci	set_bit(RAMROD_COMP_WAIT, &q_params->ramrod_flags);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
2498c2ecf20Sopenharmony_ci	    BNX2X_Q_LOGICAL_STATE_ACTIVE) {
2508c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "queue was already up. Aborting gracefully\n");
2518c2ecf20Sopenharmony_ci		goto out;
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	/* Run Queue 'construction' ramrods */
2558c2ecf20Sopenharmony_ci	q_params->cmd = BNX2X_Q_CMD_INIT;
2568c2ecf20Sopenharmony_ci	rc = bnx2x_queue_state_change(bp, q_params);
2578c2ecf20Sopenharmony_ci	if (rc)
2588c2ecf20Sopenharmony_ci		goto out;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	memcpy(&q_params->params.setup, &qctor->prep_qsetup,
2618c2ecf20Sopenharmony_ci	       sizeof(struct bnx2x_queue_setup_params));
2628c2ecf20Sopenharmony_ci	q_params->cmd = BNX2X_Q_CMD_SETUP;
2638c2ecf20Sopenharmony_ci	rc = bnx2x_queue_state_change(bp, q_params);
2648c2ecf20Sopenharmony_ci	if (rc)
2658c2ecf20Sopenharmony_ci		goto out;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* enable interrupts */
2688c2ecf20Sopenharmony_ci	bnx2x_vf_igu_ack_sb(bp, vf, vf_igu_sb(vf, bnx2x_vfq(vf, qid, sb_idx)),
2698c2ecf20Sopenharmony_ci			    USTORM_ID, 0, IGU_INT_ENABLE, 0);
2708c2ecf20Sopenharmony_ciout:
2718c2ecf20Sopenharmony_ci	return rc;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic int bnx2x_vf_queue_destroy(struct bnx2x *bp, struct bnx2x_virtf *vf,
2758c2ecf20Sopenharmony_ci				  int qid)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	enum bnx2x_queue_cmd cmds[] = {BNX2X_Q_CMD_HALT,
2788c2ecf20Sopenharmony_ci				       BNX2X_Q_CMD_TERMINATE,
2798c2ecf20Sopenharmony_ci				       BNX2X_Q_CMD_CFC_DEL};
2808c2ecf20Sopenharmony_ci	struct bnx2x_queue_state_params q_params;
2818c2ecf20Sopenharmony_ci	int rc, i;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* Prepare ramrod information */
2868c2ecf20Sopenharmony_ci	memset(&q_params, 0, sizeof(struct bnx2x_queue_state_params));
2878c2ecf20Sopenharmony_ci	q_params.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
2888c2ecf20Sopenharmony_ci	set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if (bnx2x_get_q_logical_state(bp, q_params.q_obj) ==
2918c2ecf20Sopenharmony_ci	    BNX2X_Q_LOGICAL_STATE_STOPPED) {
2928c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "queue was already stopped. Aborting gracefully\n");
2938c2ecf20Sopenharmony_ci		goto out;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* Run Queue 'destruction' ramrods */
2978c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cmds); i++) {
2988c2ecf20Sopenharmony_ci		q_params.cmd = cmds[i];
2998c2ecf20Sopenharmony_ci		rc = bnx2x_queue_state_change(bp, &q_params);
3008c2ecf20Sopenharmony_ci		if (rc) {
3018c2ecf20Sopenharmony_ci			BNX2X_ERR("Failed to run Queue command %d\n", cmds[i]);
3028c2ecf20Sopenharmony_ci			return rc;
3038c2ecf20Sopenharmony_ci		}
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ciout:
3068c2ecf20Sopenharmony_ci	/* Clean Context */
3078c2ecf20Sopenharmony_ci	if (bnx2x_vfq(vf, qid, cxt)) {
3088c2ecf20Sopenharmony_ci		bnx2x_vfq(vf, qid, cxt)->ustorm_ag_context.cdu_usage = 0;
3098c2ecf20Sopenharmony_ci		bnx2x_vfq(vf, qid, cxt)->xstorm_ag_context.cdu_reserved = 0;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	return 0;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic void
3168c2ecf20Sopenharmony_cibnx2x_vf_set_igu_info(struct bnx2x *bp, u8 igu_sb_id, u8 abs_vfid)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
3198c2ecf20Sopenharmony_ci	if (vf) {
3208c2ecf20Sopenharmony_ci		/* the first igu entry belonging to VFs of this PF */
3218c2ecf20Sopenharmony_ci		if (!BP_VFDB(bp)->first_vf_igu_entry)
3228c2ecf20Sopenharmony_ci			BP_VFDB(bp)->first_vf_igu_entry = igu_sb_id;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci		/* the first igu entry belonging to this VF */
3258c2ecf20Sopenharmony_ci		if (!vf_sb_count(vf))
3268c2ecf20Sopenharmony_ci			vf->igu_base_id = igu_sb_id;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci		++vf_sb_count(vf);
3298c2ecf20Sopenharmony_ci		++vf->sb_count;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci	BP_VFDB(bp)->vf_sbs_pool++;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic int bnx2x_vf_vlan_mac_clear(struct bnx2x *bp, struct bnx2x_virtf *vf,
3358c2ecf20Sopenharmony_ci				   int qid, bool drv_only, int type)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	struct bnx2x_vlan_mac_ramrod_params ramrod;
3388c2ecf20Sopenharmony_ci	int rc;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d] - deleting all %s\n", vf->abs_vfid,
3418c2ecf20Sopenharmony_ci			  (type == BNX2X_VF_FILTER_VLAN_MAC) ? "VLAN-MACs" :
3428c2ecf20Sopenharmony_ci			  (type == BNX2X_VF_FILTER_MAC) ? "MACs" : "VLANs");
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	/* Prepare ramrod params */
3458c2ecf20Sopenharmony_ci	memset(&ramrod, 0, sizeof(struct bnx2x_vlan_mac_ramrod_params));
3468c2ecf20Sopenharmony_ci	if (type == BNX2X_VF_FILTER_VLAN_MAC) {
3478c2ecf20Sopenharmony_ci		set_bit(BNX2X_ETH_MAC, &ramrod.user_req.vlan_mac_flags);
3488c2ecf20Sopenharmony_ci		ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_mac_obj);
3498c2ecf20Sopenharmony_ci	} else if (type == BNX2X_VF_FILTER_MAC) {
3508c2ecf20Sopenharmony_ci		set_bit(BNX2X_ETH_MAC, &ramrod.user_req.vlan_mac_flags);
3518c2ecf20Sopenharmony_ci		ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
3528c2ecf20Sopenharmony_ci	} else {
3538c2ecf20Sopenharmony_ci		ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci	ramrod.user_req.cmd = BNX2X_VLAN_MAC_DEL;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	set_bit(RAMROD_EXEC, &ramrod.ramrod_flags);
3588c2ecf20Sopenharmony_ci	if (drv_only)
3598c2ecf20Sopenharmony_ci		set_bit(RAMROD_DRV_CLR_ONLY, &ramrod.ramrod_flags);
3608c2ecf20Sopenharmony_ci	else
3618c2ecf20Sopenharmony_ci		set_bit(RAMROD_COMP_WAIT, &ramrod.ramrod_flags);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* Start deleting */
3648c2ecf20Sopenharmony_ci	rc = ramrod.vlan_mac_obj->delete_all(bp,
3658c2ecf20Sopenharmony_ci					     ramrod.vlan_mac_obj,
3668c2ecf20Sopenharmony_ci					     &ramrod.user_req.vlan_mac_flags,
3678c2ecf20Sopenharmony_ci					     &ramrod.ramrod_flags);
3688c2ecf20Sopenharmony_ci	if (rc) {
3698c2ecf20Sopenharmony_ci		BNX2X_ERR("Failed to delete all %s\n",
3708c2ecf20Sopenharmony_ci			  (type == BNX2X_VF_FILTER_VLAN_MAC) ? "VLAN-MACs" :
3718c2ecf20Sopenharmony_ci			  (type == BNX2X_VF_FILTER_MAC) ? "MACs" : "VLANs");
3728c2ecf20Sopenharmony_ci		return rc;
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return 0;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic int bnx2x_vf_mac_vlan_config(struct bnx2x *bp,
3798c2ecf20Sopenharmony_ci				    struct bnx2x_virtf *vf, int qid,
3808c2ecf20Sopenharmony_ci				    struct bnx2x_vf_mac_vlan_filter *filter,
3818c2ecf20Sopenharmony_ci				    bool drv_only)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	struct bnx2x_vlan_mac_ramrod_params ramrod;
3848c2ecf20Sopenharmony_ci	int rc;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d] - %s a %s filter\n",
3878c2ecf20Sopenharmony_ci	   vf->abs_vfid, filter->add ? "Adding" : "Deleting",
3888c2ecf20Sopenharmony_ci	   (filter->type == BNX2X_VF_FILTER_VLAN_MAC) ? "VLAN-MAC" :
3898c2ecf20Sopenharmony_ci	   (filter->type == BNX2X_VF_FILTER_MAC) ? "MAC" : "VLAN");
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* Prepare ramrod params */
3928c2ecf20Sopenharmony_ci	memset(&ramrod, 0, sizeof(struct bnx2x_vlan_mac_ramrod_params));
3938c2ecf20Sopenharmony_ci	if (filter->type == BNX2X_VF_FILTER_VLAN_MAC) {
3948c2ecf20Sopenharmony_ci		ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_mac_obj);
3958c2ecf20Sopenharmony_ci		ramrod.user_req.u.vlan.vlan = filter->vid;
3968c2ecf20Sopenharmony_ci		memcpy(&ramrod.user_req.u.mac.mac, filter->mac, ETH_ALEN);
3978c2ecf20Sopenharmony_ci		set_bit(BNX2X_ETH_MAC, &ramrod.user_req.vlan_mac_flags);
3988c2ecf20Sopenharmony_ci	} else if (filter->type == BNX2X_VF_FILTER_VLAN) {
3998c2ecf20Sopenharmony_ci		ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
4008c2ecf20Sopenharmony_ci		ramrod.user_req.u.vlan.vlan = filter->vid;
4018c2ecf20Sopenharmony_ci	} else {
4028c2ecf20Sopenharmony_ci		set_bit(BNX2X_ETH_MAC, &ramrod.user_req.vlan_mac_flags);
4038c2ecf20Sopenharmony_ci		ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
4048c2ecf20Sopenharmony_ci		memcpy(&ramrod.user_req.u.mac.mac, filter->mac, ETH_ALEN);
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci	ramrod.user_req.cmd = filter->add ? BNX2X_VLAN_MAC_ADD :
4078c2ecf20Sopenharmony_ci					    BNX2X_VLAN_MAC_DEL;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	set_bit(RAMROD_EXEC, &ramrod.ramrod_flags);
4108c2ecf20Sopenharmony_ci	if (drv_only)
4118c2ecf20Sopenharmony_ci		set_bit(RAMROD_DRV_CLR_ONLY, &ramrod.ramrod_flags);
4128c2ecf20Sopenharmony_ci	else
4138c2ecf20Sopenharmony_ci		set_bit(RAMROD_COMP_WAIT, &ramrod.ramrod_flags);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* Add/Remove the filter */
4168c2ecf20Sopenharmony_ci	rc = bnx2x_config_vlan_mac(bp, &ramrod);
4178c2ecf20Sopenharmony_ci	if (rc == -EEXIST)
4188c2ecf20Sopenharmony_ci		return 0;
4198c2ecf20Sopenharmony_ci	if (rc) {
4208c2ecf20Sopenharmony_ci		BNX2X_ERR("Failed to %s %s\n",
4218c2ecf20Sopenharmony_ci			  filter->add ? "add" : "delete",
4228c2ecf20Sopenharmony_ci			  (filter->type == BNX2X_VF_FILTER_VLAN_MAC) ?
4238c2ecf20Sopenharmony_ci				"VLAN-MAC" :
4248c2ecf20Sopenharmony_ci			  (filter->type == BNX2X_VF_FILTER_MAC) ?
4258c2ecf20Sopenharmony_ci				"MAC" : "VLAN");
4268c2ecf20Sopenharmony_ci		return rc;
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	filter->applied = true;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	return 0;
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ciint bnx2x_vf_mac_vlan_config_list(struct bnx2x *bp, struct bnx2x_virtf *vf,
4358c2ecf20Sopenharmony_ci				  struct bnx2x_vf_mac_vlan_filters *filters,
4368c2ecf20Sopenharmony_ci				  int qid, bool drv_only)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	int rc = 0, i;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	if (!bnx2x_validate_vf_sp_objs(bp, vf, true))
4438c2ecf20Sopenharmony_ci		return -EINVAL;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	/* Prepare ramrod params */
4468c2ecf20Sopenharmony_ci	for (i = 0; i < filters->count; i++) {
4478c2ecf20Sopenharmony_ci		rc = bnx2x_vf_mac_vlan_config(bp, vf, qid,
4488c2ecf20Sopenharmony_ci					      &filters->filters[i], drv_only);
4498c2ecf20Sopenharmony_ci		if (rc)
4508c2ecf20Sopenharmony_ci			break;
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* Rollback if needed */
4548c2ecf20Sopenharmony_ci	if (i != filters->count) {
4558c2ecf20Sopenharmony_ci		BNX2X_ERR("Managed only %d/%d filters - rolling back\n",
4568c2ecf20Sopenharmony_ci			  i, filters->count);
4578c2ecf20Sopenharmony_ci		while (--i >= 0) {
4588c2ecf20Sopenharmony_ci			if (!filters->filters[i].applied)
4598c2ecf20Sopenharmony_ci				continue;
4608c2ecf20Sopenharmony_ci			filters->filters[i].add = !filters->filters[i].add;
4618c2ecf20Sopenharmony_ci			bnx2x_vf_mac_vlan_config(bp, vf, qid,
4628c2ecf20Sopenharmony_ci						 &filters->filters[i],
4638c2ecf20Sopenharmony_ci						 drv_only);
4648c2ecf20Sopenharmony_ci		}
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	/* It's our responsibility to free the filters */
4688c2ecf20Sopenharmony_ci	kfree(filters);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	return rc;
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ciint bnx2x_vf_queue_setup(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid,
4748c2ecf20Sopenharmony_ci			 struct bnx2x_vf_queue_construct_params *qctor)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	int rc;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	rc = bnx2x_vf_queue_create(bp, vf, qid, qctor);
4818c2ecf20Sopenharmony_ci	if (rc)
4828c2ecf20Sopenharmony_ci		goto op_err;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	/* Schedule the configuration of any pending vlan filters */
4858c2ecf20Sopenharmony_ci	bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_HYPERVISOR_VLAN,
4868c2ecf20Sopenharmony_ci			       BNX2X_MSG_IOV);
4878c2ecf20Sopenharmony_ci	return 0;
4888c2ecf20Sopenharmony_ciop_err:
4898c2ecf20Sopenharmony_ci	BNX2X_ERR("QSETUP[%d:%d] error: rc %d\n", vf->abs_vfid, qid, rc);
4908c2ecf20Sopenharmony_ci	return rc;
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic int bnx2x_vf_queue_flr(struct bnx2x *bp, struct bnx2x_virtf *vf,
4948c2ecf20Sopenharmony_ci			       int qid)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	int rc;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	/* If needed, clean the filtering data base */
5018c2ecf20Sopenharmony_ci	if ((qid == LEADING_IDX) &&
5028c2ecf20Sopenharmony_ci	    bnx2x_validate_vf_sp_objs(bp, vf, false)) {
5038c2ecf20Sopenharmony_ci		rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true,
5048c2ecf20Sopenharmony_ci					     BNX2X_VF_FILTER_VLAN_MAC);
5058c2ecf20Sopenharmony_ci		if (rc)
5068c2ecf20Sopenharmony_ci			goto op_err;
5078c2ecf20Sopenharmony_ci		rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true,
5088c2ecf20Sopenharmony_ci					     BNX2X_VF_FILTER_VLAN);
5098c2ecf20Sopenharmony_ci		if (rc)
5108c2ecf20Sopenharmony_ci			goto op_err;
5118c2ecf20Sopenharmony_ci		rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true,
5128c2ecf20Sopenharmony_ci					     BNX2X_VF_FILTER_MAC);
5138c2ecf20Sopenharmony_ci		if (rc)
5148c2ecf20Sopenharmony_ci			goto op_err;
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/* Terminate queue */
5188c2ecf20Sopenharmony_ci	if (bnx2x_vfq(vf, qid, sp_obj).state != BNX2X_Q_STATE_RESET) {
5198c2ecf20Sopenharmony_ci		struct bnx2x_queue_state_params qstate;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci		memset(&qstate, 0, sizeof(struct bnx2x_queue_state_params));
5228c2ecf20Sopenharmony_ci		qstate.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
5238c2ecf20Sopenharmony_ci		qstate.q_obj->state = BNX2X_Q_STATE_STOPPED;
5248c2ecf20Sopenharmony_ci		qstate.cmd = BNX2X_Q_CMD_TERMINATE;
5258c2ecf20Sopenharmony_ci		set_bit(RAMROD_COMP_WAIT, &qstate.ramrod_flags);
5268c2ecf20Sopenharmony_ci		rc = bnx2x_queue_state_change(bp, &qstate);
5278c2ecf20Sopenharmony_ci		if (rc)
5288c2ecf20Sopenharmony_ci			goto op_err;
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	return 0;
5328c2ecf20Sopenharmony_ciop_err:
5338c2ecf20Sopenharmony_ci	BNX2X_ERR("vf[%d:%d] error: rc %d\n", vf->abs_vfid, qid, rc);
5348c2ecf20Sopenharmony_ci	return rc;
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ciint bnx2x_vf_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf,
5388c2ecf20Sopenharmony_ci		   bnx2x_mac_addr_t *mcasts, int mc_num, bool drv_only)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	struct bnx2x_mcast_list_elem *mc = NULL;
5418c2ecf20Sopenharmony_ci	struct bnx2x_mcast_ramrod_params mcast;
5428c2ecf20Sopenharmony_ci	int rc, i;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	/* Prepare Multicast command */
5478c2ecf20Sopenharmony_ci	memset(&mcast, 0, sizeof(struct bnx2x_mcast_ramrod_params));
5488c2ecf20Sopenharmony_ci	mcast.mcast_obj = &vf->mcast_obj;
5498c2ecf20Sopenharmony_ci	if (drv_only)
5508c2ecf20Sopenharmony_ci		set_bit(RAMROD_DRV_CLR_ONLY, &mcast.ramrod_flags);
5518c2ecf20Sopenharmony_ci	else
5528c2ecf20Sopenharmony_ci		set_bit(RAMROD_COMP_WAIT, &mcast.ramrod_flags);
5538c2ecf20Sopenharmony_ci	if (mc_num) {
5548c2ecf20Sopenharmony_ci		mc = kcalloc(mc_num, sizeof(struct bnx2x_mcast_list_elem),
5558c2ecf20Sopenharmony_ci			     GFP_KERNEL);
5568c2ecf20Sopenharmony_ci		if (!mc) {
5578c2ecf20Sopenharmony_ci			BNX2X_ERR("Cannot Configure multicasts due to lack of memory\n");
5588c2ecf20Sopenharmony_ci			return -ENOMEM;
5598c2ecf20Sopenharmony_ci		}
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (mc_num) {
5638c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&mcast.mcast_list);
5648c2ecf20Sopenharmony_ci		for (i = 0; i < mc_num; i++) {
5658c2ecf20Sopenharmony_ci			mc[i].mac = mcasts[i];
5668c2ecf20Sopenharmony_ci			list_add_tail(&mc[i].link,
5678c2ecf20Sopenharmony_ci				      &mcast.mcast_list);
5688c2ecf20Sopenharmony_ci		}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		/* add new mcasts */
5718c2ecf20Sopenharmony_ci		mcast.mcast_list_len = mc_num;
5728c2ecf20Sopenharmony_ci		rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_SET);
5738c2ecf20Sopenharmony_ci		if (rc)
5748c2ecf20Sopenharmony_ci			BNX2X_ERR("Failed to set multicasts\n");
5758c2ecf20Sopenharmony_ci	} else {
5768c2ecf20Sopenharmony_ci		/* clear existing mcasts */
5778c2ecf20Sopenharmony_ci		rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_DEL);
5788c2ecf20Sopenharmony_ci		if (rc)
5798c2ecf20Sopenharmony_ci			BNX2X_ERR("Failed to remove multicasts\n");
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	kfree(mc);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	return rc;
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_cistatic void bnx2x_vf_prep_rx_mode(struct bnx2x *bp, u8 qid,
5888c2ecf20Sopenharmony_ci				  struct bnx2x_rx_mode_ramrod_params *ramrod,
5898c2ecf20Sopenharmony_ci				  struct bnx2x_virtf *vf,
5908c2ecf20Sopenharmony_ci				  unsigned long accept_flags)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	struct bnx2x_vf_queue *vfq = vfq_get(vf, qid);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	memset(ramrod, 0, sizeof(*ramrod));
5958c2ecf20Sopenharmony_ci	ramrod->cid = vfq->cid;
5968c2ecf20Sopenharmony_ci	ramrod->cl_id = vfq_cl_id(vf, vfq);
5978c2ecf20Sopenharmony_ci	ramrod->rx_mode_obj = &bp->rx_mode_obj;
5988c2ecf20Sopenharmony_ci	ramrod->func_id = FW_VF_HANDLE(vf->abs_vfid);
5998c2ecf20Sopenharmony_ci	ramrod->rx_accept_flags = accept_flags;
6008c2ecf20Sopenharmony_ci	ramrod->tx_accept_flags = accept_flags;
6018c2ecf20Sopenharmony_ci	ramrod->pstate = &vf->filter_state;
6028c2ecf20Sopenharmony_ci	ramrod->state = BNX2X_FILTER_RX_MODE_PENDING;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	set_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state);
6058c2ecf20Sopenharmony_ci	set_bit(RAMROD_RX, &ramrod->ramrod_flags);
6068c2ecf20Sopenharmony_ci	set_bit(RAMROD_TX, &ramrod->ramrod_flags);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	ramrod->rdata = bnx2x_vf_sp(bp, vf, rx_mode_rdata.e2);
6098c2ecf20Sopenharmony_ci	ramrod->rdata_mapping = bnx2x_vf_sp_map(bp, vf, rx_mode_rdata.e2);
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ciint bnx2x_vf_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf,
6138c2ecf20Sopenharmony_ci		    int qid, unsigned long accept_flags)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	struct bnx2x_rx_mode_ramrod_params ramrod;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	bnx2x_vf_prep_rx_mode(bp, qid, &ramrod, vf, accept_flags);
6208c2ecf20Sopenharmony_ci	set_bit(RAMROD_COMP_WAIT, &ramrod.ramrod_flags);
6218c2ecf20Sopenharmony_ci	vfq_get(vf, qid)->accept_flags = ramrod.rx_accept_flags;
6228c2ecf20Sopenharmony_ci	return bnx2x_config_rx_mode(bp, &ramrod);
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ciint bnx2x_vf_queue_teardown(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid)
6268c2ecf20Sopenharmony_ci{
6278c2ecf20Sopenharmony_ci	int rc;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	/* Remove all classification configuration for leading queue */
6328c2ecf20Sopenharmony_ci	if (qid == LEADING_IDX) {
6338c2ecf20Sopenharmony_ci		rc = bnx2x_vf_rxmode(bp, vf, qid, 0);
6348c2ecf20Sopenharmony_ci		if (rc)
6358c2ecf20Sopenharmony_ci			goto op_err;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci		/* Remove filtering if feasible */
6388c2ecf20Sopenharmony_ci		if (bnx2x_validate_vf_sp_objs(bp, vf, true)) {
6398c2ecf20Sopenharmony_ci			rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid,
6408c2ecf20Sopenharmony_ci						     false,
6418c2ecf20Sopenharmony_ci						     BNX2X_VF_FILTER_VLAN_MAC);
6428c2ecf20Sopenharmony_ci			if (rc)
6438c2ecf20Sopenharmony_ci				goto op_err;
6448c2ecf20Sopenharmony_ci			rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid,
6458c2ecf20Sopenharmony_ci						     false,
6468c2ecf20Sopenharmony_ci						     BNX2X_VF_FILTER_VLAN);
6478c2ecf20Sopenharmony_ci			if (rc)
6488c2ecf20Sopenharmony_ci				goto op_err;
6498c2ecf20Sopenharmony_ci			rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid,
6508c2ecf20Sopenharmony_ci						     false,
6518c2ecf20Sopenharmony_ci						     BNX2X_VF_FILTER_MAC);
6528c2ecf20Sopenharmony_ci			if (rc)
6538c2ecf20Sopenharmony_ci				goto op_err;
6548c2ecf20Sopenharmony_ci			rc = bnx2x_vf_mcast(bp, vf, NULL, 0, false);
6558c2ecf20Sopenharmony_ci			if (rc)
6568c2ecf20Sopenharmony_ci				goto op_err;
6578c2ecf20Sopenharmony_ci		}
6588c2ecf20Sopenharmony_ci	}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	/* Destroy queue */
6618c2ecf20Sopenharmony_ci	rc = bnx2x_vf_queue_destroy(bp, vf, qid);
6628c2ecf20Sopenharmony_ci	if (rc)
6638c2ecf20Sopenharmony_ci		goto op_err;
6648c2ecf20Sopenharmony_ci	return rc;
6658c2ecf20Sopenharmony_ciop_err:
6668c2ecf20Sopenharmony_ci	BNX2X_ERR("vf[%d:%d] error: rc %d\n",
6678c2ecf20Sopenharmony_ci		  vf->abs_vfid, qid, rc);
6688c2ecf20Sopenharmony_ci	return rc;
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci/* VF enable primitives
6728c2ecf20Sopenharmony_ci * when pretend is required the caller is responsible
6738c2ecf20Sopenharmony_ci * for calling pretend prior to calling these routines
6748c2ecf20Sopenharmony_ci */
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci/* internal vf enable - until vf is enabled internally all transactions
6778c2ecf20Sopenharmony_ci * are blocked. This routine should always be called last with pretend.
6788c2ecf20Sopenharmony_ci */
6798c2ecf20Sopenharmony_cistatic void bnx2x_vf_enable_internal(struct bnx2x *bp, u8 enable)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	REG_WR(bp, PGLUE_B_REG_INTERNAL_VFID_ENABLE, enable ? 1 : 0);
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci/* clears vf error in all semi blocks */
6858c2ecf20Sopenharmony_cistatic void bnx2x_vf_semi_clear_err(struct bnx2x *bp, u8 abs_vfid)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	REG_WR(bp, TSEM_REG_VFPF_ERR_NUM, abs_vfid);
6888c2ecf20Sopenharmony_ci	REG_WR(bp, USEM_REG_VFPF_ERR_NUM, abs_vfid);
6898c2ecf20Sopenharmony_ci	REG_WR(bp, CSEM_REG_VFPF_ERR_NUM, abs_vfid);
6908c2ecf20Sopenharmony_ci	REG_WR(bp, XSEM_REG_VFPF_ERR_NUM, abs_vfid);
6918c2ecf20Sopenharmony_ci}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_cistatic void bnx2x_vf_pglue_clear_err(struct bnx2x *bp, u8 abs_vfid)
6948c2ecf20Sopenharmony_ci{
6958c2ecf20Sopenharmony_ci	u32 was_err_group = (2 * BP_PATH(bp) + abs_vfid) >> 5;
6968c2ecf20Sopenharmony_ci	u32 was_err_reg = 0;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	switch (was_err_group) {
6998c2ecf20Sopenharmony_ci	case 0:
7008c2ecf20Sopenharmony_ci	    was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_31_0_CLR;
7018c2ecf20Sopenharmony_ci	    break;
7028c2ecf20Sopenharmony_ci	case 1:
7038c2ecf20Sopenharmony_ci	    was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_63_32_CLR;
7048c2ecf20Sopenharmony_ci	    break;
7058c2ecf20Sopenharmony_ci	case 2:
7068c2ecf20Sopenharmony_ci	    was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_95_64_CLR;
7078c2ecf20Sopenharmony_ci	    break;
7088c2ecf20Sopenharmony_ci	case 3:
7098c2ecf20Sopenharmony_ci	    was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_127_96_CLR;
7108c2ecf20Sopenharmony_ci	    break;
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci	REG_WR(bp, was_err_reg, 1 << (abs_vfid & 0x1f));
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_cistatic void bnx2x_vf_igu_reset(struct bnx2x *bp, struct bnx2x_virtf *vf)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	int i;
7188c2ecf20Sopenharmony_ci	u32 val;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	/* Set VF masks and configuration - pretend */
7218c2ecf20Sopenharmony_ci	bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_LSB, 0);
7248c2ecf20Sopenharmony_ci	REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_MSB, 0);
7258c2ecf20Sopenharmony_ci	REG_WR(bp, IGU_REG_SB_MASK_LSB, 0);
7268c2ecf20Sopenharmony_ci	REG_WR(bp, IGU_REG_SB_MASK_MSB, 0);
7278c2ecf20Sopenharmony_ci	REG_WR(bp, IGU_REG_PBA_STATUS_LSB, 0);
7288c2ecf20Sopenharmony_ci	REG_WR(bp, IGU_REG_PBA_STATUS_MSB, 0);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	val = REG_RD(bp, IGU_REG_VF_CONFIGURATION);
7318c2ecf20Sopenharmony_ci	val |= (IGU_VF_CONF_FUNC_EN | IGU_VF_CONF_MSI_MSIX_EN);
7328c2ecf20Sopenharmony_ci	val &= ~IGU_VF_CONF_PARENT_MASK;
7338c2ecf20Sopenharmony_ci	val |= (BP_ABS_FUNC(bp) >> 1) << IGU_VF_CONF_PARENT_SHIFT;
7348c2ecf20Sopenharmony_ci	REG_WR(bp, IGU_REG_VF_CONFIGURATION, val);
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV,
7378c2ecf20Sopenharmony_ci	   "value in IGU_REG_VF_CONFIGURATION of vf %d after write is 0x%08x\n",
7388c2ecf20Sopenharmony_ci	   vf->abs_vfid, val);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	/* iterate over all queues, clear sb consumer */
7438c2ecf20Sopenharmony_ci	for (i = 0; i < vf_sb_count(vf); i++) {
7448c2ecf20Sopenharmony_ci		u8 igu_sb_id = vf_igu_sb(vf, i);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci		/* zero prod memory */
7478c2ecf20Sopenharmony_ci		REG_WR(bp, IGU_REG_PROD_CONS_MEMORY + igu_sb_id * 4, 0);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci		/* clear sb state machine */
7508c2ecf20Sopenharmony_ci		bnx2x_igu_clear_sb_gen(bp, vf->abs_vfid, igu_sb_id,
7518c2ecf20Sopenharmony_ci				       false /* VF */);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci		/* disable + update */
7548c2ecf20Sopenharmony_ci		bnx2x_vf_igu_ack_sb(bp, vf, igu_sb_id, USTORM_ID, 0,
7558c2ecf20Sopenharmony_ci				    IGU_INT_DISABLE, 1);
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_civoid bnx2x_vf_enable_access(struct bnx2x *bp, u8 abs_vfid)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	u16 abs_fid;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	abs_fid = FW_VF_HANDLE(abs_vfid);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	/* set the VF-PF association in the FW */
7668c2ecf20Sopenharmony_ci	storm_memset_vf_to_pf(bp, abs_fid, BP_FUNC(bp));
7678c2ecf20Sopenharmony_ci	storm_memset_func_en(bp, abs_fid, 1);
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	/* Invalidate fp_hsi version for vfs */
7708c2ecf20Sopenharmony_ci	if (bp->fw_cap & FW_CAP_INVALIDATE_VF_FP_HSI)
7718c2ecf20Sopenharmony_ci		REG_WR8(bp, BAR_XSTRORM_INTMEM +
7728c2ecf20Sopenharmony_ci			    XSTORM_ETH_FUNCTION_INFO_FP_HSI_VALID_E2_OFFSET(abs_fid), 0);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	/* clear vf errors*/
7758c2ecf20Sopenharmony_ci	bnx2x_vf_semi_clear_err(bp, abs_vfid);
7768c2ecf20Sopenharmony_ci	bnx2x_vf_pglue_clear_err(bp, abs_vfid);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	/* internal vf-enable - pretend */
7798c2ecf20Sopenharmony_ci	bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, abs_vfid));
7808c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "enabling internal access for vf %x\n", abs_vfid);
7818c2ecf20Sopenharmony_ci	bnx2x_vf_enable_internal(bp, true);
7828c2ecf20Sopenharmony_ci	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
7838c2ecf20Sopenharmony_ci}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_cistatic void bnx2x_vf_enable_traffic(struct bnx2x *bp, struct bnx2x_virtf *vf)
7868c2ecf20Sopenharmony_ci{
7878c2ecf20Sopenharmony_ci	/* Reset vf in IGU  interrupts are still disabled */
7888c2ecf20Sopenharmony_ci	bnx2x_vf_igu_reset(bp, vf);
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	/* pretend to enable the vf with the PBF */
7918c2ecf20Sopenharmony_ci	bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
7928c2ecf20Sopenharmony_ci	REG_WR(bp, PBF_REG_DISABLE_VF, 0);
7938c2ecf20Sopenharmony_ci	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic u8 bnx2x_vf_is_pcie_pending(struct bnx2x *bp, u8 abs_vfid)
7978c2ecf20Sopenharmony_ci{
7988c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
7998c2ecf20Sopenharmony_ci	struct pci_dev *dev;
8008c2ecf20Sopenharmony_ci	bool pending;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	if (!vf)
8038c2ecf20Sopenharmony_ci		return false;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	dev = pci_get_domain_bus_and_slot(vf->domain, vf->bus, vf->devfn);
8068c2ecf20Sopenharmony_ci	if (!dev)
8078c2ecf20Sopenharmony_ci		return false;
8088c2ecf20Sopenharmony_ci	pending = bnx2x_is_pcie_pending(dev);
8098c2ecf20Sopenharmony_ci	pci_dev_put(dev);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	return pending;
8128c2ecf20Sopenharmony_ci}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ciint bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	/* Verify no pending pci transactions */
8178c2ecf20Sopenharmony_ci	if (bnx2x_vf_is_pcie_pending(bp, abs_vfid))
8188c2ecf20Sopenharmony_ci		BNX2X_ERR("PCIE Transactions still pending\n");
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	return 0;
8218c2ecf20Sopenharmony_ci}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci/* must be called after the number of PF queues and the number of VFs are
8248c2ecf20Sopenharmony_ci * both known
8258c2ecf20Sopenharmony_ci */
8268c2ecf20Sopenharmony_cistatic void
8278c2ecf20Sopenharmony_cibnx2x_iov_static_resc(struct bnx2x *bp, struct bnx2x_virtf *vf)
8288c2ecf20Sopenharmony_ci{
8298c2ecf20Sopenharmony_ci	struct vf_pf_resc_request *resc = &vf->alloc_resc;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/* will be set only during VF-ACQUIRE */
8328c2ecf20Sopenharmony_ci	resc->num_rxqs = 0;
8338c2ecf20Sopenharmony_ci	resc->num_txqs = 0;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	resc->num_mac_filters = VF_MAC_CREDIT_CNT;
8368c2ecf20Sopenharmony_ci	resc->num_vlan_filters = VF_VLAN_CREDIT_CNT;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	/* no real limitation */
8398c2ecf20Sopenharmony_ci	resc->num_mc_filters = 0;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	/* num_sbs already set */
8428c2ecf20Sopenharmony_ci	resc->num_sbs = vf->sb_count;
8438c2ecf20Sopenharmony_ci}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci/* FLR routines: */
8468c2ecf20Sopenharmony_cistatic void bnx2x_vf_free_resc(struct bnx2x *bp, struct bnx2x_virtf *vf)
8478c2ecf20Sopenharmony_ci{
8488c2ecf20Sopenharmony_ci	/* reset the state variables */
8498c2ecf20Sopenharmony_ci	bnx2x_iov_static_resc(bp, vf);
8508c2ecf20Sopenharmony_ci	vf->state = VF_FREE;
8518c2ecf20Sopenharmony_ci}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cistatic void bnx2x_vf_flr_clnup_hw(struct bnx2x *bp, struct bnx2x_virtf *vf)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	u32 poll_cnt = bnx2x_flr_clnup_poll_count(bp);
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	/* DQ usage counter */
8588c2ecf20Sopenharmony_ci	bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
8598c2ecf20Sopenharmony_ci	bnx2x_flr_clnup_poll_hw_counter(bp, DORQ_REG_VF_USAGE_CNT,
8608c2ecf20Sopenharmony_ci					"DQ VF usage counter timed out",
8618c2ecf20Sopenharmony_ci					poll_cnt);
8628c2ecf20Sopenharmony_ci	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	/* FW cleanup command - poll for the results */
8658c2ecf20Sopenharmony_ci	if (bnx2x_send_final_clnup(bp, (u8)FW_VF_HANDLE(vf->abs_vfid),
8668c2ecf20Sopenharmony_ci				   poll_cnt))
8678c2ecf20Sopenharmony_ci		BNX2X_ERR("VF[%d] Final cleanup timed-out\n", vf->abs_vfid);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	/* verify TX hw is flushed */
8708c2ecf20Sopenharmony_ci	bnx2x_tx_hw_flushed(bp, poll_cnt);
8718c2ecf20Sopenharmony_ci}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_cistatic void bnx2x_vf_flr(struct bnx2x *bp, struct bnx2x_virtf *vf)
8748c2ecf20Sopenharmony_ci{
8758c2ecf20Sopenharmony_ci	int rc, i;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	/* the cleanup operations are valid if and only if the VF
8808c2ecf20Sopenharmony_ci	 * was first acquired.
8818c2ecf20Sopenharmony_ci	 */
8828c2ecf20Sopenharmony_ci	for (i = 0; i < vf_rxq_count(vf); i++) {
8838c2ecf20Sopenharmony_ci		rc = bnx2x_vf_queue_flr(bp, vf, i);
8848c2ecf20Sopenharmony_ci		if (rc)
8858c2ecf20Sopenharmony_ci			goto out;
8868c2ecf20Sopenharmony_ci	}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	/* remove multicasts */
8898c2ecf20Sopenharmony_ci	bnx2x_vf_mcast(bp, vf, NULL, 0, true);
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	/* dispatch final cleanup and wait for HW queues to flush */
8928c2ecf20Sopenharmony_ci	bnx2x_vf_flr_clnup_hw(bp, vf);
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	/* release VF resources */
8958c2ecf20Sopenharmony_ci	bnx2x_vf_free_resc(bp, vf);
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	vf->malicious = false;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	/* re-open the mailbox */
9008c2ecf20Sopenharmony_ci	bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
9018c2ecf20Sopenharmony_ci	return;
9028c2ecf20Sopenharmony_ciout:
9038c2ecf20Sopenharmony_ci	BNX2X_ERR("vf[%d:%d] failed flr: rc %d\n",
9048c2ecf20Sopenharmony_ci		  vf->abs_vfid, i, rc);
9058c2ecf20Sopenharmony_ci}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_cistatic void bnx2x_vf_flr_clnup(struct bnx2x *bp)
9088c2ecf20Sopenharmony_ci{
9098c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf;
9108c2ecf20Sopenharmony_ci	int i;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	for (i = 0; i < BNX2X_NR_VIRTFN(bp); i++) {
9138c2ecf20Sopenharmony_ci		/* VF should be RESET & in FLR cleanup states */
9148c2ecf20Sopenharmony_ci		if (bnx2x_vf(bp, i, state) != VF_RESET ||
9158c2ecf20Sopenharmony_ci		    !bnx2x_vf(bp, i, flr_clnup_stage))
9168c2ecf20Sopenharmony_ci			continue;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "next vf to cleanup: %d. Num of vfs: %d\n",
9198c2ecf20Sopenharmony_ci		   i, BNX2X_NR_VIRTFN(bp));
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci		vf = BP_VF(bp, i);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci		/* lock the vf pf channel */
9248c2ecf20Sopenharmony_ci		bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci		/* invoke the VF FLR SM */
9278c2ecf20Sopenharmony_ci		bnx2x_vf_flr(bp, vf);
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci		/* mark the VF to be ACKED and continue */
9308c2ecf20Sopenharmony_ci		vf->flr_clnup_stage = false;
9318c2ecf20Sopenharmony_ci		bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	/* Acknowledge the handled VFs.
9358c2ecf20Sopenharmony_ci	 * we are acknowledge all the vfs which an flr was requested for, even
9368c2ecf20Sopenharmony_ci	 * if amongst them there are such that we never opened, since the mcp
9378c2ecf20Sopenharmony_ci	 * will interrupt us immediately again if we only ack some of the bits,
9388c2ecf20Sopenharmony_ci	 * resulting in an endless loop. This can happen for example in KVM
9398c2ecf20Sopenharmony_ci	 * where an 'all ones' flr request is sometimes given by hyper visor
9408c2ecf20Sopenharmony_ci	 */
9418c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_MCP, "DRV_STATUS_VF_DISABLED ACK for vfs 0x%x 0x%x\n",
9428c2ecf20Sopenharmony_ci	   bp->vfdb->flrd_vfs[0], bp->vfdb->flrd_vfs[1]);
9438c2ecf20Sopenharmony_ci	for (i = 0; i < FLRD_VFS_DWORDS; i++)
9448c2ecf20Sopenharmony_ci		SHMEM2_WR(bp, drv_ack_vf_disabled[BP_FW_MB_IDX(bp)][i],
9458c2ecf20Sopenharmony_ci			  bp->vfdb->flrd_vfs[i]);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	bnx2x_fw_command(bp, DRV_MSG_CODE_VF_DISABLED_DONE, 0);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	/* clear the acked bits - better yet if the MCP implemented
9508c2ecf20Sopenharmony_ci	 * write to clear semantics
9518c2ecf20Sopenharmony_ci	 */
9528c2ecf20Sopenharmony_ci	for (i = 0; i < FLRD_VFS_DWORDS; i++)
9538c2ecf20Sopenharmony_ci		SHMEM2_WR(bp, drv_ack_vf_disabled[BP_FW_MB_IDX(bp)][i], 0);
9548c2ecf20Sopenharmony_ci}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_civoid bnx2x_vf_handle_flr_event(struct bnx2x *bp)
9578c2ecf20Sopenharmony_ci{
9588c2ecf20Sopenharmony_ci	int i;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	/* Read FLR'd VFs */
9618c2ecf20Sopenharmony_ci	for (i = 0; i < FLRD_VFS_DWORDS; i++)
9628c2ecf20Sopenharmony_ci		bp->vfdb->flrd_vfs[i] = SHMEM2_RD(bp, mcp_vf_disabled[i]);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_MCP,
9658c2ecf20Sopenharmony_ci	   "DRV_STATUS_VF_DISABLED received for vfs 0x%x 0x%x\n",
9668c2ecf20Sopenharmony_ci	   bp->vfdb->flrd_vfs[0], bp->vfdb->flrd_vfs[1]);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	for_each_vf(bp, i) {
9698c2ecf20Sopenharmony_ci		struct bnx2x_virtf *vf = BP_VF(bp, i);
9708c2ecf20Sopenharmony_ci		u32 reset = 0;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci		if (vf->abs_vfid < 32)
9738c2ecf20Sopenharmony_ci			reset = bp->vfdb->flrd_vfs[0] & (1 << vf->abs_vfid);
9748c2ecf20Sopenharmony_ci		else
9758c2ecf20Sopenharmony_ci			reset = bp->vfdb->flrd_vfs[1] &
9768c2ecf20Sopenharmony_ci				(1 << (vf->abs_vfid - 32));
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci		if (reset) {
9798c2ecf20Sopenharmony_ci			/* set as reset and ready for cleanup */
9808c2ecf20Sopenharmony_ci			vf->state = VF_RESET;
9818c2ecf20Sopenharmony_ci			vf->flr_clnup_stage = true;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci			DP(BNX2X_MSG_IOV,
9848c2ecf20Sopenharmony_ci			   "Initiating Final cleanup for VF %d\n",
9858c2ecf20Sopenharmony_ci			   vf->abs_vfid);
9868c2ecf20Sopenharmony_ci		}
9878c2ecf20Sopenharmony_ci	}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	/* do the FLR cleanup for all marked VFs*/
9908c2ecf20Sopenharmony_ci	bnx2x_vf_flr_clnup(bp);
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci/* IOV global initialization routines  */
9948c2ecf20Sopenharmony_civoid bnx2x_iov_init_dq(struct bnx2x *bp)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp))
9978c2ecf20Sopenharmony_ci		return;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	/* Set the DQ such that the CID reflect the abs_vfid */
10008c2ecf20Sopenharmony_ci	REG_WR(bp, DORQ_REG_VF_NORM_VF_BASE, 0);
10018c2ecf20Sopenharmony_ci	REG_WR(bp, DORQ_REG_MAX_RVFID_SIZE, ilog2(BNX2X_MAX_NUM_OF_VFS));
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	/* Set VFs starting CID. If its > 0 the preceding CIDs are belong to
10048c2ecf20Sopenharmony_ci	 * the PF L2 queues
10058c2ecf20Sopenharmony_ci	 */
10068c2ecf20Sopenharmony_ci	REG_WR(bp, DORQ_REG_VF_NORM_CID_BASE, BNX2X_FIRST_VF_CID);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/* The VF window size is the log2 of the max number of CIDs per VF */
10098c2ecf20Sopenharmony_ci	REG_WR(bp, DORQ_REG_VF_NORM_CID_WND_SIZE, BNX2X_VF_CID_WND);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	/* The VF doorbell size  0 - *B, 4 - 128B. We set it here to match
10128c2ecf20Sopenharmony_ci	 * the Pf doorbell size although the 2 are independent.
10138c2ecf20Sopenharmony_ci	 */
10148c2ecf20Sopenharmony_ci	REG_WR(bp, DORQ_REG_VF_NORM_CID_OFST, 3);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	/* No security checks for now -
10178c2ecf20Sopenharmony_ci	 * configure single rule (out of 16) mask = 0x1, value = 0x0,
10188c2ecf20Sopenharmony_ci	 * CID range 0 - 0x1ffff
10198c2ecf20Sopenharmony_ci	 */
10208c2ecf20Sopenharmony_ci	REG_WR(bp, DORQ_REG_VF_TYPE_MASK_0, 1);
10218c2ecf20Sopenharmony_ci	REG_WR(bp, DORQ_REG_VF_TYPE_VALUE_0, 0);
10228c2ecf20Sopenharmony_ci	REG_WR(bp, DORQ_REG_VF_TYPE_MIN_MCID_0, 0);
10238c2ecf20Sopenharmony_ci	REG_WR(bp, DORQ_REG_VF_TYPE_MAX_MCID_0, 0x1ffff);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	/* set the VF doorbell threshold. This threshold represents the amount
10268c2ecf20Sopenharmony_ci	 * of doorbells allowed in the main DORQ fifo for a specific VF.
10278c2ecf20Sopenharmony_ci	 */
10288c2ecf20Sopenharmony_ci	REG_WR(bp, DORQ_REG_VF_USAGE_CT_LIMIT, 64);
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_civoid bnx2x_iov_init_dmae(struct bnx2x *bp)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV))
10348c2ecf20Sopenharmony_ci		REG_WR(bp, DMAE_REG_BACKWARD_COMP_EN, 0);
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic int bnx2x_vf_domain(struct bnx2x *bp, int vfid)
10388c2ecf20Sopenharmony_ci{
10398c2ecf20Sopenharmony_ci	struct pci_dev *dev = bp->pdev;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	return pci_domain_nr(dev->bus);
10428c2ecf20Sopenharmony_ci}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_cistatic int bnx2x_vf_bus(struct bnx2x *bp, int vfid)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	struct pci_dev *dev = bp->pdev;
10478c2ecf20Sopenharmony_ci	struct bnx2x_sriov *iov = &bp->vfdb->sriov;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	return dev->bus->number + ((dev->devfn + iov->offset +
10508c2ecf20Sopenharmony_ci				    iov->stride * vfid) >> 8);
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_cistatic int bnx2x_vf_devfn(struct bnx2x *bp, int vfid)
10548c2ecf20Sopenharmony_ci{
10558c2ecf20Sopenharmony_ci	struct pci_dev *dev = bp->pdev;
10568c2ecf20Sopenharmony_ci	struct bnx2x_sriov *iov = &bp->vfdb->sriov;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	return (dev->devfn + iov->offset + iov->stride * vfid) & 0xff;
10598c2ecf20Sopenharmony_ci}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_cistatic void bnx2x_vf_set_bars(struct bnx2x *bp, struct bnx2x_virtf *vf)
10628c2ecf20Sopenharmony_ci{
10638c2ecf20Sopenharmony_ci	int i, n;
10648c2ecf20Sopenharmony_ci	struct pci_dev *dev = bp->pdev;
10658c2ecf20Sopenharmony_ci	struct bnx2x_sriov *iov = &bp->vfdb->sriov;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	for (i = 0, n = 0; i < PCI_SRIOV_NUM_BARS; i += 2, n++) {
10688c2ecf20Sopenharmony_ci		u64 start = pci_resource_start(dev, PCI_IOV_RESOURCES + i);
10698c2ecf20Sopenharmony_ci		u32 size = pci_resource_len(dev, PCI_IOV_RESOURCES + i);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci		size /= iov->total;
10728c2ecf20Sopenharmony_ci		vf->bars[n].bar = start + size * vf->abs_vfid;
10738c2ecf20Sopenharmony_ci		vf->bars[n].size = size;
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_cistatic int
10788c2ecf20Sopenharmony_cibnx2x_get_vf_igu_cam_info(struct bnx2x *bp)
10798c2ecf20Sopenharmony_ci{
10808c2ecf20Sopenharmony_ci	int sb_id;
10818c2ecf20Sopenharmony_ci	u32 val;
10828c2ecf20Sopenharmony_ci	u8 fid, current_pf = 0;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	/* IGU in normal mode - read CAM */
10858c2ecf20Sopenharmony_ci	for (sb_id = 0; sb_id < IGU_REG_MAPPING_MEMORY_SIZE; sb_id++) {
10868c2ecf20Sopenharmony_ci		val = REG_RD(bp, IGU_REG_MAPPING_MEMORY + sb_id * 4);
10878c2ecf20Sopenharmony_ci		if (!(val & IGU_REG_MAPPING_MEMORY_VALID))
10888c2ecf20Sopenharmony_ci			continue;
10898c2ecf20Sopenharmony_ci		fid = GET_FIELD((val), IGU_REG_MAPPING_MEMORY_FID);
10908c2ecf20Sopenharmony_ci		if (fid & IGU_FID_ENCODE_IS_PF)
10918c2ecf20Sopenharmony_ci			current_pf = fid & IGU_FID_PF_NUM_MASK;
10928c2ecf20Sopenharmony_ci		else if (current_pf == BP_FUNC(bp))
10938c2ecf20Sopenharmony_ci			bnx2x_vf_set_igu_info(bp, sb_id,
10948c2ecf20Sopenharmony_ci					      (fid & IGU_FID_VF_NUM_MASK));
10958c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "%s[%d], igu_sb_id=%d, msix=%d\n",
10968c2ecf20Sopenharmony_ci		   ((fid & IGU_FID_ENCODE_IS_PF) ? "PF" : "VF"),
10978c2ecf20Sopenharmony_ci		   ((fid & IGU_FID_ENCODE_IS_PF) ? (fid & IGU_FID_PF_NUM_MASK) :
10988c2ecf20Sopenharmony_ci		   (fid & IGU_FID_VF_NUM_MASK)), sb_id,
10998c2ecf20Sopenharmony_ci		   GET_FIELD((val), IGU_REG_MAPPING_MEMORY_VECTOR));
11008c2ecf20Sopenharmony_ci	}
11018c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf_sbs_pool is %d\n", BP_VFDB(bp)->vf_sbs_pool);
11028c2ecf20Sopenharmony_ci	return BP_VFDB(bp)->vf_sbs_pool;
11038c2ecf20Sopenharmony_ci}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_cistatic void __bnx2x_iov_free_vfdb(struct bnx2x *bp)
11068c2ecf20Sopenharmony_ci{
11078c2ecf20Sopenharmony_ci	if (bp->vfdb) {
11088c2ecf20Sopenharmony_ci		kfree(bp->vfdb->vfqs);
11098c2ecf20Sopenharmony_ci		kfree(bp->vfdb->vfs);
11108c2ecf20Sopenharmony_ci		kfree(bp->vfdb);
11118c2ecf20Sopenharmony_ci	}
11128c2ecf20Sopenharmony_ci	bp->vfdb = NULL;
11138c2ecf20Sopenharmony_ci}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_cistatic int bnx2x_sriov_pci_cfg_info(struct bnx2x *bp, struct bnx2x_sriov *iov)
11168c2ecf20Sopenharmony_ci{
11178c2ecf20Sopenharmony_ci	int pos;
11188c2ecf20Sopenharmony_ci	struct pci_dev *dev = bp->pdev;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
11218c2ecf20Sopenharmony_ci	if (!pos) {
11228c2ecf20Sopenharmony_ci		BNX2X_ERR("failed to find SRIOV capability in device\n");
11238c2ecf20Sopenharmony_ci		return -ENODEV;
11248c2ecf20Sopenharmony_ci	}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	iov->pos = pos;
11278c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "sriov ext pos %d\n", pos);
11288c2ecf20Sopenharmony_ci	pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &iov->ctrl);
11298c2ecf20Sopenharmony_ci	pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &iov->total);
11308c2ecf20Sopenharmony_ci	pci_read_config_word(dev, pos + PCI_SRIOV_INITIAL_VF, &iov->initial);
11318c2ecf20Sopenharmony_ci	pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &iov->offset);
11328c2ecf20Sopenharmony_ci	pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &iov->stride);
11338c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &iov->pgsz);
11348c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
11358c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	return 0;
11388c2ecf20Sopenharmony_ci}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_cistatic int bnx2x_sriov_info(struct bnx2x *bp, struct bnx2x_sriov *iov)
11418c2ecf20Sopenharmony_ci{
11428c2ecf20Sopenharmony_ci	u32 val;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	/* read the SRIOV capability structure
11458c2ecf20Sopenharmony_ci	 * The fields can be read via configuration read or
11468c2ecf20Sopenharmony_ci	 * directly from the device (starting at offset PCICFG_OFFSET)
11478c2ecf20Sopenharmony_ci	 */
11488c2ecf20Sopenharmony_ci	if (bnx2x_sriov_pci_cfg_info(bp, iov))
11498c2ecf20Sopenharmony_ci		return -ENODEV;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	/* get the number of SRIOV bars */
11528c2ecf20Sopenharmony_ci	iov->nres = 0;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	/* read the first_vfid */
11558c2ecf20Sopenharmony_ci	val = REG_RD(bp, PCICFG_OFFSET + GRC_CONFIG_REG_PF_INIT_VF);
11568c2ecf20Sopenharmony_ci	iov->first_vf_in_pf = ((val & GRC_CR_PF_INIT_VF_PF_FIRST_VF_NUM_MASK)
11578c2ecf20Sopenharmony_ci			       * 8) - (BNX2X_MAX_NUM_OF_VFS * BP_PATH(bp));
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV,
11608c2ecf20Sopenharmony_ci	   "IOV info[%d]: first vf %d, nres %d, cap 0x%x, ctrl 0x%x, total %d, initial %d, num vfs %d, offset %d, stride %d, page size 0x%x\n",
11618c2ecf20Sopenharmony_ci	   BP_FUNC(bp),
11628c2ecf20Sopenharmony_ci	   iov->first_vf_in_pf, iov->nres, iov->cap, iov->ctrl, iov->total,
11638c2ecf20Sopenharmony_ci	   iov->initial, iov->nr_virtfn, iov->offset, iov->stride, iov->pgsz);
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	return 0;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci/* must be called after PF bars are mapped */
11698c2ecf20Sopenharmony_ciint bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
11708c2ecf20Sopenharmony_ci		       int num_vfs_param)
11718c2ecf20Sopenharmony_ci{
11728c2ecf20Sopenharmony_ci	int err, i;
11738c2ecf20Sopenharmony_ci	struct bnx2x_sriov *iov;
11748c2ecf20Sopenharmony_ci	struct pci_dev *dev = bp->pdev;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	bp->vfdb = NULL;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	/* verify is pf */
11798c2ecf20Sopenharmony_ci	if (IS_VF(bp))
11808c2ecf20Sopenharmony_ci		return 0;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	/* verify sriov capability is present in configuration space */
11838c2ecf20Sopenharmony_ci	if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV))
11848c2ecf20Sopenharmony_ci		return 0;
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	/* verify chip revision */
11878c2ecf20Sopenharmony_ci	if (CHIP_IS_E1x(bp))
11888c2ecf20Sopenharmony_ci		return 0;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	/* check if SRIOV support is turned off */
11918c2ecf20Sopenharmony_ci	if (!num_vfs_param)
11928c2ecf20Sopenharmony_ci		return 0;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	/* SRIOV assumes that num of PF CIDs < BNX2X_FIRST_VF_CID */
11958c2ecf20Sopenharmony_ci	if (BNX2X_L2_MAX_CID(bp) >= BNX2X_FIRST_VF_CID) {
11968c2ecf20Sopenharmony_ci		BNX2X_ERR("PF cids %d are overspilling into vf space (starts at %d). Abort SRIOV\n",
11978c2ecf20Sopenharmony_ci			  BNX2X_L2_MAX_CID(bp), BNX2X_FIRST_VF_CID);
11988c2ecf20Sopenharmony_ci		return 0;
11998c2ecf20Sopenharmony_ci	}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	/* SRIOV can be enabled only with MSIX */
12028c2ecf20Sopenharmony_ci	if (int_mode_param == BNX2X_INT_MODE_MSI ||
12038c2ecf20Sopenharmony_ci	    int_mode_param == BNX2X_INT_MODE_INTX) {
12048c2ecf20Sopenharmony_ci		BNX2X_ERR("Forced MSI/INTx mode is incompatible with SRIOV\n");
12058c2ecf20Sopenharmony_ci		return 0;
12068c2ecf20Sopenharmony_ci	}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	err = -EIO;
12098c2ecf20Sopenharmony_ci	/* verify ari is enabled */
12108c2ecf20Sopenharmony_ci	if (!pci_ari_enabled(bp->pdev->bus)) {
12118c2ecf20Sopenharmony_ci		BNX2X_ERR("ARI not supported (check pci bridge ARI forwarding), SRIOV can not be enabled\n");
12128c2ecf20Sopenharmony_ci		return 0;
12138c2ecf20Sopenharmony_ci	}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	/* verify igu is in normal mode */
12168c2ecf20Sopenharmony_ci	if (CHIP_INT_MODE_IS_BC(bp)) {
12178c2ecf20Sopenharmony_ci		BNX2X_ERR("IGU not normal mode,  SRIOV can not be enabled\n");
12188c2ecf20Sopenharmony_ci		return 0;
12198c2ecf20Sopenharmony_ci	}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	/* allocate the vfs database */
12228c2ecf20Sopenharmony_ci	bp->vfdb = kzalloc(sizeof(*(bp->vfdb)), GFP_KERNEL);
12238c2ecf20Sopenharmony_ci	if (!bp->vfdb) {
12248c2ecf20Sopenharmony_ci		BNX2X_ERR("failed to allocate vf database\n");
12258c2ecf20Sopenharmony_ci		err = -ENOMEM;
12268c2ecf20Sopenharmony_ci		goto failed;
12278c2ecf20Sopenharmony_ci	}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	/* get the sriov info - Linux already collected all the pertinent
12308c2ecf20Sopenharmony_ci	 * information, however the sriov structure is for the private use
12318c2ecf20Sopenharmony_ci	 * of the pci module. Also we want this information regardless
12328c2ecf20Sopenharmony_ci	 * of the hyper-visor.
12338c2ecf20Sopenharmony_ci	 */
12348c2ecf20Sopenharmony_ci	iov = &(bp->vfdb->sriov);
12358c2ecf20Sopenharmony_ci	err = bnx2x_sriov_info(bp, iov);
12368c2ecf20Sopenharmony_ci	if (err)
12378c2ecf20Sopenharmony_ci		goto failed;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	/* SR-IOV capability was enabled but there are no VFs*/
12408c2ecf20Sopenharmony_ci	if (iov->total == 0) {
12418c2ecf20Sopenharmony_ci		err = 0;
12428c2ecf20Sopenharmony_ci		goto failed;
12438c2ecf20Sopenharmony_ci	}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	iov->nr_virtfn = min_t(u16, iov->total, num_vfs_param);
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "num_vfs_param was %d, nr_virtfn was %d\n",
12488c2ecf20Sopenharmony_ci	   num_vfs_param, iov->nr_virtfn);
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	/* allocate the vf array */
12518c2ecf20Sopenharmony_ci	bp->vfdb->vfs = kcalloc(BNX2X_NR_VIRTFN(bp),
12528c2ecf20Sopenharmony_ci				sizeof(struct bnx2x_virtf),
12538c2ecf20Sopenharmony_ci				GFP_KERNEL);
12548c2ecf20Sopenharmony_ci	if (!bp->vfdb->vfs) {
12558c2ecf20Sopenharmony_ci		BNX2X_ERR("failed to allocate vf array\n");
12568c2ecf20Sopenharmony_ci		err = -ENOMEM;
12578c2ecf20Sopenharmony_ci		goto failed;
12588c2ecf20Sopenharmony_ci	}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	/* Initial VF init - index and abs_vfid - nr_virtfn must be set */
12618c2ecf20Sopenharmony_ci	for_each_vf(bp, i) {
12628c2ecf20Sopenharmony_ci		bnx2x_vf(bp, i, index) = i;
12638c2ecf20Sopenharmony_ci		bnx2x_vf(bp, i, abs_vfid) = iov->first_vf_in_pf + i;
12648c2ecf20Sopenharmony_ci		bnx2x_vf(bp, i, state) = VF_FREE;
12658c2ecf20Sopenharmony_ci		mutex_init(&bnx2x_vf(bp, i, op_mutex));
12668c2ecf20Sopenharmony_ci		bnx2x_vf(bp, i, op_current) = CHANNEL_TLV_NONE;
12678c2ecf20Sopenharmony_ci		/* enable spoofchk by default */
12688c2ecf20Sopenharmony_ci		bnx2x_vf(bp, i, spoofchk) = 1;
12698c2ecf20Sopenharmony_ci	}
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	/* re-read the IGU CAM for VFs - index and abs_vfid must be set */
12728c2ecf20Sopenharmony_ci	if (!bnx2x_get_vf_igu_cam_info(bp)) {
12738c2ecf20Sopenharmony_ci		BNX2X_ERR("No entries in IGU CAM for vfs\n");
12748c2ecf20Sopenharmony_ci		err = -EINVAL;
12758c2ecf20Sopenharmony_ci		goto failed;
12768c2ecf20Sopenharmony_ci	}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	/* allocate the queue arrays for all VFs */
12798c2ecf20Sopenharmony_ci	bp->vfdb->vfqs = kcalloc(BNX2X_MAX_NUM_VF_QUEUES,
12808c2ecf20Sopenharmony_ci				 sizeof(struct bnx2x_vf_queue),
12818c2ecf20Sopenharmony_ci				 GFP_KERNEL);
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	if (!bp->vfdb->vfqs) {
12848c2ecf20Sopenharmony_ci		BNX2X_ERR("failed to allocate vf queue array\n");
12858c2ecf20Sopenharmony_ci		err = -ENOMEM;
12868c2ecf20Sopenharmony_ci		goto failed;
12878c2ecf20Sopenharmony_ci	}
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	/* Prepare the VFs event synchronization mechanism */
12908c2ecf20Sopenharmony_ci	mutex_init(&bp->vfdb->event_mutex);
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	mutex_init(&bp->vfdb->bulletin_mutex);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	if (SHMEM2_HAS(bp, sriov_switch_mode))
12958c2ecf20Sopenharmony_ci		SHMEM2_WR(bp, sriov_switch_mode, SRIOV_SWITCH_MODE_VEB);
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	return 0;
12988c2ecf20Sopenharmony_cifailed:
12998c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "Failed err=%d\n", err);
13008c2ecf20Sopenharmony_ci	__bnx2x_iov_free_vfdb(bp);
13018c2ecf20Sopenharmony_ci	return err;
13028c2ecf20Sopenharmony_ci}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_civoid bnx2x_iov_remove_one(struct bnx2x *bp)
13058c2ecf20Sopenharmony_ci{
13068c2ecf20Sopenharmony_ci	int vf_idx;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	/* if SRIOV is not enabled there's nothing to do */
13098c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp))
13108c2ecf20Sopenharmony_ci		return;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	bnx2x_disable_sriov(bp);
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	/* disable access to all VFs */
13158c2ecf20Sopenharmony_ci	for (vf_idx = 0; vf_idx < bp->vfdb->sriov.total; vf_idx++) {
13168c2ecf20Sopenharmony_ci		bnx2x_pretend_func(bp,
13178c2ecf20Sopenharmony_ci				   HW_VF_HANDLE(bp,
13188c2ecf20Sopenharmony_ci						bp->vfdb->sriov.first_vf_in_pf +
13198c2ecf20Sopenharmony_ci						vf_idx));
13208c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "disabling internal access for vf %d\n",
13218c2ecf20Sopenharmony_ci		   bp->vfdb->sriov.first_vf_in_pf + vf_idx);
13228c2ecf20Sopenharmony_ci		bnx2x_vf_enable_internal(bp, 0);
13238c2ecf20Sopenharmony_ci		bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
13248c2ecf20Sopenharmony_ci	}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	/* free vf database */
13278c2ecf20Sopenharmony_ci	__bnx2x_iov_free_vfdb(bp);
13288c2ecf20Sopenharmony_ci}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_civoid bnx2x_iov_free_mem(struct bnx2x *bp)
13318c2ecf20Sopenharmony_ci{
13328c2ecf20Sopenharmony_ci	int i;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp))
13358c2ecf20Sopenharmony_ci		return;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	/* free vfs hw contexts */
13388c2ecf20Sopenharmony_ci	for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
13398c2ecf20Sopenharmony_ci		struct hw_dma *cxt = &bp->vfdb->context[i];
13408c2ecf20Sopenharmony_ci		BNX2X_PCI_FREE(cxt->addr, cxt->mapping, cxt->size);
13418c2ecf20Sopenharmony_ci	}
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	BNX2X_PCI_FREE(BP_VFDB(bp)->sp_dma.addr,
13448c2ecf20Sopenharmony_ci		       BP_VFDB(bp)->sp_dma.mapping,
13458c2ecf20Sopenharmony_ci		       BP_VFDB(bp)->sp_dma.size);
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	BNX2X_PCI_FREE(BP_VF_MBX_DMA(bp)->addr,
13488c2ecf20Sopenharmony_ci		       BP_VF_MBX_DMA(bp)->mapping,
13498c2ecf20Sopenharmony_ci		       BP_VF_MBX_DMA(bp)->size);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	BNX2X_PCI_FREE(BP_VF_BULLETIN_DMA(bp)->addr,
13528c2ecf20Sopenharmony_ci		       BP_VF_BULLETIN_DMA(bp)->mapping,
13538c2ecf20Sopenharmony_ci		       BP_VF_BULLETIN_DMA(bp)->size);
13548c2ecf20Sopenharmony_ci}
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ciint bnx2x_iov_alloc_mem(struct bnx2x *bp)
13578c2ecf20Sopenharmony_ci{
13588c2ecf20Sopenharmony_ci	size_t tot_size;
13598c2ecf20Sopenharmony_ci	int i, rc = 0;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp))
13628c2ecf20Sopenharmony_ci		return rc;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	/* allocate vfs hw contexts */
13658c2ecf20Sopenharmony_ci	tot_size = (BP_VFDB(bp)->sriov.first_vf_in_pf + BNX2X_NR_VIRTFN(bp)) *
13668c2ecf20Sopenharmony_ci		BNX2X_CIDS_PER_VF * sizeof(union cdu_context);
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
13698c2ecf20Sopenharmony_ci		struct hw_dma *cxt = BP_VF_CXT_PAGE(bp, i);
13708c2ecf20Sopenharmony_ci		cxt->size = min_t(size_t, tot_size, CDU_ILT_PAGE_SZ);
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci		if (cxt->size) {
13738c2ecf20Sopenharmony_ci			cxt->addr = BNX2X_PCI_ALLOC(&cxt->mapping, cxt->size);
13748c2ecf20Sopenharmony_ci			if (!cxt->addr)
13758c2ecf20Sopenharmony_ci				goto alloc_mem_err;
13768c2ecf20Sopenharmony_ci		} else {
13778c2ecf20Sopenharmony_ci			cxt->addr = NULL;
13788c2ecf20Sopenharmony_ci			cxt->mapping = 0;
13798c2ecf20Sopenharmony_ci		}
13808c2ecf20Sopenharmony_ci		tot_size -= cxt->size;
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	/* allocate vfs ramrods dma memory - client_init and set_mac */
13848c2ecf20Sopenharmony_ci	tot_size = BNX2X_NR_VIRTFN(bp) * sizeof(struct bnx2x_vf_sp);
13858c2ecf20Sopenharmony_ci	BP_VFDB(bp)->sp_dma.addr = BNX2X_PCI_ALLOC(&BP_VFDB(bp)->sp_dma.mapping,
13868c2ecf20Sopenharmony_ci						   tot_size);
13878c2ecf20Sopenharmony_ci	if (!BP_VFDB(bp)->sp_dma.addr)
13888c2ecf20Sopenharmony_ci		goto alloc_mem_err;
13898c2ecf20Sopenharmony_ci	BP_VFDB(bp)->sp_dma.size = tot_size;
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	/* allocate mailboxes */
13928c2ecf20Sopenharmony_ci	tot_size = BNX2X_NR_VIRTFN(bp) * MBX_MSG_ALIGNED_SIZE;
13938c2ecf20Sopenharmony_ci	BP_VF_MBX_DMA(bp)->addr = BNX2X_PCI_ALLOC(&BP_VF_MBX_DMA(bp)->mapping,
13948c2ecf20Sopenharmony_ci						  tot_size);
13958c2ecf20Sopenharmony_ci	if (!BP_VF_MBX_DMA(bp)->addr)
13968c2ecf20Sopenharmony_ci		goto alloc_mem_err;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	BP_VF_MBX_DMA(bp)->size = tot_size;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	/* allocate local bulletin boards */
14018c2ecf20Sopenharmony_ci	tot_size = BNX2X_NR_VIRTFN(bp) * BULLETIN_CONTENT_SIZE;
14028c2ecf20Sopenharmony_ci	BP_VF_BULLETIN_DMA(bp)->addr = BNX2X_PCI_ALLOC(&BP_VF_BULLETIN_DMA(bp)->mapping,
14038c2ecf20Sopenharmony_ci						       tot_size);
14048c2ecf20Sopenharmony_ci	if (!BP_VF_BULLETIN_DMA(bp)->addr)
14058c2ecf20Sopenharmony_ci		goto alloc_mem_err;
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	BP_VF_BULLETIN_DMA(bp)->size = tot_size;
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	return 0;
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_cialloc_mem_err:
14128c2ecf20Sopenharmony_ci	return -ENOMEM;
14138c2ecf20Sopenharmony_ci}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_cistatic void bnx2x_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
14168c2ecf20Sopenharmony_ci			   struct bnx2x_vf_queue *q)
14178c2ecf20Sopenharmony_ci{
14188c2ecf20Sopenharmony_ci	u8 cl_id = vfq_cl_id(vf, q);
14198c2ecf20Sopenharmony_ci	u8 func_id = FW_VF_HANDLE(vf->abs_vfid);
14208c2ecf20Sopenharmony_ci	unsigned long q_type = 0;
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type);
14238c2ecf20Sopenharmony_ci	set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type);
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	/* Queue State object */
14268c2ecf20Sopenharmony_ci	bnx2x_init_queue_obj(bp, &q->sp_obj,
14278c2ecf20Sopenharmony_ci			     cl_id, &q->cid, 1, func_id,
14288c2ecf20Sopenharmony_ci			     bnx2x_vf_sp(bp, vf, q_data),
14298c2ecf20Sopenharmony_ci			     bnx2x_vf_sp_map(bp, vf, q_data),
14308c2ecf20Sopenharmony_ci			     q_type);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	/* sp indication is set only when vlan/mac/etc. are initialized */
14338c2ecf20Sopenharmony_ci	q->sp_initialized = false;
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV,
14368c2ecf20Sopenharmony_ci	   "initialized vf %d's queue object. func id set to %d. cid set to 0x%x\n",
14378c2ecf20Sopenharmony_ci	   vf->abs_vfid, q->sp_obj.func_id, q->cid);
14388c2ecf20Sopenharmony_ci}
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_cistatic int bnx2x_max_speed_cap(struct bnx2x *bp)
14418c2ecf20Sopenharmony_ci{
14428c2ecf20Sopenharmony_ci	u32 supported = bp->port.supported[bnx2x_get_link_cfg_idx(bp)];
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	if (supported &
14458c2ecf20Sopenharmony_ci	    (SUPPORTED_20000baseMLD2_Full | SUPPORTED_20000baseKR2_Full))
14468c2ecf20Sopenharmony_ci		return 20000;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	return 10000; /* assume lowest supported speed is 10G */
14498c2ecf20Sopenharmony_ci}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ciint bnx2x_iov_link_update_vf(struct bnx2x *bp, int idx)
14528c2ecf20Sopenharmony_ci{
14538c2ecf20Sopenharmony_ci	struct bnx2x_link_report_data *state = &bp->last_reported_link;
14548c2ecf20Sopenharmony_ci	struct pf_vf_bulletin_content *bulletin;
14558c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf;
14568c2ecf20Sopenharmony_ci	bool update = true;
14578c2ecf20Sopenharmony_ci	int rc = 0;
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	/* sanity and init */
14608c2ecf20Sopenharmony_ci	rc = bnx2x_vf_op_prep(bp, idx, &vf, &bulletin, false);
14618c2ecf20Sopenharmony_ci	if (rc)
14628c2ecf20Sopenharmony_ci		return rc;
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	mutex_lock(&bp->vfdb->bulletin_mutex);
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	if (vf->link_cfg == IFLA_VF_LINK_STATE_AUTO) {
14678c2ecf20Sopenharmony_ci		bulletin->valid_bitmap |= 1 << LINK_VALID;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci		bulletin->link_speed = state->line_speed;
14708c2ecf20Sopenharmony_ci		bulletin->link_flags = 0;
14718c2ecf20Sopenharmony_ci		if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
14728c2ecf20Sopenharmony_ci			     &state->link_report_flags))
14738c2ecf20Sopenharmony_ci			bulletin->link_flags |= VFPF_LINK_REPORT_LINK_DOWN;
14748c2ecf20Sopenharmony_ci		if (test_bit(BNX2X_LINK_REPORT_FD,
14758c2ecf20Sopenharmony_ci			     &state->link_report_flags))
14768c2ecf20Sopenharmony_ci			bulletin->link_flags |= VFPF_LINK_REPORT_FULL_DUPLEX;
14778c2ecf20Sopenharmony_ci		if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON,
14788c2ecf20Sopenharmony_ci			     &state->link_report_flags))
14798c2ecf20Sopenharmony_ci			bulletin->link_flags |= VFPF_LINK_REPORT_RX_FC_ON;
14808c2ecf20Sopenharmony_ci		if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON,
14818c2ecf20Sopenharmony_ci			     &state->link_report_flags))
14828c2ecf20Sopenharmony_ci			bulletin->link_flags |= VFPF_LINK_REPORT_TX_FC_ON;
14838c2ecf20Sopenharmony_ci	} else if (vf->link_cfg == IFLA_VF_LINK_STATE_DISABLE &&
14848c2ecf20Sopenharmony_ci		   !(bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN)) {
14858c2ecf20Sopenharmony_ci		bulletin->valid_bitmap |= 1 << LINK_VALID;
14868c2ecf20Sopenharmony_ci		bulletin->link_flags |= VFPF_LINK_REPORT_LINK_DOWN;
14878c2ecf20Sopenharmony_ci	} else if (vf->link_cfg == IFLA_VF_LINK_STATE_ENABLE &&
14888c2ecf20Sopenharmony_ci		   (bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN)) {
14898c2ecf20Sopenharmony_ci		bulletin->valid_bitmap |= 1 << LINK_VALID;
14908c2ecf20Sopenharmony_ci		bulletin->link_speed = bnx2x_max_speed_cap(bp);
14918c2ecf20Sopenharmony_ci		bulletin->link_flags &= ~VFPF_LINK_REPORT_LINK_DOWN;
14928c2ecf20Sopenharmony_ci	} else {
14938c2ecf20Sopenharmony_ci		update = false;
14948c2ecf20Sopenharmony_ci	}
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	if (update) {
14978c2ecf20Sopenharmony_ci		DP(NETIF_MSG_LINK | BNX2X_MSG_IOV,
14988c2ecf20Sopenharmony_ci		   "vf %d mode %u speed %d flags %x\n", idx,
14998c2ecf20Sopenharmony_ci		   vf->link_cfg, bulletin->link_speed, bulletin->link_flags);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci		/* Post update on VF's bulletin board */
15028c2ecf20Sopenharmony_ci		rc = bnx2x_post_vf_bulletin(bp, idx);
15038c2ecf20Sopenharmony_ci		if (rc) {
15048c2ecf20Sopenharmony_ci			BNX2X_ERR("failed to update VF[%d] bulletin\n", idx);
15058c2ecf20Sopenharmony_ci			goto out;
15068c2ecf20Sopenharmony_ci		}
15078c2ecf20Sopenharmony_ci	}
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ciout:
15108c2ecf20Sopenharmony_ci	mutex_unlock(&bp->vfdb->bulletin_mutex);
15118c2ecf20Sopenharmony_ci	return rc;
15128c2ecf20Sopenharmony_ci}
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ciint bnx2x_set_vf_link_state(struct net_device *dev, int idx, int link_state)
15158c2ecf20Sopenharmony_ci{
15168c2ecf20Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
15178c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf = BP_VF(bp, idx);
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	if (!vf)
15208c2ecf20Sopenharmony_ci		return -EINVAL;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	if (vf->link_cfg == link_state)
15238c2ecf20Sopenharmony_ci		return 0; /* nothing todo */
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	vf->link_cfg = link_state;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	return bnx2x_iov_link_update_vf(bp, idx);
15288c2ecf20Sopenharmony_ci}
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_civoid bnx2x_iov_link_update(struct bnx2x *bp)
15318c2ecf20Sopenharmony_ci{
15328c2ecf20Sopenharmony_ci	int vfid;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp))
15358c2ecf20Sopenharmony_ci		return;
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	for_each_vf(bp, vfid)
15388c2ecf20Sopenharmony_ci		bnx2x_iov_link_update_vf(bp, vfid);
15398c2ecf20Sopenharmony_ci}
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci/* called by bnx2x_nic_load */
15428c2ecf20Sopenharmony_ciint bnx2x_iov_nic_init(struct bnx2x *bp)
15438c2ecf20Sopenharmony_ci{
15448c2ecf20Sopenharmony_ci	int vfid;
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp)) {
15478c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "vfdb was not allocated\n");
15488c2ecf20Sopenharmony_ci		return 0;
15498c2ecf20Sopenharmony_ci	}
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "num of vfs: %d\n", (bp)->vfdb->sriov.nr_virtfn);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	/* let FLR complete ... */
15548c2ecf20Sopenharmony_ci	msleep(100);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	/* initialize vf database */
15578c2ecf20Sopenharmony_ci	for_each_vf(bp, vfid) {
15588c2ecf20Sopenharmony_ci		struct bnx2x_virtf *vf = BP_VF(bp, vfid);
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci		int base_vf_cid = (BP_VFDB(bp)->sriov.first_vf_in_pf + vfid) *
15618c2ecf20Sopenharmony_ci			BNX2X_CIDS_PER_VF;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci		union cdu_context *base_cxt = (union cdu_context *)
15648c2ecf20Sopenharmony_ci			BP_VF_CXT_PAGE(bp, base_vf_cid/ILT_PAGE_CIDS)->addr +
15658c2ecf20Sopenharmony_ci			(base_vf_cid & (ILT_PAGE_CIDS-1));
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV,
15688c2ecf20Sopenharmony_ci		   "VF[%d] Max IGU SBs: %d, base vf cid 0x%x, base cid 0x%x, base cxt %p\n",
15698c2ecf20Sopenharmony_ci		   vf->abs_vfid, vf_sb_count(vf), base_vf_cid,
15708c2ecf20Sopenharmony_ci		   BNX2X_FIRST_VF_CID + base_vf_cid, base_cxt);
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci		/* init statically provisioned resources */
15738c2ecf20Sopenharmony_ci		bnx2x_iov_static_resc(bp, vf);
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci		/* queues are initialized during VF-ACQUIRE */
15768c2ecf20Sopenharmony_ci		vf->filter_state = 0;
15778c2ecf20Sopenharmony_ci		vf->sp_cl_id = bnx2x_fp(bp, 0, cl_id);
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci		bnx2x_init_credit_pool(&vf->vf_vlans_pool, 0,
15808c2ecf20Sopenharmony_ci				       vf_vlan_rules_cnt(vf));
15818c2ecf20Sopenharmony_ci		bnx2x_init_credit_pool(&vf->vf_macs_pool, 0,
15828c2ecf20Sopenharmony_ci				       vf_mac_rules_cnt(vf));
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci		/*  init mcast object - This object will be re-initialized
15858c2ecf20Sopenharmony_ci		 *  during VF-ACQUIRE with the proper cl_id and cid.
15868c2ecf20Sopenharmony_ci		 *  It needs to be initialized here so that it can be safely
15878c2ecf20Sopenharmony_ci		 *  handled by a subsequent FLR flow.
15888c2ecf20Sopenharmony_ci		 */
15898c2ecf20Sopenharmony_ci		bnx2x_init_mcast_obj(bp, &vf->mcast_obj, 0xFF,
15908c2ecf20Sopenharmony_ci				     0xFF, 0xFF, 0xFF,
15918c2ecf20Sopenharmony_ci				     bnx2x_vf_sp(bp, vf, mcast_rdata),
15928c2ecf20Sopenharmony_ci				     bnx2x_vf_sp_map(bp, vf, mcast_rdata),
15938c2ecf20Sopenharmony_ci				     BNX2X_FILTER_MCAST_PENDING,
15948c2ecf20Sopenharmony_ci				     &vf->filter_state,
15958c2ecf20Sopenharmony_ci				     BNX2X_OBJ_TYPE_RX_TX);
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci		/* set the mailbox message addresses */
15988c2ecf20Sopenharmony_ci		BP_VF_MBX(bp, vfid)->msg = (struct bnx2x_vf_mbx_msg *)
15998c2ecf20Sopenharmony_ci			(((u8 *)BP_VF_MBX_DMA(bp)->addr) + vfid *
16008c2ecf20Sopenharmony_ci			MBX_MSG_ALIGNED_SIZE);
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci		BP_VF_MBX(bp, vfid)->msg_mapping = BP_VF_MBX_DMA(bp)->mapping +
16038c2ecf20Sopenharmony_ci			vfid * MBX_MSG_ALIGNED_SIZE;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci		/* Enable vf mailbox */
16068c2ecf20Sopenharmony_ci		bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
16078c2ecf20Sopenharmony_ci	}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	/* Final VF init */
16108c2ecf20Sopenharmony_ci	for_each_vf(bp, vfid) {
16118c2ecf20Sopenharmony_ci		struct bnx2x_virtf *vf = BP_VF(bp, vfid);
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci		/* fill in the BDF and bars */
16148c2ecf20Sopenharmony_ci		vf->domain = bnx2x_vf_domain(bp, vfid);
16158c2ecf20Sopenharmony_ci		vf->bus = bnx2x_vf_bus(bp, vfid);
16168c2ecf20Sopenharmony_ci		vf->devfn = bnx2x_vf_devfn(bp, vfid);
16178c2ecf20Sopenharmony_ci		bnx2x_vf_set_bars(bp, vf);
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV,
16208c2ecf20Sopenharmony_ci		   "VF info[%d]: bus 0x%x, devfn 0x%x, bar0 [0x%x, %d], bar1 [0x%x, %d], bar2 [0x%x, %d]\n",
16218c2ecf20Sopenharmony_ci		   vf->abs_vfid, vf->bus, vf->devfn,
16228c2ecf20Sopenharmony_ci		   (unsigned)vf->bars[0].bar, vf->bars[0].size,
16238c2ecf20Sopenharmony_ci		   (unsigned)vf->bars[1].bar, vf->bars[1].size,
16248c2ecf20Sopenharmony_ci		   (unsigned)vf->bars[2].bar, vf->bars[2].size);
16258c2ecf20Sopenharmony_ci	}
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	return 0;
16288c2ecf20Sopenharmony_ci}
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci/* called by bnx2x_chip_cleanup */
16318c2ecf20Sopenharmony_ciint bnx2x_iov_chip_cleanup(struct bnx2x *bp)
16328c2ecf20Sopenharmony_ci{
16338c2ecf20Sopenharmony_ci	int i;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp))
16368c2ecf20Sopenharmony_ci		return 0;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	/* release all the VFs */
16398c2ecf20Sopenharmony_ci	for_each_vf(bp, i)
16408c2ecf20Sopenharmony_ci		bnx2x_vf_release(bp, BP_VF(bp, i));
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	return 0;
16438c2ecf20Sopenharmony_ci}
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci/* called by bnx2x_init_hw_func, returns the next ilt line */
16468c2ecf20Sopenharmony_ciint bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line)
16478c2ecf20Sopenharmony_ci{
16488c2ecf20Sopenharmony_ci	int i;
16498c2ecf20Sopenharmony_ci	struct bnx2x_ilt *ilt = BP_ILT(bp);
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp))
16528c2ecf20Sopenharmony_ci		return line;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	/* set vfs ilt lines */
16558c2ecf20Sopenharmony_ci	for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
16568c2ecf20Sopenharmony_ci		struct hw_dma *hw_cxt = BP_VF_CXT_PAGE(bp, i);
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci		ilt->lines[line+i].page = hw_cxt->addr;
16598c2ecf20Sopenharmony_ci		ilt->lines[line+i].page_mapping = hw_cxt->mapping;
16608c2ecf20Sopenharmony_ci		ilt->lines[line+i].size = hw_cxt->size; /* doesn't matter */
16618c2ecf20Sopenharmony_ci	}
16628c2ecf20Sopenharmony_ci	return line + i;
16638c2ecf20Sopenharmony_ci}
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_cistatic u8 bnx2x_iov_is_vf_cid(struct bnx2x *bp, u16 cid)
16668c2ecf20Sopenharmony_ci{
16678c2ecf20Sopenharmony_ci	return ((cid >= BNX2X_FIRST_VF_CID) &&
16688c2ecf20Sopenharmony_ci		((cid - BNX2X_FIRST_VF_CID) < BNX2X_VF_CIDS));
16698c2ecf20Sopenharmony_ci}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_cistatic
16728c2ecf20Sopenharmony_civoid bnx2x_vf_handle_classification_eqe(struct bnx2x *bp,
16738c2ecf20Sopenharmony_ci					struct bnx2x_vf_queue *vfq,
16748c2ecf20Sopenharmony_ci					union event_ring_elem *elem)
16758c2ecf20Sopenharmony_ci{
16768c2ecf20Sopenharmony_ci	unsigned long ramrod_flags = 0;
16778c2ecf20Sopenharmony_ci	int rc = 0;
16788c2ecf20Sopenharmony_ci	u32 echo = le32_to_cpu(elem->message.data.eth_event.echo);
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	/* Always push next commands out, don't wait here */
16818c2ecf20Sopenharmony_ci	set_bit(RAMROD_CONT, &ramrod_flags);
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	switch (echo >> BNX2X_SWCID_SHIFT) {
16848c2ecf20Sopenharmony_ci	case BNX2X_FILTER_MAC_PENDING:
16858c2ecf20Sopenharmony_ci		rc = vfq->mac_obj.complete(bp, &vfq->mac_obj, elem,
16868c2ecf20Sopenharmony_ci					   &ramrod_flags);
16878c2ecf20Sopenharmony_ci		break;
16888c2ecf20Sopenharmony_ci	case BNX2X_FILTER_VLAN_PENDING:
16898c2ecf20Sopenharmony_ci		rc = vfq->vlan_obj.complete(bp, &vfq->vlan_obj, elem,
16908c2ecf20Sopenharmony_ci					    &ramrod_flags);
16918c2ecf20Sopenharmony_ci		break;
16928c2ecf20Sopenharmony_ci	default:
16938c2ecf20Sopenharmony_ci		BNX2X_ERR("Unsupported classification command: 0x%x\n", echo);
16948c2ecf20Sopenharmony_ci		return;
16958c2ecf20Sopenharmony_ci	}
16968c2ecf20Sopenharmony_ci	if (rc < 0)
16978c2ecf20Sopenharmony_ci		BNX2X_ERR("Failed to schedule new commands: %d\n", rc);
16988c2ecf20Sopenharmony_ci	else if (rc > 0)
16998c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "Scheduled next pending commands...\n");
17008c2ecf20Sopenharmony_ci}
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_cistatic
17038c2ecf20Sopenharmony_civoid bnx2x_vf_handle_mcast_eqe(struct bnx2x *bp,
17048c2ecf20Sopenharmony_ci			       struct bnx2x_virtf *vf)
17058c2ecf20Sopenharmony_ci{
17068c2ecf20Sopenharmony_ci	struct bnx2x_mcast_ramrod_params rparam = {NULL};
17078c2ecf20Sopenharmony_ci	int rc;
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	rparam.mcast_obj = &vf->mcast_obj;
17108c2ecf20Sopenharmony_ci	vf->mcast_obj.raw.clear_pending(&vf->mcast_obj.raw);
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	/* If there are pending mcast commands - send them */
17138c2ecf20Sopenharmony_ci	if (vf->mcast_obj.check_pending(&vf->mcast_obj)) {
17148c2ecf20Sopenharmony_ci		rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT);
17158c2ecf20Sopenharmony_ci		if (rc < 0)
17168c2ecf20Sopenharmony_ci			BNX2X_ERR("Failed to send pending mcast commands: %d\n",
17178c2ecf20Sopenharmony_ci				  rc);
17188c2ecf20Sopenharmony_ci	}
17198c2ecf20Sopenharmony_ci}
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_cistatic
17228c2ecf20Sopenharmony_civoid bnx2x_vf_handle_filters_eqe(struct bnx2x *bp,
17238c2ecf20Sopenharmony_ci				 struct bnx2x_virtf *vf)
17248c2ecf20Sopenharmony_ci{
17258c2ecf20Sopenharmony_ci	smp_mb__before_atomic();
17268c2ecf20Sopenharmony_ci	clear_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state);
17278c2ecf20Sopenharmony_ci	smp_mb__after_atomic();
17288c2ecf20Sopenharmony_ci}
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_cistatic void bnx2x_vf_handle_rss_update_eqe(struct bnx2x *bp,
17318c2ecf20Sopenharmony_ci					   struct bnx2x_virtf *vf)
17328c2ecf20Sopenharmony_ci{
17338c2ecf20Sopenharmony_ci	vf->rss_conf_obj.raw.clear_pending(&vf->rss_conf_obj.raw);
17348c2ecf20Sopenharmony_ci}
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ciint bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
17378c2ecf20Sopenharmony_ci{
17388c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf;
17398c2ecf20Sopenharmony_ci	int qidx = 0, abs_vfid;
17408c2ecf20Sopenharmony_ci	u8 opcode;
17418c2ecf20Sopenharmony_ci	u16 cid = 0xffff;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp))
17448c2ecf20Sopenharmony_ci		return 1;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	/* first get the cid - the only events we handle here are cfc-delete
17478c2ecf20Sopenharmony_ci	 * and set-mac completion
17488c2ecf20Sopenharmony_ci	 */
17498c2ecf20Sopenharmony_ci	opcode = elem->message.opcode;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	switch (opcode) {
17528c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_CFC_DEL:
17538c2ecf20Sopenharmony_ci		cid = SW_CID(elem->message.data.cfc_del_event.cid);
17548c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "checking cfc-del comp cid=%d\n", cid);
17558c2ecf20Sopenharmony_ci		break;
17568c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
17578c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_MULTICAST_RULES:
17588c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_FILTERS_RULES:
17598c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_RSS_UPDATE_RULES:
17608c2ecf20Sopenharmony_ci		cid = SW_CID(elem->message.data.eth_event.echo);
17618c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "checking filtering comp cid=%d\n", cid);
17628c2ecf20Sopenharmony_ci		break;
17638c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_VF_FLR:
17648c2ecf20Sopenharmony_ci		abs_vfid = elem->message.data.vf_flr_event.vf_id;
17658c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "Got VF FLR notification abs_vfid=%d\n",
17668c2ecf20Sopenharmony_ci		   abs_vfid);
17678c2ecf20Sopenharmony_ci		goto get_vf;
17688c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_MALICIOUS_VF:
17698c2ecf20Sopenharmony_ci		abs_vfid = elem->message.data.malicious_vf_event.vf_id;
17708c2ecf20Sopenharmony_ci		BNX2X_ERR("Got VF MALICIOUS notification abs_vfid=%d err_id=0x%x\n",
17718c2ecf20Sopenharmony_ci			  abs_vfid,
17728c2ecf20Sopenharmony_ci			  elem->message.data.malicious_vf_event.err_id);
17738c2ecf20Sopenharmony_ci		goto get_vf;
17748c2ecf20Sopenharmony_ci	default:
17758c2ecf20Sopenharmony_ci		return 1;
17768c2ecf20Sopenharmony_ci	}
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	/* check if the cid is the VF range */
17798c2ecf20Sopenharmony_ci	if (!bnx2x_iov_is_vf_cid(bp, cid)) {
17808c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "cid is outside vf range: %d\n", cid);
17818c2ecf20Sopenharmony_ci		return 1;
17828c2ecf20Sopenharmony_ci	}
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	/* extract vf and rxq index from vf_cid - relies on the following:
17858c2ecf20Sopenharmony_ci	 * 1. vfid on cid reflects the true abs_vfid
17868c2ecf20Sopenharmony_ci	 * 2. The max number of VFs (per path) is 64
17878c2ecf20Sopenharmony_ci	 */
17888c2ecf20Sopenharmony_ci	qidx = cid & ((1 << BNX2X_VF_CID_WND)-1);
17898c2ecf20Sopenharmony_ci	abs_vfid = (cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1);
17908c2ecf20Sopenharmony_ciget_vf:
17918c2ecf20Sopenharmony_ci	vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci	if (!vf) {
17948c2ecf20Sopenharmony_ci		BNX2X_ERR("EQ completion for unknown VF, cid %d, abs_vfid %d\n",
17958c2ecf20Sopenharmony_ci			  cid, abs_vfid);
17968c2ecf20Sopenharmony_ci		return 0;
17978c2ecf20Sopenharmony_ci	}
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	switch (opcode) {
18008c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_CFC_DEL:
18018c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "got VF [%d:%d] cfc delete ramrod\n",
18028c2ecf20Sopenharmony_ci		   vf->abs_vfid, qidx);
18038c2ecf20Sopenharmony_ci		vfq_get(vf, qidx)->sp_obj.complete_cmd(bp,
18048c2ecf20Sopenharmony_ci						       &vfq_get(vf,
18058c2ecf20Sopenharmony_ci								qidx)->sp_obj,
18068c2ecf20Sopenharmony_ci						       BNX2X_Q_CMD_CFC_DEL);
18078c2ecf20Sopenharmony_ci		break;
18088c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
18098c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mac/vlan ramrod\n",
18108c2ecf20Sopenharmony_ci		   vf->abs_vfid, qidx);
18118c2ecf20Sopenharmony_ci		bnx2x_vf_handle_classification_eqe(bp, vfq_get(vf, qidx), elem);
18128c2ecf20Sopenharmony_ci		break;
18138c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_MULTICAST_RULES:
18148c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mcast ramrod\n",
18158c2ecf20Sopenharmony_ci		   vf->abs_vfid, qidx);
18168c2ecf20Sopenharmony_ci		bnx2x_vf_handle_mcast_eqe(bp, vf);
18178c2ecf20Sopenharmony_ci		break;
18188c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_FILTERS_RULES:
18198c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "got VF [%d:%d] set rx-mode ramrod\n",
18208c2ecf20Sopenharmony_ci		   vf->abs_vfid, qidx);
18218c2ecf20Sopenharmony_ci		bnx2x_vf_handle_filters_eqe(bp, vf);
18228c2ecf20Sopenharmony_ci		break;
18238c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_RSS_UPDATE_RULES:
18248c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "got VF [%d:%d] RSS update ramrod\n",
18258c2ecf20Sopenharmony_ci		   vf->abs_vfid, qidx);
18268c2ecf20Sopenharmony_ci		bnx2x_vf_handle_rss_update_eqe(bp, vf);
18278c2ecf20Sopenharmony_ci		fallthrough;
18288c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_VF_FLR:
18298c2ecf20Sopenharmony_ci		/* Do nothing for now */
18308c2ecf20Sopenharmony_ci		return 0;
18318c2ecf20Sopenharmony_ci	case EVENT_RING_OPCODE_MALICIOUS_VF:
18328c2ecf20Sopenharmony_ci		vf->malicious = true;
18338c2ecf20Sopenharmony_ci		return 0;
18348c2ecf20Sopenharmony_ci	}
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	return 0;
18378c2ecf20Sopenharmony_ci}
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_cistatic struct bnx2x_virtf *bnx2x_vf_by_cid(struct bnx2x *bp, int vf_cid)
18408c2ecf20Sopenharmony_ci{
18418c2ecf20Sopenharmony_ci	/* extract the vf from vf_cid - relies on the following:
18428c2ecf20Sopenharmony_ci	 * 1. vfid on cid reflects the true abs_vfid
18438c2ecf20Sopenharmony_ci	 * 2. The max number of VFs (per path) is 64
18448c2ecf20Sopenharmony_ci	 */
18458c2ecf20Sopenharmony_ci	int abs_vfid = (vf_cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1);
18468c2ecf20Sopenharmony_ci	return bnx2x_vf_by_abs_fid(bp, abs_vfid);
18478c2ecf20Sopenharmony_ci}
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_civoid bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
18508c2ecf20Sopenharmony_ci				struct bnx2x_queue_sp_obj **q_obj)
18518c2ecf20Sopenharmony_ci{
18528c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf;
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp))
18558c2ecf20Sopenharmony_ci		return;
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	vf = bnx2x_vf_by_cid(bp, vf_cid);
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	if (vf) {
18608c2ecf20Sopenharmony_ci		/* extract queue index from vf_cid - relies on the following:
18618c2ecf20Sopenharmony_ci		 * 1. vfid on cid reflects the true abs_vfid
18628c2ecf20Sopenharmony_ci		 * 2. The max number of VFs (per path) is 64
18638c2ecf20Sopenharmony_ci		 */
18648c2ecf20Sopenharmony_ci		int q_index = vf_cid & ((1 << BNX2X_VF_CID_WND)-1);
18658c2ecf20Sopenharmony_ci		*q_obj = &bnx2x_vfq(vf, q_index, sp_obj);
18668c2ecf20Sopenharmony_ci	} else {
18678c2ecf20Sopenharmony_ci		BNX2X_ERR("No vf matching cid %d\n", vf_cid);
18688c2ecf20Sopenharmony_ci	}
18698c2ecf20Sopenharmony_ci}
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_civoid bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
18728c2ecf20Sopenharmony_ci{
18738c2ecf20Sopenharmony_ci	int i;
18748c2ecf20Sopenharmony_ci	int first_queue_query_index, num_queues_req;
18758c2ecf20Sopenharmony_ci	dma_addr_t cur_data_offset;
18768c2ecf20Sopenharmony_ci	struct stats_query_entry *cur_query_entry;
18778c2ecf20Sopenharmony_ci	u8 stats_count = 0;
18788c2ecf20Sopenharmony_ci	bool is_fcoe = false;
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp))
18818c2ecf20Sopenharmony_ci		return;
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	if (!NO_FCOE(bp))
18848c2ecf20Sopenharmony_ci		is_fcoe = true;
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci	/* fcoe adds one global request and one queue request */
18878c2ecf20Sopenharmony_ci	num_queues_req = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe;
18888c2ecf20Sopenharmony_ci	first_queue_query_index = BNX2X_FIRST_QUEUE_QUERY_IDX -
18898c2ecf20Sopenharmony_ci		(is_fcoe ? 0 : 1);
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS),
18928c2ecf20Sopenharmony_ci	       "BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n",
18938c2ecf20Sopenharmony_ci	       BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index,
18948c2ecf20Sopenharmony_ci	       first_queue_query_index + num_queues_req);
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci	cur_data_offset = bp->fw_stats_data_mapping +
18978c2ecf20Sopenharmony_ci		offsetof(struct bnx2x_fw_stats_data, queue_stats) +
18988c2ecf20Sopenharmony_ci		num_queues_req * sizeof(struct per_queue_stats);
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	cur_query_entry = &bp->fw_stats_req->
19018c2ecf20Sopenharmony_ci		query[first_queue_query_index + num_queues_req];
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	for_each_vf(bp, i) {
19048c2ecf20Sopenharmony_ci		int j;
19058c2ecf20Sopenharmony_ci		struct bnx2x_virtf *vf = BP_VF(bp, i);
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci		if (vf->state != VF_ENABLED) {
19088c2ecf20Sopenharmony_ci			DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS),
19098c2ecf20Sopenharmony_ci			       "vf %d not enabled so no stats for it\n",
19108c2ecf20Sopenharmony_ci			       vf->abs_vfid);
19118c2ecf20Sopenharmony_ci			continue;
19128c2ecf20Sopenharmony_ci		}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci		if (vf->malicious) {
19158c2ecf20Sopenharmony_ci			DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS),
19168c2ecf20Sopenharmony_ci			       "vf %d malicious so no stats for it\n",
19178c2ecf20Sopenharmony_ci			       vf->abs_vfid);
19188c2ecf20Sopenharmony_ci			continue;
19198c2ecf20Sopenharmony_ci		}
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci		DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS),
19228c2ecf20Sopenharmony_ci		       "add addresses for vf %d\n", vf->abs_vfid);
19238c2ecf20Sopenharmony_ci		for_each_vfq(vf, j) {
19248c2ecf20Sopenharmony_ci			struct bnx2x_vf_queue *rxq = vfq_get(vf, j);
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci			dma_addr_t q_stats_addr =
19278c2ecf20Sopenharmony_ci				vf->fw_stat_map + j * vf->stats_stride;
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci			/* collect stats fro active queues only */
19308c2ecf20Sopenharmony_ci			if (bnx2x_get_q_logical_state(bp, &rxq->sp_obj) ==
19318c2ecf20Sopenharmony_ci			    BNX2X_Q_LOGICAL_STATE_STOPPED)
19328c2ecf20Sopenharmony_ci				continue;
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci			/* create stats query entry for this queue */
19358c2ecf20Sopenharmony_ci			cur_query_entry->kind = STATS_TYPE_QUEUE;
19368c2ecf20Sopenharmony_ci			cur_query_entry->index = vfq_stat_id(vf, rxq);
19378c2ecf20Sopenharmony_ci			cur_query_entry->funcID =
19388c2ecf20Sopenharmony_ci				cpu_to_le16(FW_VF_HANDLE(vf->abs_vfid));
19398c2ecf20Sopenharmony_ci			cur_query_entry->address.hi =
19408c2ecf20Sopenharmony_ci				cpu_to_le32(U64_HI(q_stats_addr));
19418c2ecf20Sopenharmony_ci			cur_query_entry->address.lo =
19428c2ecf20Sopenharmony_ci				cpu_to_le32(U64_LO(q_stats_addr));
19438c2ecf20Sopenharmony_ci			DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS),
19448c2ecf20Sopenharmony_ci			       "added address %x %x for vf %d queue %d client %d\n",
19458c2ecf20Sopenharmony_ci			       cur_query_entry->address.hi,
19468c2ecf20Sopenharmony_ci			       cur_query_entry->address.lo,
19478c2ecf20Sopenharmony_ci			       cur_query_entry->funcID,
19488c2ecf20Sopenharmony_ci			       j, cur_query_entry->index);
19498c2ecf20Sopenharmony_ci			cur_query_entry++;
19508c2ecf20Sopenharmony_ci			cur_data_offset += sizeof(struct per_queue_stats);
19518c2ecf20Sopenharmony_ci			stats_count++;
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci			/* all stats are coalesced to the leading queue */
19548c2ecf20Sopenharmony_ci			if (vf->cfg_flags & VF_CFG_STATS_COALESCE)
19558c2ecf20Sopenharmony_ci				break;
19568c2ecf20Sopenharmony_ci		}
19578c2ecf20Sopenharmony_ci	}
19588c2ecf20Sopenharmony_ci	bp->fw_stats_req->hdr.cmd_num = bp->fw_stats_num + stats_count;
19598c2ecf20Sopenharmony_ci}
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci/* VF API helpers */
19628c2ecf20Sopenharmony_cistatic void bnx2x_vf_qtbl_set_q(struct bnx2x *bp, u8 abs_vfid, u8 qid,
19638c2ecf20Sopenharmony_ci				u8 enable)
19648c2ecf20Sopenharmony_ci{
19658c2ecf20Sopenharmony_ci	u32 reg = PXP_REG_HST_ZONE_PERMISSION_TABLE + qid * 4;
19668c2ecf20Sopenharmony_ci	u32 val = enable ? (abs_vfid | (1 << 6)) : 0;
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci	REG_WR(bp, reg, val);
19698c2ecf20Sopenharmony_ci}
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_cistatic void bnx2x_vf_clr_qtbl(struct bnx2x *bp, struct bnx2x_virtf *vf)
19728c2ecf20Sopenharmony_ci{
19738c2ecf20Sopenharmony_ci	int i;
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	for_each_vfq(vf, i)
19768c2ecf20Sopenharmony_ci		bnx2x_vf_qtbl_set_q(bp, vf->abs_vfid,
19778c2ecf20Sopenharmony_ci				    vfq_qzone_id(vf, vfq_get(vf, i)), false);
19788c2ecf20Sopenharmony_ci}
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_cistatic void bnx2x_vf_igu_disable(struct bnx2x *bp, struct bnx2x_virtf *vf)
19818c2ecf20Sopenharmony_ci{
19828c2ecf20Sopenharmony_ci	u32 val;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	/* clear the VF configuration - pretend */
19858c2ecf20Sopenharmony_ci	bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
19868c2ecf20Sopenharmony_ci	val = REG_RD(bp, IGU_REG_VF_CONFIGURATION);
19878c2ecf20Sopenharmony_ci	val &= ~(IGU_VF_CONF_MSI_MSIX_EN | IGU_VF_CONF_SINGLE_ISR_EN |
19888c2ecf20Sopenharmony_ci		 IGU_VF_CONF_FUNC_EN | IGU_VF_CONF_PARENT_MASK);
19898c2ecf20Sopenharmony_ci	REG_WR(bp, IGU_REG_VF_CONFIGURATION, val);
19908c2ecf20Sopenharmony_ci	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
19918c2ecf20Sopenharmony_ci}
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_ciu8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf)
19948c2ecf20Sopenharmony_ci{
19958c2ecf20Sopenharmony_ci	return min_t(u8, min_t(u8, vf_sb_count(vf), BNX2X_CIDS_PER_VF),
19968c2ecf20Sopenharmony_ci		     BNX2X_VF_MAX_QUEUES);
19978c2ecf20Sopenharmony_ci}
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_cistatic
20008c2ecf20Sopenharmony_ciint bnx2x_vf_chk_avail_resc(struct bnx2x *bp, struct bnx2x_virtf *vf,
20018c2ecf20Sopenharmony_ci			    struct vf_pf_resc_request *req_resc)
20028c2ecf20Sopenharmony_ci{
20038c2ecf20Sopenharmony_ci	u8 rxq_cnt = vf_rxq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);
20048c2ecf20Sopenharmony_ci	u8 txq_cnt = vf_txq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci	return ((req_resc->num_rxqs <= rxq_cnt) &&
20078c2ecf20Sopenharmony_ci		(req_resc->num_txqs <= txq_cnt) &&
20088c2ecf20Sopenharmony_ci		(req_resc->num_sbs <= vf_sb_count(vf))   &&
20098c2ecf20Sopenharmony_ci		(req_resc->num_mac_filters <= vf_mac_rules_cnt(vf)) &&
20108c2ecf20Sopenharmony_ci		(req_resc->num_vlan_filters <= vf_vlan_rules_cnt(vf)));
20118c2ecf20Sopenharmony_ci}
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci/* CORE VF API */
20148c2ecf20Sopenharmony_ciint bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
20158c2ecf20Sopenharmony_ci		     struct vf_pf_resc_request *resc)
20168c2ecf20Sopenharmony_ci{
20178c2ecf20Sopenharmony_ci	int base_vf_cid = (BP_VFDB(bp)->sriov.first_vf_in_pf + vf->index) *
20188c2ecf20Sopenharmony_ci		BNX2X_CIDS_PER_VF;
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	union cdu_context *base_cxt = (union cdu_context *)
20218c2ecf20Sopenharmony_ci		BP_VF_CXT_PAGE(bp, base_vf_cid/ILT_PAGE_CIDS)->addr +
20228c2ecf20Sopenharmony_ci		(base_vf_cid & (ILT_PAGE_CIDS-1));
20238c2ecf20Sopenharmony_ci	int i;
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci	/* if state is 'acquired' the VF was not released or FLR'd, in
20268c2ecf20Sopenharmony_ci	 * this case the returned resources match the acquired already
20278c2ecf20Sopenharmony_ci	 * acquired resources. Verify that the requested numbers do
20288c2ecf20Sopenharmony_ci	 * not exceed the already acquired numbers.
20298c2ecf20Sopenharmony_ci	 */
20308c2ecf20Sopenharmony_ci	if (vf->state == VF_ACQUIRED) {
20318c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "VF[%d] Trying to re-acquire resources (VF was not released or FLR'd)\n",
20328c2ecf20Sopenharmony_ci		   vf->abs_vfid);
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci		if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
20358c2ecf20Sopenharmony_ci			BNX2X_ERR("VF[%d] When re-acquiring resources, requested numbers must be <= then previously acquired numbers\n",
20368c2ecf20Sopenharmony_ci				  vf->abs_vfid);
20378c2ecf20Sopenharmony_ci			return -EINVAL;
20388c2ecf20Sopenharmony_ci		}
20398c2ecf20Sopenharmony_ci		return 0;
20408c2ecf20Sopenharmony_ci	}
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	/* Otherwise vf state must be 'free' or 'reset' */
20438c2ecf20Sopenharmony_ci	if (vf->state != VF_FREE && vf->state != VF_RESET) {
20448c2ecf20Sopenharmony_ci		BNX2X_ERR("VF[%d] Can not acquire a VF with state %d\n",
20458c2ecf20Sopenharmony_ci			  vf->abs_vfid, vf->state);
20468c2ecf20Sopenharmony_ci		return -EINVAL;
20478c2ecf20Sopenharmony_ci	}
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	/* static allocation:
20508c2ecf20Sopenharmony_ci	 * the global maximum number are fixed per VF. Fail the request if
20518c2ecf20Sopenharmony_ci	 * requested number exceed these globals
20528c2ecf20Sopenharmony_ci	 */
20538c2ecf20Sopenharmony_ci	if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
20548c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV,
20558c2ecf20Sopenharmony_ci		   "cannot fulfill vf resource request. Placing maximal available values in response\n");
20568c2ecf20Sopenharmony_ci		/* set the max resource in the vf */
20578c2ecf20Sopenharmony_ci		return -ENOMEM;
20588c2ecf20Sopenharmony_ci	}
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	/* Set resources counters - 0 request means max available */
20618c2ecf20Sopenharmony_ci	vf_sb_count(vf) = resc->num_sbs;
20628c2ecf20Sopenharmony_ci	vf_rxq_count(vf) = resc->num_rxqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
20638c2ecf20Sopenharmony_ci	vf_txq_count(vf) = resc->num_txqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV,
20668c2ecf20Sopenharmony_ci	   "Fulfilling vf request: sb count %d, tx_count %d, rx_count %d, mac_rules_count %d, vlan_rules_count %d\n",
20678c2ecf20Sopenharmony_ci	   vf_sb_count(vf), vf_rxq_count(vf),
20688c2ecf20Sopenharmony_ci	   vf_txq_count(vf), vf_mac_rules_cnt(vf),
20698c2ecf20Sopenharmony_ci	   vf_vlan_rules_cnt(vf));
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	/* Initialize the queues */
20728c2ecf20Sopenharmony_ci	if (!vf->vfqs) {
20738c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "vf->vfqs was not allocated\n");
20748c2ecf20Sopenharmony_ci		return -EINVAL;
20758c2ecf20Sopenharmony_ci	}
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	for_each_vfq(vf, i) {
20788c2ecf20Sopenharmony_ci		struct bnx2x_vf_queue *q = vfq_get(vf, i);
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci		if (!q) {
20818c2ecf20Sopenharmony_ci			BNX2X_ERR("q number %d was not allocated\n", i);
20828c2ecf20Sopenharmony_ci			return -EINVAL;
20838c2ecf20Sopenharmony_ci		}
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci		q->index = i;
20868c2ecf20Sopenharmony_ci		q->cxt = &((base_cxt + i)->eth);
20878c2ecf20Sopenharmony_ci		q->cid = BNX2X_FIRST_VF_CID + base_vf_cid + i;
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "VFQ[%d:%d]: index %d, cid 0x%x, cxt %p\n",
20908c2ecf20Sopenharmony_ci		   vf->abs_vfid, i, q->index, q->cid, q->cxt);
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci		/* init SP objects */
20938c2ecf20Sopenharmony_ci		bnx2x_vfq_init(bp, vf, q);
20948c2ecf20Sopenharmony_ci	}
20958c2ecf20Sopenharmony_ci	vf->state = VF_ACQUIRED;
20968c2ecf20Sopenharmony_ci	return 0;
20978c2ecf20Sopenharmony_ci}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ciint bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf, dma_addr_t *sb_map)
21008c2ecf20Sopenharmony_ci{
21018c2ecf20Sopenharmony_ci	struct bnx2x_func_init_params func_init = {0};
21028c2ecf20Sopenharmony_ci	int i;
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	/* the sb resources are initialized at this point, do the
21058c2ecf20Sopenharmony_ci	 * FW/HW initializations
21068c2ecf20Sopenharmony_ci	 */
21078c2ecf20Sopenharmony_ci	for_each_vf_sb(vf, i)
21088c2ecf20Sopenharmony_ci		bnx2x_init_sb(bp, (dma_addr_t)sb_map[i], vf->abs_vfid, true,
21098c2ecf20Sopenharmony_ci			      vf_igu_sb(vf, i), vf_igu_sb(vf, i));
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci	/* Sanity checks */
21128c2ecf20Sopenharmony_ci	if (vf->state != VF_ACQUIRED) {
21138c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "VF[%d] is not in VF_ACQUIRED, but %d\n",
21148c2ecf20Sopenharmony_ci		   vf->abs_vfid, vf->state);
21158c2ecf20Sopenharmony_ci		return -EINVAL;
21168c2ecf20Sopenharmony_ci	}
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci	/* let FLR complete ... */
21198c2ecf20Sopenharmony_ci	msleep(100);
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	/* FLR cleanup epilogue */
21228c2ecf20Sopenharmony_ci	if (bnx2x_vf_flr_clnup_epilog(bp, vf->abs_vfid))
21238c2ecf20Sopenharmony_ci		return -EBUSY;
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	/* reset IGU VF statistics: MSIX */
21268c2ecf20Sopenharmony_ci	REG_WR(bp, IGU_REG_STATISTIC_NUM_MESSAGE_SENT + vf->abs_vfid * 4 , 0);
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	/* function setup */
21298c2ecf20Sopenharmony_ci	func_init.pf_id = BP_FUNC(bp);
21308c2ecf20Sopenharmony_ci	func_init.func_id = FW_VF_HANDLE(vf->abs_vfid);
21318c2ecf20Sopenharmony_ci	bnx2x_func_init(bp, &func_init);
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	/* Enable the vf */
21348c2ecf20Sopenharmony_ci	bnx2x_vf_enable_access(bp, vf->abs_vfid);
21358c2ecf20Sopenharmony_ci	bnx2x_vf_enable_traffic(bp, vf);
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	/* queue protection table */
21388c2ecf20Sopenharmony_ci	for_each_vfq(vf, i)
21398c2ecf20Sopenharmony_ci		bnx2x_vf_qtbl_set_q(bp, vf->abs_vfid,
21408c2ecf20Sopenharmony_ci				    vfq_qzone_id(vf, vfq_get(vf, i)), true);
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	vf->state = VF_ENABLED;
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	/* update vf bulletin board */
21458c2ecf20Sopenharmony_ci	bnx2x_post_vf_bulletin(bp, vf->index);
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_ci	return 0;
21488c2ecf20Sopenharmony_ci}
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_cistruct set_vf_state_cookie {
21518c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf;
21528c2ecf20Sopenharmony_ci	u8 state;
21538c2ecf20Sopenharmony_ci};
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_cistatic void bnx2x_set_vf_state(void *cookie)
21568c2ecf20Sopenharmony_ci{
21578c2ecf20Sopenharmony_ci	struct set_vf_state_cookie *p = (struct set_vf_state_cookie *)cookie;
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci	p->vf->state = p->state;
21608c2ecf20Sopenharmony_ci}
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ciint bnx2x_vf_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
21638c2ecf20Sopenharmony_ci{
21648c2ecf20Sopenharmony_ci	int rc = 0, i;
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci	/* Close all queues */
21698c2ecf20Sopenharmony_ci	for (i = 0; i < vf_rxq_count(vf); i++) {
21708c2ecf20Sopenharmony_ci		rc = bnx2x_vf_queue_teardown(bp, vf, i);
21718c2ecf20Sopenharmony_ci		if (rc)
21728c2ecf20Sopenharmony_ci			goto op_err;
21738c2ecf20Sopenharmony_ci	}
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	/* disable the interrupts */
21768c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "disabling igu\n");
21778c2ecf20Sopenharmony_ci	bnx2x_vf_igu_disable(bp, vf);
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci	/* disable the VF */
21808c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "clearing qtbl\n");
21818c2ecf20Sopenharmony_ci	bnx2x_vf_clr_qtbl(bp, vf);
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	/* need to make sure there are no outstanding stats ramrods which may
21848c2ecf20Sopenharmony_ci	 * cause the device to access the VF's stats buffer which it will free
21858c2ecf20Sopenharmony_ci	 * as soon as we return from the close flow.
21868c2ecf20Sopenharmony_ci	 */
21878c2ecf20Sopenharmony_ci	{
21888c2ecf20Sopenharmony_ci		struct set_vf_state_cookie cookie;
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci		cookie.vf = vf;
21918c2ecf20Sopenharmony_ci		cookie.state = VF_ACQUIRED;
21928c2ecf20Sopenharmony_ci		rc = bnx2x_stats_safe_exec(bp, bnx2x_set_vf_state, &cookie);
21938c2ecf20Sopenharmony_ci		if (rc)
21948c2ecf20Sopenharmony_ci			goto op_err;
21958c2ecf20Sopenharmony_ci	}
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "set state to acquired\n");
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci	return 0;
22008c2ecf20Sopenharmony_ciop_err:
22018c2ecf20Sopenharmony_ci	BNX2X_ERR("vf[%d] CLOSE error: rc %d\n", vf->abs_vfid, rc);
22028c2ecf20Sopenharmony_ci	return rc;
22038c2ecf20Sopenharmony_ci}
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci/* VF release can be called either: 1. The VF was acquired but
22068c2ecf20Sopenharmony_ci * not enabled 2. the vf was enabled or in the process of being
22078c2ecf20Sopenharmony_ci * enabled
22088c2ecf20Sopenharmony_ci */
22098c2ecf20Sopenharmony_ciint bnx2x_vf_free(struct bnx2x *bp, struct bnx2x_virtf *vf)
22108c2ecf20Sopenharmony_ci{
22118c2ecf20Sopenharmony_ci	int rc;
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "VF[%d] STATE: %s\n", vf->abs_vfid,
22148c2ecf20Sopenharmony_ci	   vf->state == VF_FREE ? "Free" :
22158c2ecf20Sopenharmony_ci	   vf->state == VF_ACQUIRED ? "Acquired" :
22168c2ecf20Sopenharmony_ci	   vf->state == VF_ENABLED ? "Enabled" :
22178c2ecf20Sopenharmony_ci	   vf->state == VF_RESET ? "Reset" :
22188c2ecf20Sopenharmony_ci	   "Unknown");
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci	switch (vf->state) {
22218c2ecf20Sopenharmony_ci	case VF_ENABLED:
22228c2ecf20Sopenharmony_ci		rc = bnx2x_vf_close(bp, vf);
22238c2ecf20Sopenharmony_ci		if (rc)
22248c2ecf20Sopenharmony_ci			goto op_err;
22258c2ecf20Sopenharmony_ci		fallthrough;	/* to release resources */
22268c2ecf20Sopenharmony_ci	case VF_ACQUIRED:
22278c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "about to free resources\n");
22288c2ecf20Sopenharmony_ci		bnx2x_vf_free_resc(bp, vf);
22298c2ecf20Sopenharmony_ci		break;
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	case VF_FREE:
22328c2ecf20Sopenharmony_ci	case VF_RESET:
22338c2ecf20Sopenharmony_ci	default:
22348c2ecf20Sopenharmony_ci		break;
22358c2ecf20Sopenharmony_ci	}
22368c2ecf20Sopenharmony_ci	return 0;
22378c2ecf20Sopenharmony_ciop_err:
22388c2ecf20Sopenharmony_ci	BNX2X_ERR("VF[%d] RELEASE error: rc %d\n", vf->abs_vfid, rc);
22398c2ecf20Sopenharmony_ci	return rc;
22408c2ecf20Sopenharmony_ci}
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ciint bnx2x_vf_rss_update(struct bnx2x *bp, struct bnx2x_virtf *vf,
22438c2ecf20Sopenharmony_ci			struct bnx2x_config_rss_params *rss)
22448c2ecf20Sopenharmony_ci{
22458c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
22468c2ecf20Sopenharmony_ci	set_bit(RAMROD_COMP_WAIT, &rss->ramrod_flags);
22478c2ecf20Sopenharmony_ci	return bnx2x_config_rss(bp, rss);
22488c2ecf20Sopenharmony_ci}
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ciint bnx2x_vf_tpa_update(struct bnx2x *bp, struct bnx2x_virtf *vf,
22518c2ecf20Sopenharmony_ci			struct vfpf_tpa_tlv *tlv,
22528c2ecf20Sopenharmony_ci			struct bnx2x_queue_update_tpa_params *params)
22538c2ecf20Sopenharmony_ci{
22548c2ecf20Sopenharmony_ci	aligned_u64 *sge_addr = tlv->tpa_client_info.sge_addr;
22558c2ecf20Sopenharmony_ci	struct bnx2x_queue_state_params qstate;
22568c2ecf20Sopenharmony_ci	int qid, rc = 0;
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_ci	/* Set ramrod params */
22618c2ecf20Sopenharmony_ci	memset(&qstate, 0, sizeof(struct bnx2x_queue_state_params));
22628c2ecf20Sopenharmony_ci	memcpy(&qstate.params.update_tpa, params,
22638c2ecf20Sopenharmony_ci	       sizeof(struct bnx2x_queue_update_tpa_params));
22648c2ecf20Sopenharmony_ci	qstate.cmd = BNX2X_Q_CMD_UPDATE_TPA;
22658c2ecf20Sopenharmony_ci	set_bit(RAMROD_COMP_WAIT, &qstate.ramrod_flags);
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci	for (qid = 0; qid < vf_rxq_count(vf); qid++) {
22688c2ecf20Sopenharmony_ci		qstate.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
22698c2ecf20Sopenharmony_ci		qstate.params.update_tpa.sge_map = sge_addr[qid];
22708c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "sge_addr[%d:%d] %08x:%08x\n",
22718c2ecf20Sopenharmony_ci		   vf->abs_vfid, qid, U64_HI(sge_addr[qid]),
22728c2ecf20Sopenharmony_ci		   U64_LO(sge_addr[qid]));
22738c2ecf20Sopenharmony_ci		rc = bnx2x_queue_state_change(bp, &qstate);
22748c2ecf20Sopenharmony_ci		if (rc) {
22758c2ecf20Sopenharmony_ci			BNX2X_ERR("Failed to configure sge_addr %08x:%08x for [%d:%d]\n",
22768c2ecf20Sopenharmony_ci				  U64_HI(sge_addr[qid]), U64_LO(sge_addr[qid]),
22778c2ecf20Sopenharmony_ci				  vf->abs_vfid, qid);
22788c2ecf20Sopenharmony_ci			return rc;
22798c2ecf20Sopenharmony_ci		}
22808c2ecf20Sopenharmony_ci	}
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	return rc;
22838c2ecf20Sopenharmony_ci}
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci/* VF release ~ VF close + VF release-resources
22868c2ecf20Sopenharmony_ci * Release is the ultimate SW shutdown and is called whenever an
22878c2ecf20Sopenharmony_ci * irrecoverable error is encountered.
22888c2ecf20Sopenharmony_ci */
22898c2ecf20Sopenharmony_ciint bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
22908c2ecf20Sopenharmony_ci{
22918c2ecf20Sopenharmony_ci	int rc;
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "PF releasing vf %d\n", vf->abs_vfid);
22948c2ecf20Sopenharmony_ci	bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci	rc = bnx2x_vf_free(bp, vf);
22978c2ecf20Sopenharmony_ci	if (rc)
22988c2ecf20Sopenharmony_ci		WARN(rc,
22998c2ecf20Sopenharmony_ci		     "VF[%d] Failed to allocate resources for release op- rc=%d\n",
23008c2ecf20Sopenharmony_ci		     vf->abs_vfid, rc);
23018c2ecf20Sopenharmony_ci	bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
23028c2ecf20Sopenharmony_ci	return rc;
23038c2ecf20Sopenharmony_ci}
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_civoid bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
23068c2ecf20Sopenharmony_ci			      enum channel_tlvs tlv)
23078c2ecf20Sopenharmony_ci{
23088c2ecf20Sopenharmony_ci	/* we don't lock the channel for unsupported tlvs */
23098c2ecf20Sopenharmony_ci	if (!bnx2x_tlv_supported(tlv)) {
23108c2ecf20Sopenharmony_ci		BNX2X_ERR("attempting to lock with unsupported tlv. Aborting\n");
23118c2ecf20Sopenharmony_ci		return;
23128c2ecf20Sopenharmony_ci	}
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	/* lock the channel */
23158c2ecf20Sopenharmony_ci	mutex_lock(&vf->op_mutex);
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci	/* record the locking op */
23188c2ecf20Sopenharmony_ci	vf->op_current = tlv;
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_ci	/* log the lock */
23218c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel locked by %d\n",
23228c2ecf20Sopenharmony_ci	   vf->abs_vfid, tlv);
23238c2ecf20Sopenharmony_ci}
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_civoid bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
23268c2ecf20Sopenharmony_ci				enum channel_tlvs expected_tlv)
23278c2ecf20Sopenharmony_ci{
23288c2ecf20Sopenharmony_ci	enum channel_tlvs current_tlv;
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	if (!vf) {
23318c2ecf20Sopenharmony_ci		BNX2X_ERR("VF was %p\n", vf);
23328c2ecf20Sopenharmony_ci		return;
23338c2ecf20Sopenharmony_ci	}
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	current_tlv = vf->op_current;
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	/* we don't unlock the channel for unsupported tlvs */
23388c2ecf20Sopenharmony_ci	if (!bnx2x_tlv_supported(expected_tlv))
23398c2ecf20Sopenharmony_ci		return;
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	WARN(expected_tlv != vf->op_current,
23428c2ecf20Sopenharmony_ci	     "lock mismatch: expected %d found %d", expected_tlv,
23438c2ecf20Sopenharmony_ci	     vf->op_current);
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	/* record the locking op */
23468c2ecf20Sopenharmony_ci	vf->op_current = CHANNEL_TLV_NONE;
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci	/* lock the channel */
23498c2ecf20Sopenharmony_ci	mutex_unlock(&vf->op_mutex);
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_ci	/* log the unlock */
23528c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel unlocked by %d\n",
23538c2ecf20Sopenharmony_ci	   vf->abs_vfid, current_tlv);
23548c2ecf20Sopenharmony_ci}
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_cistatic int bnx2x_set_pf_tx_switching(struct bnx2x *bp, bool enable)
23578c2ecf20Sopenharmony_ci{
23588c2ecf20Sopenharmony_ci	struct bnx2x_queue_state_params q_params;
23598c2ecf20Sopenharmony_ci	u32 prev_flags;
23608c2ecf20Sopenharmony_ci	int i, rc;
23618c2ecf20Sopenharmony_ci
23628c2ecf20Sopenharmony_ci	/* Verify changes are needed and record current Tx switching state */
23638c2ecf20Sopenharmony_ci	prev_flags = bp->flags;
23648c2ecf20Sopenharmony_ci	if (enable)
23658c2ecf20Sopenharmony_ci		bp->flags |= TX_SWITCHING;
23668c2ecf20Sopenharmony_ci	else
23678c2ecf20Sopenharmony_ci		bp->flags &= ~TX_SWITCHING;
23688c2ecf20Sopenharmony_ci	if (prev_flags == bp->flags)
23698c2ecf20Sopenharmony_ci		return 0;
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	/* Verify state enables the sending of queue ramrods */
23728c2ecf20Sopenharmony_ci	if ((bp->state != BNX2X_STATE_OPEN) ||
23738c2ecf20Sopenharmony_ci	    (bnx2x_get_q_logical_state(bp,
23748c2ecf20Sopenharmony_ci				      &bnx2x_sp_obj(bp, &bp->fp[0]).q_obj) !=
23758c2ecf20Sopenharmony_ci	     BNX2X_Q_LOGICAL_STATE_ACTIVE))
23768c2ecf20Sopenharmony_ci		return 0;
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci	/* send q. update ramrod to configure Tx switching */
23798c2ecf20Sopenharmony_ci	memset(&q_params, 0, sizeof(q_params));
23808c2ecf20Sopenharmony_ci	__set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
23818c2ecf20Sopenharmony_ci	q_params.cmd = BNX2X_Q_CMD_UPDATE;
23828c2ecf20Sopenharmony_ci	__set_bit(BNX2X_Q_UPDATE_TX_SWITCHING_CHNG,
23838c2ecf20Sopenharmony_ci		  &q_params.params.update.update_flags);
23848c2ecf20Sopenharmony_ci	if (enable)
23858c2ecf20Sopenharmony_ci		__set_bit(BNX2X_Q_UPDATE_TX_SWITCHING,
23868c2ecf20Sopenharmony_ci			  &q_params.params.update.update_flags);
23878c2ecf20Sopenharmony_ci	else
23888c2ecf20Sopenharmony_ci		__clear_bit(BNX2X_Q_UPDATE_TX_SWITCHING,
23898c2ecf20Sopenharmony_ci			    &q_params.params.update.update_flags);
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci	/* send the ramrod on all the queues of the PF */
23928c2ecf20Sopenharmony_ci	for_each_eth_queue(bp, i) {
23938c2ecf20Sopenharmony_ci		struct bnx2x_fastpath *fp = &bp->fp[i];
23948c2ecf20Sopenharmony_ci		int tx_idx;
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci		/* Set the appropriate Queue object */
23978c2ecf20Sopenharmony_ci		q_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci		for (tx_idx = FIRST_TX_COS_INDEX;
24008c2ecf20Sopenharmony_ci		     tx_idx < fp->max_cos; tx_idx++) {
24018c2ecf20Sopenharmony_ci			q_params.params.update.cid_index = tx_idx;
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci			/* Update the Queue state */
24048c2ecf20Sopenharmony_ci			rc = bnx2x_queue_state_change(bp, &q_params);
24058c2ecf20Sopenharmony_ci			if (rc) {
24068c2ecf20Sopenharmony_ci				BNX2X_ERR("Failed to configure Tx switching\n");
24078c2ecf20Sopenharmony_ci				return rc;
24088c2ecf20Sopenharmony_ci			}
24098c2ecf20Sopenharmony_ci		}
24108c2ecf20Sopenharmony_ci	}
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "%s Tx Switching\n", enable ? "Enabled" : "Disabled");
24138c2ecf20Sopenharmony_ci	return 0;
24148c2ecf20Sopenharmony_ci}
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ciint bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs_param)
24178c2ecf20Sopenharmony_ci{
24188c2ecf20Sopenharmony_ci	struct bnx2x *bp = netdev_priv(pci_get_drvdata(dev));
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp)) {
24218c2ecf20Sopenharmony_ci		BNX2X_ERR("failed to configure SR-IOV since vfdb was not allocated. Check dmesg for errors in probe stage\n");
24228c2ecf20Sopenharmony_ci		return -EINVAL;
24238c2ecf20Sopenharmony_ci	}
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "bnx2x_sriov_configure called with %d, BNX2X_NR_VIRTFN(bp) was %d\n",
24268c2ecf20Sopenharmony_ci	   num_vfs_param, BNX2X_NR_VIRTFN(bp));
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci	/* HW channel is only operational when PF is up */
24298c2ecf20Sopenharmony_ci	if (bp->state != BNX2X_STATE_OPEN) {
24308c2ecf20Sopenharmony_ci		BNX2X_ERR("VF num configuration via sysfs not supported while PF is down\n");
24318c2ecf20Sopenharmony_ci		return -EINVAL;
24328c2ecf20Sopenharmony_ci	}
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	/* we are always bound by the total_vfs in the configuration space */
24358c2ecf20Sopenharmony_ci	if (num_vfs_param > BNX2X_NR_VIRTFN(bp)) {
24368c2ecf20Sopenharmony_ci		BNX2X_ERR("truncating requested number of VFs (%d) down to maximum allowed (%d)\n",
24378c2ecf20Sopenharmony_ci			  num_vfs_param, BNX2X_NR_VIRTFN(bp));
24388c2ecf20Sopenharmony_ci		num_vfs_param = BNX2X_NR_VIRTFN(bp);
24398c2ecf20Sopenharmony_ci	}
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	bp->requested_nr_virtfn = num_vfs_param;
24428c2ecf20Sopenharmony_ci	if (num_vfs_param == 0) {
24438c2ecf20Sopenharmony_ci		bnx2x_set_pf_tx_switching(bp, false);
24448c2ecf20Sopenharmony_ci		bnx2x_disable_sriov(bp);
24458c2ecf20Sopenharmony_ci		return 0;
24468c2ecf20Sopenharmony_ci	} else {
24478c2ecf20Sopenharmony_ci		return bnx2x_enable_sriov(bp);
24488c2ecf20Sopenharmony_ci	}
24498c2ecf20Sopenharmony_ci}
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_ci#define IGU_ENTRY_SIZE 4
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ciint bnx2x_enable_sriov(struct bnx2x *bp)
24548c2ecf20Sopenharmony_ci{
24558c2ecf20Sopenharmony_ci	int rc = 0, req_vfs = bp->requested_nr_virtfn;
24568c2ecf20Sopenharmony_ci	int vf_idx, sb_idx, vfq_idx, qcount, first_vf;
24578c2ecf20Sopenharmony_ci	u32 igu_entry, address;
24588c2ecf20Sopenharmony_ci	u16 num_vf_queues;
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	if (req_vfs == 0)
24618c2ecf20Sopenharmony_ci		return 0;
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_ci	first_vf = bp->vfdb->sriov.first_vf_in_pf;
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	/* statically distribute vf sb pool between VFs */
24668c2ecf20Sopenharmony_ci	num_vf_queues = min_t(u16, BNX2X_VF_MAX_QUEUES,
24678c2ecf20Sopenharmony_ci			      BP_VFDB(bp)->vf_sbs_pool / req_vfs);
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	/* zero previous values learned from igu cam */
24708c2ecf20Sopenharmony_ci	for (vf_idx = 0; vf_idx < req_vfs; vf_idx++) {
24718c2ecf20Sopenharmony_ci		struct bnx2x_virtf *vf = BP_VF(bp, vf_idx);
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_ci		vf->sb_count = 0;
24748c2ecf20Sopenharmony_ci		vf_sb_count(BP_VF(bp, vf_idx)) = 0;
24758c2ecf20Sopenharmony_ci	}
24768c2ecf20Sopenharmony_ci	bp->vfdb->vf_sbs_pool = 0;
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci	/* prepare IGU cam */
24798c2ecf20Sopenharmony_ci	sb_idx = BP_VFDB(bp)->first_vf_igu_entry;
24808c2ecf20Sopenharmony_ci	address = IGU_REG_MAPPING_MEMORY + sb_idx * IGU_ENTRY_SIZE;
24818c2ecf20Sopenharmony_ci	for (vf_idx = first_vf; vf_idx < first_vf + req_vfs; vf_idx++) {
24828c2ecf20Sopenharmony_ci		for (vfq_idx = 0; vfq_idx < num_vf_queues; vfq_idx++) {
24838c2ecf20Sopenharmony_ci			igu_entry = vf_idx << IGU_REG_MAPPING_MEMORY_FID_SHIFT |
24848c2ecf20Sopenharmony_ci				vfq_idx << IGU_REG_MAPPING_MEMORY_VECTOR_SHIFT |
24858c2ecf20Sopenharmony_ci				IGU_REG_MAPPING_MEMORY_VALID;
24868c2ecf20Sopenharmony_ci			DP(BNX2X_MSG_IOV, "assigning sb %d to vf %d\n",
24878c2ecf20Sopenharmony_ci			   sb_idx, vf_idx);
24888c2ecf20Sopenharmony_ci			REG_WR(bp, address, igu_entry);
24898c2ecf20Sopenharmony_ci			sb_idx++;
24908c2ecf20Sopenharmony_ci			address += IGU_ENTRY_SIZE;
24918c2ecf20Sopenharmony_ci		}
24928c2ecf20Sopenharmony_ci	}
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	/* Reinitialize vf database according to igu cam */
24958c2ecf20Sopenharmony_ci	bnx2x_get_vf_igu_cam_info(bp);
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "vf_sbs_pool %d, num_vf_queues %d\n",
24988c2ecf20Sopenharmony_ci	   BP_VFDB(bp)->vf_sbs_pool, num_vf_queues);
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	qcount = 0;
25018c2ecf20Sopenharmony_ci	for_each_vf(bp, vf_idx) {
25028c2ecf20Sopenharmony_ci		struct bnx2x_virtf *vf = BP_VF(bp, vf_idx);
25038c2ecf20Sopenharmony_ci
25048c2ecf20Sopenharmony_ci		/* set local queue arrays */
25058c2ecf20Sopenharmony_ci		vf->vfqs = &bp->vfdb->vfqs[qcount];
25068c2ecf20Sopenharmony_ci		qcount += vf_sb_count(vf);
25078c2ecf20Sopenharmony_ci		bnx2x_iov_static_resc(bp, vf);
25088c2ecf20Sopenharmony_ci	}
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci	/* prepare msix vectors in VF configuration space - the value in the
25118c2ecf20Sopenharmony_ci	 * PCI configuration space should be the index of the last entry,
25128c2ecf20Sopenharmony_ci	 * namely one less than the actual size of the table
25138c2ecf20Sopenharmony_ci	 */
25148c2ecf20Sopenharmony_ci	for (vf_idx = first_vf; vf_idx < first_vf + req_vfs; vf_idx++) {
25158c2ecf20Sopenharmony_ci		bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf_idx));
25168c2ecf20Sopenharmony_ci		REG_WR(bp, PCICFG_OFFSET + GRC_CONFIG_REG_VF_MSIX_CONTROL,
25178c2ecf20Sopenharmony_ci		       num_vf_queues - 1);
25188c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "set msix vec num in VF %d cfg space to %d\n",
25198c2ecf20Sopenharmony_ci		   vf_idx, num_vf_queues - 1);
25208c2ecf20Sopenharmony_ci	}
25218c2ecf20Sopenharmony_ci	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci	/* enable sriov. This will probe all the VFs, and consequentially cause
25248c2ecf20Sopenharmony_ci	 * the "acquire" messages to appear on the VF PF channel.
25258c2ecf20Sopenharmony_ci	 */
25268c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "about to call enable sriov\n");
25278c2ecf20Sopenharmony_ci	bnx2x_disable_sriov(bp);
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci	rc = bnx2x_set_pf_tx_switching(bp, true);
25308c2ecf20Sopenharmony_ci	if (rc)
25318c2ecf20Sopenharmony_ci		return rc;
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci	rc = pci_enable_sriov(bp->pdev, req_vfs);
25348c2ecf20Sopenharmony_ci	if (rc) {
25358c2ecf20Sopenharmony_ci		BNX2X_ERR("pci_enable_sriov failed with %d\n", rc);
25368c2ecf20Sopenharmony_ci		return rc;
25378c2ecf20Sopenharmony_ci	}
25388c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "sriov enabled (%d vfs)\n", req_vfs);
25398c2ecf20Sopenharmony_ci	return req_vfs;
25408c2ecf20Sopenharmony_ci}
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_civoid bnx2x_pf_set_vfs_vlan(struct bnx2x *bp)
25438c2ecf20Sopenharmony_ci{
25448c2ecf20Sopenharmony_ci	int vfidx;
25458c2ecf20Sopenharmony_ci	struct pf_vf_bulletin_content *bulletin;
25468c2ecf20Sopenharmony_ci
25478c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "configuring vlan for VFs from sp-task\n");
25488c2ecf20Sopenharmony_ci	for_each_vf(bp, vfidx) {
25498c2ecf20Sopenharmony_ci		bulletin = BP_VF_BULLETIN(bp, vfidx);
25508c2ecf20Sopenharmony_ci		if (bulletin->valid_bitmap & (1 << VLAN_VALID))
25518c2ecf20Sopenharmony_ci			bnx2x_set_vf_vlan(bp->dev, vfidx, bulletin->vlan, 0,
25528c2ecf20Sopenharmony_ci					  htons(ETH_P_8021Q));
25538c2ecf20Sopenharmony_ci	}
25548c2ecf20Sopenharmony_ci}
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_civoid bnx2x_disable_sriov(struct bnx2x *bp)
25578c2ecf20Sopenharmony_ci{
25588c2ecf20Sopenharmony_ci	if (pci_vfs_assigned(bp->pdev)) {
25598c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV,
25608c2ecf20Sopenharmony_ci		   "Unloading driver while VFs are assigned - VFs will not be deallocated\n");
25618c2ecf20Sopenharmony_ci		return;
25628c2ecf20Sopenharmony_ci	}
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci	pci_disable_sriov(bp->pdev);
25658c2ecf20Sopenharmony_ci}
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_cistatic int bnx2x_vf_op_prep(struct bnx2x *bp, int vfidx,
25688c2ecf20Sopenharmony_ci			    struct bnx2x_virtf **vf,
25698c2ecf20Sopenharmony_ci			    struct pf_vf_bulletin_content **bulletin,
25708c2ecf20Sopenharmony_ci			    bool test_queue)
25718c2ecf20Sopenharmony_ci{
25728c2ecf20Sopenharmony_ci	if (bp->state != BNX2X_STATE_OPEN) {
25738c2ecf20Sopenharmony_ci		BNX2X_ERR("PF is down - can't utilize iov-related functionality\n");
25748c2ecf20Sopenharmony_ci		return -EINVAL;
25758c2ecf20Sopenharmony_ci	}
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp)) {
25788c2ecf20Sopenharmony_ci		BNX2X_ERR("sriov is disabled - can't utilize iov-related functionality\n");
25798c2ecf20Sopenharmony_ci		return -EINVAL;
25808c2ecf20Sopenharmony_ci	}
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci	if (vfidx >= BNX2X_NR_VIRTFN(bp)) {
25838c2ecf20Sopenharmony_ci		BNX2X_ERR("VF is uninitialized - can't utilize iov-related functionality. vfidx was %d BNX2X_NR_VIRTFN was %d\n",
25848c2ecf20Sopenharmony_ci			  vfidx, BNX2X_NR_VIRTFN(bp));
25858c2ecf20Sopenharmony_ci		return -EINVAL;
25868c2ecf20Sopenharmony_ci	}
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci	/* init members */
25898c2ecf20Sopenharmony_ci	*vf = BP_VF(bp, vfidx);
25908c2ecf20Sopenharmony_ci	*bulletin = BP_VF_BULLETIN(bp, vfidx);
25918c2ecf20Sopenharmony_ci
25928c2ecf20Sopenharmony_ci	if (!*vf) {
25938c2ecf20Sopenharmony_ci		BNX2X_ERR("Unable to get VF structure for vfidx %d\n", vfidx);
25948c2ecf20Sopenharmony_ci		return -EINVAL;
25958c2ecf20Sopenharmony_ci	}
25968c2ecf20Sopenharmony_ci
25978c2ecf20Sopenharmony_ci	if (test_queue && !(*vf)->vfqs) {
25988c2ecf20Sopenharmony_ci		BNX2X_ERR("vfqs struct is null. Was this invoked before dynamically enabling SR-IOV? vfidx was %d\n",
25998c2ecf20Sopenharmony_ci			  vfidx);
26008c2ecf20Sopenharmony_ci		return -EINVAL;
26018c2ecf20Sopenharmony_ci	}
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci	if (!*bulletin) {
26048c2ecf20Sopenharmony_ci		BNX2X_ERR("Bulletin Board struct is null for vfidx %d\n",
26058c2ecf20Sopenharmony_ci			  vfidx);
26068c2ecf20Sopenharmony_ci		return -EINVAL;
26078c2ecf20Sopenharmony_ci	}
26088c2ecf20Sopenharmony_ci
26098c2ecf20Sopenharmony_ci	return 0;
26108c2ecf20Sopenharmony_ci}
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ciint bnx2x_get_vf_config(struct net_device *dev, int vfidx,
26138c2ecf20Sopenharmony_ci			struct ifla_vf_info *ivi)
26148c2ecf20Sopenharmony_ci{
26158c2ecf20Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
26168c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf = NULL;
26178c2ecf20Sopenharmony_ci	struct pf_vf_bulletin_content *bulletin = NULL;
26188c2ecf20Sopenharmony_ci	struct bnx2x_vlan_mac_obj *mac_obj;
26198c2ecf20Sopenharmony_ci	struct bnx2x_vlan_mac_obj *vlan_obj;
26208c2ecf20Sopenharmony_ci	int rc;
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	/* sanity and init */
26238c2ecf20Sopenharmony_ci	rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true);
26248c2ecf20Sopenharmony_ci	if (rc)
26258c2ecf20Sopenharmony_ci		return rc;
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	mac_obj = &bnx2x_leading_vfq(vf, mac_obj);
26288c2ecf20Sopenharmony_ci	vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj);
26298c2ecf20Sopenharmony_ci	if (!mac_obj || !vlan_obj) {
26308c2ecf20Sopenharmony_ci		BNX2X_ERR("VF partially initialized\n");
26318c2ecf20Sopenharmony_ci		return -EINVAL;
26328c2ecf20Sopenharmony_ci	}
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci	ivi->vf = vfidx;
26358c2ecf20Sopenharmony_ci	ivi->qos = 0;
26368c2ecf20Sopenharmony_ci	ivi->max_tx_rate = 10000; /* always 10G. TBA take from link struct */
26378c2ecf20Sopenharmony_ci	ivi->min_tx_rate = 0;
26388c2ecf20Sopenharmony_ci	ivi->spoofchk = vf->spoofchk ? 1 : 0;
26398c2ecf20Sopenharmony_ci	ivi->linkstate = vf->link_cfg;
26408c2ecf20Sopenharmony_ci	if (vf->state == VF_ENABLED) {
26418c2ecf20Sopenharmony_ci		/* mac and vlan are in vlan_mac objects */
26428c2ecf20Sopenharmony_ci		if (bnx2x_validate_vf_sp_objs(bp, vf, false)) {
26438c2ecf20Sopenharmony_ci			mac_obj->get_n_elements(bp, mac_obj, 1, (u8 *)&ivi->mac,
26448c2ecf20Sopenharmony_ci						0, ETH_ALEN);
26458c2ecf20Sopenharmony_ci			vlan_obj->get_n_elements(bp, vlan_obj, 1,
26468c2ecf20Sopenharmony_ci						 (u8 *)&ivi->vlan, 0,
26478c2ecf20Sopenharmony_ci						 VLAN_HLEN);
26488c2ecf20Sopenharmony_ci		}
26498c2ecf20Sopenharmony_ci	} else {
26508c2ecf20Sopenharmony_ci		mutex_lock(&bp->vfdb->bulletin_mutex);
26518c2ecf20Sopenharmony_ci		/* mac */
26528c2ecf20Sopenharmony_ci		if (bulletin->valid_bitmap & (1 << MAC_ADDR_VALID))
26538c2ecf20Sopenharmony_ci			/* mac configured by ndo so its in bulletin board */
26548c2ecf20Sopenharmony_ci			memcpy(&ivi->mac, bulletin->mac, ETH_ALEN);
26558c2ecf20Sopenharmony_ci		else
26568c2ecf20Sopenharmony_ci			/* function has not been loaded yet. Show mac as 0s */
26578c2ecf20Sopenharmony_ci			eth_zero_addr(ivi->mac);
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci		/* vlan */
26608c2ecf20Sopenharmony_ci		if (bulletin->valid_bitmap & (1 << VLAN_VALID))
26618c2ecf20Sopenharmony_ci			/* vlan configured by ndo so its in bulletin board */
26628c2ecf20Sopenharmony_ci			memcpy(&ivi->vlan, &bulletin->vlan, VLAN_HLEN);
26638c2ecf20Sopenharmony_ci		else
26648c2ecf20Sopenharmony_ci			/* function has not been loaded yet. Show vlans as 0s */
26658c2ecf20Sopenharmony_ci			memset(&ivi->vlan, 0, VLAN_HLEN);
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci		mutex_unlock(&bp->vfdb->bulletin_mutex);
26688c2ecf20Sopenharmony_ci	}
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	return 0;
26718c2ecf20Sopenharmony_ci}
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci/* New mac for VF. Consider these cases:
26748c2ecf20Sopenharmony_ci * 1. VF hasn't been acquired yet - save the mac in local bulletin board and
26758c2ecf20Sopenharmony_ci *    supply at acquire.
26768c2ecf20Sopenharmony_ci * 2. VF has already been acquired but has not yet initialized - store in local
26778c2ecf20Sopenharmony_ci *    bulletin board. mac will be posted on VF bulletin board after VF init. VF
26788c2ecf20Sopenharmony_ci *    will configure this mac when it is ready.
26798c2ecf20Sopenharmony_ci * 3. VF has already initialized but has not yet setup a queue - post the new
26808c2ecf20Sopenharmony_ci *    mac on VF's bulletin board right now. VF will configure this mac when it
26818c2ecf20Sopenharmony_ci *    is ready.
26828c2ecf20Sopenharmony_ci * 4. VF has already set a queue - delete any macs already configured for this
26838c2ecf20Sopenharmony_ci *    queue and manually config the new mac.
26848c2ecf20Sopenharmony_ci * In any event, once this function has been called refuse any attempts by the
26858c2ecf20Sopenharmony_ci * VF to configure any mac for itself except for this mac. In case of a race
26868c2ecf20Sopenharmony_ci * where the VF fails to see the new post on its bulletin board before sending a
26878c2ecf20Sopenharmony_ci * mac configuration request, the PF will simply fail the request and VF can try
26888c2ecf20Sopenharmony_ci * again after consulting its bulletin board.
26898c2ecf20Sopenharmony_ci */
26908c2ecf20Sopenharmony_ciint bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
26918c2ecf20Sopenharmony_ci{
26928c2ecf20Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
26938c2ecf20Sopenharmony_ci	int rc, q_logical_state;
26948c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf = NULL;
26958c2ecf20Sopenharmony_ci	struct pf_vf_bulletin_content *bulletin = NULL;
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(mac)) {
26988c2ecf20Sopenharmony_ci		BNX2X_ERR("mac address invalid\n");
26998c2ecf20Sopenharmony_ci		return -EINVAL;
27008c2ecf20Sopenharmony_ci	}
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_ci	/* sanity and init */
27038c2ecf20Sopenharmony_ci	rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true);
27048c2ecf20Sopenharmony_ci	if (rc)
27058c2ecf20Sopenharmony_ci		return rc;
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci	mutex_lock(&bp->vfdb->bulletin_mutex);
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_ci	/* update PF's copy of the VF's bulletin. Will no longer accept mac
27108c2ecf20Sopenharmony_ci	 * configuration requests from vf unless match this mac
27118c2ecf20Sopenharmony_ci	 */
27128c2ecf20Sopenharmony_ci	bulletin->valid_bitmap |= 1 << MAC_ADDR_VALID;
27138c2ecf20Sopenharmony_ci	memcpy(bulletin->mac, mac, ETH_ALEN);
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_ci	/* Post update on VF's bulletin board */
27168c2ecf20Sopenharmony_ci	rc = bnx2x_post_vf_bulletin(bp, vfidx);
27178c2ecf20Sopenharmony_ci
27188c2ecf20Sopenharmony_ci	/* release lock before checking return code */
27198c2ecf20Sopenharmony_ci	mutex_unlock(&bp->vfdb->bulletin_mutex);
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	if (rc) {
27228c2ecf20Sopenharmony_ci		BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx);
27238c2ecf20Sopenharmony_ci		return rc;
27248c2ecf20Sopenharmony_ci	}
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci	q_logical_state =
27278c2ecf20Sopenharmony_ci		bnx2x_get_q_logical_state(bp, &bnx2x_leading_vfq(vf, sp_obj));
27288c2ecf20Sopenharmony_ci	if (vf->state == VF_ENABLED &&
27298c2ecf20Sopenharmony_ci	    q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
27308c2ecf20Sopenharmony_ci		/* configure the mac in device on this vf's queue */
27318c2ecf20Sopenharmony_ci		unsigned long ramrod_flags = 0;
27328c2ecf20Sopenharmony_ci		struct bnx2x_vlan_mac_obj *mac_obj;
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci		/* User should be able to see failure reason in system logs */
27358c2ecf20Sopenharmony_ci		if (!bnx2x_validate_vf_sp_objs(bp, vf, true))
27368c2ecf20Sopenharmony_ci			return -EINVAL;
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci		/* must lock vfpf channel to protect against vf flows */
27398c2ecf20Sopenharmony_ci		bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
27408c2ecf20Sopenharmony_ci
27418c2ecf20Sopenharmony_ci		/* remove existing eth macs */
27428c2ecf20Sopenharmony_ci		mac_obj = &bnx2x_leading_vfq(vf, mac_obj);
27438c2ecf20Sopenharmony_ci		rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true);
27448c2ecf20Sopenharmony_ci		if (rc) {
27458c2ecf20Sopenharmony_ci			BNX2X_ERR("failed to delete eth macs\n");
27468c2ecf20Sopenharmony_ci			rc = -EINVAL;
27478c2ecf20Sopenharmony_ci			goto out;
27488c2ecf20Sopenharmony_ci		}
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_ci		/* remove existing uc list macs */
27518c2ecf20Sopenharmony_ci		rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_UC_LIST_MAC, true);
27528c2ecf20Sopenharmony_ci		if (rc) {
27538c2ecf20Sopenharmony_ci			BNX2X_ERR("failed to delete uc_list macs\n");
27548c2ecf20Sopenharmony_ci			rc = -EINVAL;
27558c2ecf20Sopenharmony_ci			goto out;
27568c2ecf20Sopenharmony_ci		}
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci		/* configure the new mac to device */
27598c2ecf20Sopenharmony_ci		__set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
27608c2ecf20Sopenharmony_ci		bnx2x_set_mac_one(bp, (u8 *)&bulletin->mac, mac_obj, true,
27618c2ecf20Sopenharmony_ci				  BNX2X_ETH_MAC, &ramrod_flags);
27628c2ecf20Sopenharmony_ci
27638c2ecf20Sopenharmony_ciout:
27648c2ecf20Sopenharmony_ci		bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
27658c2ecf20Sopenharmony_ci	}
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci	return rc;
27688c2ecf20Sopenharmony_ci}
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_cistatic void bnx2x_set_vf_vlan_acceptance(struct bnx2x *bp,
27718c2ecf20Sopenharmony_ci					 struct bnx2x_virtf *vf, bool accept)
27728c2ecf20Sopenharmony_ci{
27738c2ecf20Sopenharmony_ci	struct bnx2x_rx_mode_ramrod_params rx_ramrod;
27748c2ecf20Sopenharmony_ci	unsigned long accept_flags;
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	/* need to remove/add the VF's accept_any_vlan bit */
27778c2ecf20Sopenharmony_ci	accept_flags = bnx2x_leading_vfq(vf, accept_flags);
27788c2ecf20Sopenharmony_ci	if (accept)
27798c2ecf20Sopenharmony_ci		set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags);
27808c2ecf20Sopenharmony_ci	else
27818c2ecf20Sopenharmony_ci		clear_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags);
27828c2ecf20Sopenharmony_ci
27838c2ecf20Sopenharmony_ci	bnx2x_vf_prep_rx_mode(bp, LEADING_IDX, &rx_ramrod, vf,
27848c2ecf20Sopenharmony_ci			      accept_flags);
27858c2ecf20Sopenharmony_ci	bnx2x_leading_vfq(vf, accept_flags) = accept_flags;
27868c2ecf20Sopenharmony_ci	bnx2x_config_rx_mode(bp, &rx_ramrod);
27878c2ecf20Sopenharmony_ci}
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_cistatic int bnx2x_set_vf_vlan_filter(struct bnx2x *bp, struct bnx2x_virtf *vf,
27908c2ecf20Sopenharmony_ci				    u16 vlan, bool add)
27918c2ecf20Sopenharmony_ci{
27928c2ecf20Sopenharmony_ci	struct bnx2x_vlan_mac_ramrod_params ramrod_param;
27938c2ecf20Sopenharmony_ci	unsigned long ramrod_flags = 0;
27948c2ecf20Sopenharmony_ci	int rc = 0;
27958c2ecf20Sopenharmony_ci
27968c2ecf20Sopenharmony_ci	/* configure the new vlan to device */
27978c2ecf20Sopenharmony_ci	memset(&ramrod_param, 0, sizeof(ramrod_param));
27988c2ecf20Sopenharmony_ci	__set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
27998c2ecf20Sopenharmony_ci	ramrod_param.vlan_mac_obj = &bnx2x_leading_vfq(vf, vlan_obj);
28008c2ecf20Sopenharmony_ci	ramrod_param.ramrod_flags = ramrod_flags;
28018c2ecf20Sopenharmony_ci	ramrod_param.user_req.u.vlan.vlan = vlan;
28028c2ecf20Sopenharmony_ci	ramrod_param.user_req.cmd = add ? BNX2X_VLAN_MAC_ADD
28038c2ecf20Sopenharmony_ci					: BNX2X_VLAN_MAC_DEL;
28048c2ecf20Sopenharmony_ci	rc = bnx2x_config_vlan_mac(bp, &ramrod_param);
28058c2ecf20Sopenharmony_ci	if (rc) {
28068c2ecf20Sopenharmony_ci		BNX2X_ERR("failed to configure vlan\n");
28078c2ecf20Sopenharmony_ci		return -EINVAL;
28088c2ecf20Sopenharmony_ci	}
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ci	return 0;
28118c2ecf20Sopenharmony_ci}
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ciint bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos,
28148c2ecf20Sopenharmony_ci		      __be16 vlan_proto)
28158c2ecf20Sopenharmony_ci{
28168c2ecf20Sopenharmony_ci	struct pf_vf_bulletin_content *bulletin = NULL;
28178c2ecf20Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
28188c2ecf20Sopenharmony_ci	struct bnx2x_vlan_mac_obj *vlan_obj;
28198c2ecf20Sopenharmony_ci	unsigned long vlan_mac_flags = 0;
28208c2ecf20Sopenharmony_ci	unsigned long ramrod_flags = 0;
28218c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf = NULL;
28228c2ecf20Sopenharmony_ci	int i, rc;
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	if (vlan > 4095) {
28258c2ecf20Sopenharmony_ci		BNX2X_ERR("illegal vlan value %d\n", vlan);
28268c2ecf20Sopenharmony_ci		return -EINVAL;
28278c2ecf20Sopenharmony_ci	}
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci	if (vlan_proto != htons(ETH_P_8021Q))
28308c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "configuring VF %d with VLAN %d qos %d\n",
28338c2ecf20Sopenharmony_ci	   vfidx, vlan, 0);
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_ci	/* sanity and init */
28368c2ecf20Sopenharmony_ci	rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true);
28378c2ecf20Sopenharmony_ci	if (rc)
28388c2ecf20Sopenharmony_ci		return rc;
28398c2ecf20Sopenharmony_ci
28408c2ecf20Sopenharmony_ci	/* update PF's copy of the VF's bulletin. No point in posting the vlan
28418c2ecf20Sopenharmony_ci	 * to the VF since it doesn't have anything to do with it. But it useful
28428c2ecf20Sopenharmony_ci	 * to store it here in case the VF is not up yet and we can only
28438c2ecf20Sopenharmony_ci	 * configure the vlan later when it does. Treat vlan id 0 as remove the
28448c2ecf20Sopenharmony_ci	 * Host tag.
28458c2ecf20Sopenharmony_ci	 */
28468c2ecf20Sopenharmony_ci	mutex_lock(&bp->vfdb->bulletin_mutex);
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_ci	if (vlan > 0)
28498c2ecf20Sopenharmony_ci		bulletin->valid_bitmap |= 1 << VLAN_VALID;
28508c2ecf20Sopenharmony_ci	else
28518c2ecf20Sopenharmony_ci		bulletin->valid_bitmap &= ~(1 << VLAN_VALID);
28528c2ecf20Sopenharmony_ci	bulletin->vlan = vlan;
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci	/* Post update on VF's bulletin board */
28558c2ecf20Sopenharmony_ci	rc = bnx2x_post_vf_bulletin(bp, vfidx);
28568c2ecf20Sopenharmony_ci	if (rc)
28578c2ecf20Sopenharmony_ci		BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx);
28588c2ecf20Sopenharmony_ci	mutex_unlock(&bp->vfdb->bulletin_mutex);
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci	/* is vf initialized and queue set up? */
28618c2ecf20Sopenharmony_ci	if (vf->state != VF_ENABLED ||
28628c2ecf20Sopenharmony_ci	    bnx2x_get_q_logical_state(bp, &bnx2x_leading_vfq(vf, sp_obj)) !=
28638c2ecf20Sopenharmony_ci	    BNX2X_Q_LOGICAL_STATE_ACTIVE)
28648c2ecf20Sopenharmony_ci		return rc;
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci	/* User should be able to see error in system logs */
28678c2ecf20Sopenharmony_ci	if (!bnx2x_validate_vf_sp_objs(bp, vf, true))
28688c2ecf20Sopenharmony_ci		return -EINVAL;
28698c2ecf20Sopenharmony_ci
28708c2ecf20Sopenharmony_ci	/* must lock vfpf channel to protect against vf flows */
28718c2ecf20Sopenharmony_ci	bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN);
28728c2ecf20Sopenharmony_ci
28738c2ecf20Sopenharmony_ci	/* remove existing vlans */
28748c2ecf20Sopenharmony_ci	__set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
28758c2ecf20Sopenharmony_ci	vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj);
28768c2ecf20Sopenharmony_ci	rc = vlan_obj->delete_all(bp, vlan_obj, &vlan_mac_flags,
28778c2ecf20Sopenharmony_ci				  &ramrod_flags);
28788c2ecf20Sopenharmony_ci	if (rc) {
28798c2ecf20Sopenharmony_ci		BNX2X_ERR("failed to delete vlans\n");
28808c2ecf20Sopenharmony_ci		rc = -EINVAL;
28818c2ecf20Sopenharmony_ci		goto out;
28828c2ecf20Sopenharmony_ci	}
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_ci	/* clear accept_any_vlan when HV forces vlan, otherwise
28858c2ecf20Sopenharmony_ci	 * according to VF capabilities
28868c2ecf20Sopenharmony_ci	 */
28878c2ecf20Sopenharmony_ci	if (vlan || !(vf->cfg_flags & VF_CFG_VLAN_FILTER))
28888c2ecf20Sopenharmony_ci		bnx2x_set_vf_vlan_acceptance(bp, vf, !vlan);
28898c2ecf20Sopenharmony_ci
28908c2ecf20Sopenharmony_ci	rc = bnx2x_set_vf_vlan_filter(bp, vf, vlan, true);
28918c2ecf20Sopenharmony_ci	if (rc)
28928c2ecf20Sopenharmony_ci		goto out;
28938c2ecf20Sopenharmony_ci
28948c2ecf20Sopenharmony_ci	/* send queue update ramrods to configure default vlan and
28958c2ecf20Sopenharmony_ci	 * silent vlan removal
28968c2ecf20Sopenharmony_ci	 */
28978c2ecf20Sopenharmony_ci	for_each_vfq(vf, i) {
28988c2ecf20Sopenharmony_ci		struct bnx2x_queue_state_params q_params = {NULL};
28998c2ecf20Sopenharmony_ci		struct bnx2x_queue_update_params *update_params;
29008c2ecf20Sopenharmony_ci
29018c2ecf20Sopenharmony_ci		q_params.q_obj = &bnx2x_vfq(vf, i, sp_obj);
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci		/* validate the Q is UP */
29048c2ecf20Sopenharmony_ci		if (bnx2x_get_q_logical_state(bp, q_params.q_obj) !=
29058c2ecf20Sopenharmony_ci		    BNX2X_Q_LOGICAL_STATE_ACTIVE)
29068c2ecf20Sopenharmony_ci			continue;
29078c2ecf20Sopenharmony_ci
29088c2ecf20Sopenharmony_ci		__set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
29098c2ecf20Sopenharmony_ci		q_params.cmd = BNX2X_Q_CMD_UPDATE;
29108c2ecf20Sopenharmony_ci		update_params = &q_params.params.update;
29118c2ecf20Sopenharmony_ci		__set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG,
29128c2ecf20Sopenharmony_ci			  &update_params->update_flags);
29138c2ecf20Sopenharmony_ci		__set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG,
29148c2ecf20Sopenharmony_ci			  &update_params->update_flags);
29158c2ecf20Sopenharmony_ci		if (vlan == 0) {
29168c2ecf20Sopenharmony_ci			/* if vlan is 0 then we want to leave the VF traffic
29178c2ecf20Sopenharmony_ci			 * untagged, and leave the incoming traffic untouched
29188c2ecf20Sopenharmony_ci			 * (i.e. do not remove any vlan tags).
29198c2ecf20Sopenharmony_ci			 */
29208c2ecf20Sopenharmony_ci			__clear_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN,
29218c2ecf20Sopenharmony_ci				    &update_params->update_flags);
29228c2ecf20Sopenharmony_ci			__clear_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM,
29238c2ecf20Sopenharmony_ci				    &update_params->update_flags);
29248c2ecf20Sopenharmony_ci		} else {
29258c2ecf20Sopenharmony_ci			/* configure default vlan to vf queue and set silent
29268c2ecf20Sopenharmony_ci			 * vlan removal (the vf remains unaware of this vlan).
29278c2ecf20Sopenharmony_ci			 */
29288c2ecf20Sopenharmony_ci			__set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN,
29298c2ecf20Sopenharmony_ci				  &update_params->update_flags);
29308c2ecf20Sopenharmony_ci			__set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM,
29318c2ecf20Sopenharmony_ci				  &update_params->update_flags);
29328c2ecf20Sopenharmony_ci			update_params->def_vlan = vlan;
29338c2ecf20Sopenharmony_ci			update_params->silent_removal_value =
29348c2ecf20Sopenharmony_ci				vlan & VLAN_VID_MASK;
29358c2ecf20Sopenharmony_ci			update_params->silent_removal_mask = VLAN_VID_MASK;
29368c2ecf20Sopenharmony_ci		}
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_ci		/* Update the Queue state */
29398c2ecf20Sopenharmony_ci		rc = bnx2x_queue_state_change(bp, &q_params);
29408c2ecf20Sopenharmony_ci		if (rc) {
29418c2ecf20Sopenharmony_ci			BNX2X_ERR("Failed to configure default VLAN queue %d\n",
29428c2ecf20Sopenharmony_ci				  i);
29438c2ecf20Sopenharmony_ci			goto out;
29448c2ecf20Sopenharmony_ci		}
29458c2ecf20Sopenharmony_ci	}
29468c2ecf20Sopenharmony_ciout:
29478c2ecf20Sopenharmony_ci	bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN);
29488c2ecf20Sopenharmony_ci
29498c2ecf20Sopenharmony_ci	if (rc)
29508c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV,
29518c2ecf20Sopenharmony_ci		   "updated VF[%d] vlan configuration (vlan = %d)\n",
29528c2ecf20Sopenharmony_ci		   vfidx, vlan);
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci	return rc;
29558c2ecf20Sopenharmony_ci}
29568c2ecf20Sopenharmony_ci
29578c2ecf20Sopenharmony_ciint bnx2x_set_vf_spoofchk(struct net_device *dev, int idx, bool val)
29588c2ecf20Sopenharmony_ci{
29598c2ecf20Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
29608c2ecf20Sopenharmony_ci	struct bnx2x_virtf *vf;
29618c2ecf20Sopenharmony_ci	int i, rc = 0;
29628c2ecf20Sopenharmony_ci
29638c2ecf20Sopenharmony_ci	vf = BP_VF(bp, idx);
29648c2ecf20Sopenharmony_ci	if (!vf)
29658c2ecf20Sopenharmony_ci		return -EINVAL;
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci	/* nothing to do */
29688c2ecf20Sopenharmony_ci	if (vf->spoofchk == val)
29698c2ecf20Sopenharmony_ci		return 0;
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	vf->spoofchk = val ? 1 : 0;
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "%s spoofchk for VF %d\n",
29748c2ecf20Sopenharmony_ci	   val ? "enabling" : "disabling", idx);
29758c2ecf20Sopenharmony_ci
29768c2ecf20Sopenharmony_ci	/* is vf initialized and queue set up? */
29778c2ecf20Sopenharmony_ci	if (vf->state != VF_ENABLED ||
29788c2ecf20Sopenharmony_ci	    bnx2x_get_q_logical_state(bp, &bnx2x_leading_vfq(vf, sp_obj)) !=
29798c2ecf20Sopenharmony_ci	    BNX2X_Q_LOGICAL_STATE_ACTIVE)
29808c2ecf20Sopenharmony_ci		return rc;
29818c2ecf20Sopenharmony_ci
29828c2ecf20Sopenharmony_ci	/* User should be able to see error in system logs */
29838c2ecf20Sopenharmony_ci	if (!bnx2x_validate_vf_sp_objs(bp, vf, true))
29848c2ecf20Sopenharmony_ci		return -EINVAL;
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci	/* send queue update ramrods to configure spoofchk */
29878c2ecf20Sopenharmony_ci	for_each_vfq(vf, i) {
29888c2ecf20Sopenharmony_ci		struct bnx2x_queue_state_params q_params = {NULL};
29898c2ecf20Sopenharmony_ci		struct bnx2x_queue_update_params *update_params;
29908c2ecf20Sopenharmony_ci
29918c2ecf20Sopenharmony_ci		q_params.q_obj = &bnx2x_vfq(vf, i, sp_obj);
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_ci		/* validate the Q is UP */
29948c2ecf20Sopenharmony_ci		if (bnx2x_get_q_logical_state(bp, q_params.q_obj) !=
29958c2ecf20Sopenharmony_ci		    BNX2X_Q_LOGICAL_STATE_ACTIVE)
29968c2ecf20Sopenharmony_ci			continue;
29978c2ecf20Sopenharmony_ci
29988c2ecf20Sopenharmony_ci		__set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
29998c2ecf20Sopenharmony_ci		q_params.cmd = BNX2X_Q_CMD_UPDATE;
30008c2ecf20Sopenharmony_ci		update_params = &q_params.params.update;
30018c2ecf20Sopenharmony_ci		__set_bit(BNX2X_Q_UPDATE_ANTI_SPOOF_CHNG,
30028c2ecf20Sopenharmony_ci			  &update_params->update_flags);
30038c2ecf20Sopenharmony_ci		if (val) {
30048c2ecf20Sopenharmony_ci			__set_bit(BNX2X_Q_UPDATE_ANTI_SPOOF,
30058c2ecf20Sopenharmony_ci				  &update_params->update_flags);
30068c2ecf20Sopenharmony_ci		} else {
30078c2ecf20Sopenharmony_ci			__clear_bit(BNX2X_Q_UPDATE_ANTI_SPOOF,
30088c2ecf20Sopenharmony_ci				    &update_params->update_flags);
30098c2ecf20Sopenharmony_ci		}
30108c2ecf20Sopenharmony_ci
30118c2ecf20Sopenharmony_ci		/* Update the Queue state */
30128c2ecf20Sopenharmony_ci		rc = bnx2x_queue_state_change(bp, &q_params);
30138c2ecf20Sopenharmony_ci		if (rc) {
30148c2ecf20Sopenharmony_ci			BNX2X_ERR("Failed to %s spoofchk on VF %d - vfq %d\n",
30158c2ecf20Sopenharmony_ci				  val ? "enable" : "disable", idx, i);
30168c2ecf20Sopenharmony_ci			goto out;
30178c2ecf20Sopenharmony_ci		}
30188c2ecf20Sopenharmony_ci	}
30198c2ecf20Sopenharmony_ciout:
30208c2ecf20Sopenharmony_ci	if (!rc)
30218c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV,
30228c2ecf20Sopenharmony_ci		   "%s spoofchk for VF[%d]\n", val ? "Enabled" : "Disabled",
30238c2ecf20Sopenharmony_ci		   idx);
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	return rc;
30268c2ecf20Sopenharmony_ci}
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci/* crc is the first field in the bulletin board. Compute the crc over the
30298c2ecf20Sopenharmony_ci * entire bulletin board excluding the crc field itself. Use the length field
30308c2ecf20Sopenharmony_ci * as the Bulletin Board was posted by a PF with possibly a different version
30318c2ecf20Sopenharmony_ci * from the vf which will sample it. Therefore, the length is computed by the
30328c2ecf20Sopenharmony_ci * PF and then used blindly by the VF.
30338c2ecf20Sopenharmony_ci */
30348c2ecf20Sopenharmony_ciu32 bnx2x_crc_vf_bulletin(struct pf_vf_bulletin_content *bulletin)
30358c2ecf20Sopenharmony_ci{
30368c2ecf20Sopenharmony_ci	return crc32(BULLETIN_CRC_SEED,
30378c2ecf20Sopenharmony_ci		 ((u8 *)bulletin) + sizeof(bulletin->crc),
30388c2ecf20Sopenharmony_ci		 bulletin->length - sizeof(bulletin->crc));
30398c2ecf20Sopenharmony_ci}
30408c2ecf20Sopenharmony_ci
30418c2ecf20Sopenharmony_ci/* Check for new posts on the bulletin board */
30428c2ecf20Sopenharmony_cienum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
30438c2ecf20Sopenharmony_ci{
30448c2ecf20Sopenharmony_ci	struct pf_vf_bulletin_content *bulletin;
30458c2ecf20Sopenharmony_ci	int attempts;
30468c2ecf20Sopenharmony_ci
30478c2ecf20Sopenharmony_ci	/* sampling structure in mid post may result with corrupted data
30488c2ecf20Sopenharmony_ci	 * validate crc to ensure coherency.
30498c2ecf20Sopenharmony_ci	 */
30508c2ecf20Sopenharmony_ci	for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
30518c2ecf20Sopenharmony_ci		u32 crc;
30528c2ecf20Sopenharmony_ci
30538c2ecf20Sopenharmony_ci		/* sample the bulletin board */
30548c2ecf20Sopenharmony_ci		memcpy(&bp->shadow_bulletin, bp->pf2vf_bulletin,
30558c2ecf20Sopenharmony_ci		       sizeof(union pf_vf_bulletin));
30568c2ecf20Sopenharmony_ci
30578c2ecf20Sopenharmony_ci		crc = bnx2x_crc_vf_bulletin(&bp->shadow_bulletin.content);
30588c2ecf20Sopenharmony_ci
30598c2ecf20Sopenharmony_ci		if (bp->shadow_bulletin.content.crc == crc)
30608c2ecf20Sopenharmony_ci			break;
30618c2ecf20Sopenharmony_ci
30628c2ecf20Sopenharmony_ci		BNX2X_ERR("bad crc on bulletin board. Contained %x computed %x\n",
30638c2ecf20Sopenharmony_ci			  bp->shadow_bulletin.content.crc, crc);
30648c2ecf20Sopenharmony_ci	}
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_ci	if (attempts >= BULLETIN_ATTEMPTS) {
30678c2ecf20Sopenharmony_ci		BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n",
30688c2ecf20Sopenharmony_ci			  attempts);
30698c2ecf20Sopenharmony_ci		return PFVF_BULLETIN_CRC_ERR;
30708c2ecf20Sopenharmony_ci	}
30718c2ecf20Sopenharmony_ci	bulletin = &bp->shadow_bulletin.content;
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci	/* bulletin board hasn't changed since last sample */
30748c2ecf20Sopenharmony_ci	if (bp->old_bulletin.version == bulletin->version)
30758c2ecf20Sopenharmony_ci		return PFVF_BULLETIN_UNCHANGED;
30768c2ecf20Sopenharmony_ci
30778c2ecf20Sopenharmony_ci	/* the mac address in bulletin board is valid and is new */
30788c2ecf20Sopenharmony_ci	if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID &&
30798c2ecf20Sopenharmony_ci	    !ether_addr_equal(bulletin->mac, bp->old_bulletin.mac)) {
30808c2ecf20Sopenharmony_ci		/* update new mac to net device */
30818c2ecf20Sopenharmony_ci		memcpy(bp->dev->dev_addr, bulletin->mac, ETH_ALEN);
30828c2ecf20Sopenharmony_ci	}
30838c2ecf20Sopenharmony_ci
30848c2ecf20Sopenharmony_ci	if (bulletin->valid_bitmap & (1 << LINK_VALID)) {
30858c2ecf20Sopenharmony_ci		DP(BNX2X_MSG_IOV, "link update speed %d flags %x\n",
30868c2ecf20Sopenharmony_ci		   bulletin->link_speed, bulletin->link_flags);
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_ci		bp->vf_link_vars.line_speed = bulletin->link_speed;
30898c2ecf20Sopenharmony_ci		bp->vf_link_vars.link_report_flags = 0;
30908c2ecf20Sopenharmony_ci		/* Link is down */
30918c2ecf20Sopenharmony_ci		if (bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN)
30928c2ecf20Sopenharmony_ci			__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
30938c2ecf20Sopenharmony_ci				  &bp->vf_link_vars.link_report_flags);
30948c2ecf20Sopenharmony_ci		/* Full DUPLEX */
30958c2ecf20Sopenharmony_ci		if (bulletin->link_flags & VFPF_LINK_REPORT_FULL_DUPLEX)
30968c2ecf20Sopenharmony_ci			__set_bit(BNX2X_LINK_REPORT_FD,
30978c2ecf20Sopenharmony_ci				  &bp->vf_link_vars.link_report_flags);
30988c2ecf20Sopenharmony_ci		/* Rx Flow Control is ON */
30998c2ecf20Sopenharmony_ci		if (bulletin->link_flags & VFPF_LINK_REPORT_RX_FC_ON)
31008c2ecf20Sopenharmony_ci			__set_bit(BNX2X_LINK_REPORT_RX_FC_ON,
31018c2ecf20Sopenharmony_ci				  &bp->vf_link_vars.link_report_flags);
31028c2ecf20Sopenharmony_ci		/* Tx Flow Control is ON */
31038c2ecf20Sopenharmony_ci		if (bulletin->link_flags & VFPF_LINK_REPORT_TX_FC_ON)
31048c2ecf20Sopenharmony_ci			__set_bit(BNX2X_LINK_REPORT_TX_FC_ON,
31058c2ecf20Sopenharmony_ci				  &bp->vf_link_vars.link_report_flags);
31068c2ecf20Sopenharmony_ci		__bnx2x_link_report(bp);
31078c2ecf20Sopenharmony_ci	}
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci	/* copy new bulletin board to bp */
31108c2ecf20Sopenharmony_ci	memcpy(&bp->old_bulletin, bulletin,
31118c2ecf20Sopenharmony_ci	       sizeof(struct pf_vf_bulletin_content));
31128c2ecf20Sopenharmony_ci
31138c2ecf20Sopenharmony_ci	return PFVF_BULLETIN_UPDATED;
31148c2ecf20Sopenharmony_ci}
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_civoid bnx2x_timer_sriov(struct bnx2x *bp)
31178c2ecf20Sopenharmony_ci{
31188c2ecf20Sopenharmony_ci	bnx2x_sample_bulletin(bp);
31198c2ecf20Sopenharmony_ci
31208c2ecf20Sopenharmony_ci	/* if channel is down we need to self destruct */
31218c2ecf20Sopenharmony_ci	if (bp->old_bulletin.valid_bitmap & 1 << CHANNEL_DOWN)
31228c2ecf20Sopenharmony_ci		bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN,
31238c2ecf20Sopenharmony_ci				       BNX2X_MSG_IOV);
31248c2ecf20Sopenharmony_ci}
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_civoid __iomem *bnx2x_vf_doorbells(struct bnx2x *bp)
31278c2ecf20Sopenharmony_ci{
31288c2ecf20Sopenharmony_ci	/* vf doorbells are embedded within the regview */
31298c2ecf20Sopenharmony_ci	return bp->regview + PXP_VF_ADDR_DB_START;
31308c2ecf20Sopenharmony_ci}
31318c2ecf20Sopenharmony_ci
31328c2ecf20Sopenharmony_civoid bnx2x_vf_pci_dealloc(struct bnx2x *bp)
31338c2ecf20Sopenharmony_ci{
31348c2ecf20Sopenharmony_ci	BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
31358c2ecf20Sopenharmony_ci		       sizeof(struct bnx2x_vf_mbx_msg));
31368c2ecf20Sopenharmony_ci	BNX2X_PCI_FREE(bp->pf2vf_bulletin, bp->pf2vf_bulletin_mapping,
31378c2ecf20Sopenharmony_ci		       sizeof(union pf_vf_bulletin));
31388c2ecf20Sopenharmony_ci}
31398c2ecf20Sopenharmony_ci
31408c2ecf20Sopenharmony_ciint bnx2x_vf_pci_alloc(struct bnx2x *bp)
31418c2ecf20Sopenharmony_ci{
31428c2ecf20Sopenharmony_ci	mutex_init(&bp->vf2pf_mutex);
31438c2ecf20Sopenharmony_ci
31448c2ecf20Sopenharmony_ci	/* allocate vf2pf mailbox for vf to pf channel */
31458c2ecf20Sopenharmony_ci	bp->vf2pf_mbox = BNX2X_PCI_ALLOC(&bp->vf2pf_mbox_mapping,
31468c2ecf20Sopenharmony_ci					 sizeof(struct bnx2x_vf_mbx_msg));
31478c2ecf20Sopenharmony_ci	if (!bp->vf2pf_mbox)
31488c2ecf20Sopenharmony_ci		goto alloc_mem_err;
31498c2ecf20Sopenharmony_ci
31508c2ecf20Sopenharmony_ci	/* allocate pf 2 vf bulletin board */
31518c2ecf20Sopenharmony_ci	bp->pf2vf_bulletin = BNX2X_PCI_ALLOC(&bp->pf2vf_bulletin_mapping,
31528c2ecf20Sopenharmony_ci					     sizeof(union pf_vf_bulletin));
31538c2ecf20Sopenharmony_ci	if (!bp->pf2vf_bulletin)
31548c2ecf20Sopenharmony_ci		goto alloc_mem_err;
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_ci	bnx2x_vf_bulletin_finalize(&bp->pf2vf_bulletin->content, true);
31578c2ecf20Sopenharmony_ci
31588c2ecf20Sopenharmony_ci	return 0;
31598c2ecf20Sopenharmony_ci
31608c2ecf20Sopenharmony_cialloc_mem_err:
31618c2ecf20Sopenharmony_ci	bnx2x_vf_pci_dealloc(bp);
31628c2ecf20Sopenharmony_ci	return -ENOMEM;
31638c2ecf20Sopenharmony_ci}
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_civoid bnx2x_iov_channel_down(struct bnx2x *bp)
31668c2ecf20Sopenharmony_ci{
31678c2ecf20Sopenharmony_ci	int vf_idx;
31688c2ecf20Sopenharmony_ci	struct pf_vf_bulletin_content *bulletin;
31698c2ecf20Sopenharmony_ci
31708c2ecf20Sopenharmony_ci	if (!IS_SRIOV(bp))
31718c2ecf20Sopenharmony_ci		return;
31728c2ecf20Sopenharmony_ci
31738c2ecf20Sopenharmony_ci	for_each_vf(bp, vf_idx) {
31748c2ecf20Sopenharmony_ci		/* locate this VFs bulletin board and update the channel down
31758c2ecf20Sopenharmony_ci		 * bit
31768c2ecf20Sopenharmony_ci		 */
31778c2ecf20Sopenharmony_ci		bulletin = BP_VF_BULLETIN(bp, vf_idx);
31788c2ecf20Sopenharmony_ci		bulletin->valid_bitmap |= 1 << CHANNEL_DOWN;
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci		/* update vf bulletin board */
31818c2ecf20Sopenharmony_ci		bnx2x_post_vf_bulletin(bp, vf_idx);
31828c2ecf20Sopenharmony_ci	}
31838c2ecf20Sopenharmony_ci}
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_civoid bnx2x_iov_task(struct work_struct *work)
31868c2ecf20Sopenharmony_ci{
31878c2ecf20Sopenharmony_ci	struct bnx2x *bp = container_of(work, struct bnx2x, iov_task.work);
31888c2ecf20Sopenharmony_ci
31898c2ecf20Sopenharmony_ci	if (!netif_running(bp->dev))
31908c2ecf20Sopenharmony_ci		return;
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci	if (test_and_clear_bit(BNX2X_IOV_HANDLE_FLR,
31938c2ecf20Sopenharmony_ci			       &bp->iov_task_state))
31948c2ecf20Sopenharmony_ci		bnx2x_vf_handle_flr_event(bp);
31958c2ecf20Sopenharmony_ci
31968c2ecf20Sopenharmony_ci	if (test_and_clear_bit(BNX2X_IOV_HANDLE_VF_MSG,
31978c2ecf20Sopenharmony_ci			       &bp->iov_task_state))
31988c2ecf20Sopenharmony_ci		bnx2x_vf_mbx(bp);
31998c2ecf20Sopenharmony_ci}
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_civoid bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag)
32028c2ecf20Sopenharmony_ci{
32038c2ecf20Sopenharmony_ci	smp_mb__before_atomic();
32048c2ecf20Sopenharmony_ci	set_bit(flag, &bp->iov_task_state);
32058c2ecf20Sopenharmony_ci	smp_mb__after_atomic();
32068c2ecf20Sopenharmony_ci	DP(BNX2X_MSG_IOV, "Scheduling iov task [Flag: %d]\n", flag);
32078c2ecf20Sopenharmony_ci	queue_delayed_work(bnx2x_iov_wq, &bp->iov_task, 0);
32088c2ecf20Sopenharmony_ci}
3209