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