18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* QLogic qed NIC Driver 38c2ecf20Sopenharmony_ci * Copyright (c) 2015-2017 QLogic Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2019-2020 Marvell International Ltd. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 88c2ecf20Sopenharmony_ci#include <linux/crc32.h> 98c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 108c2ecf20Sopenharmony_ci#include <linux/crash_dump.h> 118c2ecf20Sopenharmony_ci#include <linux/qed/qed_iov_if.h> 128c2ecf20Sopenharmony_ci#include "qed_cxt.h" 138c2ecf20Sopenharmony_ci#include "qed_hsi.h" 148c2ecf20Sopenharmony_ci#include "qed_hw.h" 158c2ecf20Sopenharmony_ci#include "qed_init_ops.h" 168c2ecf20Sopenharmony_ci#include "qed_int.h" 178c2ecf20Sopenharmony_ci#include "qed_mcp.h" 188c2ecf20Sopenharmony_ci#include "qed_reg_addr.h" 198c2ecf20Sopenharmony_ci#include "qed_sp.h" 208c2ecf20Sopenharmony_ci#include "qed_sriov.h" 218c2ecf20Sopenharmony_ci#include "qed_vf.h" 228c2ecf20Sopenharmony_cistatic int qed_sriov_eqe_event(struct qed_hwfn *p_hwfn, 238c2ecf20Sopenharmony_ci u8 opcode, 248c2ecf20Sopenharmony_ci __le16 echo, 258c2ecf20Sopenharmony_ci union event_ring_data *data, u8 fw_return_code); 268c2ecf20Sopenharmony_cistatic int qed_iov_bulletin_set_mac(struct qed_hwfn *p_hwfn, u8 *mac, int vfid); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic u8 qed_vf_calculate_legacy(struct qed_vf_info *p_vf) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci u8 legacy = 0; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (p_vf->acquire.vfdev_info.eth_fp_hsi_minor == 338c2ecf20Sopenharmony_ci ETH_HSI_VER_NO_PKT_LEN_TUNN) 348c2ecf20Sopenharmony_ci legacy |= QED_QCID_LEGACY_VF_RX_PROD; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (!(p_vf->acquire.vfdev_info.capabilities & 378c2ecf20Sopenharmony_ci VFPF_ACQUIRE_CAP_QUEUE_QIDS)) 388c2ecf20Sopenharmony_ci legacy |= QED_QCID_LEGACY_VF_CID; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci return legacy; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* IOV ramrods */ 448c2ecf20Sopenharmony_cistatic int qed_sp_vf_start(struct qed_hwfn *p_hwfn, struct qed_vf_info *p_vf) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct vf_start_ramrod_data *p_ramrod = NULL; 478c2ecf20Sopenharmony_ci struct qed_spq_entry *p_ent = NULL; 488c2ecf20Sopenharmony_ci struct qed_sp_init_data init_data; 498c2ecf20Sopenharmony_ci int rc = -EINVAL; 508c2ecf20Sopenharmony_ci u8 fp_minor; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* Get SPQ entry */ 538c2ecf20Sopenharmony_ci memset(&init_data, 0, sizeof(init_data)); 548c2ecf20Sopenharmony_ci init_data.cid = qed_spq_get_cid(p_hwfn); 558c2ecf20Sopenharmony_ci init_data.opaque_fid = p_vf->opaque_fid; 568c2ecf20Sopenharmony_ci init_data.comp_mode = QED_SPQ_MODE_EBLOCK; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci rc = qed_sp_init_request(p_hwfn, &p_ent, 598c2ecf20Sopenharmony_ci COMMON_RAMROD_VF_START, 608c2ecf20Sopenharmony_ci PROTOCOLID_COMMON, &init_data); 618c2ecf20Sopenharmony_ci if (rc) 628c2ecf20Sopenharmony_ci return rc; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci p_ramrod = &p_ent->ramrod.vf_start; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci p_ramrod->vf_id = GET_FIELD(p_vf->concrete_fid, PXP_CONCRETE_FID_VFID); 678c2ecf20Sopenharmony_ci p_ramrod->opaque_fid = cpu_to_le16(p_vf->opaque_fid); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci switch (p_hwfn->hw_info.personality) { 708c2ecf20Sopenharmony_ci case QED_PCI_ETH: 718c2ecf20Sopenharmony_ci p_ramrod->personality = PERSONALITY_ETH; 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci case QED_PCI_ETH_ROCE: 748c2ecf20Sopenharmony_ci case QED_PCI_ETH_IWARP: 758c2ecf20Sopenharmony_ci p_ramrod->personality = PERSONALITY_RDMA_AND_ETH; 768c2ecf20Sopenharmony_ci break; 778c2ecf20Sopenharmony_ci default: 788c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Unknown VF personality %d\n", 798c2ecf20Sopenharmony_ci p_hwfn->hw_info.personality); 808c2ecf20Sopenharmony_ci qed_sp_destroy_request(p_hwfn, p_ent); 818c2ecf20Sopenharmony_ci return -EINVAL; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci fp_minor = p_vf->acquire.vfdev_info.eth_fp_hsi_minor; 858c2ecf20Sopenharmony_ci if (fp_minor > ETH_HSI_VER_MINOR && 868c2ecf20Sopenharmony_ci fp_minor != ETH_HSI_VER_NO_PKT_LEN_TUNN) { 878c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 888c2ecf20Sopenharmony_ci QED_MSG_IOV, 898c2ecf20Sopenharmony_ci "VF [%d] - Requested fp hsi %02x.%02x which is slightly newer than PF's %02x.%02x; Configuring PFs version\n", 908c2ecf20Sopenharmony_ci p_vf->abs_vf_id, 918c2ecf20Sopenharmony_ci ETH_HSI_VER_MAJOR, 928c2ecf20Sopenharmony_ci fp_minor, ETH_HSI_VER_MAJOR, ETH_HSI_VER_MINOR); 938c2ecf20Sopenharmony_ci fp_minor = ETH_HSI_VER_MINOR; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci p_ramrod->hsi_fp_ver.major_ver_arr[ETH_VER_KEY] = ETH_HSI_VER_MAJOR; 978c2ecf20Sopenharmony_ci p_ramrod->hsi_fp_ver.minor_ver_arr[ETH_VER_KEY] = fp_minor; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 1008c2ecf20Sopenharmony_ci "VF[%d] - Starting using HSI %02x.%02x\n", 1018c2ecf20Sopenharmony_ci p_vf->abs_vf_id, ETH_HSI_VER_MAJOR, fp_minor); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return qed_spq_post(p_hwfn, p_ent, NULL); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int qed_sp_vf_stop(struct qed_hwfn *p_hwfn, 1078c2ecf20Sopenharmony_ci u32 concrete_vfid, u16 opaque_vfid) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct vf_stop_ramrod_data *p_ramrod = NULL; 1108c2ecf20Sopenharmony_ci struct qed_spq_entry *p_ent = NULL; 1118c2ecf20Sopenharmony_ci struct qed_sp_init_data init_data; 1128c2ecf20Sopenharmony_ci int rc = -EINVAL; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Get SPQ entry */ 1158c2ecf20Sopenharmony_ci memset(&init_data, 0, sizeof(init_data)); 1168c2ecf20Sopenharmony_ci init_data.cid = qed_spq_get_cid(p_hwfn); 1178c2ecf20Sopenharmony_ci init_data.opaque_fid = opaque_vfid; 1188c2ecf20Sopenharmony_ci init_data.comp_mode = QED_SPQ_MODE_EBLOCK; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci rc = qed_sp_init_request(p_hwfn, &p_ent, 1218c2ecf20Sopenharmony_ci COMMON_RAMROD_VF_STOP, 1228c2ecf20Sopenharmony_ci PROTOCOLID_COMMON, &init_data); 1238c2ecf20Sopenharmony_ci if (rc) 1248c2ecf20Sopenharmony_ci return rc; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci p_ramrod = &p_ent->ramrod.vf_stop; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci p_ramrod->vf_id = GET_FIELD(concrete_vfid, PXP_CONCRETE_FID_VFID); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return qed_spq_post(p_hwfn, p_ent, NULL); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cibool qed_iov_is_valid_vfid(struct qed_hwfn *p_hwfn, 1348c2ecf20Sopenharmony_ci int rel_vf_id, 1358c2ecf20Sopenharmony_ci bool b_enabled_only, bool b_non_malicious) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci if (!p_hwfn->pf_iov_info) { 1388c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn->cdev, "No iov info\n"); 1398c2ecf20Sopenharmony_ci return false; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if ((rel_vf_id >= p_hwfn->cdev->p_iov_info->total_vfs) || 1438c2ecf20Sopenharmony_ci (rel_vf_id < 0)) 1448c2ecf20Sopenharmony_ci return false; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if ((!p_hwfn->pf_iov_info->vfs_array[rel_vf_id].b_init) && 1478c2ecf20Sopenharmony_ci b_enabled_only) 1488c2ecf20Sopenharmony_ci return false; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if ((p_hwfn->pf_iov_info->vfs_array[rel_vf_id].b_malicious) && 1518c2ecf20Sopenharmony_ci b_non_malicious) 1528c2ecf20Sopenharmony_ci return false; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return true; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic struct qed_vf_info *qed_iov_get_vf_info(struct qed_hwfn *p_hwfn, 1588c2ecf20Sopenharmony_ci u16 relative_vf_id, 1598c2ecf20Sopenharmony_ci bool b_enabled_only) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci struct qed_vf_info *vf = NULL; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (!p_hwfn->pf_iov_info) { 1648c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn->cdev, "No iov info\n"); 1658c2ecf20Sopenharmony_ci return NULL; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (qed_iov_is_valid_vfid(p_hwfn, relative_vf_id, 1698c2ecf20Sopenharmony_ci b_enabled_only, false)) 1708c2ecf20Sopenharmony_ci vf = &p_hwfn->pf_iov_info->vfs_array[relative_vf_id]; 1718c2ecf20Sopenharmony_ci else 1728c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "qed_iov_get_vf_info: VF[%d] is not enabled\n", 1738c2ecf20Sopenharmony_ci relative_vf_id); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return vf; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic struct qed_queue_cid * 1798c2ecf20Sopenharmony_ciqed_iov_get_vf_rx_queue_cid(struct qed_vf_queue *p_queue) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci int i; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { 1848c2ecf20Sopenharmony_ci if (p_queue->cids[i].p_cid && !p_queue->cids[i].b_is_tx) 1858c2ecf20Sopenharmony_ci return p_queue->cids[i].p_cid; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return NULL; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cienum qed_iov_validate_q_mode { 1928c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_NA, 1938c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_ENABLE, 1948c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_DISABLE, 1958c2ecf20Sopenharmony_ci}; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic bool qed_iov_validate_queue_mode(struct qed_hwfn *p_hwfn, 1988c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 1998c2ecf20Sopenharmony_ci u16 qid, 2008c2ecf20Sopenharmony_ci enum qed_iov_validate_q_mode mode, 2018c2ecf20Sopenharmony_ci bool b_is_tx) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci int i; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (mode == QED_IOV_VALIDATE_Q_NA) 2068c2ecf20Sopenharmony_ci return true; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { 2098c2ecf20Sopenharmony_ci struct qed_vf_queue_cid *p_qcid; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci p_qcid = &p_vf->vf_queues[qid].cids[i]; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (!p_qcid->p_cid) 2148c2ecf20Sopenharmony_ci continue; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (p_qcid->b_is_tx != b_is_tx) 2178c2ecf20Sopenharmony_ci continue; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return mode == QED_IOV_VALIDATE_Q_ENABLE; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* In case we haven't found any valid cid, then its disabled */ 2238c2ecf20Sopenharmony_ci return mode == QED_IOV_VALIDATE_Q_DISABLE; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic bool qed_iov_validate_rxq(struct qed_hwfn *p_hwfn, 2278c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 2288c2ecf20Sopenharmony_ci u16 rx_qid, 2298c2ecf20Sopenharmony_ci enum qed_iov_validate_q_mode mode) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci if (rx_qid >= p_vf->num_rxqs) { 2328c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 2338c2ecf20Sopenharmony_ci QED_MSG_IOV, 2348c2ecf20Sopenharmony_ci "VF[0x%02x] - can't touch Rx queue[%04x]; Only 0x%04x are allocated\n", 2358c2ecf20Sopenharmony_ci p_vf->abs_vf_id, rx_qid, p_vf->num_rxqs); 2368c2ecf20Sopenharmony_ci return false; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return qed_iov_validate_queue_mode(p_hwfn, p_vf, rx_qid, mode, false); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic bool qed_iov_validate_txq(struct qed_hwfn *p_hwfn, 2438c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 2448c2ecf20Sopenharmony_ci u16 tx_qid, 2458c2ecf20Sopenharmony_ci enum qed_iov_validate_q_mode mode) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci if (tx_qid >= p_vf->num_txqs) { 2488c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 2498c2ecf20Sopenharmony_ci QED_MSG_IOV, 2508c2ecf20Sopenharmony_ci "VF[0x%02x] - can't touch Tx queue[%04x]; Only 0x%04x are allocated\n", 2518c2ecf20Sopenharmony_ci p_vf->abs_vf_id, tx_qid, p_vf->num_txqs); 2528c2ecf20Sopenharmony_ci return false; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return qed_iov_validate_queue_mode(p_hwfn, p_vf, tx_qid, mode, true); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic bool qed_iov_validate_sb(struct qed_hwfn *p_hwfn, 2598c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, u16 sb_idx) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci int i; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci for (i = 0; i < p_vf->num_sbs; i++) 2648c2ecf20Sopenharmony_ci if (p_vf->igu_sbs[i] == sb_idx) 2658c2ecf20Sopenharmony_ci return true; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 2688c2ecf20Sopenharmony_ci QED_MSG_IOV, 2698c2ecf20Sopenharmony_ci "VF[0%02x] - tried using sb_idx %04x which doesn't exist as one of its 0x%02x SBs\n", 2708c2ecf20Sopenharmony_ci p_vf->abs_vf_id, sb_idx, p_vf->num_sbs); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return false; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic bool qed_iov_validate_active_rxq(struct qed_hwfn *p_hwfn, 2768c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci u8 i; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci for (i = 0; i < p_vf->num_rxqs; i++) 2818c2ecf20Sopenharmony_ci if (qed_iov_validate_queue_mode(p_hwfn, p_vf, i, 2828c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_ENABLE, 2838c2ecf20Sopenharmony_ci false)) 2848c2ecf20Sopenharmony_ci return true; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return false; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic bool qed_iov_validate_active_txq(struct qed_hwfn *p_hwfn, 2908c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci u8 i; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci for (i = 0; i < p_vf->num_txqs; i++) 2958c2ecf20Sopenharmony_ci if (qed_iov_validate_queue_mode(p_hwfn, p_vf, i, 2968c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_ENABLE, 2978c2ecf20Sopenharmony_ci true)) 2988c2ecf20Sopenharmony_ci return true; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return false; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int qed_iov_post_vf_bulletin(struct qed_hwfn *p_hwfn, 3048c2ecf20Sopenharmony_ci int vfid, struct qed_ptt *p_ptt) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct qed_bulletin_content *p_bulletin; 3078c2ecf20Sopenharmony_ci int crc_size = sizeof(p_bulletin->crc); 3088c2ecf20Sopenharmony_ci struct qed_dmae_params params; 3098c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci p_vf = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 3128c2ecf20Sopenharmony_ci if (!p_vf) 3138c2ecf20Sopenharmony_ci return -EINVAL; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (!p_vf->vf_bulletin) 3168c2ecf20Sopenharmony_ci return -EINVAL; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci p_bulletin = p_vf->bulletin.p_virt; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Increment bulletin board version and compute crc */ 3218c2ecf20Sopenharmony_ci p_bulletin->version++; 3228c2ecf20Sopenharmony_ci p_bulletin->crc = crc32(0, (u8 *)p_bulletin + crc_size, 3238c2ecf20Sopenharmony_ci p_vf->bulletin.size - crc_size); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 3268c2ecf20Sopenharmony_ci "Posting Bulletin 0x%08x to VF[%d] (CRC 0x%08x)\n", 3278c2ecf20Sopenharmony_ci p_bulletin->version, p_vf->relative_vf_id, p_bulletin->crc); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* propagate bulletin board via dmae to vm memory */ 3308c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 3318c2ecf20Sopenharmony_ci SET_FIELD(params.flags, QED_DMAE_PARAMS_DST_VF_VALID, 0x1); 3328c2ecf20Sopenharmony_ci params.dst_vfid = p_vf->abs_vf_id; 3338c2ecf20Sopenharmony_ci return qed_dmae_host2host(p_hwfn, p_ptt, p_vf->bulletin.phys, 3348c2ecf20Sopenharmony_ci p_vf->vf_bulletin, p_vf->bulletin.size / 4, 3358c2ecf20Sopenharmony_ci ¶ms); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int qed_iov_pci_cfg_info(struct qed_dev *cdev) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct qed_hw_sriov_info *iov = cdev->p_iov_info; 3418c2ecf20Sopenharmony_ci int pos = iov->pos; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_IOV, "sriov ext pos %d\n", pos); 3448c2ecf20Sopenharmony_ci pci_read_config_word(cdev->pdev, pos + PCI_SRIOV_CTRL, &iov->ctrl); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci pci_read_config_word(cdev->pdev, 3478c2ecf20Sopenharmony_ci pos + PCI_SRIOV_TOTAL_VF, &iov->total_vfs); 3488c2ecf20Sopenharmony_ci pci_read_config_word(cdev->pdev, 3498c2ecf20Sopenharmony_ci pos + PCI_SRIOV_INITIAL_VF, &iov->initial_vfs); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci pci_read_config_word(cdev->pdev, pos + PCI_SRIOV_NUM_VF, &iov->num_vfs); 3528c2ecf20Sopenharmony_ci if (iov->num_vfs) { 3538c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, 3548c2ecf20Sopenharmony_ci QED_MSG_IOV, 3558c2ecf20Sopenharmony_ci "Number of VFs are already set to non-zero value. Ignoring PCI configuration value\n"); 3568c2ecf20Sopenharmony_ci iov->num_vfs = 0; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci pci_read_config_word(cdev->pdev, 3608c2ecf20Sopenharmony_ci pos + PCI_SRIOV_VF_OFFSET, &iov->offset); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci pci_read_config_word(cdev->pdev, 3638c2ecf20Sopenharmony_ci pos + PCI_SRIOV_VF_STRIDE, &iov->stride); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci pci_read_config_word(cdev->pdev, 3668c2ecf20Sopenharmony_ci pos + PCI_SRIOV_VF_DID, &iov->vf_device_id); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci pci_read_config_dword(cdev->pdev, 3698c2ecf20Sopenharmony_ci pos + PCI_SRIOV_SUP_PGSIZE, &iov->pgsz); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci pci_read_config_dword(cdev->pdev, pos + PCI_SRIOV_CAP, &iov->cap); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci pci_read_config_byte(cdev->pdev, pos + PCI_SRIOV_FUNC_LINK, &iov->link); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, 3768c2ecf20Sopenharmony_ci QED_MSG_IOV, 3778c2ecf20Sopenharmony_ci "IOV info: nres %d, cap 0x%x, ctrl 0x%x, total %d, initial %d, num vfs %d, offset %d, stride %d, page size 0x%x\n", 3788c2ecf20Sopenharmony_ci iov->nres, 3798c2ecf20Sopenharmony_ci iov->cap, 3808c2ecf20Sopenharmony_ci iov->ctrl, 3818c2ecf20Sopenharmony_ci iov->total_vfs, 3828c2ecf20Sopenharmony_ci iov->initial_vfs, 3838c2ecf20Sopenharmony_ci iov->nr_virtfn, iov->offset, iov->stride, iov->pgsz); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Some sanity checks */ 3868c2ecf20Sopenharmony_ci if (iov->num_vfs > NUM_OF_VFS(cdev) || 3878c2ecf20Sopenharmony_ci iov->total_vfs > NUM_OF_VFS(cdev)) { 3888c2ecf20Sopenharmony_ci /* This can happen only due to a bug. In this case we set 3898c2ecf20Sopenharmony_ci * num_vfs to zero to avoid memory corruption in the code that 3908c2ecf20Sopenharmony_ci * assumes max number of vfs 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 3938c2ecf20Sopenharmony_ci "IOV: Unexpected number of vfs set: %d setting num_vf to zero\n", 3948c2ecf20Sopenharmony_ci iov->num_vfs); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci iov->num_vfs = 0; 3978c2ecf20Sopenharmony_ci iov->total_vfs = 0; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic void qed_iov_setup_vfdb(struct qed_hwfn *p_hwfn) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct qed_hw_sriov_info *p_iov = p_hwfn->cdev->p_iov_info; 4068c2ecf20Sopenharmony_ci struct qed_pf_iov *p_iov_info = p_hwfn->pf_iov_info; 4078c2ecf20Sopenharmony_ci struct qed_bulletin_content *p_bulletin_virt; 4088c2ecf20Sopenharmony_ci dma_addr_t req_p, rply_p, bulletin_p; 4098c2ecf20Sopenharmony_ci union pfvf_tlvs *p_reply_virt_addr; 4108c2ecf20Sopenharmony_ci union vfpf_tlvs *p_req_virt_addr; 4118c2ecf20Sopenharmony_ci u8 idx = 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci memset(p_iov_info->vfs_array, 0, sizeof(p_iov_info->vfs_array)); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci p_req_virt_addr = p_iov_info->mbx_msg_virt_addr; 4168c2ecf20Sopenharmony_ci req_p = p_iov_info->mbx_msg_phys_addr; 4178c2ecf20Sopenharmony_ci p_reply_virt_addr = p_iov_info->mbx_reply_virt_addr; 4188c2ecf20Sopenharmony_ci rply_p = p_iov_info->mbx_reply_phys_addr; 4198c2ecf20Sopenharmony_ci p_bulletin_virt = p_iov_info->p_bulletins; 4208c2ecf20Sopenharmony_ci bulletin_p = p_iov_info->bulletins_phys; 4218c2ecf20Sopenharmony_ci if (!p_req_virt_addr || !p_reply_virt_addr || !p_bulletin_virt) { 4228c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 4238c2ecf20Sopenharmony_ci "qed_iov_setup_vfdb called without allocating mem first\n"); 4248c2ecf20Sopenharmony_ci return; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci for (idx = 0; idx < p_iov->total_vfs; idx++) { 4288c2ecf20Sopenharmony_ci struct qed_vf_info *vf = &p_iov_info->vfs_array[idx]; 4298c2ecf20Sopenharmony_ci u32 concrete; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci vf->vf_mbx.req_virt = p_req_virt_addr + idx; 4328c2ecf20Sopenharmony_ci vf->vf_mbx.req_phys = req_p + idx * sizeof(union vfpf_tlvs); 4338c2ecf20Sopenharmony_ci vf->vf_mbx.reply_virt = p_reply_virt_addr + idx; 4348c2ecf20Sopenharmony_ci vf->vf_mbx.reply_phys = rply_p + idx * sizeof(union pfvf_tlvs); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci vf->state = VF_STOPPED; 4378c2ecf20Sopenharmony_ci vf->b_init = false; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci vf->bulletin.phys = idx * 4408c2ecf20Sopenharmony_ci sizeof(struct qed_bulletin_content) + 4418c2ecf20Sopenharmony_ci bulletin_p; 4428c2ecf20Sopenharmony_ci vf->bulletin.p_virt = p_bulletin_virt + idx; 4438c2ecf20Sopenharmony_ci vf->bulletin.size = sizeof(struct qed_bulletin_content); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci vf->relative_vf_id = idx; 4468c2ecf20Sopenharmony_ci vf->abs_vf_id = idx + p_iov->first_vf_in_pf; 4478c2ecf20Sopenharmony_ci concrete = qed_vfid_to_concrete(p_hwfn, vf->abs_vf_id); 4488c2ecf20Sopenharmony_ci vf->concrete_fid = concrete; 4498c2ecf20Sopenharmony_ci vf->opaque_fid = (p_hwfn->hw_info.opaque_fid & 0xff) | 4508c2ecf20Sopenharmony_ci (vf->abs_vf_id << 8); 4518c2ecf20Sopenharmony_ci vf->vport_id = idx + 1; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci vf->num_mac_filters = QED_ETH_VF_NUM_MAC_FILTERS; 4548c2ecf20Sopenharmony_ci vf->num_vlan_filters = QED_ETH_VF_NUM_VLAN_FILTERS; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int qed_iov_allocate_vfdb(struct qed_hwfn *p_hwfn) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct qed_pf_iov *p_iov_info = p_hwfn->pf_iov_info; 4618c2ecf20Sopenharmony_ci void **p_v_addr; 4628c2ecf20Sopenharmony_ci u16 num_vfs = 0; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci num_vfs = p_hwfn->cdev->p_iov_info->total_vfs; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 4678c2ecf20Sopenharmony_ci "qed_iov_allocate_vfdb for %d VFs\n", num_vfs); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* Allocate PF Mailbox buffer (per-VF) */ 4708c2ecf20Sopenharmony_ci p_iov_info->mbx_msg_size = sizeof(union vfpf_tlvs) * num_vfs; 4718c2ecf20Sopenharmony_ci p_v_addr = &p_iov_info->mbx_msg_virt_addr; 4728c2ecf20Sopenharmony_ci *p_v_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 4738c2ecf20Sopenharmony_ci p_iov_info->mbx_msg_size, 4748c2ecf20Sopenharmony_ci &p_iov_info->mbx_msg_phys_addr, 4758c2ecf20Sopenharmony_ci GFP_KERNEL); 4768c2ecf20Sopenharmony_ci if (!*p_v_addr) 4778c2ecf20Sopenharmony_ci return -ENOMEM; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* Allocate PF Mailbox Reply buffer (per-VF) */ 4808c2ecf20Sopenharmony_ci p_iov_info->mbx_reply_size = sizeof(union pfvf_tlvs) * num_vfs; 4818c2ecf20Sopenharmony_ci p_v_addr = &p_iov_info->mbx_reply_virt_addr; 4828c2ecf20Sopenharmony_ci *p_v_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 4838c2ecf20Sopenharmony_ci p_iov_info->mbx_reply_size, 4848c2ecf20Sopenharmony_ci &p_iov_info->mbx_reply_phys_addr, 4858c2ecf20Sopenharmony_ci GFP_KERNEL); 4868c2ecf20Sopenharmony_ci if (!*p_v_addr) 4878c2ecf20Sopenharmony_ci return -ENOMEM; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci p_iov_info->bulletins_size = sizeof(struct qed_bulletin_content) * 4908c2ecf20Sopenharmony_ci num_vfs; 4918c2ecf20Sopenharmony_ci p_v_addr = &p_iov_info->p_bulletins; 4928c2ecf20Sopenharmony_ci *p_v_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 4938c2ecf20Sopenharmony_ci p_iov_info->bulletins_size, 4948c2ecf20Sopenharmony_ci &p_iov_info->bulletins_phys, 4958c2ecf20Sopenharmony_ci GFP_KERNEL); 4968c2ecf20Sopenharmony_ci if (!*p_v_addr) 4978c2ecf20Sopenharmony_ci return -ENOMEM; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 5008c2ecf20Sopenharmony_ci QED_MSG_IOV, 5018c2ecf20Sopenharmony_ci "PF's Requests mailbox [%p virt 0x%llx phys], Response mailbox [%p virt 0x%llx phys] Bulletins [%p virt 0x%llx phys]\n", 5028c2ecf20Sopenharmony_ci p_iov_info->mbx_msg_virt_addr, 5038c2ecf20Sopenharmony_ci (u64) p_iov_info->mbx_msg_phys_addr, 5048c2ecf20Sopenharmony_ci p_iov_info->mbx_reply_virt_addr, 5058c2ecf20Sopenharmony_ci (u64) p_iov_info->mbx_reply_phys_addr, 5068c2ecf20Sopenharmony_ci p_iov_info->p_bulletins, (u64) p_iov_info->bulletins_phys); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci return 0; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic void qed_iov_free_vfdb(struct qed_hwfn *p_hwfn) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct qed_pf_iov *p_iov_info = p_hwfn->pf_iov_info; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (p_hwfn->pf_iov_info->mbx_msg_virt_addr) 5168c2ecf20Sopenharmony_ci dma_free_coherent(&p_hwfn->cdev->pdev->dev, 5178c2ecf20Sopenharmony_ci p_iov_info->mbx_msg_size, 5188c2ecf20Sopenharmony_ci p_iov_info->mbx_msg_virt_addr, 5198c2ecf20Sopenharmony_ci p_iov_info->mbx_msg_phys_addr); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (p_hwfn->pf_iov_info->mbx_reply_virt_addr) 5228c2ecf20Sopenharmony_ci dma_free_coherent(&p_hwfn->cdev->pdev->dev, 5238c2ecf20Sopenharmony_ci p_iov_info->mbx_reply_size, 5248c2ecf20Sopenharmony_ci p_iov_info->mbx_reply_virt_addr, 5258c2ecf20Sopenharmony_ci p_iov_info->mbx_reply_phys_addr); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (p_iov_info->p_bulletins) 5288c2ecf20Sopenharmony_ci dma_free_coherent(&p_hwfn->cdev->pdev->dev, 5298c2ecf20Sopenharmony_ci p_iov_info->bulletins_size, 5308c2ecf20Sopenharmony_ci p_iov_info->p_bulletins, 5318c2ecf20Sopenharmony_ci p_iov_info->bulletins_phys); 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ciint qed_iov_alloc(struct qed_hwfn *p_hwfn) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct qed_pf_iov *p_sriov; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (!IS_PF_SRIOV(p_hwfn)) { 5398c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 5408c2ecf20Sopenharmony_ci "No SR-IOV - no need for IOV db\n"); 5418c2ecf20Sopenharmony_ci return 0; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci p_sriov = kzalloc(sizeof(*p_sriov), GFP_KERNEL); 5458c2ecf20Sopenharmony_ci if (!p_sriov) 5468c2ecf20Sopenharmony_ci return -ENOMEM; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci p_hwfn->pf_iov_info = p_sriov; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci qed_spq_register_async_cb(p_hwfn, PROTOCOLID_COMMON, 5518c2ecf20Sopenharmony_ci qed_sriov_eqe_event); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return qed_iov_allocate_vfdb(p_hwfn); 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_civoid qed_iov_setup(struct qed_hwfn *p_hwfn) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci if (!IS_PF_SRIOV(p_hwfn) || !IS_PF_SRIOV_ALLOC(p_hwfn)) 5598c2ecf20Sopenharmony_ci return; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci qed_iov_setup_vfdb(p_hwfn); 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_civoid qed_iov_free(struct qed_hwfn *p_hwfn) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_COMMON); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (IS_PF_SRIOV_ALLOC(p_hwfn)) { 5698c2ecf20Sopenharmony_ci qed_iov_free_vfdb(p_hwfn); 5708c2ecf20Sopenharmony_ci kfree(p_hwfn->pf_iov_info); 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_civoid qed_iov_free_hw_info(struct qed_dev *cdev) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci kfree(cdev->p_iov_info); 5778c2ecf20Sopenharmony_ci cdev->p_iov_info = NULL; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ciint qed_iov_hw_info(struct qed_hwfn *p_hwfn) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 5838c2ecf20Sopenharmony_ci int pos; 5848c2ecf20Sopenharmony_ci int rc; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (is_kdump_kernel()) 5878c2ecf20Sopenharmony_ci return 0; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* Learn the PCI configuration */ 5938c2ecf20Sopenharmony_ci pos = pci_find_ext_capability(p_hwfn->cdev->pdev, 5948c2ecf20Sopenharmony_ci PCI_EXT_CAP_ID_SRIOV); 5958c2ecf20Sopenharmony_ci if (!pos) { 5968c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, "No PCIe IOV support\n"); 5978c2ecf20Sopenharmony_ci return 0; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* Allocate a new struct for IOV information */ 6018c2ecf20Sopenharmony_ci cdev->p_iov_info = kzalloc(sizeof(*cdev->p_iov_info), GFP_KERNEL); 6028c2ecf20Sopenharmony_ci if (!cdev->p_iov_info) 6038c2ecf20Sopenharmony_ci return -ENOMEM; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci cdev->p_iov_info->pos = pos; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci rc = qed_iov_pci_cfg_info(cdev); 6088c2ecf20Sopenharmony_ci if (rc) 6098c2ecf20Sopenharmony_ci return rc; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* We want PF IOV to be synonemous with the existance of p_iov_info; 6128c2ecf20Sopenharmony_ci * In case the capability is published but there are no VFs, simply 6138c2ecf20Sopenharmony_ci * de-allocate the struct. 6148c2ecf20Sopenharmony_ci */ 6158c2ecf20Sopenharmony_ci if (!cdev->p_iov_info->total_vfs) { 6168c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 6178c2ecf20Sopenharmony_ci "IOV capabilities, but no VFs are published\n"); 6188c2ecf20Sopenharmony_ci kfree(cdev->p_iov_info); 6198c2ecf20Sopenharmony_ci cdev->p_iov_info = NULL; 6208c2ecf20Sopenharmony_ci return 0; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* First VF index based on offset is tricky: 6248c2ecf20Sopenharmony_ci * - If ARI is supported [likely], offset - (16 - pf_id) would 6258c2ecf20Sopenharmony_ci * provide the number for eng0. 2nd engine Vfs would begin 6268c2ecf20Sopenharmony_ci * after the first engine's VFs. 6278c2ecf20Sopenharmony_ci * - If !ARI, VFs would start on next device. 6288c2ecf20Sopenharmony_ci * so offset - (256 - pf_id) would provide the number. 6298c2ecf20Sopenharmony_ci * Utilize the fact that (256 - pf_id) is achieved only by later 6308c2ecf20Sopenharmony_ci * to differentiate between the two. 6318c2ecf20Sopenharmony_ci */ 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (p_hwfn->cdev->p_iov_info->offset < (256 - p_hwfn->abs_pf_id)) { 6348c2ecf20Sopenharmony_ci u32 first = p_hwfn->cdev->p_iov_info->offset + 6358c2ecf20Sopenharmony_ci p_hwfn->abs_pf_id - 16; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci cdev->p_iov_info->first_vf_in_pf = first; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (QED_PATH_ID(p_hwfn)) 6408c2ecf20Sopenharmony_ci cdev->p_iov_info->first_vf_in_pf -= MAX_NUM_VFS_BB; 6418c2ecf20Sopenharmony_ci } else { 6428c2ecf20Sopenharmony_ci u32 first = p_hwfn->cdev->p_iov_info->offset + 6438c2ecf20Sopenharmony_ci p_hwfn->abs_pf_id - 256; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci cdev->p_iov_info->first_vf_in_pf = first; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 6498c2ecf20Sopenharmony_ci "First VF in hwfn 0x%08x\n", 6508c2ecf20Sopenharmony_ci cdev->p_iov_info->first_vf_in_pf); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci return 0; 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic bool _qed_iov_pf_sanity_check(struct qed_hwfn *p_hwfn, 6568c2ecf20Sopenharmony_ci int vfid, bool b_fail_malicious) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci /* Check PF supports sriov */ 6598c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev) || !IS_QED_SRIOV(p_hwfn->cdev) || 6608c2ecf20Sopenharmony_ci !IS_PF_SRIOV_ALLOC(p_hwfn)) 6618c2ecf20Sopenharmony_ci return false; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* Check VF validity */ 6648c2ecf20Sopenharmony_ci if (!qed_iov_is_valid_vfid(p_hwfn, vfid, true, b_fail_malicious)) 6658c2ecf20Sopenharmony_ci return false; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci return true; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic bool qed_iov_pf_sanity_check(struct qed_hwfn *p_hwfn, int vfid) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci return _qed_iov_pf_sanity_check(p_hwfn, vfid, true); 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic void qed_iov_set_vf_to_disable(struct qed_dev *cdev, 6768c2ecf20Sopenharmony_ci u16 rel_vf_id, u8 to_disable) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct qed_vf_info *vf; 6798c2ecf20Sopenharmony_ci int i; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 6828c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, false); 6858c2ecf20Sopenharmony_ci if (!vf) 6868c2ecf20Sopenharmony_ci continue; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci vf->to_disable = to_disable; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic void qed_iov_set_vfs_to_disable(struct qed_dev *cdev, u8 to_disable) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci u16 i; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (!IS_QED_SRIOV(cdev)) 6978c2ecf20Sopenharmony_ci return; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci for (i = 0; i < cdev->p_iov_info->total_vfs; i++) 7008c2ecf20Sopenharmony_ci qed_iov_set_vf_to_disable(cdev, i, to_disable); 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic void qed_iov_vf_pglue_clear_err(struct qed_hwfn *p_hwfn, 7048c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u8 abs_vfid) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, 7078c2ecf20Sopenharmony_ci PGLUE_B_REG_WAS_ERROR_VF_31_0_CLR + (abs_vfid >> 5) * 4, 7088c2ecf20Sopenharmony_ci 1 << (abs_vfid & 0x1f)); 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic void qed_iov_vf_igu_reset(struct qed_hwfn *p_hwfn, 7128c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, struct qed_vf_info *vf) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci int i; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* Set VF masks and configuration - pretend */ 7178c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, (u16) vf->concrete_fid); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, IGU_REG_STATISTIC_NUM_VF_MSG_SENT, 0); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* unpretend */ 7228c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, (u16) p_hwfn->hw_info.concrete_fid); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* iterate over all queues, clear sb consumer */ 7258c2ecf20Sopenharmony_ci for (i = 0; i < vf->num_sbs; i++) 7268c2ecf20Sopenharmony_ci qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, 7278c2ecf20Sopenharmony_ci vf->igu_sbs[i], 7288c2ecf20Sopenharmony_ci vf->opaque_fid, true); 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic void qed_iov_vf_igu_set_int(struct qed_hwfn *p_hwfn, 7328c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 7338c2ecf20Sopenharmony_ci struct qed_vf_info *vf, bool enable) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci u32 igu_vf_conf; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, (u16) vf->concrete_fid); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci igu_vf_conf = qed_rd(p_hwfn, p_ptt, IGU_REG_VF_CONFIGURATION); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (enable) 7428c2ecf20Sopenharmony_ci igu_vf_conf |= IGU_VF_CONF_MSI_MSIX_EN; 7438c2ecf20Sopenharmony_ci else 7448c2ecf20Sopenharmony_ci igu_vf_conf &= ~IGU_VF_CONF_MSI_MSIX_EN; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, IGU_REG_VF_CONFIGURATION, igu_vf_conf); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* unpretend */ 7498c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, (u16) p_hwfn->hw_info.concrete_fid); 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic int 7538c2ecf20Sopenharmony_ciqed_iov_enable_vf_access_msix(struct qed_hwfn *p_hwfn, 7548c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u8 abs_vf_id, u8 num_sbs) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci u8 current_max = 0; 7578c2ecf20Sopenharmony_ci int i; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* For AH onward, configuration is per-PF. Find maximum of all 7608c2ecf20Sopenharmony_ci * the currently enabled child VFs, and set the number to be that. 7618c2ecf20Sopenharmony_ci */ 7628c2ecf20Sopenharmony_ci if (!QED_IS_BB(p_hwfn->cdev)) { 7638c2ecf20Sopenharmony_ci qed_for_each_vf(p_hwfn, i) { 7648c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci p_vf = qed_iov_get_vf_info(p_hwfn, (u16)i, true); 7678c2ecf20Sopenharmony_ci if (!p_vf) 7688c2ecf20Sopenharmony_ci continue; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci current_max = max_t(u8, current_max, p_vf->num_sbs); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (num_sbs > current_max) 7758c2ecf20Sopenharmony_ci return qed_mcp_config_vf_msix(p_hwfn, p_ptt, 7768c2ecf20Sopenharmony_ci abs_vf_id, num_sbs); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci return 0; 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic int qed_iov_enable_vf_access(struct qed_hwfn *p_hwfn, 7828c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 7838c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci u32 igu_vf_conf = IGU_VF_CONF_FUNC_EN; 7868c2ecf20Sopenharmony_ci int rc; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* It's possible VF was previously considered malicious - 7898c2ecf20Sopenharmony_ci * clear the indication even if we're only going to disable VF. 7908c2ecf20Sopenharmony_ci */ 7918c2ecf20Sopenharmony_ci vf->b_malicious = false; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (vf->to_disable) 7948c2ecf20Sopenharmony_ci return 0; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 7978c2ecf20Sopenharmony_ci QED_MSG_IOV, 7988c2ecf20Sopenharmony_ci "Enable internal access for vf %x [abs %x]\n", 7998c2ecf20Sopenharmony_ci vf->abs_vf_id, QED_VF_ABS_ID(p_hwfn, vf)); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci qed_iov_vf_pglue_clear_err(p_hwfn, p_ptt, QED_VF_ABS_ID(p_hwfn, vf)); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci qed_iov_vf_igu_reset(p_hwfn, p_ptt, vf); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci rc = qed_iov_enable_vf_access_msix(p_hwfn, p_ptt, 8068c2ecf20Sopenharmony_ci vf->abs_vf_id, vf->num_sbs); 8078c2ecf20Sopenharmony_ci if (rc) 8088c2ecf20Sopenharmony_ci return rc; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, (u16) vf->concrete_fid); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci SET_FIELD(igu_vf_conf, IGU_VF_CONF_PARENT, p_hwfn->rel_pf_id); 8138c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, IGU_REG_VF_CONFIGURATION_RT_OFFSET, igu_vf_conf); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci qed_init_run(p_hwfn, p_ptt, PHASE_VF, vf->abs_vf_id, 8168c2ecf20Sopenharmony_ci p_hwfn->hw_info.hw_mode); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* unpretend */ 8198c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, (u16) p_hwfn->hw_info.concrete_fid); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci vf->state = VF_FREE; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci return rc; 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci/** 8278c2ecf20Sopenharmony_ci * qed_iov_config_perm_table() - Configure the permission zone table. 8288c2ecf20Sopenharmony_ci * 8298c2ecf20Sopenharmony_ci * @p_hwfn: HW device data. 8308c2ecf20Sopenharmony_ci * @p_ptt: PTT window for writing the registers. 8318c2ecf20Sopenharmony_ci * @vf: VF info data. 8328c2ecf20Sopenharmony_ci * @enable: The actual permision for this VF. 8338c2ecf20Sopenharmony_ci * 8348c2ecf20Sopenharmony_ci * In E4, queue zone permission table size is 320x9. There 8358c2ecf20Sopenharmony_ci * are 320 VF queues for single engine device (256 for dual 8368c2ecf20Sopenharmony_ci * engine device), and each entry has the following format: 8378c2ecf20Sopenharmony_ci * {Valid, VF[7:0]} 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_cistatic void qed_iov_config_perm_table(struct qed_hwfn *p_hwfn, 8408c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 8418c2ecf20Sopenharmony_ci struct qed_vf_info *vf, u8 enable) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci u32 reg_addr, val; 8448c2ecf20Sopenharmony_ci u16 qzone_id = 0; 8458c2ecf20Sopenharmony_ci int qid; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci for (qid = 0; qid < vf->num_rxqs; qid++) { 8488c2ecf20Sopenharmony_ci qed_fw_l2_queue(p_hwfn, vf->vf_queues[qid].fw_rx_qid, 8498c2ecf20Sopenharmony_ci &qzone_id); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci reg_addr = PSWHST_REG_ZONE_PERMISSION_TABLE + qzone_id * 4; 8528c2ecf20Sopenharmony_ci val = enable ? (vf->abs_vf_id | BIT(8)) : 0; 8538c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, reg_addr, val); 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic void qed_iov_enable_vf_traffic(struct qed_hwfn *p_hwfn, 8588c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 8598c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci /* Reset vf in IGU - interrupts are still disabled */ 8628c2ecf20Sopenharmony_ci qed_iov_vf_igu_reset(p_hwfn, p_ptt, vf); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci qed_iov_vf_igu_set_int(p_hwfn, p_ptt, vf, 1); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* Permission Table */ 8678c2ecf20Sopenharmony_ci qed_iov_config_perm_table(p_hwfn, p_ptt, vf, true); 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_cistatic u8 qed_iov_alloc_vf_igu_sbs(struct qed_hwfn *p_hwfn, 8718c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 8728c2ecf20Sopenharmony_ci struct qed_vf_info *vf, u16 num_rx_queues) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci struct qed_igu_block *p_block; 8758c2ecf20Sopenharmony_ci struct cau_sb_entry sb_entry; 8768c2ecf20Sopenharmony_ci int qid = 0; 8778c2ecf20Sopenharmony_ci u32 val = 0; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (num_rx_queues > p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov) 8808c2ecf20Sopenharmony_ci num_rx_queues = p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov; 8818c2ecf20Sopenharmony_ci p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov -= num_rx_queues; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci SET_FIELD(val, IGU_MAPPING_LINE_FUNCTION_NUMBER, vf->abs_vf_id); 8848c2ecf20Sopenharmony_ci SET_FIELD(val, IGU_MAPPING_LINE_VALID, 1); 8858c2ecf20Sopenharmony_ci SET_FIELD(val, IGU_MAPPING_LINE_PF_VALID, 0); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci for (qid = 0; qid < num_rx_queues; qid++) { 8888c2ecf20Sopenharmony_ci p_block = qed_get_igu_free_sb(p_hwfn, false); 8898c2ecf20Sopenharmony_ci vf->igu_sbs[qid] = p_block->igu_sb_id; 8908c2ecf20Sopenharmony_ci p_block->status &= ~QED_IGU_STATUS_FREE; 8918c2ecf20Sopenharmony_ci SET_FIELD(val, IGU_MAPPING_LINE_VECTOR_NUMBER, qid); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, 8948c2ecf20Sopenharmony_ci IGU_REG_MAPPING_MEMORY + 8958c2ecf20Sopenharmony_ci sizeof(u32) * p_block->igu_sb_id, val); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* Configure igu sb in CAU which were marked valid */ 8988c2ecf20Sopenharmony_ci qed_init_cau_sb_entry(p_hwfn, &sb_entry, 8998c2ecf20Sopenharmony_ci p_hwfn->rel_pf_id, vf->abs_vf_id, 1); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci qed_dmae_host2grc(p_hwfn, p_ptt, 9028c2ecf20Sopenharmony_ci (u64)(uintptr_t)&sb_entry, 9038c2ecf20Sopenharmony_ci CAU_REG_SB_VAR_MEMORY + 9048c2ecf20Sopenharmony_ci p_block->igu_sb_id * sizeof(u64), 2, NULL); 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci vf->num_sbs = (u8) num_rx_queues; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci return vf->num_sbs; 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_cistatic void qed_iov_free_vf_igu_sbs(struct qed_hwfn *p_hwfn, 9138c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 9148c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci struct qed_igu_info *p_info = p_hwfn->hw_info.p_igu_info; 9178c2ecf20Sopenharmony_ci int idx, igu_id; 9188c2ecf20Sopenharmony_ci u32 addr, val; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* Invalidate igu CAM lines and mark them as free */ 9218c2ecf20Sopenharmony_ci for (idx = 0; idx < vf->num_sbs; idx++) { 9228c2ecf20Sopenharmony_ci igu_id = vf->igu_sbs[idx]; 9238c2ecf20Sopenharmony_ci addr = IGU_REG_MAPPING_MEMORY + sizeof(u32) * igu_id; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci val = qed_rd(p_hwfn, p_ptt, addr); 9268c2ecf20Sopenharmony_ci SET_FIELD(val, IGU_MAPPING_LINE_VALID, 0); 9278c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, addr, val); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci p_info->entry[igu_id].status |= QED_IGU_STATUS_FREE; 9308c2ecf20Sopenharmony_ci p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov++; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci vf->num_sbs = 0; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cistatic void qed_iov_set_link(struct qed_hwfn *p_hwfn, 9378c2ecf20Sopenharmony_ci u16 vfid, 9388c2ecf20Sopenharmony_ci struct qed_mcp_link_params *params, 9398c2ecf20Sopenharmony_ci struct qed_mcp_link_state *link, 9408c2ecf20Sopenharmony_ci struct qed_mcp_link_capabilities *p_caps) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf = qed_iov_get_vf_info(p_hwfn, 9438c2ecf20Sopenharmony_ci vfid, 9448c2ecf20Sopenharmony_ci false); 9458c2ecf20Sopenharmony_ci struct qed_bulletin_content *p_bulletin; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci if (!p_vf) 9488c2ecf20Sopenharmony_ci return; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci p_bulletin = p_vf->bulletin.p_virt; 9518c2ecf20Sopenharmony_ci p_bulletin->req_autoneg = params->speed.autoneg; 9528c2ecf20Sopenharmony_ci p_bulletin->req_adv_speed = params->speed.advertised_speeds; 9538c2ecf20Sopenharmony_ci p_bulletin->req_forced_speed = params->speed.forced_speed; 9548c2ecf20Sopenharmony_ci p_bulletin->req_autoneg_pause = params->pause.autoneg; 9558c2ecf20Sopenharmony_ci p_bulletin->req_forced_rx = params->pause.forced_rx; 9568c2ecf20Sopenharmony_ci p_bulletin->req_forced_tx = params->pause.forced_tx; 9578c2ecf20Sopenharmony_ci p_bulletin->req_loopback = params->loopback_mode; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci p_bulletin->link_up = link->link_up; 9608c2ecf20Sopenharmony_ci p_bulletin->speed = link->speed; 9618c2ecf20Sopenharmony_ci p_bulletin->full_duplex = link->full_duplex; 9628c2ecf20Sopenharmony_ci p_bulletin->autoneg = link->an; 9638c2ecf20Sopenharmony_ci p_bulletin->autoneg_complete = link->an_complete; 9648c2ecf20Sopenharmony_ci p_bulletin->parallel_detection = link->parallel_detection; 9658c2ecf20Sopenharmony_ci p_bulletin->pfc_enabled = link->pfc_enabled; 9668c2ecf20Sopenharmony_ci p_bulletin->partner_adv_speed = link->partner_adv_speed; 9678c2ecf20Sopenharmony_ci p_bulletin->partner_tx_flow_ctrl_en = link->partner_tx_flow_ctrl_en; 9688c2ecf20Sopenharmony_ci p_bulletin->partner_rx_flow_ctrl_en = link->partner_rx_flow_ctrl_en; 9698c2ecf20Sopenharmony_ci p_bulletin->partner_adv_pause = link->partner_adv_pause; 9708c2ecf20Sopenharmony_ci p_bulletin->sfp_tx_fault = link->sfp_tx_fault; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci p_bulletin->capability_speed = p_caps->speed_capabilities; 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic int qed_iov_init_hw_for_vf(struct qed_hwfn *p_hwfn, 9768c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 9778c2ecf20Sopenharmony_ci struct qed_iov_vf_init_params *p_params) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci struct qed_mcp_link_capabilities link_caps; 9808c2ecf20Sopenharmony_ci struct qed_mcp_link_params link_params; 9818c2ecf20Sopenharmony_ci struct qed_mcp_link_state link_state; 9828c2ecf20Sopenharmony_ci u8 num_of_vf_avaiable_chains = 0; 9838c2ecf20Sopenharmony_ci struct qed_vf_info *vf = NULL; 9848c2ecf20Sopenharmony_ci u16 qid, num_irqs; 9858c2ecf20Sopenharmony_ci int rc = 0; 9868c2ecf20Sopenharmony_ci u32 cids; 9878c2ecf20Sopenharmony_ci u8 i; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci vf = qed_iov_get_vf_info(p_hwfn, p_params->rel_vf_id, false); 9908c2ecf20Sopenharmony_ci if (!vf) { 9918c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "qed_iov_init_hw_for_vf : vf is NULL\n"); 9928c2ecf20Sopenharmony_ci return -EINVAL; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (vf->b_init) { 9968c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "VF[%d] is already active.\n", 9978c2ecf20Sopenharmony_ci p_params->rel_vf_id); 9988c2ecf20Sopenharmony_ci return -EINVAL; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* Perform sanity checking on the requested queue_id */ 10028c2ecf20Sopenharmony_ci for (i = 0; i < p_params->num_queues; i++) { 10038c2ecf20Sopenharmony_ci u16 min_vf_qzone = FEAT_NUM(p_hwfn, QED_PF_L2_QUE); 10048c2ecf20Sopenharmony_ci u16 max_vf_qzone = min_vf_qzone + 10058c2ecf20Sopenharmony_ci FEAT_NUM(p_hwfn, QED_VF_L2_QUE) - 1; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci qid = p_params->req_rx_queue[i]; 10088c2ecf20Sopenharmony_ci if (qid < min_vf_qzone || qid > max_vf_qzone) { 10098c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 10108c2ecf20Sopenharmony_ci "Can't enable Rx qid [%04x] for VF[%d]: qids [0x%04x,...,0x%04x] available\n", 10118c2ecf20Sopenharmony_ci qid, 10128c2ecf20Sopenharmony_ci p_params->rel_vf_id, 10138c2ecf20Sopenharmony_ci min_vf_qzone, max_vf_qzone); 10148c2ecf20Sopenharmony_ci return -EINVAL; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci qid = p_params->req_tx_queue[i]; 10188c2ecf20Sopenharmony_ci if (qid > max_vf_qzone) { 10198c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 10208c2ecf20Sopenharmony_ci "Can't enable Tx qid [%04x] for VF[%d]: max qid 0x%04x\n", 10218c2ecf20Sopenharmony_ci qid, p_params->rel_vf_id, max_vf_qzone); 10228c2ecf20Sopenharmony_ci return -EINVAL; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci /* If client *really* wants, Tx qid can be shared with PF */ 10268c2ecf20Sopenharmony_ci if (qid < min_vf_qzone) 10278c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 10288c2ecf20Sopenharmony_ci QED_MSG_IOV, 10298c2ecf20Sopenharmony_ci "VF[%d] is using PF qid [0x%04x] for Txq[0x%02x]\n", 10308c2ecf20Sopenharmony_ci p_params->rel_vf_id, qid, i); 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci /* Limit number of queues according to number of CIDs */ 10348c2ecf20Sopenharmony_ci qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ETH, &cids); 10358c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 10368c2ecf20Sopenharmony_ci QED_MSG_IOV, 10378c2ecf20Sopenharmony_ci "VF[%d] - requesting to initialize for 0x%04x queues [0x%04x CIDs available]\n", 10388c2ecf20Sopenharmony_ci vf->relative_vf_id, p_params->num_queues, (u16)cids); 10398c2ecf20Sopenharmony_ci num_irqs = min_t(u16, p_params->num_queues, ((u16)cids)); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci num_of_vf_avaiable_chains = qed_iov_alloc_vf_igu_sbs(p_hwfn, 10428c2ecf20Sopenharmony_ci p_ptt, 10438c2ecf20Sopenharmony_ci vf, num_irqs); 10448c2ecf20Sopenharmony_ci if (!num_of_vf_avaiable_chains) { 10458c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "no available igu sbs\n"); 10468c2ecf20Sopenharmony_ci return -ENOMEM; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* Choose queue number and index ranges */ 10508c2ecf20Sopenharmony_ci vf->num_rxqs = num_of_vf_avaiable_chains; 10518c2ecf20Sopenharmony_ci vf->num_txqs = num_of_vf_avaiable_chains; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci for (i = 0; i < vf->num_rxqs; i++) { 10548c2ecf20Sopenharmony_ci struct qed_vf_queue *p_queue = &vf->vf_queues[i]; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci p_queue->fw_rx_qid = p_params->req_rx_queue[i]; 10578c2ecf20Sopenharmony_ci p_queue->fw_tx_qid = p_params->req_tx_queue[i]; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 10608c2ecf20Sopenharmony_ci "VF[%d] - Q[%d] SB %04x, qid [Rx %04x Tx %04x]\n", 10618c2ecf20Sopenharmony_ci vf->relative_vf_id, i, vf->igu_sbs[i], 10628c2ecf20Sopenharmony_ci p_queue->fw_rx_qid, p_queue->fw_tx_qid); 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci /* Update the link configuration in bulletin */ 10668c2ecf20Sopenharmony_ci memcpy(&link_params, qed_mcp_get_link_params(p_hwfn), 10678c2ecf20Sopenharmony_ci sizeof(link_params)); 10688c2ecf20Sopenharmony_ci memcpy(&link_state, qed_mcp_get_link_state(p_hwfn), sizeof(link_state)); 10698c2ecf20Sopenharmony_ci memcpy(&link_caps, qed_mcp_get_link_capabilities(p_hwfn), 10708c2ecf20Sopenharmony_ci sizeof(link_caps)); 10718c2ecf20Sopenharmony_ci qed_iov_set_link(p_hwfn, p_params->rel_vf_id, 10728c2ecf20Sopenharmony_ci &link_params, &link_state, &link_caps); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci rc = qed_iov_enable_vf_access(p_hwfn, p_ptt, vf); 10758c2ecf20Sopenharmony_ci if (!rc) { 10768c2ecf20Sopenharmony_ci vf->b_init = true; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn)) 10798c2ecf20Sopenharmony_ci p_hwfn->cdev->p_iov_info->num_vfs++; 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci return rc; 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistatic int qed_iov_release_hw_for_vf(struct qed_hwfn *p_hwfn, 10868c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u16 rel_vf_id) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci struct qed_mcp_link_capabilities caps; 10898c2ecf20Sopenharmony_ci struct qed_mcp_link_params params; 10908c2ecf20Sopenharmony_ci struct qed_mcp_link_state link; 10918c2ecf20Sopenharmony_ci struct qed_vf_info *vf = NULL; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, true); 10948c2ecf20Sopenharmony_ci if (!vf) { 10958c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "qed_iov_release_hw_for_vf : vf is NULL\n"); 10968c2ecf20Sopenharmony_ci return -EINVAL; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (vf->bulletin.p_virt) 11008c2ecf20Sopenharmony_ci memset(vf->bulletin.p_virt, 0, sizeof(*vf->bulletin.p_virt)); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci memset(&vf->p_vf_info, 0, sizeof(vf->p_vf_info)); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* Get the link configuration back in bulletin so 11058c2ecf20Sopenharmony_ci * that when VFs are re-enabled they get the actual 11068c2ecf20Sopenharmony_ci * link configuration. 11078c2ecf20Sopenharmony_ci */ 11088c2ecf20Sopenharmony_ci memcpy(¶ms, qed_mcp_get_link_params(p_hwfn), sizeof(params)); 11098c2ecf20Sopenharmony_ci memcpy(&link, qed_mcp_get_link_state(p_hwfn), sizeof(link)); 11108c2ecf20Sopenharmony_ci memcpy(&caps, qed_mcp_get_link_capabilities(p_hwfn), sizeof(caps)); 11118c2ecf20Sopenharmony_ci qed_iov_set_link(p_hwfn, rel_vf_id, ¶ms, &link, &caps); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* Forget the VF's acquisition message */ 11148c2ecf20Sopenharmony_ci memset(&vf->acquire, 0, sizeof(vf->acquire)); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci /* disablng interrupts and resetting permission table was done during 11178c2ecf20Sopenharmony_ci * vf-close, however, we could get here without going through vf_close 11188c2ecf20Sopenharmony_ci */ 11198c2ecf20Sopenharmony_ci /* Disable Interrupts for VF */ 11208c2ecf20Sopenharmony_ci qed_iov_vf_igu_set_int(p_hwfn, p_ptt, vf, 0); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* Reset Permission table */ 11238c2ecf20Sopenharmony_ci qed_iov_config_perm_table(p_hwfn, p_ptt, vf, 0); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci vf->num_rxqs = 0; 11268c2ecf20Sopenharmony_ci vf->num_txqs = 0; 11278c2ecf20Sopenharmony_ci qed_iov_free_vf_igu_sbs(p_hwfn, p_ptt, vf); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci if (vf->b_init) { 11308c2ecf20Sopenharmony_ci vf->b_init = false; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn)) 11338c2ecf20Sopenharmony_ci p_hwfn->cdev->p_iov_info->num_vfs--; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci return 0; 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_cistatic bool qed_iov_tlv_supported(u16 tlvtype) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci return CHANNEL_TLV_NONE < tlvtype && tlvtype < CHANNEL_TLV_MAX; 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci/* place a given tlv on the tlv buffer, continuing current tlv list */ 11458c2ecf20Sopenharmony_civoid *qed_add_tlv(struct qed_hwfn *p_hwfn, u8 **offset, u16 type, u16 length) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci struct channel_tlv *tl = (struct channel_tlv *)*offset; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci tl->type = type; 11508c2ecf20Sopenharmony_ci tl->length = length; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci /* Offset should keep pointing to next TLV (the end of the last) */ 11538c2ecf20Sopenharmony_ci *offset += length; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* Return a pointer to the start of the added tlv */ 11568c2ecf20Sopenharmony_ci return *offset - length; 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci/* list the types and lengths of the tlvs on the buffer */ 11608c2ecf20Sopenharmony_civoid qed_dp_tlv_list(struct qed_hwfn *p_hwfn, void *tlvs_list) 11618c2ecf20Sopenharmony_ci{ 11628c2ecf20Sopenharmony_ci u16 i = 1, total_length = 0; 11638c2ecf20Sopenharmony_ci struct channel_tlv *tlv; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci do { 11668c2ecf20Sopenharmony_ci tlv = (struct channel_tlv *)((u8 *)tlvs_list + total_length); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci /* output tlv */ 11698c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 11708c2ecf20Sopenharmony_ci "TLV number %d: type %d, length %d\n", 11718c2ecf20Sopenharmony_ci i, tlv->type, tlv->length); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci if (tlv->type == CHANNEL_TLV_LIST_END) 11748c2ecf20Sopenharmony_ci return; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci /* Validate entry - protect against malicious VFs */ 11778c2ecf20Sopenharmony_ci if (!tlv->length) { 11788c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "TLV of length 0 found\n"); 11798c2ecf20Sopenharmony_ci return; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci total_length += tlv->length; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci if (total_length >= sizeof(struct tlv_buffer_size)) { 11858c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "TLV ==> Buffer overflow\n"); 11868c2ecf20Sopenharmony_ci return; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci i++; 11908c2ecf20Sopenharmony_ci } while (1); 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_cistatic void qed_iov_send_response(struct qed_hwfn *p_hwfn, 11948c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 11958c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 11968c2ecf20Sopenharmony_ci u16 length, u8 status) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx; 11998c2ecf20Sopenharmony_ci struct qed_dmae_params params; 12008c2ecf20Sopenharmony_ci u8 eng_vf_id; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci mbx->reply_virt->default_resp.hdr.status = status; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci qed_dp_tlv_list(p_hwfn, mbx->reply_virt); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci eng_vf_id = p_vf->abs_vf_id; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 12098c2ecf20Sopenharmony_ci SET_FIELD(params.flags, QED_DMAE_PARAMS_DST_VF_VALID, 0x1); 12108c2ecf20Sopenharmony_ci params.dst_vfid = eng_vf_id; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci qed_dmae_host2host(p_hwfn, p_ptt, mbx->reply_phys + sizeof(u64), 12138c2ecf20Sopenharmony_ci mbx->req_virt->first_tlv.reply_address + 12148c2ecf20Sopenharmony_ci sizeof(u64), 12158c2ecf20Sopenharmony_ci (sizeof(union pfvf_tlvs) - sizeof(u64)) / 4, 12168c2ecf20Sopenharmony_ci ¶ms); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* Once PF copies the rc to the VF, the latter can continue 12198c2ecf20Sopenharmony_ci * and send an additional message. So we have to make sure the 12208c2ecf20Sopenharmony_ci * channel would be re-set to ready prior to that. 12218c2ecf20Sopenharmony_ci */ 12228c2ecf20Sopenharmony_ci REG_WR(p_hwfn, 12238c2ecf20Sopenharmony_ci GTT_BAR0_MAP_REG_USDM_RAM + 12248c2ecf20Sopenharmony_ci USTORM_VF_PF_CHANNEL_READY_OFFSET(eng_vf_id), 1); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci qed_dmae_host2host(p_hwfn, p_ptt, mbx->reply_phys, 12278c2ecf20Sopenharmony_ci mbx->req_virt->first_tlv.reply_address, 12288c2ecf20Sopenharmony_ci sizeof(u64) / 4, ¶ms); 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_cistatic u16 qed_iov_vport_to_tlv(struct qed_hwfn *p_hwfn, 12328c2ecf20Sopenharmony_ci enum qed_iov_vport_update_flag flag) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci switch (flag) { 12358c2ecf20Sopenharmony_ci case QED_IOV_VP_UPDATE_ACTIVATE: 12368c2ecf20Sopenharmony_ci return CHANNEL_TLV_VPORT_UPDATE_ACTIVATE; 12378c2ecf20Sopenharmony_ci case QED_IOV_VP_UPDATE_VLAN_STRIP: 12388c2ecf20Sopenharmony_ci return CHANNEL_TLV_VPORT_UPDATE_VLAN_STRIP; 12398c2ecf20Sopenharmony_ci case QED_IOV_VP_UPDATE_TX_SWITCH: 12408c2ecf20Sopenharmony_ci return CHANNEL_TLV_VPORT_UPDATE_TX_SWITCH; 12418c2ecf20Sopenharmony_ci case QED_IOV_VP_UPDATE_MCAST: 12428c2ecf20Sopenharmony_ci return CHANNEL_TLV_VPORT_UPDATE_MCAST; 12438c2ecf20Sopenharmony_ci case QED_IOV_VP_UPDATE_ACCEPT_PARAM: 12448c2ecf20Sopenharmony_ci return CHANNEL_TLV_VPORT_UPDATE_ACCEPT_PARAM; 12458c2ecf20Sopenharmony_ci case QED_IOV_VP_UPDATE_RSS: 12468c2ecf20Sopenharmony_ci return CHANNEL_TLV_VPORT_UPDATE_RSS; 12478c2ecf20Sopenharmony_ci case QED_IOV_VP_UPDATE_ACCEPT_ANY_VLAN: 12488c2ecf20Sopenharmony_ci return CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN; 12498c2ecf20Sopenharmony_ci case QED_IOV_VP_UPDATE_SGE_TPA: 12508c2ecf20Sopenharmony_ci return CHANNEL_TLV_VPORT_UPDATE_SGE_TPA; 12518c2ecf20Sopenharmony_ci default: 12528c2ecf20Sopenharmony_ci return 0; 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic u16 qed_iov_prep_vp_update_resp_tlvs(struct qed_hwfn *p_hwfn, 12578c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 12588c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *p_mbx, 12598c2ecf20Sopenharmony_ci u8 status, 12608c2ecf20Sopenharmony_ci u16 tlvs_mask, u16 tlvs_accepted) 12618c2ecf20Sopenharmony_ci{ 12628c2ecf20Sopenharmony_ci struct pfvf_def_resp_tlv *resp; 12638c2ecf20Sopenharmony_ci u16 size, total_len, i; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci memset(p_mbx->reply_virt, 0, sizeof(union pfvf_tlvs)); 12668c2ecf20Sopenharmony_ci p_mbx->offset = (u8 *)p_mbx->reply_virt; 12678c2ecf20Sopenharmony_ci size = sizeof(struct pfvf_def_resp_tlv); 12688c2ecf20Sopenharmony_ci total_len = size; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci qed_add_tlv(p_hwfn, &p_mbx->offset, CHANNEL_TLV_VPORT_UPDATE, size); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci /* Prepare response for all extended tlvs if they are found by PF */ 12738c2ecf20Sopenharmony_ci for (i = 0; i < QED_IOV_VP_UPDATE_MAX; i++) { 12748c2ecf20Sopenharmony_ci if (!(tlvs_mask & BIT(i))) 12758c2ecf20Sopenharmony_ci continue; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci resp = qed_add_tlv(p_hwfn, &p_mbx->offset, 12788c2ecf20Sopenharmony_ci qed_iov_vport_to_tlv(p_hwfn, i), size); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci if (tlvs_accepted & BIT(i)) 12818c2ecf20Sopenharmony_ci resp->hdr.status = status; 12828c2ecf20Sopenharmony_ci else 12838c2ecf20Sopenharmony_ci resp->hdr.status = PFVF_STATUS_NOT_SUPPORTED; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 12868c2ecf20Sopenharmony_ci QED_MSG_IOV, 12878c2ecf20Sopenharmony_ci "VF[%d] - vport_update response: TLV %d, status %02x\n", 12888c2ecf20Sopenharmony_ci p_vf->relative_vf_id, 12898c2ecf20Sopenharmony_ci qed_iov_vport_to_tlv(p_hwfn, i), resp->hdr.status); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci total_len += size; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci qed_add_tlv(p_hwfn, &p_mbx->offset, CHANNEL_TLV_LIST_END, 12958c2ecf20Sopenharmony_ci sizeof(struct channel_list_end_tlv)); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci return total_len; 12988c2ecf20Sopenharmony_ci} 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_cistatic void qed_iov_prepare_resp(struct qed_hwfn *p_hwfn, 13018c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 13028c2ecf20Sopenharmony_ci struct qed_vf_info *vf_info, 13038c2ecf20Sopenharmony_ci u16 type, u16 length, u8 status) 13048c2ecf20Sopenharmony_ci{ 13058c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf_info->vf_mbx; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci mbx->offset = (u8 *)mbx->reply_virt; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci qed_add_tlv(p_hwfn, &mbx->offset, type, length); 13108c2ecf20Sopenharmony_ci qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_LIST_END, 13118c2ecf20Sopenharmony_ci sizeof(struct channel_list_end_tlv)); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci qed_iov_send_response(p_hwfn, p_ptt, vf_info, length, status); 13148c2ecf20Sopenharmony_ci} 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_cistatic struct 13178c2ecf20Sopenharmony_ciqed_public_vf_info *qed_iov_get_public_vf_info(struct qed_hwfn *p_hwfn, 13188c2ecf20Sopenharmony_ci u16 relative_vf_id, 13198c2ecf20Sopenharmony_ci bool b_enabled_only) 13208c2ecf20Sopenharmony_ci{ 13218c2ecf20Sopenharmony_ci struct qed_vf_info *vf = NULL; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci vf = qed_iov_get_vf_info(p_hwfn, relative_vf_id, b_enabled_only); 13248c2ecf20Sopenharmony_ci if (!vf) 13258c2ecf20Sopenharmony_ci return NULL; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci return &vf->p_vf_info; 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_cistatic void qed_iov_clean_vf(struct qed_hwfn *p_hwfn, u8 vfid) 13318c2ecf20Sopenharmony_ci{ 13328c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf_info; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci vf_info = qed_iov_get_public_vf_info(p_hwfn, vfid, false); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci if (!vf_info) 13378c2ecf20Sopenharmony_ci return; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci /* Clear the VF mac */ 13408c2ecf20Sopenharmony_ci eth_zero_addr(vf_info->mac); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci vf_info->rx_accept_mode = 0; 13438c2ecf20Sopenharmony_ci vf_info->tx_accept_mode = 0; 13448c2ecf20Sopenharmony_ci} 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_cistatic void qed_iov_vf_cleanup(struct qed_hwfn *p_hwfn, 13478c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf) 13488c2ecf20Sopenharmony_ci{ 13498c2ecf20Sopenharmony_ci u32 i, j; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci p_vf->vf_bulletin = 0; 13528c2ecf20Sopenharmony_ci p_vf->vport_instance = 0; 13538c2ecf20Sopenharmony_ci p_vf->configured_features = 0; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci /* If VF previously requested less resources, go back to default */ 13568c2ecf20Sopenharmony_ci p_vf->num_rxqs = p_vf->num_sbs; 13578c2ecf20Sopenharmony_ci p_vf->num_txqs = p_vf->num_sbs; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci p_vf->num_active_rxqs = 0; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci for (i = 0; i < QED_MAX_VF_CHAINS_PER_PF; i++) { 13628c2ecf20Sopenharmony_ci struct qed_vf_queue *p_queue = &p_vf->vf_queues[i]; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci for (j = 0; j < MAX_QUEUES_PER_QZONE; j++) { 13658c2ecf20Sopenharmony_ci if (!p_queue->cids[j].p_cid) 13668c2ecf20Sopenharmony_ci continue; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci qed_eth_queue_cid_release(p_hwfn, 13698c2ecf20Sopenharmony_ci p_queue->cids[j].p_cid); 13708c2ecf20Sopenharmony_ci p_queue->cids[j].p_cid = NULL; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci memset(&p_vf->shadow_config, 0, sizeof(p_vf->shadow_config)); 13758c2ecf20Sopenharmony_ci memset(&p_vf->acquire, 0, sizeof(p_vf->acquire)); 13768c2ecf20Sopenharmony_ci qed_iov_clean_vf(p_hwfn, p_vf->relative_vf_id); 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci/* Returns either 0, or log(size) */ 13808c2ecf20Sopenharmony_cistatic u32 qed_iov_vf_db_bar_size(struct qed_hwfn *p_hwfn, 13818c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 13828c2ecf20Sopenharmony_ci{ 13838c2ecf20Sopenharmony_ci u32 val = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_VF_BAR1_SIZE); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci if (val) 13868c2ecf20Sopenharmony_ci return val + 11; 13878c2ecf20Sopenharmony_ci return 0; 13888c2ecf20Sopenharmony_ci} 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_cistatic void 13918c2ecf20Sopenharmony_ciqed_iov_vf_mbx_acquire_resc_cids(struct qed_hwfn *p_hwfn, 13928c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 13938c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 13948c2ecf20Sopenharmony_ci struct vf_pf_resc_request *p_req, 13958c2ecf20Sopenharmony_ci struct pf_vf_resc *p_resp) 13968c2ecf20Sopenharmony_ci{ 13978c2ecf20Sopenharmony_ci u8 num_vf_cons = p_hwfn->pf_params.eth_pf_params.num_vf_cons; 13988c2ecf20Sopenharmony_ci u8 db_size = qed_db_addr_vf(1, DQ_DEMS_LEGACY) - 13998c2ecf20Sopenharmony_ci qed_db_addr_vf(0, DQ_DEMS_LEGACY); 14008c2ecf20Sopenharmony_ci u32 bar_size; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci p_resp->num_cids = min_t(u8, p_req->num_cids, num_vf_cons); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci /* If VF didn't bother asking for QIDs than don't bother limiting 14058c2ecf20Sopenharmony_ci * number of CIDs. The VF doesn't care about the number, and this 14068c2ecf20Sopenharmony_ci * has the likely result of causing an additional acquisition. 14078c2ecf20Sopenharmony_ci */ 14088c2ecf20Sopenharmony_ci if (!(p_vf->acquire.vfdev_info.capabilities & 14098c2ecf20Sopenharmony_ci VFPF_ACQUIRE_CAP_QUEUE_QIDS)) 14108c2ecf20Sopenharmony_ci return; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci /* If doorbell bar was mapped by VF, limit the VF CIDs to an amount 14138c2ecf20Sopenharmony_ci * that would make sure doorbells for all CIDs fall within the bar. 14148c2ecf20Sopenharmony_ci * If it doesn't, make sure regview window is sufficient. 14158c2ecf20Sopenharmony_ci */ 14168c2ecf20Sopenharmony_ci if (p_vf->acquire.vfdev_info.capabilities & 14178c2ecf20Sopenharmony_ci VFPF_ACQUIRE_CAP_PHYSICAL_BAR) { 14188c2ecf20Sopenharmony_ci bar_size = qed_iov_vf_db_bar_size(p_hwfn, p_ptt); 14198c2ecf20Sopenharmony_ci if (bar_size) 14208c2ecf20Sopenharmony_ci bar_size = 1 << bar_size; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (p_hwfn->cdev->num_hwfns > 1) 14238c2ecf20Sopenharmony_ci bar_size /= 2; 14248c2ecf20Sopenharmony_ci } else { 14258c2ecf20Sopenharmony_ci bar_size = PXP_VF_BAR0_DQ_LENGTH; 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if (bar_size / db_size < 256) 14298c2ecf20Sopenharmony_ci p_resp->num_cids = min_t(u8, p_resp->num_cids, 14308c2ecf20Sopenharmony_ci (u8)(bar_size / db_size)); 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_cistatic u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, 14348c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 14358c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 14368c2ecf20Sopenharmony_ci struct vf_pf_resc_request *p_req, 14378c2ecf20Sopenharmony_ci struct pf_vf_resc *p_resp) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci u8 i; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci /* Queue related information */ 14428c2ecf20Sopenharmony_ci p_resp->num_rxqs = p_vf->num_rxqs; 14438c2ecf20Sopenharmony_ci p_resp->num_txqs = p_vf->num_txqs; 14448c2ecf20Sopenharmony_ci p_resp->num_sbs = p_vf->num_sbs; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci for (i = 0; i < p_resp->num_sbs; i++) { 14478c2ecf20Sopenharmony_ci p_resp->hw_sbs[i].hw_sb_id = p_vf->igu_sbs[i]; 14488c2ecf20Sopenharmony_ci p_resp->hw_sbs[i].sb_qid = 0; 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci /* These fields are filled for backward compatibility. 14528c2ecf20Sopenharmony_ci * Unused by modern vfs. 14538c2ecf20Sopenharmony_ci */ 14548c2ecf20Sopenharmony_ci for (i = 0; i < p_resp->num_rxqs; i++) { 14558c2ecf20Sopenharmony_ci qed_fw_l2_queue(p_hwfn, p_vf->vf_queues[i].fw_rx_qid, 14568c2ecf20Sopenharmony_ci (u16 *)&p_resp->hw_qid[i]); 14578c2ecf20Sopenharmony_ci p_resp->cid[i] = i; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* Filter related information */ 14618c2ecf20Sopenharmony_ci p_resp->num_mac_filters = min_t(u8, p_vf->num_mac_filters, 14628c2ecf20Sopenharmony_ci p_req->num_mac_filters); 14638c2ecf20Sopenharmony_ci p_resp->num_vlan_filters = min_t(u8, p_vf->num_vlan_filters, 14648c2ecf20Sopenharmony_ci p_req->num_vlan_filters); 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci qed_iov_vf_mbx_acquire_resc_cids(p_hwfn, p_ptt, p_vf, p_req, p_resp); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci /* This isn't really needed/enforced, but some legacy VFs might depend 14698c2ecf20Sopenharmony_ci * on the correct filling of this field. 14708c2ecf20Sopenharmony_ci */ 14718c2ecf20Sopenharmony_ci p_resp->num_mc_filters = QED_MAX_MC_ADDRS; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci /* Validate sufficient resources for VF */ 14748c2ecf20Sopenharmony_ci if (p_resp->num_rxqs < p_req->num_rxqs || 14758c2ecf20Sopenharmony_ci p_resp->num_txqs < p_req->num_txqs || 14768c2ecf20Sopenharmony_ci p_resp->num_sbs < p_req->num_sbs || 14778c2ecf20Sopenharmony_ci p_resp->num_mac_filters < p_req->num_mac_filters || 14788c2ecf20Sopenharmony_ci p_resp->num_vlan_filters < p_req->num_vlan_filters || 14798c2ecf20Sopenharmony_ci p_resp->num_mc_filters < p_req->num_mc_filters || 14808c2ecf20Sopenharmony_ci p_resp->num_cids < p_req->num_cids) { 14818c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 14828c2ecf20Sopenharmony_ci QED_MSG_IOV, 14838c2ecf20Sopenharmony_ci "VF[%d] - Insufficient resources: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x] cids [%02x/%02x]\n", 14848c2ecf20Sopenharmony_ci p_vf->abs_vf_id, 14858c2ecf20Sopenharmony_ci p_req->num_rxqs, 14868c2ecf20Sopenharmony_ci p_resp->num_rxqs, 14878c2ecf20Sopenharmony_ci p_req->num_rxqs, 14888c2ecf20Sopenharmony_ci p_resp->num_txqs, 14898c2ecf20Sopenharmony_ci p_req->num_sbs, 14908c2ecf20Sopenharmony_ci p_resp->num_sbs, 14918c2ecf20Sopenharmony_ci p_req->num_mac_filters, 14928c2ecf20Sopenharmony_ci p_resp->num_mac_filters, 14938c2ecf20Sopenharmony_ci p_req->num_vlan_filters, 14948c2ecf20Sopenharmony_ci p_resp->num_vlan_filters, 14958c2ecf20Sopenharmony_ci p_req->num_mc_filters, 14968c2ecf20Sopenharmony_ci p_resp->num_mc_filters, 14978c2ecf20Sopenharmony_ci p_req->num_cids, p_resp->num_cids); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci /* Some legacy OSes are incapable of correctly handling this 15008c2ecf20Sopenharmony_ci * failure. 15018c2ecf20Sopenharmony_ci */ 15028c2ecf20Sopenharmony_ci if ((p_vf->acquire.vfdev_info.eth_fp_hsi_minor == 15038c2ecf20Sopenharmony_ci ETH_HSI_VER_NO_PKT_LEN_TUNN) && 15048c2ecf20Sopenharmony_ci (p_vf->acquire.vfdev_info.os_type == 15058c2ecf20Sopenharmony_ci VFPF_ACQUIRE_OS_WINDOWS)) 15068c2ecf20Sopenharmony_ci return PFVF_STATUS_SUCCESS; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci return PFVF_STATUS_NO_RESOURCE; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci return PFVF_STATUS_SUCCESS; 15128c2ecf20Sopenharmony_ci} 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_acquire_stats(struct qed_hwfn *p_hwfn, 15158c2ecf20Sopenharmony_ci struct pfvf_stats_info *p_stats) 15168c2ecf20Sopenharmony_ci{ 15178c2ecf20Sopenharmony_ci p_stats->mstats.address = PXP_VF_BAR0_START_MSDM_ZONE_B + 15188c2ecf20Sopenharmony_ci offsetof(struct mstorm_vf_zone, 15198c2ecf20Sopenharmony_ci non_trigger.eth_queue_stat); 15208c2ecf20Sopenharmony_ci p_stats->mstats.len = sizeof(struct eth_mstorm_per_queue_stat); 15218c2ecf20Sopenharmony_ci p_stats->ustats.address = PXP_VF_BAR0_START_USDM_ZONE_B + 15228c2ecf20Sopenharmony_ci offsetof(struct ustorm_vf_zone, 15238c2ecf20Sopenharmony_ci non_trigger.eth_queue_stat); 15248c2ecf20Sopenharmony_ci p_stats->ustats.len = sizeof(struct eth_ustorm_per_queue_stat); 15258c2ecf20Sopenharmony_ci p_stats->pstats.address = PXP_VF_BAR0_START_PSDM_ZONE_B + 15268c2ecf20Sopenharmony_ci offsetof(struct pstorm_vf_zone, 15278c2ecf20Sopenharmony_ci non_trigger.eth_queue_stat); 15288c2ecf20Sopenharmony_ci p_stats->pstats.len = sizeof(struct eth_pstorm_per_queue_stat); 15298c2ecf20Sopenharmony_ci p_stats->tstats.address = 0; 15308c2ecf20Sopenharmony_ci p_stats->tstats.len = 0; 15318c2ecf20Sopenharmony_ci} 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_acquire(struct qed_hwfn *p_hwfn, 15348c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 15358c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 15368c2ecf20Sopenharmony_ci{ 15378c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 15388c2ecf20Sopenharmony_ci struct pfvf_acquire_resp_tlv *resp = &mbx->reply_virt->acquire_resp; 15398c2ecf20Sopenharmony_ci struct pf_vf_pfdev_info *pfdev_info = &resp->pfdev_info; 15408c2ecf20Sopenharmony_ci struct vfpf_acquire_tlv *req = &mbx->req_virt->acquire; 15418c2ecf20Sopenharmony_ci u8 vfpf_status = PFVF_STATUS_NOT_SUPPORTED; 15428c2ecf20Sopenharmony_ci struct pf_vf_resc *resc = &resp->resc; 15438c2ecf20Sopenharmony_ci int rc; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci memset(resp, 0, sizeof(*resp)); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci /* Write the PF version so that VF would know which version 15488c2ecf20Sopenharmony_ci * is supported - might be later overriden. This guarantees that 15498c2ecf20Sopenharmony_ci * VF could recognize legacy PF based on lack of versions in reply. 15508c2ecf20Sopenharmony_ci */ 15518c2ecf20Sopenharmony_ci pfdev_info->major_fp_hsi = ETH_HSI_VER_MAJOR; 15528c2ecf20Sopenharmony_ci pfdev_info->minor_fp_hsi = ETH_HSI_VER_MINOR; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci if (vf->state != VF_FREE && vf->state != VF_STOPPED) { 15558c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 15568c2ecf20Sopenharmony_ci QED_MSG_IOV, 15578c2ecf20Sopenharmony_ci "VF[%d] sent ACQUIRE but is already in state %d - fail request\n", 15588c2ecf20Sopenharmony_ci vf->abs_vf_id, vf->state); 15598c2ecf20Sopenharmony_ci goto out; 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci /* Validate FW compatibility */ 15638c2ecf20Sopenharmony_ci if (req->vfdev_info.eth_fp_hsi_major != ETH_HSI_VER_MAJOR) { 15648c2ecf20Sopenharmony_ci if (req->vfdev_info.capabilities & 15658c2ecf20Sopenharmony_ci VFPF_ACQUIRE_CAP_PRE_FP_HSI) { 15668c2ecf20Sopenharmony_ci struct vf_pf_vfdev_info *p_vfdev = &req->vfdev_info; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 15698c2ecf20Sopenharmony_ci "VF[%d] is pre-fastpath HSI\n", 15708c2ecf20Sopenharmony_ci vf->abs_vf_id); 15718c2ecf20Sopenharmony_ci p_vfdev->eth_fp_hsi_major = ETH_HSI_VER_MAJOR; 15728c2ecf20Sopenharmony_ci p_vfdev->eth_fp_hsi_minor = ETH_HSI_VER_NO_PKT_LEN_TUNN; 15738c2ecf20Sopenharmony_ci } else { 15748c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 15758c2ecf20Sopenharmony_ci "VF[%d] needs fastpath HSI %02x.%02x, which is incompatible with loaded FW's fastpath HSI %02x.%02x\n", 15768c2ecf20Sopenharmony_ci vf->abs_vf_id, 15778c2ecf20Sopenharmony_ci req->vfdev_info.eth_fp_hsi_major, 15788c2ecf20Sopenharmony_ci req->vfdev_info.eth_fp_hsi_minor, 15798c2ecf20Sopenharmony_ci ETH_HSI_VER_MAJOR, ETH_HSI_VER_MINOR); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci goto out; 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci /* On 100g PFs, prevent old VFs from loading */ 15868c2ecf20Sopenharmony_ci if ((p_hwfn->cdev->num_hwfns > 1) && 15878c2ecf20Sopenharmony_ci !(req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_100G)) { 15888c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 15898c2ecf20Sopenharmony_ci "VF[%d] is running an old driver that doesn't support 100g\n", 15908c2ecf20Sopenharmony_ci vf->abs_vf_id); 15918c2ecf20Sopenharmony_ci goto out; 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci /* Store the acquire message */ 15958c2ecf20Sopenharmony_ci memcpy(&vf->acquire, req, sizeof(vf->acquire)); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci vf->opaque_fid = req->vfdev_info.opaque_fid; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci vf->vf_bulletin = req->bulletin_addr; 16008c2ecf20Sopenharmony_ci vf->bulletin.size = (vf->bulletin.size < req->bulletin_size) ? 16018c2ecf20Sopenharmony_ci vf->bulletin.size : req->bulletin_size; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci /* fill in pfdev info */ 16048c2ecf20Sopenharmony_ci pfdev_info->chip_num = p_hwfn->cdev->chip_num; 16058c2ecf20Sopenharmony_ci pfdev_info->db_size = 0; 16068c2ecf20Sopenharmony_ci pfdev_info->indices_per_sb = PIS_PER_SB_E4; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci pfdev_info->capabilities = PFVF_ACQUIRE_CAP_DEFAULT_UNTAGGED | 16098c2ecf20Sopenharmony_ci PFVF_ACQUIRE_CAP_POST_FW_OVERRIDE; 16108c2ecf20Sopenharmony_ci if (p_hwfn->cdev->num_hwfns > 1) 16118c2ecf20Sopenharmony_ci pfdev_info->capabilities |= PFVF_ACQUIRE_CAP_100G; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci /* Share our ability to use multiple queue-ids only with VFs 16148c2ecf20Sopenharmony_ci * that request it. 16158c2ecf20Sopenharmony_ci */ 16168c2ecf20Sopenharmony_ci if (req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_QUEUE_QIDS) 16178c2ecf20Sopenharmony_ci pfdev_info->capabilities |= PFVF_ACQUIRE_CAP_QUEUE_QIDS; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci /* Share the sizes of the bars with VF */ 16208c2ecf20Sopenharmony_ci resp->pfdev_info.bar_size = qed_iov_vf_db_bar_size(p_hwfn, p_ptt); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci qed_iov_vf_mbx_acquire_stats(p_hwfn, &pfdev_info->stats_info); 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci memcpy(pfdev_info->port_mac, p_hwfn->hw_info.hw_mac_addr, ETH_ALEN); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci pfdev_info->fw_major = FW_MAJOR_VERSION; 16278c2ecf20Sopenharmony_ci pfdev_info->fw_minor = FW_MINOR_VERSION; 16288c2ecf20Sopenharmony_ci pfdev_info->fw_rev = FW_REVISION_VERSION; 16298c2ecf20Sopenharmony_ci pfdev_info->fw_eng = FW_ENGINEERING_VERSION; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci /* Incorrect when legacy, but doesn't matter as legacy isn't reading 16328c2ecf20Sopenharmony_ci * this field. 16338c2ecf20Sopenharmony_ci */ 16348c2ecf20Sopenharmony_ci pfdev_info->minor_fp_hsi = min_t(u8, ETH_HSI_VER_MINOR, 16358c2ecf20Sopenharmony_ci req->vfdev_info.eth_fp_hsi_minor); 16368c2ecf20Sopenharmony_ci pfdev_info->os_type = VFPF_ACQUIRE_OS_LINUX; 16378c2ecf20Sopenharmony_ci qed_mcp_get_mfw_ver(p_hwfn, p_ptt, &pfdev_info->mfw_ver, NULL); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci pfdev_info->dev_type = p_hwfn->cdev->type; 16408c2ecf20Sopenharmony_ci pfdev_info->chip_rev = p_hwfn->cdev->chip_rev; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci /* Fill resources available to VF; Make sure there are enough to 16438c2ecf20Sopenharmony_ci * satisfy the VF's request. 16448c2ecf20Sopenharmony_ci */ 16458c2ecf20Sopenharmony_ci vfpf_status = qed_iov_vf_mbx_acquire_resc(p_hwfn, p_ptt, vf, 16468c2ecf20Sopenharmony_ci &req->resc_request, resc); 16478c2ecf20Sopenharmony_ci if (vfpf_status != PFVF_STATUS_SUCCESS) 16488c2ecf20Sopenharmony_ci goto out; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci /* Start the VF in FW */ 16518c2ecf20Sopenharmony_ci rc = qed_sp_vf_start(p_hwfn, vf); 16528c2ecf20Sopenharmony_ci if (rc) { 16538c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to start VF[%02x]\n", vf->abs_vf_id); 16548c2ecf20Sopenharmony_ci vfpf_status = PFVF_STATUS_FAILURE; 16558c2ecf20Sopenharmony_ci goto out; 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci /* Fill agreed size of bulletin board in response */ 16598c2ecf20Sopenharmony_ci resp->bulletin_size = vf->bulletin.size; 16608c2ecf20Sopenharmony_ci qed_iov_post_vf_bulletin(p_hwfn, vf->relative_vf_id, p_ptt); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 16638c2ecf20Sopenharmony_ci QED_MSG_IOV, 16648c2ecf20Sopenharmony_ci "VF[%d] ACQUIRE_RESPONSE: pfdev_info- chip_num=0x%x, db_size=%d, idx_per_sb=%d, pf_cap=0x%llx\n" 16658c2ecf20Sopenharmony_ci "resources- n_rxq-%d, n_txq-%d, n_sbs-%d, n_macs-%d, n_vlans-%d\n", 16668c2ecf20Sopenharmony_ci vf->abs_vf_id, 16678c2ecf20Sopenharmony_ci resp->pfdev_info.chip_num, 16688c2ecf20Sopenharmony_ci resp->pfdev_info.db_size, 16698c2ecf20Sopenharmony_ci resp->pfdev_info.indices_per_sb, 16708c2ecf20Sopenharmony_ci resp->pfdev_info.capabilities, 16718c2ecf20Sopenharmony_ci resc->num_rxqs, 16728c2ecf20Sopenharmony_ci resc->num_txqs, 16738c2ecf20Sopenharmony_ci resc->num_sbs, 16748c2ecf20Sopenharmony_ci resc->num_mac_filters, 16758c2ecf20Sopenharmony_ci resc->num_vlan_filters); 16768c2ecf20Sopenharmony_ci vf->state = VF_ACQUIRED; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci /* Prepare Response */ 16798c2ecf20Sopenharmony_ciout: 16808c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_ACQUIRE, 16818c2ecf20Sopenharmony_ci sizeof(struct pfvf_acquire_resp_tlv), vfpf_status); 16828c2ecf20Sopenharmony_ci} 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_cistatic int __qed_iov_spoofchk_set(struct qed_hwfn *p_hwfn, 16858c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, bool val) 16868c2ecf20Sopenharmony_ci{ 16878c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params params; 16888c2ecf20Sopenharmony_ci int rc; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (val == p_vf->spoof_chk) { 16918c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 16928c2ecf20Sopenharmony_ci "Spoofchk value[%d] is already configured\n", val); 16938c2ecf20Sopenharmony_ci return 0; 16948c2ecf20Sopenharmony_ci } 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(struct qed_sp_vport_update_params)); 16978c2ecf20Sopenharmony_ci params.opaque_fid = p_vf->opaque_fid; 16988c2ecf20Sopenharmony_ci params.vport_id = p_vf->vport_id; 16998c2ecf20Sopenharmony_ci params.update_anti_spoofing_en_flg = 1; 17008c2ecf20Sopenharmony_ci params.anti_spoofing_en = val; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci rc = qed_sp_vport_update(p_hwfn, ¶ms, QED_SPQ_MODE_EBLOCK, NULL); 17038c2ecf20Sopenharmony_ci if (!rc) { 17048c2ecf20Sopenharmony_ci p_vf->spoof_chk = val; 17058c2ecf20Sopenharmony_ci p_vf->req_spoofchk_val = p_vf->spoof_chk; 17068c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 17078c2ecf20Sopenharmony_ci "Spoofchk val[%d] configured\n", val); 17088c2ecf20Sopenharmony_ci } else { 17098c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 17108c2ecf20Sopenharmony_ci "Spoofchk configuration[val:%d] failed for VF[%d]\n", 17118c2ecf20Sopenharmony_ci val, p_vf->relative_vf_id); 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci return rc; 17158c2ecf20Sopenharmony_ci} 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_cistatic int qed_iov_reconfigure_unicast_vlan(struct qed_hwfn *p_hwfn, 17188c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf) 17198c2ecf20Sopenharmony_ci{ 17208c2ecf20Sopenharmony_ci struct qed_filter_ucast filter; 17218c2ecf20Sopenharmony_ci int rc = 0; 17228c2ecf20Sopenharmony_ci int i; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci memset(&filter, 0, sizeof(filter)); 17258c2ecf20Sopenharmony_ci filter.is_rx_filter = 1; 17268c2ecf20Sopenharmony_ci filter.is_tx_filter = 1; 17278c2ecf20Sopenharmony_ci filter.vport_to_add_to = p_vf->vport_id; 17288c2ecf20Sopenharmony_ci filter.opcode = QED_FILTER_ADD; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci /* Reconfigure vlans */ 17318c2ecf20Sopenharmony_ci for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++) { 17328c2ecf20Sopenharmony_ci if (!p_vf->shadow_config.vlans[i].used) 17338c2ecf20Sopenharmony_ci continue; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci filter.type = QED_FILTER_VLAN; 17368c2ecf20Sopenharmony_ci filter.vlan = p_vf->shadow_config.vlans[i].vid; 17378c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 17388c2ecf20Sopenharmony_ci "Reconfiguring VLAN [0x%04x] for VF [%04x]\n", 17398c2ecf20Sopenharmony_ci filter.vlan, p_vf->relative_vf_id); 17408c2ecf20Sopenharmony_ci rc = qed_sp_eth_filter_ucast(p_hwfn, p_vf->opaque_fid, 17418c2ecf20Sopenharmony_ci &filter, QED_SPQ_MODE_CB, NULL); 17428c2ecf20Sopenharmony_ci if (rc) { 17438c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 17448c2ecf20Sopenharmony_ci "Failed to configure VLAN [%04x] to VF [%04x]\n", 17458c2ecf20Sopenharmony_ci filter.vlan, p_vf->relative_vf_id); 17468c2ecf20Sopenharmony_ci break; 17478c2ecf20Sopenharmony_ci } 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci return rc; 17518c2ecf20Sopenharmony_ci} 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_cistatic int 17548c2ecf20Sopenharmony_ciqed_iov_reconfigure_unicast_shadow(struct qed_hwfn *p_hwfn, 17558c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, u64 events) 17568c2ecf20Sopenharmony_ci{ 17578c2ecf20Sopenharmony_ci int rc = 0; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci if ((events & BIT(VLAN_ADDR_FORCED)) && 17608c2ecf20Sopenharmony_ci !(p_vf->configured_features & (1 << VLAN_ADDR_FORCED))) 17618c2ecf20Sopenharmony_ci rc = qed_iov_reconfigure_unicast_vlan(p_hwfn, p_vf); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci return rc; 17648c2ecf20Sopenharmony_ci} 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_cistatic int qed_iov_configure_vport_forced(struct qed_hwfn *p_hwfn, 17678c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, u64 events) 17688c2ecf20Sopenharmony_ci{ 17698c2ecf20Sopenharmony_ci int rc = 0; 17708c2ecf20Sopenharmony_ci struct qed_filter_ucast filter; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci if (!p_vf->vport_instance) 17738c2ecf20Sopenharmony_ci return -EINVAL; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci if ((events & BIT(MAC_ADDR_FORCED)) || 17768c2ecf20Sopenharmony_ci p_vf->p_vf_info.is_trusted_configured) { 17778c2ecf20Sopenharmony_ci /* Since there's no way [currently] of removing the MAC, 17788c2ecf20Sopenharmony_ci * we can always assume this means we need to force it. 17798c2ecf20Sopenharmony_ci */ 17808c2ecf20Sopenharmony_ci memset(&filter, 0, sizeof(filter)); 17818c2ecf20Sopenharmony_ci filter.type = QED_FILTER_MAC; 17828c2ecf20Sopenharmony_ci filter.opcode = QED_FILTER_REPLACE; 17838c2ecf20Sopenharmony_ci filter.is_rx_filter = 1; 17848c2ecf20Sopenharmony_ci filter.is_tx_filter = 1; 17858c2ecf20Sopenharmony_ci filter.vport_to_add_to = p_vf->vport_id; 17868c2ecf20Sopenharmony_ci ether_addr_copy(filter.mac, p_vf->bulletin.p_virt->mac); 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci rc = qed_sp_eth_filter_ucast(p_hwfn, p_vf->opaque_fid, 17898c2ecf20Sopenharmony_ci &filter, QED_SPQ_MODE_CB, NULL); 17908c2ecf20Sopenharmony_ci if (rc) { 17918c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 17928c2ecf20Sopenharmony_ci "PF failed to configure MAC for VF\n"); 17938c2ecf20Sopenharmony_ci return rc; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci if (p_vf->p_vf_info.is_trusted_configured) 17968c2ecf20Sopenharmony_ci p_vf->configured_features |= 17978c2ecf20Sopenharmony_ci BIT(VFPF_BULLETIN_MAC_ADDR); 17988c2ecf20Sopenharmony_ci else 17998c2ecf20Sopenharmony_ci p_vf->configured_features |= 18008c2ecf20Sopenharmony_ci BIT(MAC_ADDR_FORCED); 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci if (events & BIT(VLAN_ADDR_FORCED)) { 18048c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params vport_update; 18058c2ecf20Sopenharmony_ci u8 removal; 18068c2ecf20Sopenharmony_ci int i; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci memset(&filter, 0, sizeof(filter)); 18098c2ecf20Sopenharmony_ci filter.type = QED_FILTER_VLAN; 18108c2ecf20Sopenharmony_ci filter.is_rx_filter = 1; 18118c2ecf20Sopenharmony_ci filter.is_tx_filter = 1; 18128c2ecf20Sopenharmony_ci filter.vport_to_add_to = p_vf->vport_id; 18138c2ecf20Sopenharmony_ci filter.vlan = p_vf->bulletin.p_virt->pvid; 18148c2ecf20Sopenharmony_ci filter.opcode = filter.vlan ? QED_FILTER_REPLACE : 18158c2ecf20Sopenharmony_ci QED_FILTER_FLUSH; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci /* Send the ramrod */ 18188c2ecf20Sopenharmony_ci rc = qed_sp_eth_filter_ucast(p_hwfn, p_vf->opaque_fid, 18198c2ecf20Sopenharmony_ci &filter, QED_SPQ_MODE_CB, NULL); 18208c2ecf20Sopenharmony_ci if (rc) { 18218c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 18228c2ecf20Sopenharmony_ci "PF failed to configure VLAN for VF\n"); 18238c2ecf20Sopenharmony_ci return rc; 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci /* Update the default-vlan & silent vlan stripping */ 18278c2ecf20Sopenharmony_ci memset(&vport_update, 0, sizeof(vport_update)); 18288c2ecf20Sopenharmony_ci vport_update.opaque_fid = p_vf->opaque_fid; 18298c2ecf20Sopenharmony_ci vport_update.vport_id = p_vf->vport_id; 18308c2ecf20Sopenharmony_ci vport_update.update_default_vlan_enable_flg = 1; 18318c2ecf20Sopenharmony_ci vport_update.default_vlan_enable_flg = filter.vlan ? 1 : 0; 18328c2ecf20Sopenharmony_ci vport_update.update_default_vlan_flg = 1; 18338c2ecf20Sopenharmony_ci vport_update.default_vlan = filter.vlan; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci vport_update.update_inner_vlan_removal_flg = 1; 18368c2ecf20Sopenharmony_ci removal = filter.vlan ? 1 18378c2ecf20Sopenharmony_ci : p_vf->shadow_config.inner_vlan_removal; 18388c2ecf20Sopenharmony_ci vport_update.inner_vlan_removal_flg = removal; 18398c2ecf20Sopenharmony_ci vport_update.silent_vlan_removal_flg = filter.vlan ? 1 : 0; 18408c2ecf20Sopenharmony_ci rc = qed_sp_vport_update(p_hwfn, 18418c2ecf20Sopenharmony_ci &vport_update, 18428c2ecf20Sopenharmony_ci QED_SPQ_MODE_EBLOCK, NULL); 18438c2ecf20Sopenharmony_ci if (rc) { 18448c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 18458c2ecf20Sopenharmony_ci "PF failed to configure VF vport for vlan\n"); 18468c2ecf20Sopenharmony_ci return rc; 18478c2ecf20Sopenharmony_ci } 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci /* Update all the Rx queues */ 18508c2ecf20Sopenharmony_ci for (i = 0; i < QED_MAX_VF_CHAINS_PER_PF; i++) { 18518c2ecf20Sopenharmony_ci struct qed_vf_queue *p_queue = &p_vf->vf_queues[i]; 18528c2ecf20Sopenharmony_ci struct qed_queue_cid *p_cid = NULL; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci /* There can be at most 1 Rx queue on qzone. Find it */ 18558c2ecf20Sopenharmony_ci p_cid = qed_iov_get_vf_rx_queue_cid(p_queue); 18568c2ecf20Sopenharmony_ci if (!p_cid) 18578c2ecf20Sopenharmony_ci continue; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci rc = qed_sp_eth_rx_queues_update(p_hwfn, 18608c2ecf20Sopenharmony_ci (void **)&p_cid, 18618c2ecf20Sopenharmony_ci 1, 0, 1, 18628c2ecf20Sopenharmony_ci QED_SPQ_MODE_EBLOCK, 18638c2ecf20Sopenharmony_ci NULL); 18648c2ecf20Sopenharmony_ci if (rc) { 18658c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 18668c2ecf20Sopenharmony_ci "Failed to send Rx update fo queue[0x%04x]\n", 18678c2ecf20Sopenharmony_ci p_cid->rel.queue_id); 18688c2ecf20Sopenharmony_ci return rc; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci if (filter.vlan) 18738c2ecf20Sopenharmony_ci p_vf->configured_features |= 1 << VLAN_ADDR_FORCED; 18748c2ecf20Sopenharmony_ci else 18758c2ecf20Sopenharmony_ci p_vf->configured_features &= ~BIT(VLAN_ADDR_FORCED); 18768c2ecf20Sopenharmony_ci } 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci /* If forced features are terminated, we need to configure the shadow 18798c2ecf20Sopenharmony_ci * configuration back again. 18808c2ecf20Sopenharmony_ci */ 18818c2ecf20Sopenharmony_ci if (events) 18828c2ecf20Sopenharmony_ci qed_iov_reconfigure_unicast_shadow(p_hwfn, p_vf, events); 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci return rc; 18858c2ecf20Sopenharmony_ci} 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_start_vport(struct qed_hwfn *p_hwfn, 18888c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 18898c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci struct qed_sp_vport_start_params params = { 0 }; 18928c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 18938c2ecf20Sopenharmony_ci struct vfpf_vport_start_tlv *start; 18948c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_SUCCESS; 18958c2ecf20Sopenharmony_ci struct qed_vf_info *vf_info; 18968c2ecf20Sopenharmony_ci u64 *p_bitmap; 18978c2ecf20Sopenharmony_ci int sb_id; 18988c2ecf20Sopenharmony_ci int rc; 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vf->relative_vf_id, true); 19018c2ecf20Sopenharmony_ci if (!vf_info) { 19028c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn->cdev, 19038c2ecf20Sopenharmony_ci "Failed to get VF info, invalid vfid [%d]\n", 19048c2ecf20Sopenharmony_ci vf->relative_vf_id); 19058c2ecf20Sopenharmony_ci return; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci vf->state = VF_ENABLED; 19098c2ecf20Sopenharmony_ci start = &mbx->req_virt->start_vport; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci qed_iov_enable_vf_traffic(p_hwfn, p_ptt, vf); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci /* Initialize Status block in CAU */ 19148c2ecf20Sopenharmony_ci for (sb_id = 0; sb_id < vf->num_sbs; sb_id++) { 19158c2ecf20Sopenharmony_ci if (!start->sb_addr[sb_id]) { 19168c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 19178c2ecf20Sopenharmony_ci "VF[%d] did not fill the address of SB %d\n", 19188c2ecf20Sopenharmony_ci vf->relative_vf_id, sb_id); 19198c2ecf20Sopenharmony_ci break; 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci qed_int_cau_conf_sb(p_hwfn, p_ptt, 19238c2ecf20Sopenharmony_ci start->sb_addr[sb_id], 19248c2ecf20Sopenharmony_ci vf->igu_sbs[sb_id], vf->abs_vf_id, 1); 19258c2ecf20Sopenharmony_ci } 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci vf->mtu = start->mtu; 19288c2ecf20Sopenharmony_ci vf->shadow_config.inner_vlan_removal = start->inner_vlan_removal; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci /* Take into consideration configuration forced by hypervisor; 19318c2ecf20Sopenharmony_ci * If none is configured, use the supplied VF values [for old 19328c2ecf20Sopenharmony_ci * vfs that would still be fine, since they passed '0' as padding]. 19338c2ecf20Sopenharmony_ci */ 19348c2ecf20Sopenharmony_ci p_bitmap = &vf_info->bulletin.p_virt->valid_bitmap; 19358c2ecf20Sopenharmony_ci if (!(*p_bitmap & BIT(VFPF_BULLETIN_UNTAGGED_DEFAULT_FORCED))) { 19368c2ecf20Sopenharmony_ci u8 vf_req = start->only_untagged; 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci vf_info->bulletin.p_virt->default_only_untagged = vf_req; 19398c2ecf20Sopenharmony_ci *p_bitmap |= 1 << VFPF_BULLETIN_UNTAGGED_DEFAULT; 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci params.tpa_mode = start->tpa_mode; 19438c2ecf20Sopenharmony_ci params.remove_inner_vlan = start->inner_vlan_removal; 19448c2ecf20Sopenharmony_ci params.tx_switching = true; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci params.only_untagged = vf_info->bulletin.p_virt->default_only_untagged; 19478c2ecf20Sopenharmony_ci params.drop_ttl0 = false; 19488c2ecf20Sopenharmony_ci params.concrete_fid = vf->concrete_fid; 19498c2ecf20Sopenharmony_ci params.opaque_fid = vf->opaque_fid; 19508c2ecf20Sopenharmony_ci params.vport_id = vf->vport_id; 19518c2ecf20Sopenharmony_ci params.max_buffers_per_cqe = start->max_buffers_per_cqe; 19528c2ecf20Sopenharmony_ci params.mtu = vf->mtu; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci /* Non trusted VFs should enable control frame filtering */ 19558c2ecf20Sopenharmony_ci params.check_mac = !vf->p_vf_info.is_trusted_configured; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci rc = qed_sp_eth_vport_start(p_hwfn, ¶ms); 19588c2ecf20Sopenharmony_ci if (rc) { 19598c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 19608c2ecf20Sopenharmony_ci "qed_iov_vf_mbx_start_vport returned error %d\n", rc); 19618c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 19628c2ecf20Sopenharmony_ci } else { 19638c2ecf20Sopenharmony_ci vf->vport_instance++; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci /* Force configuration if needed on the newly opened vport */ 19668c2ecf20Sopenharmony_ci qed_iov_configure_vport_forced(p_hwfn, vf, *p_bitmap); 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci __qed_iov_spoofchk_set(p_hwfn, vf, vf->req_spoofchk_val); 19698c2ecf20Sopenharmony_ci } 19708c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_VPORT_START, 19718c2ecf20Sopenharmony_ci sizeof(struct pfvf_def_resp_tlv), status); 19728c2ecf20Sopenharmony_ci} 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_stop_vport(struct qed_hwfn *p_hwfn, 19758c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 19768c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 19778c2ecf20Sopenharmony_ci{ 19788c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_SUCCESS; 19798c2ecf20Sopenharmony_ci int rc; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci vf->vport_instance--; 19828c2ecf20Sopenharmony_ci vf->spoof_chk = false; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci if ((qed_iov_validate_active_rxq(p_hwfn, vf)) || 19858c2ecf20Sopenharmony_ci (qed_iov_validate_active_txq(p_hwfn, vf))) { 19868c2ecf20Sopenharmony_ci vf->b_malicious = true; 19878c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 19888c2ecf20Sopenharmony_ci "VF [%02x] - considered malicious; Unable to stop RX/TX queues\n", 19898c2ecf20Sopenharmony_ci vf->abs_vf_id); 19908c2ecf20Sopenharmony_ci status = PFVF_STATUS_MALICIOUS; 19918c2ecf20Sopenharmony_ci goto out; 19928c2ecf20Sopenharmony_ci } 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci rc = qed_sp_vport_stop(p_hwfn, vf->opaque_fid, vf->vport_id); 19958c2ecf20Sopenharmony_ci if (rc) { 19968c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "qed_iov_vf_mbx_stop_vport returned error %d\n", 19978c2ecf20Sopenharmony_ci rc); 19988c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci /* Forget the configuration on the vport */ 20028c2ecf20Sopenharmony_ci vf->configured_features = 0; 20038c2ecf20Sopenharmony_ci memset(&vf->shadow_config, 0, sizeof(vf->shadow_config)); 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ciout: 20068c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_VPORT_TEARDOWN, 20078c2ecf20Sopenharmony_ci sizeof(struct pfvf_def_resp_tlv), status); 20088c2ecf20Sopenharmony_ci} 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_start_rxq_resp(struct qed_hwfn *p_hwfn, 20118c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 20128c2ecf20Sopenharmony_ci struct qed_vf_info *vf, 20138c2ecf20Sopenharmony_ci u8 status, bool b_legacy) 20148c2ecf20Sopenharmony_ci{ 20158c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 20168c2ecf20Sopenharmony_ci struct pfvf_start_queue_resp_tlv *p_tlv; 20178c2ecf20Sopenharmony_ci struct vfpf_start_rxq_tlv *req; 20188c2ecf20Sopenharmony_ci u16 length; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci mbx->offset = (u8 *)mbx->reply_virt; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci /* Taking a bigger struct instead of adding a TLV to list was a 20238c2ecf20Sopenharmony_ci * mistake, but one which we're now stuck with, as some older 20248c2ecf20Sopenharmony_ci * clients assume the size of the previous response. 20258c2ecf20Sopenharmony_ci */ 20268c2ecf20Sopenharmony_ci if (!b_legacy) 20278c2ecf20Sopenharmony_ci length = sizeof(*p_tlv); 20288c2ecf20Sopenharmony_ci else 20298c2ecf20Sopenharmony_ci length = sizeof(struct pfvf_def_resp_tlv); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci p_tlv = qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_START_RXQ, 20328c2ecf20Sopenharmony_ci length); 20338c2ecf20Sopenharmony_ci qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_LIST_END, 20348c2ecf20Sopenharmony_ci sizeof(struct channel_list_end_tlv)); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci /* Update the TLV with the response */ 20378c2ecf20Sopenharmony_ci if ((status == PFVF_STATUS_SUCCESS) && !b_legacy) { 20388c2ecf20Sopenharmony_ci req = &mbx->req_virt->start_rxq; 20398c2ecf20Sopenharmony_ci p_tlv->offset = PXP_VF_BAR0_START_MSDM_ZONE_B + 20408c2ecf20Sopenharmony_ci offsetof(struct mstorm_vf_zone, 20418c2ecf20Sopenharmony_ci non_trigger.eth_rx_queue_producers) + 20428c2ecf20Sopenharmony_ci sizeof(struct eth_rx_prod_data) * req->rx_qid; 20438c2ecf20Sopenharmony_ci } 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci qed_iov_send_response(p_hwfn, p_ptt, vf, length, status); 20468c2ecf20Sopenharmony_ci} 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_cistatic u8 qed_iov_vf_mbx_qid(struct qed_hwfn *p_hwfn, 20498c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, bool b_is_tx) 20508c2ecf20Sopenharmony_ci{ 20518c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *p_mbx = &p_vf->vf_mbx; 20528c2ecf20Sopenharmony_ci struct vfpf_qid_tlv *p_qid_tlv; 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci /* Search for the qid if the VF published its going to provide it */ 20558c2ecf20Sopenharmony_ci if (!(p_vf->acquire.vfdev_info.capabilities & 20568c2ecf20Sopenharmony_ci VFPF_ACQUIRE_CAP_QUEUE_QIDS)) { 20578c2ecf20Sopenharmony_ci if (b_is_tx) 20588c2ecf20Sopenharmony_ci return QED_IOV_LEGACY_QID_TX; 20598c2ecf20Sopenharmony_ci else 20608c2ecf20Sopenharmony_ci return QED_IOV_LEGACY_QID_RX; 20618c2ecf20Sopenharmony_ci } 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci p_qid_tlv = (struct vfpf_qid_tlv *) 20648c2ecf20Sopenharmony_ci qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, 20658c2ecf20Sopenharmony_ci CHANNEL_TLV_QID); 20668c2ecf20Sopenharmony_ci if (!p_qid_tlv) { 20678c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 20688c2ecf20Sopenharmony_ci "VF[%2x]: Failed to provide qid\n", 20698c2ecf20Sopenharmony_ci p_vf->relative_vf_id); 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci return QED_IOV_QID_INVALID; 20728c2ecf20Sopenharmony_ci } 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci if (p_qid_tlv->qid >= MAX_QUEUES_PER_QZONE) { 20758c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 20768c2ecf20Sopenharmony_ci "VF[%02x]: Provided qid out-of-bounds %02x\n", 20778c2ecf20Sopenharmony_ci p_vf->relative_vf_id, p_qid_tlv->qid); 20788c2ecf20Sopenharmony_ci return QED_IOV_QID_INVALID; 20798c2ecf20Sopenharmony_ci } 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci return p_qid_tlv->qid; 20828c2ecf20Sopenharmony_ci} 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, 20858c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 20868c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 20878c2ecf20Sopenharmony_ci{ 20888c2ecf20Sopenharmony_ci struct qed_queue_start_common_params params; 20898c2ecf20Sopenharmony_ci struct qed_queue_cid_vf_params vf_params; 20908c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 20918c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_NO_RESOURCE; 20928c2ecf20Sopenharmony_ci u8 qid_usage_idx, vf_legacy = 0; 20938c2ecf20Sopenharmony_ci struct vfpf_start_rxq_tlv *req; 20948c2ecf20Sopenharmony_ci struct qed_vf_queue *p_queue; 20958c2ecf20Sopenharmony_ci struct qed_queue_cid *p_cid; 20968c2ecf20Sopenharmony_ci struct qed_sb_info sb_dummy; 20978c2ecf20Sopenharmony_ci int rc; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci req = &mbx->req_virt->start_rxq; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci if (!qed_iov_validate_rxq(p_hwfn, vf, req->rx_qid, 21028c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_DISABLE) || 21038c2ecf20Sopenharmony_ci !qed_iov_validate_sb(p_hwfn, vf, req->hw_sb)) 21048c2ecf20Sopenharmony_ci goto out; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); 21078c2ecf20Sopenharmony_ci if (qid_usage_idx == QED_IOV_QID_INVALID) 21088c2ecf20Sopenharmony_ci goto out; 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci p_queue = &vf->vf_queues[req->rx_qid]; 21118c2ecf20Sopenharmony_ci if (p_queue->cids[qid_usage_idx].p_cid) 21128c2ecf20Sopenharmony_ci goto out; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci vf_legacy = qed_vf_calculate_legacy(vf); 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci /* Acquire a new queue-cid */ 21178c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 21188c2ecf20Sopenharmony_ci params.queue_id = p_queue->fw_rx_qid; 21198c2ecf20Sopenharmony_ci params.vport_id = vf->vport_id; 21208c2ecf20Sopenharmony_ci params.stats_id = vf->abs_vf_id + 0x10; 21218c2ecf20Sopenharmony_ci /* Since IGU index is passed via sb_info, construct a dummy one */ 21228c2ecf20Sopenharmony_ci memset(&sb_dummy, 0, sizeof(sb_dummy)); 21238c2ecf20Sopenharmony_ci sb_dummy.igu_sb_id = req->hw_sb; 21248c2ecf20Sopenharmony_ci params.p_sb = &sb_dummy; 21258c2ecf20Sopenharmony_ci params.sb_idx = req->sb_index; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci memset(&vf_params, 0, sizeof(vf_params)); 21288c2ecf20Sopenharmony_ci vf_params.vfid = vf->relative_vf_id; 21298c2ecf20Sopenharmony_ci vf_params.vf_qid = (u8)req->rx_qid; 21308c2ecf20Sopenharmony_ci vf_params.vf_legacy = vf_legacy; 21318c2ecf20Sopenharmony_ci vf_params.qid_usage_idx = qid_usage_idx; 21328c2ecf20Sopenharmony_ci p_cid = qed_eth_queue_to_cid(p_hwfn, vf->opaque_fid, 21338c2ecf20Sopenharmony_ci ¶ms, true, &vf_params); 21348c2ecf20Sopenharmony_ci if (!p_cid) 21358c2ecf20Sopenharmony_ci goto out; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci /* Legacy VFs have their Producers in a different location, which they 21388c2ecf20Sopenharmony_ci * calculate on their own and clean the producer prior to this. 21398c2ecf20Sopenharmony_ci */ 21408c2ecf20Sopenharmony_ci if (!(vf_legacy & QED_QCID_LEGACY_VF_RX_PROD)) 21418c2ecf20Sopenharmony_ci REG_WR(p_hwfn, 21428c2ecf20Sopenharmony_ci GTT_BAR0_MAP_REG_MSDM_RAM + 21438c2ecf20Sopenharmony_ci MSTORM_ETH_VF_PRODS_OFFSET(vf->abs_vf_id, req->rx_qid), 21448c2ecf20Sopenharmony_ci 0); 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci rc = qed_eth_rxq_start_ramrod(p_hwfn, p_cid, 21478c2ecf20Sopenharmony_ci req->bd_max_bytes, 21488c2ecf20Sopenharmony_ci req->rxq_addr, 21498c2ecf20Sopenharmony_ci req->cqe_pbl_addr, req->cqe_pbl_size); 21508c2ecf20Sopenharmony_ci if (rc) { 21518c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 21528c2ecf20Sopenharmony_ci qed_eth_queue_cid_release(p_hwfn, p_cid); 21538c2ecf20Sopenharmony_ci } else { 21548c2ecf20Sopenharmony_ci p_queue->cids[qid_usage_idx].p_cid = p_cid; 21558c2ecf20Sopenharmony_ci p_queue->cids[qid_usage_idx].b_is_tx = false; 21568c2ecf20Sopenharmony_ci status = PFVF_STATUS_SUCCESS; 21578c2ecf20Sopenharmony_ci vf->num_active_rxqs++; 21588c2ecf20Sopenharmony_ci } 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ciout: 21618c2ecf20Sopenharmony_ci qed_iov_vf_mbx_start_rxq_resp(p_hwfn, p_ptt, vf, status, 21628c2ecf20Sopenharmony_ci !!(vf_legacy & 21638c2ecf20Sopenharmony_ci QED_QCID_LEGACY_VF_RX_PROD)); 21648c2ecf20Sopenharmony_ci} 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_cistatic void 21678c2ecf20Sopenharmony_ciqed_iov_pf_update_tun_response(struct pfvf_update_tunn_param_tlv *p_resp, 21688c2ecf20Sopenharmony_ci struct qed_tunnel_info *p_tun, 21698c2ecf20Sopenharmony_ci u16 tunn_feature_mask) 21708c2ecf20Sopenharmony_ci{ 21718c2ecf20Sopenharmony_ci p_resp->tunn_feature_mask = tunn_feature_mask; 21728c2ecf20Sopenharmony_ci p_resp->vxlan_mode = p_tun->vxlan.b_mode_enabled; 21738c2ecf20Sopenharmony_ci p_resp->l2geneve_mode = p_tun->l2_geneve.b_mode_enabled; 21748c2ecf20Sopenharmony_ci p_resp->ipgeneve_mode = p_tun->ip_geneve.b_mode_enabled; 21758c2ecf20Sopenharmony_ci p_resp->l2gre_mode = p_tun->l2_gre.b_mode_enabled; 21768c2ecf20Sopenharmony_ci p_resp->ipgre_mode = p_tun->l2_gre.b_mode_enabled; 21778c2ecf20Sopenharmony_ci p_resp->vxlan_clss = p_tun->vxlan.tun_cls; 21788c2ecf20Sopenharmony_ci p_resp->l2gre_clss = p_tun->l2_gre.tun_cls; 21798c2ecf20Sopenharmony_ci p_resp->ipgre_clss = p_tun->ip_gre.tun_cls; 21808c2ecf20Sopenharmony_ci p_resp->l2geneve_clss = p_tun->l2_geneve.tun_cls; 21818c2ecf20Sopenharmony_ci p_resp->ipgeneve_clss = p_tun->ip_geneve.tun_cls; 21828c2ecf20Sopenharmony_ci p_resp->geneve_udp_port = p_tun->geneve_port.port; 21838c2ecf20Sopenharmony_ci p_resp->vxlan_udp_port = p_tun->vxlan_port.port; 21848c2ecf20Sopenharmony_ci} 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_cistatic void 21878c2ecf20Sopenharmony_ci__qed_iov_pf_update_tun_param(struct vfpf_update_tunn_param_tlv *p_req, 21888c2ecf20Sopenharmony_ci struct qed_tunn_update_type *p_tun, 21898c2ecf20Sopenharmony_ci enum qed_tunn_mode mask, u8 tun_cls) 21908c2ecf20Sopenharmony_ci{ 21918c2ecf20Sopenharmony_ci if (p_req->tun_mode_update_mask & BIT(mask)) { 21928c2ecf20Sopenharmony_ci p_tun->b_update_mode = true; 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci if (p_req->tunn_mode & BIT(mask)) 21958c2ecf20Sopenharmony_ci p_tun->b_mode_enabled = true; 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci p_tun->tun_cls = tun_cls; 21998c2ecf20Sopenharmony_ci} 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_cistatic void 22028c2ecf20Sopenharmony_ciqed_iov_pf_update_tun_param(struct vfpf_update_tunn_param_tlv *p_req, 22038c2ecf20Sopenharmony_ci struct qed_tunn_update_type *p_tun, 22048c2ecf20Sopenharmony_ci struct qed_tunn_update_udp_port *p_port, 22058c2ecf20Sopenharmony_ci enum qed_tunn_mode mask, 22068c2ecf20Sopenharmony_ci u8 tun_cls, u8 update_port, u16 port) 22078c2ecf20Sopenharmony_ci{ 22088c2ecf20Sopenharmony_ci if (update_port) { 22098c2ecf20Sopenharmony_ci p_port->b_update_port = true; 22108c2ecf20Sopenharmony_ci p_port->port = port; 22118c2ecf20Sopenharmony_ci } 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci __qed_iov_pf_update_tun_param(p_req, p_tun, mask, tun_cls); 22148c2ecf20Sopenharmony_ci} 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_cistatic bool 22178c2ecf20Sopenharmony_ciqed_iov_pf_validate_tunn_param(struct vfpf_update_tunn_param_tlv *p_req) 22188c2ecf20Sopenharmony_ci{ 22198c2ecf20Sopenharmony_ci bool b_update_requested = false; 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci if (p_req->tun_mode_update_mask || p_req->update_tun_cls || 22228c2ecf20Sopenharmony_ci p_req->update_geneve_port || p_req->update_vxlan_port) 22238c2ecf20Sopenharmony_ci b_update_requested = true; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci return b_update_requested; 22268c2ecf20Sopenharmony_ci} 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_cistatic void qed_pf_validate_tunn_mode(struct qed_tunn_update_type *tun, int *rc) 22298c2ecf20Sopenharmony_ci{ 22308c2ecf20Sopenharmony_ci if (tun->b_update_mode && !tun->b_mode_enabled) { 22318c2ecf20Sopenharmony_ci tun->b_update_mode = false; 22328c2ecf20Sopenharmony_ci *rc = -EINVAL; 22338c2ecf20Sopenharmony_ci } 22348c2ecf20Sopenharmony_ci} 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_cistatic int 22378c2ecf20Sopenharmony_ciqed_pf_validate_modify_tunn_config(struct qed_hwfn *p_hwfn, 22388c2ecf20Sopenharmony_ci u16 *tun_features, bool *update, 22398c2ecf20Sopenharmony_ci struct qed_tunnel_info *tun_src) 22408c2ecf20Sopenharmony_ci{ 22418c2ecf20Sopenharmony_ci struct qed_eth_cb_ops *ops = p_hwfn->cdev->protocol_ops.eth; 22428c2ecf20Sopenharmony_ci struct qed_tunnel_info *tun = &p_hwfn->cdev->tunnel; 22438c2ecf20Sopenharmony_ci u16 bultn_vxlan_port, bultn_geneve_port; 22448c2ecf20Sopenharmony_ci void *cookie = p_hwfn->cdev->ops_cookie; 22458c2ecf20Sopenharmony_ci int i, rc = 0; 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci *tun_features = p_hwfn->cdev->tunn_feature_mask; 22488c2ecf20Sopenharmony_ci bultn_vxlan_port = tun->vxlan_port.port; 22498c2ecf20Sopenharmony_ci bultn_geneve_port = tun->geneve_port.port; 22508c2ecf20Sopenharmony_ci qed_pf_validate_tunn_mode(&tun_src->vxlan, &rc); 22518c2ecf20Sopenharmony_ci qed_pf_validate_tunn_mode(&tun_src->l2_geneve, &rc); 22528c2ecf20Sopenharmony_ci qed_pf_validate_tunn_mode(&tun_src->ip_geneve, &rc); 22538c2ecf20Sopenharmony_ci qed_pf_validate_tunn_mode(&tun_src->l2_gre, &rc); 22548c2ecf20Sopenharmony_ci qed_pf_validate_tunn_mode(&tun_src->ip_gre, &rc); 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci if ((tun_src->b_update_rx_cls || tun_src->b_update_tx_cls) && 22578c2ecf20Sopenharmony_ci (tun_src->vxlan.tun_cls != QED_TUNN_CLSS_MAC_VLAN || 22588c2ecf20Sopenharmony_ci tun_src->l2_geneve.tun_cls != QED_TUNN_CLSS_MAC_VLAN || 22598c2ecf20Sopenharmony_ci tun_src->ip_geneve.tun_cls != QED_TUNN_CLSS_MAC_VLAN || 22608c2ecf20Sopenharmony_ci tun_src->l2_gre.tun_cls != QED_TUNN_CLSS_MAC_VLAN || 22618c2ecf20Sopenharmony_ci tun_src->ip_gre.tun_cls != QED_TUNN_CLSS_MAC_VLAN)) { 22628c2ecf20Sopenharmony_ci tun_src->b_update_rx_cls = false; 22638c2ecf20Sopenharmony_ci tun_src->b_update_tx_cls = false; 22648c2ecf20Sopenharmony_ci rc = -EINVAL; 22658c2ecf20Sopenharmony_ci } 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci if (tun_src->vxlan_port.b_update_port) { 22688c2ecf20Sopenharmony_ci if (tun_src->vxlan_port.port == tun->vxlan_port.port) { 22698c2ecf20Sopenharmony_ci tun_src->vxlan_port.b_update_port = false; 22708c2ecf20Sopenharmony_ci } else { 22718c2ecf20Sopenharmony_ci *update = true; 22728c2ecf20Sopenharmony_ci bultn_vxlan_port = tun_src->vxlan_port.port; 22738c2ecf20Sopenharmony_ci } 22748c2ecf20Sopenharmony_ci } 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci if (tun_src->geneve_port.b_update_port) { 22778c2ecf20Sopenharmony_ci if (tun_src->geneve_port.port == tun->geneve_port.port) { 22788c2ecf20Sopenharmony_ci tun_src->geneve_port.b_update_port = false; 22798c2ecf20Sopenharmony_ci } else { 22808c2ecf20Sopenharmony_ci *update = true; 22818c2ecf20Sopenharmony_ci bultn_geneve_port = tun_src->geneve_port.port; 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci qed_for_each_vf(p_hwfn, i) { 22868c2ecf20Sopenharmony_ci qed_iov_bulletin_set_udp_ports(p_hwfn, i, bultn_vxlan_port, 22878c2ecf20Sopenharmony_ci bultn_geneve_port); 22888c2ecf20Sopenharmony_ci } 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci qed_schedule_iov(p_hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); 22918c2ecf20Sopenharmony_ci ops->ports_update(cookie, bultn_vxlan_port, bultn_geneve_port); 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci return rc; 22948c2ecf20Sopenharmony_ci} 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_update_tunn_param(struct qed_hwfn *p_hwfn, 22978c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 22988c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf) 22998c2ecf20Sopenharmony_ci{ 23008c2ecf20Sopenharmony_ci struct qed_tunnel_info *p_tun = &p_hwfn->cdev->tunnel; 23018c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx; 23028c2ecf20Sopenharmony_ci struct pfvf_update_tunn_param_tlv *p_resp; 23038c2ecf20Sopenharmony_ci struct vfpf_update_tunn_param_tlv *p_req; 23048c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_SUCCESS; 23058c2ecf20Sopenharmony_ci bool b_update_required = false; 23068c2ecf20Sopenharmony_ci struct qed_tunnel_info tunn; 23078c2ecf20Sopenharmony_ci u16 tunn_feature_mask = 0; 23088c2ecf20Sopenharmony_ci int i, rc = 0; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci mbx->offset = (u8 *)mbx->reply_virt; 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci memset(&tunn, 0, sizeof(tunn)); 23138c2ecf20Sopenharmony_ci p_req = &mbx->req_virt->tunn_param_update; 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci if (!qed_iov_pf_validate_tunn_param(p_req)) { 23168c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 23178c2ecf20Sopenharmony_ci "No tunnel update requested by VF\n"); 23188c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 23198c2ecf20Sopenharmony_ci goto send_resp; 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci tunn.b_update_rx_cls = p_req->update_tun_cls; 23238c2ecf20Sopenharmony_ci tunn.b_update_tx_cls = p_req->update_tun_cls; 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci qed_iov_pf_update_tun_param(p_req, &tunn.vxlan, &tunn.vxlan_port, 23268c2ecf20Sopenharmony_ci QED_MODE_VXLAN_TUNN, p_req->vxlan_clss, 23278c2ecf20Sopenharmony_ci p_req->update_vxlan_port, 23288c2ecf20Sopenharmony_ci p_req->vxlan_port); 23298c2ecf20Sopenharmony_ci qed_iov_pf_update_tun_param(p_req, &tunn.l2_geneve, &tunn.geneve_port, 23308c2ecf20Sopenharmony_ci QED_MODE_L2GENEVE_TUNN, 23318c2ecf20Sopenharmony_ci p_req->l2geneve_clss, 23328c2ecf20Sopenharmony_ci p_req->update_geneve_port, 23338c2ecf20Sopenharmony_ci p_req->geneve_port); 23348c2ecf20Sopenharmony_ci __qed_iov_pf_update_tun_param(p_req, &tunn.ip_geneve, 23358c2ecf20Sopenharmony_ci QED_MODE_IPGENEVE_TUNN, 23368c2ecf20Sopenharmony_ci p_req->ipgeneve_clss); 23378c2ecf20Sopenharmony_ci __qed_iov_pf_update_tun_param(p_req, &tunn.l2_gre, 23388c2ecf20Sopenharmony_ci QED_MODE_L2GRE_TUNN, p_req->l2gre_clss); 23398c2ecf20Sopenharmony_ci __qed_iov_pf_update_tun_param(p_req, &tunn.ip_gre, 23408c2ecf20Sopenharmony_ci QED_MODE_IPGRE_TUNN, p_req->ipgre_clss); 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci /* If PF modifies VF's req then it should 23438c2ecf20Sopenharmony_ci * still return an error in case of partial configuration 23448c2ecf20Sopenharmony_ci * or modified configuration as opposed to requested one. 23458c2ecf20Sopenharmony_ci */ 23468c2ecf20Sopenharmony_ci rc = qed_pf_validate_modify_tunn_config(p_hwfn, &tunn_feature_mask, 23478c2ecf20Sopenharmony_ci &b_update_required, &tunn); 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci if (rc) 23508c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci /* If QED client is willing to update anything ? */ 23538c2ecf20Sopenharmony_ci if (b_update_required) { 23548c2ecf20Sopenharmony_ci u16 geneve_port; 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci rc = qed_sp_pf_update_tunn_cfg(p_hwfn, p_ptt, &tunn, 23578c2ecf20Sopenharmony_ci QED_SPQ_MODE_EBLOCK, NULL); 23588c2ecf20Sopenharmony_ci if (rc) 23598c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci geneve_port = p_tun->geneve_port.port; 23628c2ecf20Sopenharmony_ci qed_for_each_vf(p_hwfn, i) { 23638c2ecf20Sopenharmony_ci qed_iov_bulletin_set_udp_ports(p_hwfn, i, 23648c2ecf20Sopenharmony_ci p_tun->vxlan_port.port, 23658c2ecf20Sopenharmony_ci geneve_port); 23668c2ecf20Sopenharmony_ci } 23678c2ecf20Sopenharmony_ci } 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_cisend_resp: 23708c2ecf20Sopenharmony_ci p_resp = qed_add_tlv(p_hwfn, &mbx->offset, 23718c2ecf20Sopenharmony_ci CHANNEL_TLV_UPDATE_TUNN_PARAM, sizeof(*p_resp)); 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci qed_iov_pf_update_tun_response(p_resp, p_tun, tunn_feature_mask); 23748c2ecf20Sopenharmony_ci qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_LIST_END, 23758c2ecf20Sopenharmony_ci sizeof(struct channel_list_end_tlv)); 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci qed_iov_send_response(p_hwfn, p_ptt, p_vf, sizeof(*p_resp), status); 23788c2ecf20Sopenharmony_ci} 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_start_txq_resp(struct qed_hwfn *p_hwfn, 23818c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 23828c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 23838c2ecf20Sopenharmony_ci u32 cid, u8 status) 23848c2ecf20Sopenharmony_ci{ 23858c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx; 23868c2ecf20Sopenharmony_ci struct pfvf_start_queue_resp_tlv *p_tlv; 23878c2ecf20Sopenharmony_ci bool b_legacy = false; 23888c2ecf20Sopenharmony_ci u16 length; 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci mbx->offset = (u8 *)mbx->reply_virt; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci /* Taking a bigger struct instead of adding a TLV to list was a 23938c2ecf20Sopenharmony_ci * mistake, but one which we're now stuck with, as some older 23948c2ecf20Sopenharmony_ci * clients assume the size of the previous response. 23958c2ecf20Sopenharmony_ci */ 23968c2ecf20Sopenharmony_ci if (p_vf->acquire.vfdev_info.eth_fp_hsi_minor == 23978c2ecf20Sopenharmony_ci ETH_HSI_VER_NO_PKT_LEN_TUNN) 23988c2ecf20Sopenharmony_ci b_legacy = true; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci if (!b_legacy) 24018c2ecf20Sopenharmony_ci length = sizeof(*p_tlv); 24028c2ecf20Sopenharmony_ci else 24038c2ecf20Sopenharmony_ci length = sizeof(struct pfvf_def_resp_tlv); 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci p_tlv = qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_START_TXQ, 24068c2ecf20Sopenharmony_ci length); 24078c2ecf20Sopenharmony_ci qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_LIST_END, 24088c2ecf20Sopenharmony_ci sizeof(struct channel_list_end_tlv)); 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci /* Update the TLV with the response */ 24118c2ecf20Sopenharmony_ci if ((status == PFVF_STATUS_SUCCESS) && !b_legacy) 24128c2ecf20Sopenharmony_ci p_tlv->offset = qed_db_addr_vf(cid, DQ_DEMS_LEGACY); 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci qed_iov_send_response(p_hwfn, p_ptt, p_vf, length, status); 24158c2ecf20Sopenharmony_ci} 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, 24188c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 24198c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 24208c2ecf20Sopenharmony_ci{ 24218c2ecf20Sopenharmony_ci struct qed_queue_start_common_params params; 24228c2ecf20Sopenharmony_ci struct qed_queue_cid_vf_params vf_params; 24238c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 24248c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_NO_RESOURCE; 24258c2ecf20Sopenharmony_ci struct vfpf_start_txq_tlv *req; 24268c2ecf20Sopenharmony_ci struct qed_vf_queue *p_queue; 24278c2ecf20Sopenharmony_ci struct qed_queue_cid *p_cid; 24288c2ecf20Sopenharmony_ci struct qed_sb_info sb_dummy; 24298c2ecf20Sopenharmony_ci u8 qid_usage_idx, vf_legacy; 24308c2ecf20Sopenharmony_ci u32 cid = 0; 24318c2ecf20Sopenharmony_ci int rc; 24328c2ecf20Sopenharmony_ci u16 pq; 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 24358c2ecf20Sopenharmony_ci req = &mbx->req_virt->start_txq; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci if (!qed_iov_validate_txq(p_hwfn, vf, req->tx_qid, 24388c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_NA) || 24398c2ecf20Sopenharmony_ci !qed_iov_validate_sb(p_hwfn, vf, req->hw_sb)) 24408c2ecf20Sopenharmony_ci goto out; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, true); 24438c2ecf20Sopenharmony_ci if (qid_usage_idx == QED_IOV_QID_INVALID) 24448c2ecf20Sopenharmony_ci goto out; 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci p_queue = &vf->vf_queues[req->tx_qid]; 24478c2ecf20Sopenharmony_ci if (p_queue->cids[qid_usage_idx].p_cid) 24488c2ecf20Sopenharmony_ci goto out; 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci vf_legacy = qed_vf_calculate_legacy(vf); 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci /* Acquire a new queue-cid */ 24538c2ecf20Sopenharmony_ci params.queue_id = p_queue->fw_tx_qid; 24548c2ecf20Sopenharmony_ci params.vport_id = vf->vport_id; 24558c2ecf20Sopenharmony_ci params.stats_id = vf->abs_vf_id + 0x10; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci /* Since IGU index is passed via sb_info, construct a dummy one */ 24588c2ecf20Sopenharmony_ci memset(&sb_dummy, 0, sizeof(sb_dummy)); 24598c2ecf20Sopenharmony_ci sb_dummy.igu_sb_id = req->hw_sb; 24608c2ecf20Sopenharmony_ci params.p_sb = &sb_dummy; 24618c2ecf20Sopenharmony_ci params.sb_idx = req->sb_index; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci memset(&vf_params, 0, sizeof(vf_params)); 24648c2ecf20Sopenharmony_ci vf_params.vfid = vf->relative_vf_id; 24658c2ecf20Sopenharmony_ci vf_params.vf_qid = (u8)req->tx_qid; 24668c2ecf20Sopenharmony_ci vf_params.vf_legacy = vf_legacy; 24678c2ecf20Sopenharmony_ci vf_params.qid_usage_idx = qid_usage_idx; 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci p_cid = qed_eth_queue_to_cid(p_hwfn, vf->opaque_fid, 24708c2ecf20Sopenharmony_ci ¶ms, false, &vf_params); 24718c2ecf20Sopenharmony_ci if (!p_cid) 24728c2ecf20Sopenharmony_ci goto out; 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci pq = qed_get_cm_pq_idx_vf(p_hwfn, vf->relative_vf_id); 24758c2ecf20Sopenharmony_ci rc = qed_eth_txq_start_ramrod(p_hwfn, p_cid, 24768c2ecf20Sopenharmony_ci req->pbl_addr, req->pbl_size, pq); 24778c2ecf20Sopenharmony_ci if (rc) { 24788c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 24798c2ecf20Sopenharmony_ci qed_eth_queue_cid_release(p_hwfn, p_cid); 24808c2ecf20Sopenharmony_ci } else { 24818c2ecf20Sopenharmony_ci status = PFVF_STATUS_SUCCESS; 24828c2ecf20Sopenharmony_ci p_queue->cids[qid_usage_idx].p_cid = p_cid; 24838c2ecf20Sopenharmony_ci p_queue->cids[qid_usage_idx].b_is_tx = true; 24848c2ecf20Sopenharmony_ci cid = p_cid->cid; 24858c2ecf20Sopenharmony_ci } 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ciout: 24888c2ecf20Sopenharmony_ci qed_iov_vf_mbx_start_txq_resp(p_hwfn, p_ptt, vf, cid, status); 24898c2ecf20Sopenharmony_ci} 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_cistatic int qed_iov_vf_stop_rxqs(struct qed_hwfn *p_hwfn, 24928c2ecf20Sopenharmony_ci struct qed_vf_info *vf, 24938c2ecf20Sopenharmony_ci u16 rxq_id, 24948c2ecf20Sopenharmony_ci u8 qid_usage_idx, bool cqe_completion) 24958c2ecf20Sopenharmony_ci{ 24968c2ecf20Sopenharmony_ci struct qed_vf_queue *p_queue; 24978c2ecf20Sopenharmony_ci int rc = 0; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci if (!qed_iov_validate_rxq(p_hwfn, vf, rxq_id, QED_IOV_VALIDATE_Q_NA)) { 25008c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 25018c2ecf20Sopenharmony_ci QED_MSG_IOV, 25028c2ecf20Sopenharmony_ci "VF[%d] Tried Closing Rx 0x%04x.%02x which is inactive\n", 25038c2ecf20Sopenharmony_ci vf->relative_vf_id, rxq_id, qid_usage_idx); 25048c2ecf20Sopenharmony_ci return -EINVAL; 25058c2ecf20Sopenharmony_ci } 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci p_queue = &vf->vf_queues[rxq_id]; 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci /* We've validated the index and the existence of the active RXQ - 25108c2ecf20Sopenharmony_ci * now we need to make sure that it's using the correct qid. 25118c2ecf20Sopenharmony_ci */ 25128c2ecf20Sopenharmony_ci if (!p_queue->cids[qid_usage_idx].p_cid || 25138c2ecf20Sopenharmony_ci p_queue->cids[qid_usage_idx].b_is_tx) { 25148c2ecf20Sopenharmony_ci struct qed_queue_cid *p_cid; 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci p_cid = qed_iov_get_vf_rx_queue_cid(p_queue); 25178c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 25188c2ecf20Sopenharmony_ci QED_MSG_IOV, 25198c2ecf20Sopenharmony_ci "VF[%d] - Tried Closing Rx 0x%04x.%02x, but Rx is at %04x.%02x\n", 25208c2ecf20Sopenharmony_ci vf->relative_vf_id, 25218c2ecf20Sopenharmony_ci rxq_id, qid_usage_idx, rxq_id, p_cid->qid_usage_idx); 25228c2ecf20Sopenharmony_ci return -EINVAL; 25238c2ecf20Sopenharmony_ci } 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci /* Now that we know we have a valid Rx-queue - close it */ 25268c2ecf20Sopenharmony_ci rc = qed_eth_rx_queue_stop(p_hwfn, 25278c2ecf20Sopenharmony_ci p_queue->cids[qid_usage_idx].p_cid, 25288c2ecf20Sopenharmony_ci false, cqe_completion); 25298c2ecf20Sopenharmony_ci if (rc) 25308c2ecf20Sopenharmony_ci return rc; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci p_queue->cids[qid_usage_idx].p_cid = NULL; 25338c2ecf20Sopenharmony_ci vf->num_active_rxqs--; 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci return 0; 25368c2ecf20Sopenharmony_ci} 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_cistatic int qed_iov_vf_stop_txqs(struct qed_hwfn *p_hwfn, 25398c2ecf20Sopenharmony_ci struct qed_vf_info *vf, 25408c2ecf20Sopenharmony_ci u16 txq_id, u8 qid_usage_idx) 25418c2ecf20Sopenharmony_ci{ 25428c2ecf20Sopenharmony_ci struct qed_vf_queue *p_queue; 25438c2ecf20Sopenharmony_ci int rc = 0; 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci if (!qed_iov_validate_txq(p_hwfn, vf, txq_id, QED_IOV_VALIDATE_Q_NA)) 25468c2ecf20Sopenharmony_ci return -EINVAL; 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci p_queue = &vf->vf_queues[txq_id]; 25498c2ecf20Sopenharmony_ci if (!p_queue->cids[qid_usage_idx].p_cid || 25508c2ecf20Sopenharmony_ci !p_queue->cids[qid_usage_idx].b_is_tx) 25518c2ecf20Sopenharmony_ci return -EINVAL; 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci rc = qed_eth_tx_queue_stop(p_hwfn, p_queue->cids[qid_usage_idx].p_cid); 25548c2ecf20Sopenharmony_ci if (rc) 25558c2ecf20Sopenharmony_ci return rc; 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci p_queue->cids[qid_usage_idx].p_cid = NULL; 25588c2ecf20Sopenharmony_ci return 0; 25598c2ecf20Sopenharmony_ci} 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_stop_rxqs(struct qed_hwfn *p_hwfn, 25628c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 25638c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 25648c2ecf20Sopenharmony_ci{ 25658c2ecf20Sopenharmony_ci u16 length = sizeof(struct pfvf_def_resp_tlv); 25668c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 25678c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_FAILURE; 25688c2ecf20Sopenharmony_ci struct vfpf_stop_rxqs_tlv *req; 25698c2ecf20Sopenharmony_ci u8 qid_usage_idx; 25708c2ecf20Sopenharmony_ci int rc; 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci /* There has never been an official driver that used this interface 25738c2ecf20Sopenharmony_ci * for stopping multiple queues, and it is now considered deprecated. 25748c2ecf20Sopenharmony_ci * Validate this isn't used here. 25758c2ecf20Sopenharmony_ci */ 25768c2ecf20Sopenharmony_ci req = &mbx->req_virt->stop_rxqs; 25778c2ecf20Sopenharmony_ci if (req->num_rxqs != 1) { 25788c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 25798c2ecf20Sopenharmony_ci "Odd; VF[%d] tried stopping multiple Rx queues\n", 25808c2ecf20Sopenharmony_ci vf->relative_vf_id); 25818c2ecf20Sopenharmony_ci status = PFVF_STATUS_NOT_SUPPORTED; 25828c2ecf20Sopenharmony_ci goto out; 25838c2ecf20Sopenharmony_ci } 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci /* Find which qid-index is associated with the queue */ 25868c2ecf20Sopenharmony_ci qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); 25878c2ecf20Sopenharmony_ci if (qid_usage_idx == QED_IOV_QID_INVALID) 25888c2ecf20Sopenharmony_ci goto out; 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci rc = qed_iov_vf_stop_rxqs(p_hwfn, vf, req->rx_qid, 25918c2ecf20Sopenharmony_ci qid_usage_idx, req->cqe_completion); 25928c2ecf20Sopenharmony_ci if (!rc) 25938c2ecf20Sopenharmony_ci status = PFVF_STATUS_SUCCESS; 25948c2ecf20Sopenharmony_ciout: 25958c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_STOP_RXQS, 25968c2ecf20Sopenharmony_ci length, status); 25978c2ecf20Sopenharmony_ci} 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_stop_txqs(struct qed_hwfn *p_hwfn, 26008c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 26018c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 26028c2ecf20Sopenharmony_ci{ 26038c2ecf20Sopenharmony_ci u16 length = sizeof(struct pfvf_def_resp_tlv); 26048c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 26058c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_FAILURE; 26068c2ecf20Sopenharmony_ci struct vfpf_stop_txqs_tlv *req; 26078c2ecf20Sopenharmony_ci u8 qid_usage_idx; 26088c2ecf20Sopenharmony_ci int rc; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci /* There has never been an official driver that used this interface 26118c2ecf20Sopenharmony_ci * for stopping multiple queues, and it is now considered deprecated. 26128c2ecf20Sopenharmony_ci * Validate this isn't used here. 26138c2ecf20Sopenharmony_ci */ 26148c2ecf20Sopenharmony_ci req = &mbx->req_virt->stop_txqs; 26158c2ecf20Sopenharmony_ci if (req->num_txqs != 1) { 26168c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 26178c2ecf20Sopenharmony_ci "Odd; VF[%d] tried stopping multiple Tx queues\n", 26188c2ecf20Sopenharmony_ci vf->relative_vf_id); 26198c2ecf20Sopenharmony_ci status = PFVF_STATUS_NOT_SUPPORTED; 26208c2ecf20Sopenharmony_ci goto out; 26218c2ecf20Sopenharmony_ci } 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci /* Find which qid-index is associated with the queue */ 26248c2ecf20Sopenharmony_ci qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, true); 26258c2ecf20Sopenharmony_ci if (qid_usage_idx == QED_IOV_QID_INVALID) 26268c2ecf20Sopenharmony_ci goto out; 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci rc = qed_iov_vf_stop_txqs(p_hwfn, vf, req->tx_qid, qid_usage_idx); 26298c2ecf20Sopenharmony_ci if (!rc) 26308c2ecf20Sopenharmony_ci status = PFVF_STATUS_SUCCESS; 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ciout: 26338c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_STOP_TXQS, 26348c2ecf20Sopenharmony_ci length, status); 26358c2ecf20Sopenharmony_ci} 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_update_rxqs(struct qed_hwfn *p_hwfn, 26388c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 26398c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 26408c2ecf20Sopenharmony_ci{ 26418c2ecf20Sopenharmony_ci struct qed_queue_cid *handlers[QED_MAX_VF_CHAINS_PER_PF]; 26428c2ecf20Sopenharmony_ci u16 length = sizeof(struct pfvf_def_resp_tlv); 26438c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 26448c2ecf20Sopenharmony_ci struct vfpf_update_rxq_tlv *req; 26458c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_FAILURE; 26468c2ecf20Sopenharmony_ci u8 complete_event_flg; 26478c2ecf20Sopenharmony_ci u8 complete_cqe_flg; 26488c2ecf20Sopenharmony_ci u8 qid_usage_idx; 26498c2ecf20Sopenharmony_ci int rc; 26508c2ecf20Sopenharmony_ci u8 i; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci req = &mbx->req_virt->update_rxq; 26538c2ecf20Sopenharmony_ci complete_cqe_flg = !!(req->flags & VFPF_RXQ_UPD_COMPLETE_CQE_FLAG); 26548c2ecf20Sopenharmony_ci complete_event_flg = !!(req->flags & VFPF_RXQ_UPD_COMPLETE_EVENT_FLAG); 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); 26578c2ecf20Sopenharmony_ci if (qid_usage_idx == QED_IOV_QID_INVALID) 26588c2ecf20Sopenharmony_ci goto out; 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci /* There shouldn't exist a VF that uses queue-qids yet uses this 26618c2ecf20Sopenharmony_ci * API with multiple Rx queues. Validate this. 26628c2ecf20Sopenharmony_ci */ 26638c2ecf20Sopenharmony_ci if ((vf->acquire.vfdev_info.capabilities & 26648c2ecf20Sopenharmony_ci VFPF_ACQUIRE_CAP_QUEUE_QIDS) && req->num_rxqs != 1) { 26658c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 26668c2ecf20Sopenharmony_ci "VF[%d] supports QIDs but sends multiple queues\n", 26678c2ecf20Sopenharmony_ci vf->relative_vf_id); 26688c2ecf20Sopenharmony_ci goto out; 26698c2ecf20Sopenharmony_ci } 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci /* Validate inputs - for the legacy case this is still true since 26728c2ecf20Sopenharmony_ci * qid_usage_idx for each Rx queue would be LEGACY_QID_RX. 26738c2ecf20Sopenharmony_ci */ 26748c2ecf20Sopenharmony_ci for (i = req->rx_qid; i < req->rx_qid + req->num_rxqs; i++) { 26758c2ecf20Sopenharmony_ci if (!qed_iov_validate_rxq(p_hwfn, vf, i, 26768c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_NA) || 26778c2ecf20Sopenharmony_ci !vf->vf_queues[i].cids[qid_usage_idx].p_cid || 26788c2ecf20Sopenharmony_ci vf->vf_queues[i].cids[qid_usage_idx].b_is_tx) { 26798c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 26808c2ecf20Sopenharmony_ci "VF[%d]: Incorrect Rxqs [%04x, %02x]\n", 26818c2ecf20Sopenharmony_ci vf->relative_vf_id, req->rx_qid, 26828c2ecf20Sopenharmony_ci req->num_rxqs); 26838c2ecf20Sopenharmony_ci goto out; 26848c2ecf20Sopenharmony_ci } 26858c2ecf20Sopenharmony_ci } 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci /* Prepare the handlers */ 26888c2ecf20Sopenharmony_ci for (i = 0; i < req->num_rxqs; i++) { 26898c2ecf20Sopenharmony_ci u16 qid = req->rx_qid + i; 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci handlers[i] = vf->vf_queues[qid].cids[qid_usage_idx].p_cid; 26928c2ecf20Sopenharmony_ci } 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci rc = qed_sp_eth_rx_queues_update(p_hwfn, (void **)&handlers, 26958c2ecf20Sopenharmony_ci req->num_rxqs, 26968c2ecf20Sopenharmony_ci complete_cqe_flg, 26978c2ecf20Sopenharmony_ci complete_event_flg, 26988c2ecf20Sopenharmony_ci QED_SPQ_MODE_EBLOCK, NULL); 26998c2ecf20Sopenharmony_ci if (rc) 27008c2ecf20Sopenharmony_ci goto out; 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci status = PFVF_STATUS_SUCCESS; 27038c2ecf20Sopenharmony_ciout: 27048c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_UPDATE_RXQ, 27058c2ecf20Sopenharmony_ci length, status); 27068c2ecf20Sopenharmony_ci} 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_civoid *qed_iov_search_list_tlvs(struct qed_hwfn *p_hwfn, 27098c2ecf20Sopenharmony_ci void *p_tlvs_list, u16 req_type) 27108c2ecf20Sopenharmony_ci{ 27118c2ecf20Sopenharmony_ci struct channel_tlv *p_tlv = (struct channel_tlv *)p_tlvs_list; 27128c2ecf20Sopenharmony_ci int len = 0; 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci do { 27158c2ecf20Sopenharmony_ci if (!p_tlv->length) { 27168c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Zero length TLV found\n"); 27178c2ecf20Sopenharmony_ci return NULL; 27188c2ecf20Sopenharmony_ci } 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_ci if (p_tlv->type == req_type) { 27218c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 27228c2ecf20Sopenharmony_ci "Extended tlv type %d, length %d found\n", 27238c2ecf20Sopenharmony_ci p_tlv->type, p_tlv->length); 27248c2ecf20Sopenharmony_ci return p_tlv; 27258c2ecf20Sopenharmony_ci } 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci len += p_tlv->length; 27288c2ecf20Sopenharmony_ci p_tlv = (struct channel_tlv *)((u8 *)p_tlv + p_tlv->length); 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci if ((len + p_tlv->length) > TLV_BUFFER_SIZE) { 27318c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "TLVs has overrun the buffer size\n"); 27328c2ecf20Sopenharmony_ci return NULL; 27338c2ecf20Sopenharmony_ci } 27348c2ecf20Sopenharmony_ci } while (p_tlv->type != CHANNEL_TLV_LIST_END); 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci return NULL; 27378c2ecf20Sopenharmony_ci} 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_cistatic void 27408c2ecf20Sopenharmony_ciqed_iov_vp_update_act_param(struct qed_hwfn *p_hwfn, 27418c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params *p_data, 27428c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 27438c2ecf20Sopenharmony_ci{ 27448c2ecf20Sopenharmony_ci struct vfpf_vport_update_activate_tlv *p_act_tlv; 27458c2ecf20Sopenharmony_ci u16 tlv = CHANNEL_TLV_VPORT_UPDATE_ACTIVATE; 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci p_act_tlv = (struct vfpf_vport_update_activate_tlv *) 27488c2ecf20Sopenharmony_ci qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 27498c2ecf20Sopenharmony_ci if (!p_act_tlv) 27508c2ecf20Sopenharmony_ci return; 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci p_data->update_vport_active_rx_flg = p_act_tlv->update_rx; 27538c2ecf20Sopenharmony_ci p_data->vport_active_rx_flg = p_act_tlv->active_rx; 27548c2ecf20Sopenharmony_ci p_data->update_vport_active_tx_flg = p_act_tlv->update_tx; 27558c2ecf20Sopenharmony_ci p_data->vport_active_tx_flg = p_act_tlv->active_tx; 27568c2ecf20Sopenharmony_ci *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_ACTIVATE; 27578c2ecf20Sopenharmony_ci} 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_cistatic void 27608c2ecf20Sopenharmony_ciqed_iov_vp_update_vlan_param(struct qed_hwfn *p_hwfn, 27618c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params *p_data, 27628c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 27638c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 27648c2ecf20Sopenharmony_ci{ 27658c2ecf20Sopenharmony_ci struct vfpf_vport_update_vlan_strip_tlv *p_vlan_tlv; 27668c2ecf20Sopenharmony_ci u16 tlv = CHANNEL_TLV_VPORT_UPDATE_VLAN_STRIP; 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci p_vlan_tlv = (struct vfpf_vport_update_vlan_strip_tlv *) 27698c2ecf20Sopenharmony_ci qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 27708c2ecf20Sopenharmony_ci if (!p_vlan_tlv) 27718c2ecf20Sopenharmony_ci return; 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci p_vf->shadow_config.inner_vlan_removal = p_vlan_tlv->remove_vlan; 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci /* Ignore the VF request if we're forcing a vlan */ 27768c2ecf20Sopenharmony_ci if (!(p_vf->configured_features & BIT(VLAN_ADDR_FORCED))) { 27778c2ecf20Sopenharmony_ci p_data->update_inner_vlan_removal_flg = 1; 27788c2ecf20Sopenharmony_ci p_data->inner_vlan_removal_flg = p_vlan_tlv->remove_vlan; 27798c2ecf20Sopenharmony_ci } 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_VLAN_STRIP; 27828c2ecf20Sopenharmony_ci} 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_cistatic void 27858c2ecf20Sopenharmony_ciqed_iov_vp_update_tx_switch(struct qed_hwfn *p_hwfn, 27868c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params *p_data, 27878c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 27888c2ecf20Sopenharmony_ci{ 27898c2ecf20Sopenharmony_ci struct vfpf_vport_update_tx_switch_tlv *p_tx_switch_tlv; 27908c2ecf20Sopenharmony_ci u16 tlv = CHANNEL_TLV_VPORT_UPDATE_TX_SWITCH; 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci p_tx_switch_tlv = (struct vfpf_vport_update_tx_switch_tlv *) 27938c2ecf20Sopenharmony_ci qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, 27948c2ecf20Sopenharmony_ci tlv); 27958c2ecf20Sopenharmony_ci if (!p_tx_switch_tlv) 27968c2ecf20Sopenharmony_ci return; 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci p_data->update_tx_switching_flg = 1; 27998c2ecf20Sopenharmony_ci p_data->tx_switching_flg = p_tx_switch_tlv->tx_switching; 28008c2ecf20Sopenharmony_ci *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_TX_SWITCH; 28018c2ecf20Sopenharmony_ci} 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_cistatic void 28048c2ecf20Sopenharmony_ciqed_iov_vp_update_mcast_bin_param(struct qed_hwfn *p_hwfn, 28058c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params *p_data, 28068c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 28078c2ecf20Sopenharmony_ci{ 28088c2ecf20Sopenharmony_ci struct vfpf_vport_update_mcast_bin_tlv *p_mcast_tlv; 28098c2ecf20Sopenharmony_ci u16 tlv = CHANNEL_TLV_VPORT_UPDATE_MCAST; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci p_mcast_tlv = (struct vfpf_vport_update_mcast_bin_tlv *) 28128c2ecf20Sopenharmony_ci qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 28138c2ecf20Sopenharmony_ci if (!p_mcast_tlv) 28148c2ecf20Sopenharmony_ci return; 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci p_data->update_approx_mcast_flg = 1; 28178c2ecf20Sopenharmony_ci memcpy(p_data->bins, p_mcast_tlv->bins, 28188c2ecf20Sopenharmony_ci sizeof(u32) * ETH_MULTICAST_MAC_BINS_IN_REGS); 28198c2ecf20Sopenharmony_ci *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_MCAST; 28208c2ecf20Sopenharmony_ci} 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_cistatic void 28238c2ecf20Sopenharmony_ciqed_iov_vp_update_accept_flag(struct qed_hwfn *p_hwfn, 28248c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params *p_data, 28258c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 28268c2ecf20Sopenharmony_ci{ 28278c2ecf20Sopenharmony_ci struct qed_filter_accept_flags *p_flags = &p_data->accept_flags; 28288c2ecf20Sopenharmony_ci struct vfpf_vport_update_accept_param_tlv *p_accept_tlv; 28298c2ecf20Sopenharmony_ci u16 tlv = CHANNEL_TLV_VPORT_UPDATE_ACCEPT_PARAM; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci p_accept_tlv = (struct vfpf_vport_update_accept_param_tlv *) 28328c2ecf20Sopenharmony_ci qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 28338c2ecf20Sopenharmony_ci if (!p_accept_tlv) 28348c2ecf20Sopenharmony_ci return; 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci p_flags->update_rx_mode_config = p_accept_tlv->update_rx_mode; 28378c2ecf20Sopenharmony_ci p_flags->rx_accept_filter = p_accept_tlv->rx_accept_filter; 28388c2ecf20Sopenharmony_ci p_flags->update_tx_mode_config = p_accept_tlv->update_tx_mode; 28398c2ecf20Sopenharmony_ci p_flags->tx_accept_filter = p_accept_tlv->tx_accept_filter; 28408c2ecf20Sopenharmony_ci *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_ACCEPT_PARAM; 28418c2ecf20Sopenharmony_ci} 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_cistatic void 28448c2ecf20Sopenharmony_ciqed_iov_vp_update_accept_any_vlan(struct qed_hwfn *p_hwfn, 28458c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params *p_data, 28468c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 28478c2ecf20Sopenharmony_ci{ 28488c2ecf20Sopenharmony_ci struct vfpf_vport_update_accept_any_vlan_tlv *p_accept_any_vlan; 28498c2ecf20Sopenharmony_ci u16 tlv = CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN; 28508c2ecf20Sopenharmony_ci 28518c2ecf20Sopenharmony_ci p_accept_any_vlan = (struct vfpf_vport_update_accept_any_vlan_tlv *) 28528c2ecf20Sopenharmony_ci qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, 28538c2ecf20Sopenharmony_ci tlv); 28548c2ecf20Sopenharmony_ci if (!p_accept_any_vlan) 28558c2ecf20Sopenharmony_ci return; 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci p_data->accept_any_vlan = p_accept_any_vlan->accept_any_vlan; 28588c2ecf20Sopenharmony_ci p_data->update_accept_any_vlan_flg = 28598c2ecf20Sopenharmony_ci p_accept_any_vlan->update_accept_any_vlan_flg; 28608c2ecf20Sopenharmony_ci *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_ACCEPT_ANY_VLAN; 28618c2ecf20Sopenharmony_ci} 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_cistatic void 28648c2ecf20Sopenharmony_ciqed_iov_vp_update_rss_param(struct qed_hwfn *p_hwfn, 28658c2ecf20Sopenharmony_ci struct qed_vf_info *vf, 28668c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params *p_data, 28678c2ecf20Sopenharmony_ci struct qed_rss_params *p_rss, 28688c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *p_mbx, 28698c2ecf20Sopenharmony_ci u16 *tlvs_mask, u16 *tlvs_accepted) 28708c2ecf20Sopenharmony_ci{ 28718c2ecf20Sopenharmony_ci struct vfpf_vport_update_rss_tlv *p_rss_tlv; 28728c2ecf20Sopenharmony_ci u16 tlv = CHANNEL_TLV_VPORT_UPDATE_RSS; 28738c2ecf20Sopenharmony_ci bool b_reject = false; 28748c2ecf20Sopenharmony_ci u16 table_size; 28758c2ecf20Sopenharmony_ci u16 i, q_idx; 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci p_rss_tlv = (struct vfpf_vport_update_rss_tlv *) 28788c2ecf20Sopenharmony_ci qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 28798c2ecf20Sopenharmony_ci if (!p_rss_tlv) { 28808c2ecf20Sopenharmony_ci p_data->rss_params = NULL; 28818c2ecf20Sopenharmony_ci return; 28828c2ecf20Sopenharmony_ci } 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_ci memset(p_rss, 0, sizeof(struct qed_rss_params)); 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci p_rss->update_rss_config = !!(p_rss_tlv->update_rss_flags & 28878c2ecf20Sopenharmony_ci VFPF_UPDATE_RSS_CONFIG_FLAG); 28888c2ecf20Sopenharmony_ci p_rss->update_rss_capabilities = !!(p_rss_tlv->update_rss_flags & 28898c2ecf20Sopenharmony_ci VFPF_UPDATE_RSS_CAPS_FLAG); 28908c2ecf20Sopenharmony_ci p_rss->update_rss_ind_table = !!(p_rss_tlv->update_rss_flags & 28918c2ecf20Sopenharmony_ci VFPF_UPDATE_RSS_IND_TABLE_FLAG); 28928c2ecf20Sopenharmony_ci p_rss->update_rss_key = !!(p_rss_tlv->update_rss_flags & 28938c2ecf20Sopenharmony_ci VFPF_UPDATE_RSS_KEY_FLAG); 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci p_rss->rss_enable = p_rss_tlv->rss_enable; 28968c2ecf20Sopenharmony_ci p_rss->rss_eng_id = vf->relative_vf_id + 1; 28978c2ecf20Sopenharmony_ci p_rss->rss_caps = p_rss_tlv->rss_caps; 28988c2ecf20Sopenharmony_ci p_rss->rss_table_size_log = p_rss_tlv->rss_table_size_log; 28998c2ecf20Sopenharmony_ci memcpy(p_rss->rss_key, p_rss_tlv->rss_key, sizeof(p_rss->rss_key)); 29008c2ecf20Sopenharmony_ci 29018c2ecf20Sopenharmony_ci table_size = min_t(u16, ARRAY_SIZE(p_rss->rss_ind_table), 29028c2ecf20Sopenharmony_ci (1 << p_rss_tlv->rss_table_size_log)); 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci for (i = 0; i < table_size; i++) { 29058c2ecf20Sopenharmony_ci struct qed_queue_cid *p_cid; 29068c2ecf20Sopenharmony_ci 29078c2ecf20Sopenharmony_ci q_idx = p_rss_tlv->rss_ind_table[i]; 29088c2ecf20Sopenharmony_ci if (!qed_iov_validate_rxq(p_hwfn, vf, q_idx, 29098c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_ENABLE)) { 29108c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 29118c2ecf20Sopenharmony_ci QED_MSG_IOV, 29128c2ecf20Sopenharmony_ci "VF[%d]: Omitting RSS due to wrong queue %04x\n", 29138c2ecf20Sopenharmony_ci vf->relative_vf_id, q_idx); 29148c2ecf20Sopenharmony_ci b_reject = true; 29158c2ecf20Sopenharmony_ci goto out; 29168c2ecf20Sopenharmony_ci } 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci p_cid = qed_iov_get_vf_rx_queue_cid(&vf->vf_queues[q_idx]); 29198c2ecf20Sopenharmony_ci p_rss->rss_ind_table[i] = p_cid; 29208c2ecf20Sopenharmony_ci } 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci p_data->rss_params = p_rss; 29238c2ecf20Sopenharmony_ciout: 29248c2ecf20Sopenharmony_ci *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_RSS; 29258c2ecf20Sopenharmony_ci if (!b_reject) 29268c2ecf20Sopenharmony_ci *tlvs_accepted |= 1 << QED_IOV_VP_UPDATE_RSS; 29278c2ecf20Sopenharmony_ci} 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_cistatic void 29308c2ecf20Sopenharmony_ciqed_iov_vp_update_sge_tpa_param(struct qed_hwfn *p_hwfn, 29318c2ecf20Sopenharmony_ci struct qed_vf_info *vf, 29328c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params *p_data, 29338c2ecf20Sopenharmony_ci struct qed_sge_tpa_params *p_sge_tpa, 29348c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 29358c2ecf20Sopenharmony_ci{ 29368c2ecf20Sopenharmony_ci struct vfpf_vport_update_sge_tpa_tlv *p_sge_tpa_tlv; 29378c2ecf20Sopenharmony_ci u16 tlv = CHANNEL_TLV_VPORT_UPDATE_SGE_TPA; 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci p_sge_tpa_tlv = (struct vfpf_vport_update_sge_tpa_tlv *) 29408c2ecf20Sopenharmony_ci qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci if (!p_sge_tpa_tlv) { 29438c2ecf20Sopenharmony_ci p_data->sge_tpa_params = NULL; 29448c2ecf20Sopenharmony_ci return; 29458c2ecf20Sopenharmony_ci } 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_ci memset(p_sge_tpa, 0, sizeof(struct qed_sge_tpa_params)); 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ci p_sge_tpa->update_tpa_en_flg = 29508c2ecf20Sopenharmony_ci !!(p_sge_tpa_tlv->update_sge_tpa_flags & VFPF_UPDATE_TPA_EN_FLAG); 29518c2ecf20Sopenharmony_ci p_sge_tpa->update_tpa_param_flg = 29528c2ecf20Sopenharmony_ci !!(p_sge_tpa_tlv->update_sge_tpa_flags & 29538c2ecf20Sopenharmony_ci VFPF_UPDATE_TPA_PARAM_FLAG); 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci p_sge_tpa->tpa_ipv4_en_flg = 29568c2ecf20Sopenharmony_ci !!(p_sge_tpa_tlv->sge_tpa_flags & VFPF_TPA_IPV4_EN_FLAG); 29578c2ecf20Sopenharmony_ci p_sge_tpa->tpa_ipv6_en_flg = 29588c2ecf20Sopenharmony_ci !!(p_sge_tpa_tlv->sge_tpa_flags & VFPF_TPA_IPV6_EN_FLAG); 29598c2ecf20Sopenharmony_ci p_sge_tpa->tpa_pkt_split_flg = 29608c2ecf20Sopenharmony_ci !!(p_sge_tpa_tlv->sge_tpa_flags & VFPF_TPA_PKT_SPLIT_FLAG); 29618c2ecf20Sopenharmony_ci p_sge_tpa->tpa_hdr_data_split_flg = 29628c2ecf20Sopenharmony_ci !!(p_sge_tpa_tlv->sge_tpa_flags & VFPF_TPA_HDR_DATA_SPLIT_FLAG); 29638c2ecf20Sopenharmony_ci p_sge_tpa->tpa_gro_consistent_flg = 29648c2ecf20Sopenharmony_ci !!(p_sge_tpa_tlv->sge_tpa_flags & VFPF_TPA_GRO_CONSIST_FLAG); 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ci p_sge_tpa->tpa_max_aggs_num = p_sge_tpa_tlv->tpa_max_aggs_num; 29678c2ecf20Sopenharmony_ci p_sge_tpa->tpa_max_size = p_sge_tpa_tlv->tpa_max_size; 29688c2ecf20Sopenharmony_ci p_sge_tpa->tpa_min_size_to_start = p_sge_tpa_tlv->tpa_min_size_to_start; 29698c2ecf20Sopenharmony_ci p_sge_tpa->tpa_min_size_to_cont = p_sge_tpa_tlv->tpa_min_size_to_cont; 29708c2ecf20Sopenharmony_ci p_sge_tpa->max_buffers_per_cqe = p_sge_tpa_tlv->max_buffers_per_cqe; 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci p_data->sge_tpa_params = p_sge_tpa; 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_SGE_TPA; 29758c2ecf20Sopenharmony_ci} 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_cistatic int qed_iov_pre_update_vport(struct qed_hwfn *hwfn, 29788c2ecf20Sopenharmony_ci u8 vfid, 29798c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params *params, 29808c2ecf20Sopenharmony_ci u16 *tlvs) 29818c2ecf20Sopenharmony_ci{ 29828c2ecf20Sopenharmony_ci u8 mask = QED_ACCEPT_UCAST_UNMATCHED | QED_ACCEPT_MCAST_UNMATCHED; 29838c2ecf20Sopenharmony_ci struct qed_filter_accept_flags *flags = ¶ms->accept_flags; 29848c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf_info; 29858c2ecf20Sopenharmony_ci u16 tlv_mask; 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci tlv_mask = BIT(QED_IOV_VP_UPDATE_ACCEPT_PARAM) | 29888c2ecf20Sopenharmony_ci BIT(QED_IOV_VP_UPDATE_ACCEPT_ANY_VLAN); 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci /* Untrusted VFs can't even be trusted to know that fact. 29918c2ecf20Sopenharmony_ci * Simply indicate everything is configured fine, and trace 29928c2ecf20Sopenharmony_ci * configuration 'behind their back'. 29938c2ecf20Sopenharmony_ci */ 29948c2ecf20Sopenharmony_ci if (!(*tlvs & tlv_mask)) 29958c2ecf20Sopenharmony_ci return 0; 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci vf_info = qed_iov_get_public_vf_info(hwfn, vfid, true); 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci if (flags->update_rx_mode_config) { 30008c2ecf20Sopenharmony_ci vf_info->rx_accept_mode = flags->rx_accept_filter; 30018c2ecf20Sopenharmony_ci if (!vf_info->is_trusted_configured) 30028c2ecf20Sopenharmony_ci flags->rx_accept_filter &= ~mask; 30038c2ecf20Sopenharmony_ci } 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci if (flags->update_tx_mode_config) { 30068c2ecf20Sopenharmony_ci vf_info->tx_accept_mode = flags->tx_accept_filter; 30078c2ecf20Sopenharmony_ci if (!vf_info->is_trusted_configured) 30088c2ecf20Sopenharmony_ci flags->tx_accept_filter &= ~mask; 30098c2ecf20Sopenharmony_ci } 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci if (params->update_accept_any_vlan_flg) { 30128c2ecf20Sopenharmony_ci vf_info->accept_any_vlan = params->accept_any_vlan; 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci if (vf_info->forced_vlan && !vf_info->is_trusted_configured) 30158c2ecf20Sopenharmony_ci params->accept_any_vlan = false; 30168c2ecf20Sopenharmony_ci } 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci return 0; 30198c2ecf20Sopenharmony_ci} 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_vport_update(struct qed_hwfn *p_hwfn, 30228c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 30238c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 30248c2ecf20Sopenharmony_ci{ 30258c2ecf20Sopenharmony_ci struct qed_rss_params *p_rss_params = NULL; 30268c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params params; 30278c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 30288c2ecf20Sopenharmony_ci struct qed_sge_tpa_params sge_tpa_params; 30298c2ecf20Sopenharmony_ci u16 tlvs_mask = 0, tlvs_accepted = 0; 30308c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_SUCCESS; 30318c2ecf20Sopenharmony_ci u16 length; 30328c2ecf20Sopenharmony_ci int rc; 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ci /* Valiate PF can send such a request */ 30358c2ecf20Sopenharmony_ci if (!vf->vport_instance) { 30368c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 30378c2ecf20Sopenharmony_ci QED_MSG_IOV, 30388c2ecf20Sopenharmony_ci "No VPORT instance available for VF[%d], failing vport update\n", 30398c2ecf20Sopenharmony_ci vf->abs_vf_id); 30408c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 30418c2ecf20Sopenharmony_ci goto out; 30428c2ecf20Sopenharmony_ci } 30438c2ecf20Sopenharmony_ci p_rss_params = vzalloc(sizeof(*p_rss_params)); 30448c2ecf20Sopenharmony_ci if (p_rss_params == NULL) { 30458c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 30468c2ecf20Sopenharmony_ci goto out; 30478c2ecf20Sopenharmony_ci } 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 30508c2ecf20Sopenharmony_ci params.opaque_fid = vf->opaque_fid; 30518c2ecf20Sopenharmony_ci params.vport_id = vf->vport_id; 30528c2ecf20Sopenharmony_ci params.rss_params = NULL; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci /* Search for extended tlvs list and update values 30558c2ecf20Sopenharmony_ci * from VF in struct qed_sp_vport_update_params. 30568c2ecf20Sopenharmony_ci */ 30578c2ecf20Sopenharmony_ci qed_iov_vp_update_act_param(p_hwfn, ¶ms, mbx, &tlvs_mask); 30588c2ecf20Sopenharmony_ci qed_iov_vp_update_vlan_param(p_hwfn, ¶ms, vf, mbx, &tlvs_mask); 30598c2ecf20Sopenharmony_ci qed_iov_vp_update_tx_switch(p_hwfn, ¶ms, mbx, &tlvs_mask); 30608c2ecf20Sopenharmony_ci qed_iov_vp_update_mcast_bin_param(p_hwfn, ¶ms, mbx, &tlvs_mask); 30618c2ecf20Sopenharmony_ci qed_iov_vp_update_accept_flag(p_hwfn, ¶ms, mbx, &tlvs_mask); 30628c2ecf20Sopenharmony_ci qed_iov_vp_update_accept_any_vlan(p_hwfn, ¶ms, mbx, &tlvs_mask); 30638c2ecf20Sopenharmony_ci qed_iov_vp_update_sge_tpa_param(p_hwfn, vf, ¶ms, 30648c2ecf20Sopenharmony_ci &sge_tpa_params, mbx, &tlvs_mask); 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ci tlvs_accepted = tlvs_mask; 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci /* Some of the extended TLVs need to be validated first; In that case, 30698c2ecf20Sopenharmony_ci * they can update the mask without updating the accepted [so that 30708c2ecf20Sopenharmony_ci * PF could communicate to VF it has rejected request]. 30718c2ecf20Sopenharmony_ci */ 30728c2ecf20Sopenharmony_ci qed_iov_vp_update_rss_param(p_hwfn, vf, ¶ms, p_rss_params, 30738c2ecf20Sopenharmony_ci mbx, &tlvs_mask, &tlvs_accepted); 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci if (qed_iov_pre_update_vport(p_hwfn, vf->relative_vf_id, 30768c2ecf20Sopenharmony_ci ¶ms, &tlvs_accepted)) { 30778c2ecf20Sopenharmony_ci tlvs_accepted = 0; 30788c2ecf20Sopenharmony_ci status = PFVF_STATUS_NOT_SUPPORTED; 30798c2ecf20Sopenharmony_ci goto out; 30808c2ecf20Sopenharmony_ci } 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci if (!tlvs_accepted) { 30838c2ecf20Sopenharmony_ci if (tlvs_mask) 30848c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 30858c2ecf20Sopenharmony_ci "Upper-layer prevents VF vport configuration\n"); 30868c2ecf20Sopenharmony_ci else 30878c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 30888c2ecf20Sopenharmony_ci "No feature tlvs found for vport update\n"); 30898c2ecf20Sopenharmony_ci status = PFVF_STATUS_NOT_SUPPORTED; 30908c2ecf20Sopenharmony_ci goto out; 30918c2ecf20Sopenharmony_ci } 30928c2ecf20Sopenharmony_ci 30938c2ecf20Sopenharmony_ci rc = qed_sp_vport_update(p_hwfn, ¶ms, QED_SPQ_MODE_EBLOCK, NULL); 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci if (rc) 30968c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ciout: 30998c2ecf20Sopenharmony_ci vfree(p_rss_params); 31008c2ecf20Sopenharmony_ci length = qed_iov_prep_vp_update_resp_tlvs(p_hwfn, vf, mbx, status, 31018c2ecf20Sopenharmony_ci tlvs_mask, tlvs_accepted); 31028c2ecf20Sopenharmony_ci qed_iov_send_response(p_hwfn, p_ptt, vf, length, status); 31038c2ecf20Sopenharmony_ci} 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_cistatic int qed_iov_vf_update_vlan_shadow(struct qed_hwfn *p_hwfn, 31068c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 31078c2ecf20Sopenharmony_ci struct qed_filter_ucast *p_params) 31088c2ecf20Sopenharmony_ci{ 31098c2ecf20Sopenharmony_ci int i; 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci /* First remove entries and then add new ones */ 31128c2ecf20Sopenharmony_ci if (p_params->opcode == QED_FILTER_REMOVE) { 31138c2ecf20Sopenharmony_ci for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++) 31148c2ecf20Sopenharmony_ci if (p_vf->shadow_config.vlans[i].used && 31158c2ecf20Sopenharmony_ci p_vf->shadow_config.vlans[i].vid == 31168c2ecf20Sopenharmony_ci p_params->vlan) { 31178c2ecf20Sopenharmony_ci p_vf->shadow_config.vlans[i].used = false; 31188c2ecf20Sopenharmony_ci break; 31198c2ecf20Sopenharmony_ci } 31208c2ecf20Sopenharmony_ci if (i == QED_ETH_VF_NUM_VLAN_FILTERS + 1) { 31218c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 31228c2ecf20Sopenharmony_ci QED_MSG_IOV, 31238c2ecf20Sopenharmony_ci "VF [%d] - Tries to remove a non-existing vlan\n", 31248c2ecf20Sopenharmony_ci p_vf->relative_vf_id); 31258c2ecf20Sopenharmony_ci return -EINVAL; 31268c2ecf20Sopenharmony_ci } 31278c2ecf20Sopenharmony_ci } else if (p_params->opcode == QED_FILTER_REPLACE || 31288c2ecf20Sopenharmony_ci p_params->opcode == QED_FILTER_FLUSH) { 31298c2ecf20Sopenharmony_ci for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++) 31308c2ecf20Sopenharmony_ci p_vf->shadow_config.vlans[i].used = false; 31318c2ecf20Sopenharmony_ci } 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci /* In forced mode, we're willing to remove entries - but we don't add 31348c2ecf20Sopenharmony_ci * new ones. 31358c2ecf20Sopenharmony_ci */ 31368c2ecf20Sopenharmony_ci if (p_vf->bulletin.p_virt->valid_bitmap & BIT(VLAN_ADDR_FORCED)) 31378c2ecf20Sopenharmony_ci return 0; 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci if (p_params->opcode == QED_FILTER_ADD || 31408c2ecf20Sopenharmony_ci p_params->opcode == QED_FILTER_REPLACE) { 31418c2ecf20Sopenharmony_ci for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++) { 31428c2ecf20Sopenharmony_ci if (p_vf->shadow_config.vlans[i].used) 31438c2ecf20Sopenharmony_ci continue; 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci p_vf->shadow_config.vlans[i].used = true; 31468c2ecf20Sopenharmony_ci p_vf->shadow_config.vlans[i].vid = p_params->vlan; 31478c2ecf20Sopenharmony_ci break; 31488c2ecf20Sopenharmony_ci } 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci if (i == QED_ETH_VF_NUM_VLAN_FILTERS + 1) { 31518c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 31528c2ecf20Sopenharmony_ci QED_MSG_IOV, 31538c2ecf20Sopenharmony_ci "VF [%d] - Tries to configure more than %d vlan filters\n", 31548c2ecf20Sopenharmony_ci p_vf->relative_vf_id, 31558c2ecf20Sopenharmony_ci QED_ETH_VF_NUM_VLAN_FILTERS + 1); 31568c2ecf20Sopenharmony_ci return -EINVAL; 31578c2ecf20Sopenharmony_ci } 31588c2ecf20Sopenharmony_ci } 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_ci return 0; 31618c2ecf20Sopenharmony_ci} 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_cistatic int qed_iov_vf_update_mac_shadow(struct qed_hwfn *p_hwfn, 31648c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 31658c2ecf20Sopenharmony_ci struct qed_filter_ucast *p_params) 31668c2ecf20Sopenharmony_ci{ 31678c2ecf20Sopenharmony_ci int i; 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ci /* If we're in forced-mode, we don't allow any change */ 31708c2ecf20Sopenharmony_ci if (p_vf->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED)) 31718c2ecf20Sopenharmony_ci return 0; 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_ci /* Don't keep track of shadow copy since we don't intend to restore. */ 31748c2ecf20Sopenharmony_ci if (p_vf->p_vf_info.is_trusted_configured) 31758c2ecf20Sopenharmony_ci return 0; 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_ci /* First remove entries and then add new ones */ 31788c2ecf20Sopenharmony_ci if (p_params->opcode == QED_FILTER_REMOVE) { 31798c2ecf20Sopenharmony_ci for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) { 31808c2ecf20Sopenharmony_ci if (ether_addr_equal(p_vf->shadow_config.macs[i], 31818c2ecf20Sopenharmony_ci p_params->mac)) { 31828c2ecf20Sopenharmony_ci eth_zero_addr(p_vf->shadow_config.macs[i]); 31838c2ecf20Sopenharmony_ci break; 31848c2ecf20Sopenharmony_ci } 31858c2ecf20Sopenharmony_ci } 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci if (i == QED_ETH_VF_NUM_MAC_FILTERS) { 31888c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 31898c2ecf20Sopenharmony_ci "MAC isn't configured\n"); 31908c2ecf20Sopenharmony_ci return -EINVAL; 31918c2ecf20Sopenharmony_ci } 31928c2ecf20Sopenharmony_ci } else if (p_params->opcode == QED_FILTER_REPLACE || 31938c2ecf20Sopenharmony_ci p_params->opcode == QED_FILTER_FLUSH) { 31948c2ecf20Sopenharmony_ci for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) 31958c2ecf20Sopenharmony_ci eth_zero_addr(p_vf->shadow_config.macs[i]); 31968c2ecf20Sopenharmony_ci } 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_ci /* List the new MAC address */ 31998c2ecf20Sopenharmony_ci if (p_params->opcode != QED_FILTER_ADD && 32008c2ecf20Sopenharmony_ci p_params->opcode != QED_FILTER_REPLACE) 32018c2ecf20Sopenharmony_ci return 0; 32028c2ecf20Sopenharmony_ci 32038c2ecf20Sopenharmony_ci for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) { 32048c2ecf20Sopenharmony_ci if (is_zero_ether_addr(p_vf->shadow_config.macs[i])) { 32058c2ecf20Sopenharmony_ci ether_addr_copy(p_vf->shadow_config.macs[i], 32068c2ecf20Sopenharmony_ci p_params->mac); 32078c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 32088c2ecf20Sopenharmony_ci "Added MAC at %d entry in shadow\n", i); 32098c2ecf20Sopenharmony_ci break; 32108c2ecf20Sopenharmony_ci } 32118c2ecf20Sopenharmony_ci } 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci if (i == QED_ETH_VF_NUM_MAC_FILTERS) { 32148c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, "No available place for MAC\n"); 32158c2ecf20Sopenharmony_ci return -EINVAL; 32168c2ecf20Sopenharmony_ci } 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci return 0; 32198c2ecf20Sopenharmony_ci} 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_cistatic int 32228c2ecf20Sopenharmony_ciqed_iov_vf_update_unicast_shadow(struct qed_hwfn *p_hwfn, 32238c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, 32248c2ecf20Sopenharmony_ci struct qed_filter_ucast *p_params) 32258c2ecf20Sopenharmony_ci{ 32268c2ecf20Sopenharmony_ci int rc = 0; 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci if (p_params->type == QED_FILTER_MAC) { 32298c2ecf20Sopenharmony_ci rc = qed_iov_vf_update_mac_shadow(p_hwfn, p_vf, p_params); 32308c2ecf20Sopenharmony_ci if (rc) 32318c2ecf20Sopenharmony_ci return rc; 32328c2ecf20Sopenharmony_ci } 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci if (p_params->type == QED_FILTER_VLAN) 32358c2ecf20Sopenharmony_ci rc = qed_iov_vf_update_vlan_shadow(p_hwfn, p_vf, p_params); 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci return rc; 32388c2ecf20Sopenharmony_ci} 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_cistatic int qed_iov_chk_ucast(struct qed_hwfn *hwfn, 32418c2ecf20Sopenharmony_ci int vfid, struct qed_filter_ucast *params) 32428c2ecf20Sopenharmony_ci{ 32438c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf; 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci vf = qed_iov_get_public_vf_info(hwfn, vfid, true); 32468c2ecf20Sopenharmony_ci if (!vf) 32478c2ecf20Sopenharmony_ci return -EINVAL; 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci /* No real decision to make; Store the configured MAC */ 32508c2ecf20Sopenharmony_ci if (params->type == QED_FILTER_MAC || 32518c2ecf20Sopenharmony_ci params->type == QED_FILTER_MAC_VLAN) { 32528c2ecf20Sopenharmony_ci ether_addr_copy(vf->mac, params->mac); 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci if (vf->is_trusted_configured) { 32558c2ecf20Sopenharmony_ci qed_iov_bulletin_set_mac(hwfn, vf->mac, vfid); 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci /* Update and post bulleitin again */ 32588c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); 32598c2ecf20Sopenharmony_ci } 32608c2ecf20Sopenharmony_ci } 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_ci return 0; 32638c2ecf20Sopenharmony_ci} 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_ucast_filter(struct qed_hwfn *p_hwfn, 32668c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 32678c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 32688c2ecf20Sopenharmony_ci{ 32698c2ecf20Sopenharmony_ci struct qed_bulletin_content *p_bulletin = vf->bulletin.p_virt; 32708c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 32718c2ecf20Sopenharmony_ci struct vfpf_ucast_filter_tlv *req; 32728c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_SUCCESS; 32738c2ecf20Sopenharmony_ci struct qed_filter_ucast params; 32748c2ecf20Sopenharmony_ci int rc; 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci /* Prepare the unicast filter params */ 32778c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(struct qed_filter_ucast)); 32788c2ecf20Sopenharmony_ci req = &mbx->req_virt->ucast_filter; 32798c2ecf20Sopenharmony_ci params.opcode = (enum qed_filter_opcode)req->opcode; 32808c2ecf20Sopenharmony_ci params.type = (enum qed_filter_ucast_type)req->type; 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci params.is_rx_filter = 1; 32838c2ecf20Sopenharmony_ci params.is_tx_filter = 1; 32848c2ecf20Sopenharmony_ci params.vport_to_remove_from = vf->vport_id; 32858c2ecf20Sopenharmony_ci params.vport_to_add_to = vf->vport_id; 32868c2ecf20Sopenharmony_ci memcpy(params.mac, req->mac, ETH_ALEN); 32878c2ecf20Sopenharmony_ci params.vlan = req->vlan; 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 32908c2ecf20Sopenharmony_ci QED_MSG_IOV, 32918c2ecf20Sopenharmony_ci "VF[%d]: opcode 0x%02x type 0x%02x [%s %s] [vport 0x%02x] MAC %pM, vlan 0x%04x\n", 32928c2ecf20Sopenharmony_ci vf->abs_vf_id, params.opcode, params.type, 32938c2ecf20Sopenharmony_ci params.is_rx_filter ? "RX" : "", 32948c2ecf20Sopenharmony_ci params.is_tx_filter ? "TX" : "", 32958c2ecf20Sopenharmony_ci params.vport_to_add_to, 32968c2ecf20Sopenharmony_ci params.mac, params.vlan); 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_ci if (!vf->vport_instance) { 32998c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 33008c2ecf20Sopenharmony_ci QED_MSG_IOV, 33018c2ecf20Sopenharmony_ci "No VPORT instance available for VF[%d], failing ucast MAC configuration\n", 33028c2ecf20Sopenharmony_ci vf->abs_vf_id); 33038c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 33048c2ecf20Sopenharmony_ci goto out; 33058c2ecf20Sopenharmony_ci } 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci /* Update shadow copy of the VF configuration */ 33088c2ecf20Sopenharmony_ci if (qed_iov_vf_update_unicast_shadow(p_hwfn, vf, ¶ms)) { 33098c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 33108c2ecf20Sopenharmony_ci goto out; 33118c2ecf20Sopenharmony_ci } 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_ci /* Determine if the unicast filtering is acceptible by PF */ 33148c2ecf20Sopenharmony_ci if ((p_bulletin->valid_bitmap & BIT(VLAN_ADDR_FORCED)) && 33158c2ecf20Sopenharmony_ci (params.type == QED_FILTER_VLAN || 33168c2ecf20Sopenharmony_ci params.type == QED_FILTER_MAC_VLAN)) { 33178c2ecf20Sopenharmony_ci /* Once VLAN is forced or PVID is set, do not allow 33188c2ecf20Sopenharmony_ci * to add/replace any further VLANs. 33198c2ecf20Sopenharmony_ci */ 33208c2ecf20Sopenharmony_ci if (params.opcode == QED_FILTER_ADD || 33218c2ecf20Sopenharmony_ci params.opcode == QED_FILTER_REPLACE) 33228c2ecf20Sopenharmony_ci status = PFVF_STATUS_FORCED; 33238c2ecf20Sopenharmony_ci goto out; 33248c2ecf20Sopenharmony_ci } 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci if ((p_bulletin->valid_bitmap & BIT(MAC_ADDR_FORCED)) && 33278c2ecf20Sopenharmony_ci (params.type == QED_FILTER_MAC || 33288c2ecf20Sopenharmony_ci params.type == QED_FILTER_MAC_VLAN)) { 33298c2ecf20Sopenharmony_ci if (!ether_addr_equal(p_bulletin->mac, params.mac) || 33308c2ecf20Sopenharmony_ci (params.opcode != QED_FILTER_ADD && 33318c2ecf20Sopenharmony_ci params.opcode != QED_FILTER_REPLACE)) 33328c2ecf20Sopenharmony_ci status = PFVF_STATUS_FORCED; 33338c2ecf20Sopenharmony_ci goto out; 33348c2ecf20Sopenharmony_ci } 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ci rc = qed_iov_chk_ucast(p_hwfn, vf->relative_vf_id, ¶ms); 33378c2ecf20Sopenharmony_ci if (rc) { 33388c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 33398c2ecf20Sopenharmony_ci goto out; 33408c2ecf20Sopenharmony_ci } 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci rc = qed_sp_eth_filter_ucast(p_hwfn, vf->opaque_fid, ¶ms, 33438c2ecf20Sopenharmony_ci QED_SPQ_MODE_CB, NULL); 33448c2ecf20Sopenharmony_ci if (rc) 33458c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ciout: 33488c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_UCAST_FILTER, 33498c2ecf20Sopenharmony_ci sizeof(struct pfvf_def_resp_tlv), status); 33508c2ecf20Sopenharmony_ci} 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_int_cleanup(struct qed_hwfn *p_hwfn, 33538c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 33548c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 33558c2ecf20Sopenharmony_ci{ 33568c2ecf20Sopenharmony_ci int i; 33578c2ecf20Sopenharmony_ci 33588c2ecf20Sopenharmony_ci /* Reset the SBs */ 33598c2ecf20Sopenharmony_ci for (i = 0; i < vf->num_sbs; i++) 33608c2ecf20Sopenharmony_ci qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, 33618c2ecf20Sopenharmony_ci vf->igu_sbs[i], 33628c2ecf20Sopenharmony_ci vf->opaque_fid, false); 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_INT_CLEANUP, 33658c2ecf20Sopenharmony_ci sizeof(struct pfvf_def_resp_tlv), 33668c2ecf20Sopenharmony_ci PFVF_STATUS_SUCCESS); 33678c2ecf20Sopenharmony_ci} 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_close(struct qed_hwfn *p_hwfn, 33708c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, struct qed_vf_info *vf) 33718c2ecf20Sopenharmony_ci{ 33728c2ecf20Sopenharmony_ci u16 length = sizeof(struct pfvf_def_resp_tlv); 33738c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_SUCCESS; 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_ci /* Disable Interrupts for VF */ 33768c2ecf20Sopenharmony_ci qed_iov_vf_igu_set_int(p_hwfn, p_ptt, vf, 0); 33778c2ecf20Sopenharmony_ci 33788c2ecf20Sopenharmony_ci /* Reset Permission table */ 33798c2ecf20Sopenharmony_ci qed_iov_config_perm_table(p_hwfn, p_ptt, vf, 0); 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_CLOSE, 33828c2ecf20Sopenharmony_ci length, status); 33838c2ecf20Sopenharmony_ci} 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_cistatic void qed_iov_vf_mbx_release(struct qed_hwfn *p_hwfn, 33868c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 33878c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf) 33888c2ecf20Sopenharmony_ci{ 33898c2ecf20Sopenharmony_ci u16 length = sizeof(struct pfvf_def_resp_tlv); 33908c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_SUCCESS; 33918c2ecf20Sopenharmony_ci int rc = 0; 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci qed_iov_vf_cleanup(p_hwfn, p_vf); 33948c2ecf20Sopenharmony_ci 33958c2ecf20Sopenharmony_ci if (p_vf->state != VF_STOPPED && p_vf->state != VF_FREE) { 33968c2ecf20Sopenharmony_ci /* Stopping the VF */ 33978c2ecf20Sopenharmony_ci rc = qed_sp_vf_stop(p_hwfn, p_vf->concrete_fid, 33988c2ecf20Sopenharmony_ci p_vf->opaque_fid); 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ci if (rc) { 34018c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "qed_sp_vf_stop returned error %d\n", 34028c2ecf20Sopenharmony_ci rc); 34038c2ecf20Sopenharmony_ci status = PFVF_STATUS_FAILURE; 34048c2ecf20Sopenharmony_ci } 34058c2ecf20Sopenharmony_ci 34068c2ecf20Sopenharmony_ci p_vf->state = VF_STOPPED; 34078c2ecf20Sopenharmony_ci } 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, p_vf, CHANNEL_TLV_RELEASE, 34108c2ecf20Sopenharmony_ci length, status); 34118c2ecf20Sopenharmony_ci} 34128c2ecf20Sopenharmony_ci 34138c2ecf20Sopenharmony_cistatic void qed_iov_vf_pf_get_coalesce(struct qed_hwfn *p_hwfn, 34148c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 34158c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf) 34168c2ecf20Sopenharmony_ci{ 34178c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx; 34188c2ecf20Sopenharmony_ci struct pfvf_read_coal_resp_tlv *p_resp; 34198c2ecf20Sopenharmony_ci struct vfpf_read_coal_req_tlv *req; 34208c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_FAILURE; 34218c2ecf20Sopenharmony_ci struct qed_vf_queue *p_queue; 34228c2ecf20Sopenharmony_ci struct qed_queue_cid *p_cid; 34238c2ecf20Sopenharmony_ci u16 coal = 0, qid, i; 34248c2ecf20Sopenharmony_ci bool b_is_rx; 34258c2ecf20Sopenharmony_ci int rc = 0; 34268c2ecf20Sopenharmony_ci 34278c2ecf20Sopenharmony_ci mbx->offset = (u8 *)mbx->reply_virt; 34288c2ecf20Sopenharmony_ci req = &mbx->req_virt->read_coal_req; 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci qid = req->qid; 34318c2ecf20Sopenharmony_ci b_is_rx = req->is_rx ? true : false; 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci if (b_is_rx) { 34348c2ecf20Sopenharmony_ci if (!qed_iov_validate_rxq(p_hwfn, p_vf, qid, 34358c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_ENABLE)) { 34368c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 34378c2ecf20Sopenharmony_ci "VF[%d]: Invalid Rx queue_id = %d\n", 34388c2ecf20Sopenharmony_ci p_vf->abs_vf_id, qid); 34398c2ecf20Sopenharmony_ci goto send_resp; 34408c2ecf20Sopenharmony_ci } 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci p_cid = qed_iov_get_vf_rx_queue_cid(&p_vf->vf_queues[qid]); 34438c2ecf20Sopenharmony_ci rc = qed_get_rxq_coalesce(p_hwfn, p_ptt, p_cid, &coal); 34448c2ecf20Sopenharmony_ci if (rc) 34458c2ecf20Sopenharmony_ci goto send_resp; 34468c2ecf20Sopenharmony_ci } else { 34478c2ecf20Sopenharmony_ci if (!qed_iov_validate_txq(p_hwfn, p_vf, qid, 34488c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_ENABLE)) { 34498c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 34508c2ecf20Sopenharmony_ci "VF[%d]: Invalid Tx queue_id = %d\n", 34518c2ecf20Sopenharmony_ci p_vf->abs_vf_id, qid); 34528c2ecf20Sopenharmony_ci goto send_resp; 34538c2ecf20Sopenharmony_ci } 34548c2ecf20Sopenharmony_ci for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { 34558c2ecf20Sopenharmony_ci p_queue = &p_vf->vf_queues[qid]; 34568c2ecf20Sopenharmony_ci if ((!p_queue->cids[i].p_cid) || 34578c2ecf20Sopenharmony_ci (!p_queue->cids[i].b_is_tx)) 34588c2ecf20Sopenharmony_ci continue; 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_ci p_cid = p_queue->cids[i].p_cid; 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci rc = qed_get_txq_coalesce(p_hwfn, p_ptt, p_cid, &coal); 34638c2ecf20Sopenharmony_ci if (rc) 34648c2ecf20Sopenharmony_ci goto send_resp; 34658c2ecf20Sopenharmony_ci break; 34668c2ecf20Sopenharmony_ci } 34678c2ecf20Sopenharmony_ci } 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci status = PFVF_STATUS_SUCCESS; 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_cisend_resp: 34728c2ecf20Sopenharmony_ci p_resp = qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_COALESCE_READ, 34738c2ecf20Sopenharmony_ci sizeof(*p_resp)); 34748c2ecf20Sopenharmony_ci p_resp->coal = coal; 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_LIST_END, 34778c2ecf20Sopenharmony_ci sizeof(struct channel_list_end_tlv)); 34788c2ecf20Sopenharmony_ci 34798c2ecf20Sopenharmony_ci qed_iov_send_response(p_hwfn, p_ptt, p_vf, sizeof(*p_resp), status); 34808c2ecf20Sopenharmony_ci} 34818c2ecf20Sopenharmony_ci 34828c2ecf20Sopenharmony_cistatic void qed_iov_vf_pf_set_coalesce(struct qed_hwfn *p_hwfn, 34838c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 34848c2ecf20Sopenharmony_ci struct qed_vf_info *vf) 34858c2ecf20Sopenharmony_ci{ 34868c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 34878c2ecf20Sopenharmony_ci struct vfpf_update_coalesce *req; 34888c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_FAILURE; 34898c2ecf20Sopenharmony_ci struct qed_queue_cid *p_cid; 34908c2ecf20Sopenharmony_ci u16 rx_coal, tx_coal; 34918c2ecf20Sopenharmony_ci int rc = 0, i; 34928c2ecf20Sopenharmony_ci u16 qid; 34938c2ecf20Sopenharmony_ci 34948c2ecf20Sopenharmony_ci req = &mbx->req_virt->update_coalesce; 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci rx_coal = req->rx_coal; 34978c2ecf20Sopenharmony_ci tx_coal = req->tx_coal; 34988c2ecf20Sopenharmony_ci qid = req->qid; 34998c2ecf20Sopenharmony_ci 35008c2ecf20Sopenharmony_ci if (!qed_iov_validate_rxq(p_hwfn, vf, qid, 35018c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_ENABLE) && rx_coal) { 35028c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 35038c2ecf20Sopenharmony_ci "VF[%d]: Invalid Rx queue_id = %d\n", 35048c2ecf20Sopenharmony_ci vf->abs_vf_id, qid); 35058c2ecf20Sopenharmony_ci goto out; 35068c2ecf20Sopenharmony_ci } 35078c2ecf20Sopenharmony_ci 35088c2ecf20Sopenharmony_ci if (!qed_iov_validate_txq(p_hwfn, vf, qid, 35098c2ecf20Sopenharmony_ci QED_IOV_VALIDATE_Q_ENABLE) && tx_coal) { 35108c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 35118c2ecf20Sopenharmony_ci "VF[%d]: Invalid Tx queue_id = %d\n", 35128c2ecf20Sopenharmony_ci vf->abs_vf_id, qid); 35138c2ecf20Sopenharmony_ci goto out; 35148c2ecf20Sopenharmony_ci } 35158c2ecf20Sopenharmony_ci 35168c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 35178c2ecf20Sopenharmony_ci QED_MSG_IOV, 35188c2ecf20Sopenharmony_ci "VF[%d]: Setting coalesce for VF rx_coal = %d, tx_coal = %d at queue = %d\n", 35198c2ecf20Sopenharmony_ci vf->abs_vf_id, rx_coal, tx_coal, qid); 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci if (rx_coal) { 35228c2ecf20Sopenharmony_ci p_cid = qed_iov_get_vf_rx_queue_cid(&vf->vf_queues[qid]); 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci rc = qed_set_rxq_coalesce(p_hwfn, p_ptt, rx_coal, p_cid); 35258c2ecf20Sopenharmony_ci if (rc) { 35268c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 35278c2ecf20Sopenharmony_ci QED_MSG_IOV, 35288c2ecf20Sopenharmony_ci "VF[%d]: Unable to set rx queue = %d coalesce\n", 35298c2ecf20Sopenharmony_ci vf->abs_vf_id, vf->vf_queues[qid].fw_rx_qid); 35308c2ecf20Sopenharmony_ci goto out; 35318c2ecf20Sopenharmony_ci } 35328c2ecf20Sopenharmony_ci vf->rx_coal = rx_coal; 35338c2ecf20Sopenharmony_ci } 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_ci if (tx_coal) { 35368c2ecf20Sopenharmony_ci struct qed_vf_queue *p_queue = &vf->vf_queues[qid]; 35378c2ecf20Sopenharmony_ci 35388c2ecf20Sopenharmony_ci for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { 35398c2ecf20Sopenharmony_ci if (!p_queue->cids[i].p_cid) 35408c2ecf20Sopenharmony_ci continue; 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci if (!p_queue->cids[i].b_is_tx) 35438c2ecf20Sopenharmony_ci continue; 35448c2ecf20Sopenharmony_ci 35458c2ecf20Sopenharmony_ci rc = qed_set_txq_coalesce(p_hwfn, p_ptt, tx_coal, 35468c2ecf20Sopenharmony_ci p_queue->cids[i].p_cid); 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_ci if (rc) { 35498c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 35508c2ecf20Sopenharmony_ci QED_MSG_IOV, 35518c2ecf20Sopenharmony_ci "VF[%d]: Unable to set tx queue coalesce\n", 35528c2ecf20Sopenharmony_ci vf->abs_vf_id); 35538c2ecf20Sopenharmony_ci goto out; 35548c2ecf20Sopenharmony_ci } 35558c2ecf20Sopenharmony_ci } 35568c2ecf20Sopenharmony_ci vf->tx_coal = tx_coal; 35578c2ecf20Sopenharmony_ci } 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ci status = PFVF_STATUS_SUCCESS; 35608c2ecf20Sopenharmony_ciout: 35618c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_COALESCE_UPDATE, 35628c2ecf20Sopenharmony_ci sizeof(struct pfvf_def_resp_tlv), status); 35638c2ecf20Sopenharmony_ci} 35648c2ecf20Sopenharmony_cistatic int 35658c2ecf20Sopenharmony_ciqed_iov_vf_flr_poll_dorq(struct qed_hwfn *p_hwfn, 35668c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, struct qed_ptt *p_ptt) 35678c2ecf20Sopenharmony_ci{ 35688c2ecf20Sopenharmony_ci int cnt; 35698c2ecf20Sopenharmony_ci u32 val; 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, (u16) p_vf->concrete_fid); 35728c2ecf20Sopenharmony_ci 35738c2ecf20Sopenharmony_ci for (cnt = 0; cnt < 50; cnt++) { 35748c2ecf20Sopenharmony_ci val = qed_rd(p_hwfn, p_ptt, DORQ_REG_VF_USAGE_CNT); 35758c2ecf20Sopenharmony_ci if (!val) 35768c2ecf20Sopenharmony_ci break; 35778c2ecf20Sopenharmony_ci msleep(20); 35788c2ecf20Sopenharmony_ci } 35798c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, (u16) p_hwfn->hw_info.concrete_fid); 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci if (cnt == 50) { 35828c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 35838c2ecf20Sopenharmony_ci "VF[%d] - dorq failed to cleanup [usage 0x%08x]\n", 35848c2ecf20Sopenharmony_ci p_vf->abs_vf_id, val); 35858c2ecf20Sopenharmony_ci return -EBUSY; 35868c2ecf20Sopenharmony_ci } 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci return 0; 35898c2ecf20Sopenharmony_ci} 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_cistatic int 35928c2ecf20Sopenharmony_ciqed_iov_vf_flr_poll_pbf(struct qed_hwfn *p_hwfn, 35938c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, struct qed_ptt *p_ptt) 35948c2ecf20Sopenharmony_ci{ 35958c2ecf20Sopenharmony_ci u32 cons[MAX_NUM_VOQS_E4], distance[MAX_NUM_VOQS_E4]; 35968c2ecf20Sopenharmony_ci int i, cnt; 35978c2ecf20Sopenharmony_ci 35988c2ecf20Sopenharmony_ci /* Read initial consumers & producers */ 35998c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NUM_VOQS_E4; i++) { 36008c2ecf20Sopenharmony_ci u32 prod; 36018c2ecf20Sopenharmony_ci 36028c2ecf20Sopenharmony_ci cons[i] = qed_rd(p_hwfn, p_ptt, 36038c2ecf20Sopenharmony_ci PBF_REG_NUM_BLOCKS_ALLOCATED_CONS_VOQ0 + 36048c2ecf20Sopenharmony_ci i * 0x40); 36058c2ecf20Sopenharmony_ci prod = qed_rd(p_hwfn, p_ptt, 36068c2ecf20Sopenharmony_ci PBF_REG_NUM_BLOCKS_ALLOCATED_PROD_VOQ0 + 36078c2ecf20Sopenharmony_ci i * 0x40); 36088c2ecf20Sopenharmony_ci distance[i] = prod - cons[i]; 36098c2ecf20Sopenharmony_ci } 36108c2ecf20Sopenharmony_ci 36118c2ecf20Sopenharmony_ci /* Wait for consumers to pass the producers */ 36128c2ecf20Sopenharmony_ci i = 0; 36138c2ecf20Sopenharmony_ci for (cnt = 0; cnt < 50; cnt++) { 36148c2ecf20Sopenharmony_ci for (; i < MAX_NUM_VOQS_E4; i++) { 36158c2ecf20Sopenharmony_ci u32 tmp; 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci tmp = qed_rd(p_hwfn, p_ptt, 36188c2ecf20Sopenharmony_ci PBF_REG_NUM_BLOCKS_ALLOCATED_CONS_VOQ0 + 36198c2ecf20Sopenharmony_ci i * 0x40); 36208c2ecf20Sopenharmony_ci if (distance[i] > tmp - cons[i]) 36218c2ecf20Sopenharmony_ci break; 36228c2ecf20Sopenharmony_ci } 36238c2ecf20Sopenharmony_ci 36248c2ecf20Sopenharmony_ci if (i == MAX_NUM_VOQS_E4) 36258c2ecf20Sopenharmony_ci break; 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_ci msleep(20); 36288c2ecf20Sopenharmony_ci } 36298c2ecf20Sopenharmony_ci 36308c2ecf20Sopenharmony_ci if (cnt == 50) { 36318c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "VF[%d] - pbf polling failed on VOQ %d\n", 36328c2ecf20Sopenharmony_ci p_vf->abs_vf_id, i); 36338c2ecf20Sopenharmony_ci return -EBUSY; 36348c2ecf20Sopenharmony_ci } 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_ci return 0; 36378c2ecf20Sopenharmony_ci} 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_cistatic int qed_iov_vf_flr_poll(struct qed_hwfn *p_hwfn, 36408c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf, struct qed_ptt *p_ptt) 36418c2ecf20Sopenharmony_ci{ 36428c2ecf20Sopenharmony_ci int rc; 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci rc = qed_iov_vf_flr_poll_dorq(p_hwfn, p_vf, p_ptt); 36458c2ecf20Sopenharmony_ci if (rc) 36468c2ecf20Sopenharmony_ci return rc; 36478c2ecf20Sopenharmony_ci 36488c2ecf20Sopenharmony_ci rc = qed_iov_vf_flr_poll_pbf(p_hwfn, p_vf, p_ptt); 36498c2ecf20Sopenharmony_ci if (rc) 36508c2ecf20Sopenharmony_ci return rc; 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci return 0; 36538c2ecf20Sopenharmony_ci} 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_cistatic int 36568c2ecf20Sopenharmony_ciqed_iov_execute_vf_flr_cleanup(struct qed_hwfn *p_hwfn, 36578c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 36588c2ecf20Sopenharmony_ci u16 rel_vf_id, u32 *ack_vfs) 36598c2ecf20Sopenharmony_ci{ 36608c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf; 36618c2ecf20Sopenharmony_ci int rc = 0; 36628c2ecf20Sopenharmony_ci 36638c2ecf20Sopenharmony_ci p_vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, false); 36648c2ecf20Sopenharmony_ci if (!p_vf) 36658c2ecf20Sopenharmony_ci return 0; 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci if (p_hwfn->pf_iov_info->pending_flr[rel_vf_id / 64] & 36688c2ecf20Sopenharmony_ci (1ULL << (rel_vf_id % 64))) { 36698c2ecf20Sopenharmony_ci u16 vfid = p_vf->abs_vf_id; 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 36728c2ecf20Sopenharmony_ci "VF[%d] - Handling FLR\n", vfid); 36738c2ecf20Sopenharmony_ci 36748c2ecf20Sopenharmony_ci qed_iov_vf_cleanup(p_hwfn, p_vf); 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci /* If VF isn't active, no need for anything but SW */ 36778c2ecf20Sopenharmony_ci if (!p_vf->b_init) 36788c2ecf20Sopenharmony_ci goto cleanup; 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci rc = qed_iov_vf_flr_poll(p_hwfn, p_vf, p_ptt); 36818c2ecf20Sopenharmony_ci if (rc) 36828c2ecf20Sopenharmony_ci goto cleanup; 36838c2ecf20Sopenharmony_ci 36848c2ecf20Sopenharmony_ci rc = qed_final_cleanup(p_hwfn, p_ptt, vfid, true); 36858c2ecf20Sopenharmony_ci if (rc) { 36868c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Failed handle FLR of VF[%d]\n", vfid); 36878c2ecf20Sopenharmony_ci return rc; 36888c2ecf20Sopenharmony_ci } 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci /* Workaround to make VF-PF channel ready, as FW 36918c2ecf20Sopenharmony_ci * doesn't do that as a part of FLR. 36928c2ecf20Sopenharmony_ci */ 36938c2ecf20Sopenharmony_ci REG_WR(p_hwfn, 36948c2ecf20Sopenharmony_ci GTT_BAR0_MAP_REG_USDM_RAM + 36958c2ecf20Sopenharmony_ci USTORM_VF_PF_CHANNEL_READY_OFFSET(vfid), 1); 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci /* VF_STOPPED has to be set only after final cleanup 36988c2ecf20Sopenharmony_ci * but prior to re-enabling the VF. 36998c2ecf20Sopenharmony_ci */ 37008c2ecf20Sopenharmony_ci p_vf->state = VF_STOPPED; 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci rc = qed_iov_enable_vf_access(p_hwfn, p_ptt, p_vf); 37038c2ecf20Sopenharmony_ci if (rc) { 37048c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Failed to re-enable VF[%d] acces\n", 37058c2ecf20Sopenharmony_ci vfid); 37068c2ecf20Sopenharmony_ci return rc; 37078c2ecf20Sopenharmony_ci } 37088c2ecf20Sopenharmony_cicleanup: 37098c2ecf20Sopenharmony_ci /* Mark VF for ack and clean pending state */ 37108c2ecf20Sopenharmony_ci if (p_vf->state == VF_RESET) 37118c2ecf20Sopenharmony_ci p_vf->state = VF_STOPPED; 37128c2ecf20Sopenharmony_ci ack_vfs[vfid / 32] |= BIT((vfid % 32)); 37138c2ecf20Sopenharmony_ci p_hwfn->pf_iov_info->pending_flr[rel_vf_id / 64] &= 37148c2ecf20Sopenharmony_ci ~(1ULL << (rel_vf_id % 64)); 37158c2ecf20Sopenharmony_ci p_vf->vf_mbx.b_pending_msg = false; 37168c2ecf20Sopenharmony_ci } 37178c2ecf20Sopenharmony_ci 37188c2ecf20Sopenharmony_ci return rc; 37198c2ecf20Sopenharmony_ci} 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_cistatic int 37228c2ecf20Sopenharmony_ciqed_iov_vf_flr_cleanup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 37238c2ecf20Sopenharmony_ci{ 37248c2ecf20Sopenharmony_ci u32 ack_vfs[VF_MAX_STATIC / 32]; 37258c2ecf20Sopenharmony_ci int rc = 0; 37268c2ecf20Sopenharmony_ci u16 i; 37278c2ecf20Sopenharmony_ci 37288c2ecf20Sopenharmony_ci memset(ack_vfs, 0, sizeof(u32) * (VF_MAX_STATIC / 32)); 37298c2ecf20Sopenharmony_ci 37308c2ecf20Sopenharmony_ci /* Since BRB <-> PRS interface can't be tested as part of the flr 37318c2ecf20Sopenharmony_ci * polling due to HW limitations, simply sleep a bit. And since 37328c2ecf20Sopenharmony_ci * there's no need to wait per-vf, do it before looping. 37338c2ecf20Sopenharmony_ci */ 37348c2ecf20Sopenharmony_ci msleep(100); 37358c2ecf20Sopenharmony_ci 37368c2ecf20Sopenharmony_ci for (i = 0; i < p_hwfn->cdev->p_iov_info->total_vfs; i++) 37378c2ecf20Sopenharmony_ci qed_iov_execute_vf_flr_cleanup(p_hwfn, p_ptt, i, ack_vfs); 37388c2ecf20Sopenharmony_ci 37398c2ecf20Sopenharmony_ci rc = qed_mcp_ack_vf_flr(p_hwfn, p_ptt, ack_vfs); 37408c2ecf20Sopenharmony_ci return rc; 37418c2ecf20Sopenharmony_ci} 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_cibool qed_iov_mark_vf_flr(struct qed_hwfn *p_hwfn, u32 *p_disabled_vfs) 37448c2ecf20Sopenharmony_ci{ 37458c2ecf20Sopenharmony_ci bool found = false; 37468c2ecf20Sopenharmony_ci u16 i; 37478c2ecf20Sopenharmony_ci 37488c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, "Marking FLR-ed VFs\n"); 37498c2ecf20Sopenharmony_ci for (i = 0; i < (VF_MAX_STATIC / 32); i++) 37508c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 37518c2ecf20Sopenharmony_ci "[%08x,...,%08x]: %08x\n", 37528c2ecf20Sopenharmony_ci i * 32, (i + 1) * 32 - 1, p_disabled_vfs[i]); 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci if (!p_hwfn->cdev->p_iov_info) { 37558c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "VF flr but no IOV\n"); 37568c2ecf20Sopenharmony_ci return false; 37578c2ecf20Sopenharmony_ci } 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci /* Mark VFs */ 37608c2ecf20Sopenharmony_ci for (i = 0; i < p_hwfn->cdev->p_iov_info->total_vfs; i++) { 37618c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf; 37628c2ecf20Sopenharmony_ci u8 vfid; 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci p_vf = qed_iov_get_vf_info(p_hwfn, i, false); 37658c2ecf20Sopenharmony_ci if (!p_vf) 37668c2ecf20Sopenharmony_ci continue; 37678c2ecf20Sopenharmony_ci 37688c2ecf20Sopenharmony_ci vfid = p_vf->abs_vf_id; 37698c2ecf20Sopenharmony_ci if (BIT((vfid % 32)) & p_disabled_vfs[vfid / 32]) { 37708c2ecf20Sopenharmony_ci u64 *p_flr = p_hwfn->pf_iov_info->pending_flr; 37718c2ecf20Sopenharmony_ci u16 rel_vf_id = p_vf->relative_vf_id; 37728c2ecf20Sopenharmony_ci 37738c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 37748c2ecf20Sopenharmony_ci "VF[%d] [rel %d] got FLR-ed\n", 37758c2ecf20Sopenharmony_ci vfid, rel_vf_id); 37768c2ecf20Sopenharmony_ci 37778c2ecf20Sopenharmony_ci p_vf->state = VF_RESET; 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci /* No need to lock here, since pending_flr should 37808c2ecf20Sopenharmony_ci * only change here and before ACKing MFw. Since 37818c2ecf20Sopenharmony_ci * MFW will not trigger an additional attention for 37828c2ecf20Sopenharmony_ci * VF flr until ACKs, we're safe. 37838c2ecf20Sopenharmony_ci */ 37848c2ecf20Sopenharmony_ci p_flr[rel_vf_id / 64] |= 1ULL << (rel_vf_id % 64); 37858c2ecf20Sopenharmony_ci found = true; 37868c2ecf20Sopenharmony_ci } 37878c2ecf20Sopenharmony_ci } 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci return found; 37908c2ecf20Sopenharmony_ci} 37918c2ecf20Sopenharmony_ci 37928c2ecf20Sopenharmony_cistatic int qed_iov_get_link(struct qed_hwfn *p_hwfn, 37938c2ecf20Sopenharmony_ci u16 vfid, 37948c2ecf20Sopenharmony_ci struct qed_mcp_link_params *p_params, 37958c2ecf20Sopenharmony_ci struct qed_mcp_link_state *p_link, 37968c2ecf20Sopenharmony_ci struct qed_mcp_link_capabilities *p_caps) 37978c2ecf20Sopenharmony_ci{ 37988c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf = qed_iov_get_vf_info(p_hwfn, 37998c2ecf20Sopenharmony_ci vfid, 38008c2ecf20Sopenharmony_ci false); 38018c2ecf20Sopenharmony_ci struct qed_bulletin_content *p_bulletin; 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci if (!p_vf) 38048c2ecf20Sopenharmony_ci return -EINVAL; 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ci p_bulletin = p_vf->bulletin.p_virt; 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci if (p_params) 38098c2ecf20Sopenharmony_ci __qed_vf_get_link_params(p_hwfn, p_params, p_bulletin); 38108c2ecf20Sopenharmony_ci if (p_link) 38118c2ecf20Sopenharmony_ci __qed_vf_get_link_state(p_hwfn, p_link, p_bulletin); 38128c2ecf20Sopenharmony_ci if (p_caps) 38138c2ecf20Sopenharmony_ci __qed_vf_get_link_caps(p_hwfn, p_caps, p_bulletin); 38148c2ecf20Sopenharmony_ci return 0; 38158c2ecf20Sopenharmony_ci} 38168c2ecf20Sopenharmony_ci 38178c2ecf20Sopenharmony_cistatic int 38188c2ecf20Sopenharmony_ciqed_iov_vf_pf_bulletin_update_mac(struct qed_hwfn *p_hwfn, 38198c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 38208c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf) 38218c2ecf20Sopenharmony_ci{ 38228c2ecf20Sopenharmony_ci struct qed_bulletin_content *p_bulletin = p_vf->bulletin.p_virt; 38238c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx; 38248c2ecf20Sopenharmony_ci struct vfpf_bulletin_update_mac_tlv *p_req; 38258c2ecf20Sopenharmony_ci u8 status = PFVF_STATUS_SUCCESS; 38268c2ecf20Sopenharmony_ci int rc = 0; 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_ci if (!p_vf->p_vf_info.is_trusted_configured) { 38298c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 38308c2ecf20Sopenharmony_ci QED_MSG_IOV, 38318c2ecf20Sopenharmony_ci "Blocking bulletin update request from untrusted VF[%d]\n", 38328c2ecf20Sopenharmony_ci p_vf->abs_vf_id); 38338c2ecf20Sopenharmony_ci status = PFVF_STATUS_NOT_SUPPORTED; 38348c2ecf20Sopenharmony_ci rc = -EINVAL; 38358c2ecf20Sopenharmony_ci goto send_status; 38368c2ecf20Sopenharmony_ci } 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_ci p_req = &mbx->req_virt->bulletin_update_mac; 38398c2ecf20Sopenharmony_ci ether_addr_copy(p_bulletin->mac, p_req->mac); 38408c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 38418c2ecf20Sopenharmony_ci "Updated bulletin of VF[%d] with requested MAC[%pM]\n", 38428c2ecf20Sopenharmony_ci p_vf->abs_vf_id, p_req->mac); 38438c2ecf20Sopenharmony_ci 38448c2ecf20Sopenharmony_cisend_status: 38458c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, p_vf, 38468c2ecf20Sopenharmony_ci CHANNEL_TLV_BULLETIN_UPDATE_MAC, 38478c2ecf20Sopenharmony_ci sizeof(struct pfvf_def_resp_tlv), status); 38488c2ecf20Sopenharmony_ci return rc; 38498c2ecf20Sopenharmony_ci} 38508c2ecf20Sopenharmony_ci 38518c2ecf20Sopenharmony_cistatic void qed_iov_process_mbx_req(struct qed_hwfn *p_hwfn, 38528c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, int vfid) 38538c2ecf20Sopenharmony_ci{ 38548c2ecf20Sopenharmony_ci struct qed_iov_vf_mbx *mbx; 38558c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf; 38568c2ecf20Sopenharmony_ci 38578c2ecf20Sopenharmony_ci p_vf = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 38588c2ecf20Sopenharmony_ci if (!p_vf) 38598c2ecf20Sopenharmony_ci return; 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci mbx = &p_vf->vf_mbx; 38628c2ecf20Sopenharmony_ci 38638c2ecf20Sopenharmony_ci /* qed_iov_process_mbx_request */ 38648c2ecf20Sopenharmony_ci if (!mbx->b_pending_msg) { 38658c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 38668c2ecf20Sopenharmony_ci "VF[%02x]: Trying to process mailbox message when none is pending\n", 38678c2ecf20Sopenharmony_ci p_vf->abs_vf_id); 38688c2ecf20Sopenharmony_ci return; 38698c2ecf20Sopenharmony_ci } 38708c2ecf20Sopenharmony_ci mbx->b_pending_msg = false; 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ci mbx->first_tlv = mbx->req_virt->first_tlv; 38738c2ecf20Sopenharmony_ci 38748c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 38758c2ecf20Sopenharmony_ci "VF[%02x]: Processing mailbox message [type %04x]\n", 38768c2ecf20Sopenharmony_ci p_vf->abs_vf_id, mbx->first_tlv.tl.type); 38778c2ecf20Sopenharmony_ci 38788c2ecf20Sopenharmony_ci /* check if tlv type is known */ 38798c2ecf20Sopenharmony_ci if (qed_iov_tlv_supported(mbx->first_tlv.tl.type) && 38808c2ecf20Sopenharmony_ci !p_vf->b_malicious) { 38818c2ecf20Sopenharmony_ci switch (mbx->first_tlv.tl.type) { 38828c2ecf20Sopenharmony_ci case CHANNEL_TLV_ACQUIRE: 38838c2ecf20Sopenharmony_ci qed_iov_vf_mbx_acquire(p_hwfn, p_ptt, p_vf); 38848c2ecf20Sopenharmony_ci break; 38858c2ecf20Sopenharmony_ci case CHANNEL_TLV_VPORT_START: 38868c2ecf20Sopenharmony_ci qed_iov_vf_mbx_start_vport(p_hwfn, p_ptt, p_vf); 38878c2ecf20Sopenharmony_ci break; 38888c2ecf20Sopenharmony_ci case CHANNEL_TLV_VPORT_TEARDOWN: 38898c2ecf20Sopenharmony_ci qed_iov_vf_mbx_stop_vport(p_hwfn, p_ptt, p_vf); 38908c2ecf20Sopenharmony_ci break; 38918c2ecf20Sopenharmony_ci case CHANNEL_TLV_START_RXQ: 38928c2ecf20Sopenharmony_ci qed_iov_vf_mbx_start_rxq(p_hwfn, p_ptt, p_vf); 38938c2ecf20Sopenharmony_ci break; 38948c2ecf20Sopenharmony_ci case CHANNEL_TLV_START_TXQ: 38958c2ecf20Sopenharmony_ci qed_iov_vf_mbx_start_txq(p_hwfn, p_ptt, p_vf); 38968c2ecf20Sopenharmony_ci break; 38978c2ecf20Sopenharmony_ci case CHANNEL_TLV_STOP_RXQS: 38988c2ecf20Sopenharmony_ci qed_iov_vf_mbx_stop_rxqs(p_hwfn, p_ptt, p_vf); 38998c2ecf20Sopenharmony_ci break; 39008c2ecf20Sopenharmony_ci case CHANNEL_TLV_STOP_TXQS: 39018c2ecf20Sopenharmony_ci qed_iov_vf_mbx_stop_txqs(p_hwfn, p_ptt, p_vf); 39028c2ecf20Sopenharmony_ci break; 39038c2ecf20Sopenharmony_ci case CHANNEL_TLV_UPDATE_RXQ: 39048c2ecf20Sopenharmony_ci qed_iov_vf_mbx_update_rxqs(p_hwfn, p_ptt, p_vf); 39058c2ecf20Sopenharmony_ci break; 39068c2ecf20Sopenharmony_ci case CHANNEL_TLV_VPORT_UPDATE: 39078c2ecf20Sopenharmony_ci qed_iov_vf_mbx_vport_update(p_hwfn, p_ptt, p_vf); 39088c2ecf20Sopenharmony_ci break; 39098c2ecf20Sopenharmony_ci case CHANNEL_TLV_UCAST_FILTER: 39108c2ecf20Sopenharmony_ci qed_iov_vf_mbx_ucast_filter(p_hwfn, p_ptt, p_vf); 39118c2ecf20Sopenharmony_ci break; 39128c2ecf20Sopenharmony_ci case CHANNEL_TLV_CLOSE: 39138c2ecf20Sopenharmony_ci qed_iov_vf_mbx_close(p_hwfn, p_ptt, p_vf); 39148c2ecf20Sopenharmony_ci break; 39158c2ecf20Sopenharmony_ci case CHANNEL_TLV_INT_CLEANUP: 39168c2ecf20Sopenharmony_ci qed_iov_vf_mbx_int_cleanup(p_hwfn, p_ptt, p_vf); 39178c2ecf20Sopenharmony_ci break; 39188c2ecf20Sopenharmony_ci case CHANNEL_TLV_RELEASE: 39198c2ecf20Sopenharmony_ci qed_iov_vf_mbx_release(p_hwfn, p_ptt, p_vf); 39208c2ecf20Sopenharmony_ci break; 39218c2ecf20Sopenharmony_ci case CHANNEL_TLV_UPDATE_TUNN_PARAM: 39228c2ecf20Sopenharmony_ci qed_iov_vf_mbx_update_tunn_param(p_hwfn, p_ptt, p_vf); 39238c2ecf20Sopenharmony_ci break; 39248c2ecf20Sopenharmony_ci case CHANNEL_TLV_COALESCE_UPDATE: 39258c2ecf20Sopenharmony_ci qed_iov_vf_pf_set_coalesce(p_hwfn, p_ptt, p_vf); 39268c2ecf20Sopenharmony_ci break; 39278c2ecf20Sopenharmony_ci case CHANNEL_TLV_COALESCE_READ: 39288c2ecf20Sopenharmony_ci qed_iov_vf_pf_get_coalesce(p_hwfn, p_ptt, p_vf); 39298c2ecf20Sopenharmony_ci break; 39308c2ecf20Sopenharmony_ci case CHANNEL_TLV_BULLETIN_UPDATE_MAC: 39318c2ecf20Sopenharmony_ci qed_iov_vf_pf_bulletin_update_mac(p_hwfn, p_ptt, p_vf); 39328c2ecf20Sopenharmony_ci break; 39338c2ecf20Sopenharmony_ci } 39348c2ecf20Sopenharmony_ci } else if (qed_iov_tlv_supported(mbx->first_tlv.tl.type)) { 39358c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 39368c2ecf20Sopenharmony_ci "VF [%02x] - considered malicious; Ignoring TLV [%04x]\n", 39378c2ecf20Sopenharmony_ci p_vf->abs_vf_id, mbx->first_tlv.tl.type); 39388c2ecf20Sopenharmony_ci 39398c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, p_vf, 39408c2ecf20Sopenharmony_ci mbx->first_tlv.tl.type, 39418c2ecf20Sopenharmony_ci sizeof(struct pfvf_def_resp_tlv), 39428c2ecf20Sopenharmony_ci PFVF_STATUS_MALICIOUS); 39438c2ecf20Sopenharmony_ci } else { 39448c2ecf20Sopenharmony_ci /* unknown TLV - this may belong to a VF driver from the future 39458c2ecf20Sopenharmony_ci * - a version written after this PF driver was written, which 39468c2ecf20Sopenharmony_ci * supports features unknown as of yet. Too bad since we don't 39478c2ecf20Sopenharmony_ci * support them. Or this may be because someone wrote a crappy 39488c2ecf20Sopenharmony_ci * VF driver and is sending garbage over the channel. 39498c2ecf20Sopenharmony_ci */ 39508c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 39518c2ecf20Sopenharmony_ci "VF[%02x]: unknown TLV. type %04x length %04x padding %08x reply address %llu\n", 39528c2ecf20Sopenharmony_ci p_vf->abs_vf_id, 39538c2ecf20Sopenharmony_ci mbx->first_tlv.tl.type, 39548c2ecf20Sopenharmony_ci mbx->first_tlv.tl.length, 39558c2ecf20Sopenharmony_ci mbx->first_tlv.padding, mbx->first_tlv.reply_address); 39568c2ecf20Sopenharmony_ci 39578c2ecf20Sopenharmony_ci /* Try replying in case reply address matches the acquisition's 39588c2ecf20Sopenharmony_ci * posted address. 39598c2ecf20Sopenharmony_ci */ 39608c2ecf20Sopenharmony_ci if (p_vf->acquire.first_tlv.reply_address && 39618c2ecf20Sopenharmony_ci (mbx->first_tlv.reply_address == 39628c2ecf20Sopenharmony_ci p_vf->acquire.first_tlv.reply_address)) { 39638c2ecf20Sopenharmony_ci qed_iov_prepare_resp(p_hwfn, p_ptt, p_vf, 39648c2ecf20Sopenharmony_ci mbx->first_tlv.tl.type, 39658c2ecf20Sopenharmony_ci sizeof(struct pfvf_def_resp_tlv), 39668c2ecf20Sopenharmony_ci PFVF_STATUS_NOT_SUPPORTED); 39678c2ecf20Sopenharmony_ci } else { 39688c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 39698c2ecf20Sopenharmony_ci QED_MSG_IOV, 39708c2ecf20Sopenharmony_ci "VF[%02x]: Can't respond to TLV - no valid reply address\n", 39718c2ecf20Sopenharmony_ci p_vf->abs_vf_id); 39728c2ecf20Sopenharmony_ci } 39738c2ecf20Sopenharmony_ci } 39748c2ecf20Sopenharmony_ci} 39758c2ecf20Sopenharmony_ci 39768c2ecf20Sopenharmony_cistatic void qed_iov_pf_get_pending_events(struct qed_hwfn *p_hwfn, u64 *events) 39778c2ecf20Sopenharmony_ci{ 39788c2ecf20Sopenharmony_ci int i; 39798c2ecf20Sopenharmony_ci 39808c2ecf20Sopenharmony_ci memset(events, 0, sizeof(u64) * QED_VF_ARRAY_LENGTH); 39818c2ecf20Sopenharmony_ci 39828c2ecf20Sopenharmony_ci qed_for_each_vf(p_hwfn, i) { 39838c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf; 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_ci p_vf = &p_hwfn->pf_iov_info->vfs_array[i]; 39868c2ecf20Sopenharmony_ci if (p_vf->vf_mbx.b_pending_msg) 39878c2ecf20Sopenharmony_ci events[i / 64] |= 1ULL << (i % 64); 39888c2ecf20Sopenharmony_ci } 39898c2ecf20Sopenharmony_ci} 39908c2ecf20Sopenharmony_ci 39918c2ecf20Sopenharmony_cistatic struct qed_vf_info *qed_sriov_get_vf_from_absid(struct qed_hwfn *p_hwfn, 39928c2ecf20Sopenharmony_ci u16 abs_vfid) 39938c2ecf20Sopenharmony_ci{ 39948c2ecf20Sopenharmony_ci u8 min = (u8) p_hwfn->cdev->p_iov_info->first_vf_in_pf; 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci if (!_qed_iov_pf_sanity_check(p_hwfn, (int)abs_vfid - min, false)) { 39978c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 39988c2ecf20Sopenharmony_ci QED_MSG_IOV, 39998c2ecf20Sopenharmony_ci "Got indication for VF [abs 0x%08x] that cannot be handled by PF\n", 40008c2ecf20Sopenharmony_ci abs_vfid); 40018c2ecf20Sopenharmony_ci return NULL; 40028c2ecf20Sopenharmony_ci } 40038c2ecf20Sopenharmony_ci 40048c2ecf20Sopenharmony_ci return &p_hwfn->pf_iov_info->vfs_array[(u8) abs_vfid - min]; 40058c2ecf20Sopenharmony_ci} 40068c2ecf20Sopenharmony_ci 40078c2ecf20Sopenharmony_cistatic int qed_sriov_vfpf_msg(struct qed_hwfn *p_hwfn, 40088c2ecf20Sopenharmony_ci u16 abs_vfid, struct regpair *vf_msg) 40098c2ecf20Sopenharmony_ci{ 40108c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf = qed_sriov_get_vf_from_absid(p_hwfn, 40118c2ecf20Sopenharmony_ci abs_vfid); 40128c2ecf20Sopenharmony_ci 40138c2ecf20Sopenharmony_ci if (!p_vf) 40148c2ecf20Sopenharmony_ci return 0; 40158c2ecf20Sopenharmony_ci 40168c2ecf20Sopenharmony_ci /* List the physical address of the request so that handler 40178c2ecf20Sopenharmony_ci * could later on copy the message from it. 40188c2ecf20Sopenharmony_ci */ 40198c2ecf20Sopenharmony_ci p_vf->vf_mbx.pending_req = HILO_64(vf_msg->hi, vf_msg->lo); 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ci /* Mark the event and schedule the workqueue */ 40228c2ecf20Sopenharmony_ci p_vf->vf_mbx.b_pending_msg = true; 40238c2ecf20Sopenharmony_ci qed_schedule_iov(p_hwfn, QED_IOV_WQ_MSG_FLAG); 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_ci return 0; 40268c2ecf20Sopenharmony_ci} 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_cistatic void qed_sriov_vfpf_malicious(struct qed_hwfn *p_hwfn, 40298c2ecf20Sopenharmony_ci struct malicious_vf_eqe_data *p_data) 40308c2ecf20Sopenharmony_ci{ 40318c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf; 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci p_vf = qed_sriov_get_vf_from_absid(p_hwfn, p_data->vf_id); 40348c2ecf20Sopenharmony_ci 40358c2ecf20Sopenharmony_ci if (!p_vf) 40368c2ecf20Sopenharmony_ci return; 40378c2ecf20Sopenharmony_ci 40388c2ecf20Sopenharmony_ci if (!p_vf->b_malicious) { 40398c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 40408c2ecf20Sopenharmony_ci "VF [%d] - Malicious behavior [%02x]\n", 40418c2ecf20Sopenharmony_ci p_vf->abs_vf_id, p_data->err_id); 40428c2ecf20Sopenharmony_ci 40438c2ecf20Sopenharmony_ci p_vf->b_malicious = true; 40448c2ecf20Sopenharmony_ci } else { 40458c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 40468c2ecf20Sopenharmony_ci "VF [%d] - Malicious behavior [%02x]\n", 40478c2ecf20Sopenharmony_ci p_vf->abs_vf_id, p_data->err_id); 40488c2ecf20Sopenharmony_ci } 40498c2ecf20Sopenharmony_ci} 40508c2ecf20Sopenharmony_ci 40518c2ecf20Sopenharmony_cistatic int qed_sriov_eqe_event(struct qed_hwfn *p_hwfn, u8 opcode, __le16 echo, 40528c2ecf20Sopenharmony_ci union event_ring_data *data, u8 fw_return_code) 40538c2ecf20Sopenharmony_ci{ 40548c2ecf20Sopenharmony_ci switch (opcode) { 40558c2ecf20Sopenharmony_ci case COMMON_EVENT_VF_PF_CHANNEL: 40568c2ecf20Sopenharmony_ci return qed_sriov_vfpf_msg(p_hwfn, le16_to_cpu(echo), 40578c2ecf20Sopenharmony_ci &data->vf_pf_channel.msg_addr); 40588c2ecf20Sopenharmony_ci case COMMON_EVENT_MALICIOUS_VF: 40598c2ecf20Sopenharmony_ci qed_sriov_vfpf_malicious(p_hwfn, &data->malicious_vf); 40608c2ecf20Sopenharmony_ci return 0; 40618c2ecf20Sopenharmony_ci default: 40628c2ecf20Sopenharmony_ci DP_INFO(p_hwfn->cdev, "Unknown sriov eqe event 0x%02x\n", 40638c2ecf20Sopenharmony_ci opcode); 40648c2ecf20Sopenharmony_ci return -EINVAL; 40658c2ecf20Sopenharmony_ci } 40668c2ecf20Sopenharmony_ci} 40678c2ecf20Sopenharmony_ci 40688c2ecf20Sopenharmony_ciu16 qed_iov_get_next_active_vf(struct qed_hwfn *p_hwfn, u16 rel_vf_id) 40698c2ecf20Sopenharmony_ci{ 40708c2ecf20Sopenharmony_ci struct qed_hw_sriov_info *p_iov = p_hwfn->cdev->p_iov_info; 40718c2ecf20Sopenharmony_ci u16 i; 40728c2ecf20Sopenharmony_ci 40738c2ecf20Sopenharmony_ci if (!p_iov) 40748c2ecf20Sopenharmony_ci goto out; 40758c2ecf20Sopenharmony_ci 40768c2ecf20Sopenharmony_ci for (i = rel_vf_id; i < p_iov->total_vfs; i++) 40778c2ecf20Sopenharmony_ci if (qed_iov_is_valid_vfid(p_hwfn, rel_vf_id, true, false)) 40788c2ecf20Sopenharmony_ci return i; 40798c2ecf20Sopenharmony_ci 40808c2ecf20Sopenharmony_ciout: 40818c2ecf20Sopenharmony_ci return MAX_NUM_VFS; 40828c2ecf20Sopenharmony_ci} 40838c2ecf20Sopenharmony_ci 40848c2ecf20Sopenharmony_cistatic int qed_iov_copy_vf_msg(struct qed_hwfn *p_hwfn, struct qed_ptt *ptt, 40858c2ecf20Sopenharmony_ci int vfid) 40868c2ecf20Sopenharmony_ci{ 40878c2ecf20Sopenharmony_ci struct qed_dmae_params params; 40888c2ecf20Sopenharmony_ci struct qed_vf_info *vf_info; 40898c2ecf20Sopenharmony_ci 40908c2ecf20Sopenharmony_ci vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 40918c2ecf20Sopenharmony_ci if (!vf_info) 40928c2ecf20Sopenharmony_ci return -EINVAL; 40938c2ecf20Sopenharmony_ci 40948c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 40958c2ecf20Sopenharmony_ci SET_FIELD(params.flags, QED_DMAE_PARAMS_SRC_VF_VALID, 0x1); 40968c2ecf20Sopenharmony_ci SET_FIELD(params.flags, QED_DMAE_PARAMS_COMPLETION_DST, 0x1); 40978c2ecf20Sopenharmony_ci params.src_vfid = vf_info->abs_vf_id; 40988c2ecf20Sopenharmony_ci 40998c2ecf20Sopenharmony_ci if (qed_dmae_host2host(p_hwfn, ptt, 41008c2ecf20Sopenharmony_ci vf_info->vf_mbx.pending_req, 41018c2ecf20Sopenharmony_ci vf_info->vf_mbx.req_phys, 41028c2ecf20Sopenharmony_ci sizeof(union vfpf_tlvs) / 4, ¶ms)) { 41038c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 41048c2ecf20Sopenharmony_ci "Failed to copy message from VF 0x%02x\n", vfid); 41058c2ecf20Sopenharmony_ci 41068c2ecf20Sopenharmony_ci return -EIO; 41078c2ecf20Sopenharmony_ci } 41088c2ecf20Sopenharmony_ci 41098c2ecf20Sopenharmony_ci return 0; 41108c2ecf20Sopenharmony_ci} 41118c2ecf20Sopenharmony_ci 41128c2ecf20Sopenharmony_cistatic void qed_iov_bulletin_set_forced_mac(struct qed_hwfn *p_hwfn, 41138c2ecf20Sopenharmony_ci u8 *mac, int vfid) 41148c2ecf20Sopenharmony_ci{ 41158c2ecf20Sopenharmony_ci struct qed_vf_info *vf_info; 41168c2ecf20Sopenharmony_ci u64 feature; 41178c2ecf20Sopenharmony_ci 41188c2ecf20Sopenharmony_ci vf_info = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true); 41198c2ecf20Sopenharmony_ci if (!vf_info) { 41208c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn->cdev, 41218c2ecf20Sopenharmony_ci "Can not set forced MAC, invalid vfid [%d]\n", vfid); 41228c2ecf20Sopenharmony_ci return; 41238c2ecf20Sopenharmony_ci } 41248c2ecf20Sopenharmony_ci 41258c2ecf20Sopenharmony_ci if (vf_info->b_malicious) { 41268c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn->cdev, 41278c2ecf20Sopenharmony_ci "Can't set forced MAC to malicious VF [%d]\n", vfid); 41288c2ecf20Sopenharmony_ci return; 41298c2ecf20Sopenharmony_ci } 41308c2ecf20Sopenharmony_ci 41318c2ecf20Sopenharmony_ci if (vf_info->p_vf_info.is_trusted_configured) { 41328c2ecf20Sopenharmony_ci feature = BIT(VFPF_BULLETIN_MAC_ADDR); 41338c2ecf20Sopenharmony_ci /* Trust mode will disable Forced MAC */ 41348c2ecf20Sopenharmony_ci vf_info->bulletin.p_virt->valid_bitmap &= 41358c2ecf20Sopenharmony_ci ~BIT(MAC_ADDR_FORCED); 41368c2ecf20Sopenharmony_ci } else { 41378c2ecf20Sopenharmony_ci feature = BIT(MAC_ADDR_FORCED); 41388c2ecf20Sopenharmony_ci /* Forced MAC will disable MAC_ADDR */ 41398c2ecf20Sopenharmony_ci vf_info->bulletin.p_virt->valid_bitmap &= 41408c2ecf20Sopenharmony_ci ~BIT(VFPF_BULLETIN_MAC_ADDR); 41418c2ecf20Sopenharmony_ci } 41428c2ecf20Sopenharmony_ci 41438c2ecf20Sopenharmony_ci memcpy(vf_info->bulletin.p_virt->mac, mac, ETH_ALEN); 41448c2ecf20Sopenharmony_ci 41458c2ecf20Sopenharmony_ci vf_info->bulletin.p_virt->valid_bitmap |= feature; 41468c2ecf20Sopenharmony_ci 41478c2ecf20Sopenharmony_ci qed_iov_configure_vport_forced(p_hwfn, vf_info, feature); 41488c2ecf20Sopenharmony_ci} 41498c2ecf20Sopenharmony_ci 41508c2ecf20Sopenharmony_cistatic int qed_iov_bulletin_set_mac(struct qed_hwfn *p_hwfn, u8 *mac, int vfid) 41518c2ecf20Sopenharmony_ci{ 41528c2ecf20Sopenharmony_ci struct qed_vf_info *vf_info; 41538c2ecf20Sopenharmony_ci u64 feature; 41548c2ecf20Sopenharmony_ci 41558c2ecf20Sopenharmony_ci vf_info = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true); 41568c2ecf20Sopenharmony_ci if (!vf_info) { 41578c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn->cdev, "Can not set MAC, invalid vfid [%d]\n", 41588c2ecf20Sopenharmony_ci vfid); 41598c2ecf20Sopenharmony_ci return -EINVAL; 41608c2ecf20Sopenharmony_ci } 41618c2ecf20Sopenharmony_ci 41628c2ecf20Sopenharmony_ci if (vf_info->b_malicious) { 41638c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn->cdev, "Can't set MAC to malicious VF [%d]\n", 41648c2ecf20Sopenharmony_ci vfid); 41658c2ecf20Sopenharmony_ci return -EINVAL; 41668c2ecf20Sopenharmony_ci } 41678c2ecf20Sopenharmony_ci 41688c2ecf20Sopenharmony_ci if (vf_info->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED)) { 41698c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 41708c2ecf20Sopenharmony_ci "Can not set MAC, Forced MAC is configured\n"); 41718c2ecf20Sopenharmony_ci return -EINVAL; 41728c2ecf20Sopenharmony_ci } 41738c2ecf20Sopenharmony_ci 41748c2ecf20Sopenharmony_ci feature = BIT(VFPF_BULLETIN_MAC_ADDR); 41758c2ecf20Sopenharmony_ci ether_addr_copy(vf_info->bulletin.p_virt->mac, mac); 41768c2ecf20Sopenharmony_ci 41778c2ecf20Sopenharmony_ci vf_info->bulletin.p_virt->valid_bitmap |= feature; 41788c2ecf20Sopenharmony_ci 41798c2ecf20Sopenharmony_ci if (vf_info->p_vf_info.is_trusted_configured) 41808c2ecf20Sopenharmony_ci qed_iov_configure_vport_forced(p_hwfn, vf_info, feature); 41818c2ecf20Sopenharmony_ci 41828c2ecf20Sopenharmony_ci return 0; 41838c2ecf20Sopenharmony_ci} 41848c2ecf20Sopenharmony_ci 41858c2ecf20Sopenharmony_cistatic void qed_iov_bulletin_set_forced_vlan(struct qed_hwfn *p_hwfn, 41868c2ecf20Sopenharmony_ci u16 pvid, int vfid) 41878c2ecf20Sopenharmony_ci{ 41888c2ecf20Sopenharmony_ci struct qed_vf_info *vf_info; 41898c2ecf20Sopenharmony_ci u64 feature; 41908c2ecf20Sopenharmony_ci 41918c2ecf20Sopenharmony_ci vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 41928c2ecf20Sopenharmony_ci if (!vf_info) { 41938c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn->cdev, 41948c2ecf20Sopenharmony_ci "Can not set forced MAC, invalid vfid [%d]\n", vfid); 41958c2ecf20Sopenharmony_ci return; 41968c2ecf20Sopenharmony_ci } 41978c2ecf20Sopenharmony_ci 41988c2ecf20Sopenharmony_ci if (vf_info->b_malicious) { 41998c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn->cdev, 42008c2ecf20Sopenharmony_ci "Can't set forced vlan to malicious VF [%d]\n", vfid); 42018c2ecf20Sopenharmony_ci return; 42028c2ecf20Sopenharmony_ci } 42038c2ecf20Sopenharmony_ci 42048c2ecf20Sopenharmony_ci feature = 1 << VLAN_ADDR_FORCED; 42058c2ecf20Sopenharmony_ci vf_info->bulletin.p_virt->pvid = pvid; 42068c2ecf20Sopenharmony_ci if (pvid) 42078c2ecf20Sopenharmony_ci vf_info->bulletin.p_virt->valid_bitmap |= feature; 42088c2ecf20Sopenharmony_ci else 42098c2ecf20Sopenharmony_ci vf_info->bulletin.p_virt->valid_bitmap &= ~feature; 42108c2ecf20Sopenharmony_ci 42118c2ecf20Sopenharmony_ci qed_iov_configure_vport_forced(p_hwfn, vf_info, feature); 42128c2ecf20Sopenharmony_ci} 42138c2ecf20Sopenharmony_ci 42148c2ecf20Sopenharmony_civoid qed_iov_bulletin_set_udp_ports(struct qed_hwfn *p_hwfn, 42158c2ecf20Sopenharmony_ci int vfid, u16 vxlan_port, u16 geneve_port) 42168c2ecf20Sopenharmony_ci{ 42178c2ecf20Sopenharmony_ci struct qed_vf_info *vf_info; 42188c2ecf20Sopenharmony_ci 42198c2ecf20Sopenharmony_ci vf_info = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true); 42208c2ecf20Sopenharmony_ci if (!vf_info) { 42218c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn->cdev, 42228c2ecf20Sopenharmony_ci "Can not set udp ports, invalid vfid [%d]\n", vfid); 42238c2ecf20Sopenharmony_ci return; 42248c2ecf20Sopenharmony_ci } 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci if (vf_info->b_malicious) { 42278c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 42288c2ecf20Sopenharmony_ci "Can not set udp ports to malicious VF [%d]\n", 42298c2ecf20Sopenharmony_ci vfid); 42308c2ecf20Sopenharmony_ci return; 42318c2ecf20Sopenharmony_ci } 42328c2ecf20Sopenharmony_ci 42338c2ecf20Sopenharmony_ci vf_info->bulletin.p_virt->vxlan_udp_port = vxlan_port; 42348c2ecf20Sopenharmony_ci vf_info->bulletin.p_virt->geneve_udp_port = geneve_port; 42358c2ecf20Sopenharmony_ci} 42368c2ecf20Sopenharmony_ci 42378c2ecf20Sopenharmony_cistatic bool qed_iov_vf_has_vport_instance(struct qed_hwfn *p_hwfn, int vfid) 42388c2ecf20Sopenharmony_ci{ 42398c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf_info; 42408c2ecf20Sopenharmony_ci 42418c2ecf20Sopenharmony_ci p_vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 42428c2ecf20Sopenharmony_ci if (!p_vf_info) 42438c2ecf20Sopenharmony_ci return false; 42448c2ecf20Sopenharmony_ci 42458c2ecf20Sopenharmony_ci return !!p_vf_info->vport_instance; 42468c2ecf20Sopenharmony_ci} 42478c2ecf20Sopenharmony_ci 42488c2ecf20Sopenharmony_cistatic bool qed_iov_is_vf_stopped(struct qed_hwfn *p_hwfn, int vfid) 42498c2ecf20Sopenharmony_ci{ 42508c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf_info; 42518c2ecf20Sopenharmony_ci 42528c2ecf20Sopenharmony_ci p_vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 42538c2ecf20Sopenharmony_ci if (!p_vf_info) 42548c2ecf20Sopenharmony_ci return true; 42558c2ecf20Sopenharmony_ci 42568c2ecf20Sopenharmony_ci return p_vf_info->state == VF_STOPPED; 42578c2ecf20Sopenharmony_ci} 42588c2ecf20Sopenharmony_ci 42598c2ecf20Sopenharmony_cistatic bool qed_iov_spoofchk_get(struct qed_hwfn *p_hwfn, int vfid) 42608c2ecf20Sopenharmony_ci{ 42618c2ecf20Sopenharmony_ci struct qed_vf_info *vf_info; 42628c2ecf20Sopenharmony_ci 42638c2ecf20Sopenharmony_ci vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 42648c2ecf20Sopenharmony_ci if (!vf_info) 42658c2ecf20Sopenharmony_ci return false; 42668c2ecf20Sopenharmony_ci 42678c2ecf20Sopenharmony_ci return vf_info->spoof_chk; 42688c2ecf20Sopenharmony_ci} 42698c2ecf20Sopenharmony_ci 42708c2ecf20Sopenharmony_cistatic int qed_iov_spoofchk_set(struct qed_hwfn *p_hwfn, int vfid, bool val) 42718c2ecf20Sopenharmony_ci{ 42728c2ecf20Sopenharmony_ci struct qed_vf_info *vf; 42738c2ecf20Sopenharmony_ci int rc = -EINVAL; 42748c2ecf20Sopenharmony_ci 42758c2ecf20Sopenharmony_ci if (!qed_iov_pf_sanity_check(p_hwfn, vfid)) { 42768c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 42778c2ecf20Sopenharmony_ci "SR-IOV sanity check failed, can't set spoofchk\n"); 42788c2ecf20Sopenharmony_ci goto out; 42798c2ecf20Sopenharmony_ci } 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_ci vf = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 42828c2ecf20Sopenharmony_ci if (!vf) 42838c2ecf20Sopenharmony_ci goto out; 42848c2ecf20Sopenharmony_ci 42858c2ecf20Sopenharmony_ci if (!qed_iov_vf_has_vport_instance(p_hwfn, vfid)) { 42868c2ecf20Sopenharmony_ci /* After VF VPORT start PF will configure spoof check */ 42878c2ecf20Sopenharmony_ci vf->req_spoofchk_val = val; 42888c2ecf20Sopenharmony_ci rc = 0; 42898c2ecf20Sopenharmony_ci goto out; 42908c2ecf20Sopenharmony_ci } 42918c2ecf20Sopenharmony_ci 42928c2ecf20Sopenharmony_ci rc = __qed_iov_spoofchk_set(p_hwfn, vf, val); 42938c2ecf20Sopenharmony_ci 42948c2ecf20Sopenharmony_ciout: 42958c2ecf20Sopenharmony_ci return rc; 42968c2ecf20Sopenharmony_ci} 42978c2ecf20Sopenharmony_ci 42988c2ecf20Sopenharmony_cistatic u8 *qed_iov_bulletin_get_mac(struct qed_hwfn *p_hwfn, u16 rel_vf_id) 42998c2ecf20Sopenharmony_ci{ 43008c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf; 43018c2ecf20Sopenharmony_ci 43028c2ecf20Sopenharmony_ci p_vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, true); 43038c2ecf20Sopenharmony_ci if (!p_vf || !p_vf->bulletin.p_virt) 43048c2ecf20Sopenharmony_ci return NULL; 43058c2ecf20Sopenharmony_ci 43068c2ecf20Sopenharmony_ci if (!(p_vf->bulletin.p_virt->valid_bitmap & 43078c2ecf20Sopenharmony_ci BIT(VFPF_BULLETIN_MAC_ADDR))) 43088c2ecf20Sopenharmony_ci return NULL; 43098c2ecf20Sopenharmony_ci 43108c2ecf20Sopenharmony_ci return p_vf->bulletin.p_virt->mac; 43118c2ecf20Sopenharmony_ci} 43128c2ecf20Sopenharmony_ci 43138c2ecf20Sopenharmony_cistatic u8 *qed_iov_bulletin_get_forced_mac(struct qed_hwfn *p_hwfn, 43148c2ecf20Sopenharmony_ci u16 rel_vf_id) 43158c2ecf20Sopenharmony_ci{ 43168c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf; 43178c2ecf20Sopenharmony_ci 43188c2ecf20Sopenharmony_ci p_vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, true); 43198c2ecf20Sopenharmony_ci if (!p_vf || !p_vf->bulletin.p_virt) 43208c2ecf20Sopenharmony_ci return NULL; 43218c2ecf20Sopenharmony_ci 43228c2ecf20Sopenharmony_ci if (!(p_vf->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED))) 43238c2ecf20Sopenharmony_ci return NULL; 43248c2ecf20Sopenharmony_ci 43258c2ecf20Sopenharmony_ci return p_vf->bulletin.p_virt->mac; 43268c2ecf20Sopenharmony_ci} 43278c2ecf20Sopenharmony_ci 43288c2ecf20Sopenharmony_cistatic u16 43298c2ecf20Sopenharmony_ciqed_iov_bulletin_get_forced_vlan(struct qed_hwfn *p_hwfn, u16 rel_vf_id) 43308c2ecf20Sopenharmony_ci{ 43318c2ecf20Sopenharmony_ci struct qed_vf_info *p_vf; 43328c2ecf20Sopenharmony_ci 43338c2ecf20Sopenharmony_ci p_vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, true); 43348c2ecf20Sopenharmony_ci if (!p_vf || !p_vf->bulletin.p_virt) 43358c2ecf20Sopenharmony_ci return 0; 43368c2ecf20Sopenharmony_ci 43378c2ecf20Sopenharmony_ci if (!(p_vf->bulletin.p_virt->valid_bitmap & BIT(VLAN_ADDR_FORCED))) 43388c2ecf20Sopenharmony_ci return 0; 43398c2ecf20Sopenharmony_ci 43408c2ecf20Sopenharmony_ci return p_vf->bulletin.p_virt->pvid; 43418c2ecf20Sopenharmony_ci} 43428c2ecf20Sopenharmony_ci 43438c2ecf20Sopenharmony_cistatic int qed_iov_configure_tx_rate(struct qed_hwfn *p_hwfn, 43448c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, int vfid, int val) 43458c2ecf20Sopenharmony_ci{ 43468c2ecf20Sopenharmony_ci struct qed_vf_info *vf; 43478c2ecf20Sopenharmony_ci u8 abs_vp_id = 0; 43488c2ecf20Sopenharmony_ci u16 rl_id; 43498c2ecf20Sopenharmony_ci int rc; 43508c2ecf20Sopenharmony_ci 43518c2ecf20Sopenharmony_ci vf = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true); 43528c2ecf20Sopenharmony_ci if (!vf) 43538c2ecf20Sopenharmony_ci return -EINVAL; 43548c2ecf20Sopenharmony_ci 43558c2ecf20Sopenharmony_ci rc = qed_fw_vport(p_hwfn, vf->vport_id, &abs_vp_id); 43568c2ecf20Sopenharmony_ci if (rc) 43578c2ecf20Sopenharmony_ci return rc; 43588c2ecf20Sopenharmony_ci 43598c2ecf20Sopenharmony_ci rl_id = abs_vp_id; /* The "rl_id" is set as the "vport_id" */ 43608c2ecf20Sopenharmony_ci return qed_init_global_rl(p_hwfn, p_ptt, rl_id, (u32)val); 43618c2ecf20Sopenharmony_ci} 43628c2ecf20Sopenharmony_ci 43638c2ecf20Sopenharmony_cistatic int 43648c2ecf20Sopenharmony_ciqed_iov_configure_min_tx_rate(struct qed_dev *cdev, int vfid, u32 rate) 43658c2ecf20Sopenharmony_ci{ 43668c2ecf20Sopenharmony_ci struct qed_vf_info *vf; 43678c2ecf20Sopenharmony_ci u8 vport_id; 43688c2ecf20Sopenharmony_ci int i; 43698c2ecf20Sopenharmony_ci 43708c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 43718c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 43728c2ecf20Sopenharmony_ci 43738c2ecf20Sopenharmony_ci if (!qed_iov_pf_sanity_check(p_hwfn, vfid)) { 43748c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 43758c2ecf20Sopenharmony_ci "SR-IOV sanity check failed, can't set min rate\n"); 43768c2ecf20Sopenharmony_ci return -EINVAL; 43778c2ecf20Sopenharmony_ci } 43788c2ecf20Sopenharmony_ci } 43798c2ecf20Sopenharmony_ci 43808c2ecf20Sopenharmony_ci vf = qed_iov_get_vf_info(QED_LEADING_HWFN(cdev), (u16)vfid, true); 43818c2ecf20Sopenharmony_ci if (!vf) 43828c2ecf20Sopenharmony_ci return -EINVAL; 43838c2ecf20Sopenharmony_ci 43848c2ecf20Sopenharmony_ci vport_id = vf->vport_id; 43858c2ecf20Sopenharmony_ci 43868c2ecf20Sopenharmony_ci return qed_configure_vport_wfq(cdev, vport_id, rate); 43878c2ecf20Sopenharmony_ci} 43888c2ecf20Sopenharmony_ci 43898c2ecf20Sopenharmony_cistatic int qed_iov_get_vf_min_rate(struct qed_hwfn *p_hwfn, int vfid) 43908c2ecf20Sopenharmony_ci{ 43918c2ecf20Sopenharmony_ci struct qed_wfq_data *vf_vp_wfq; 43928c2ecf20Sopenharmony_ci struct qed_vf_info *vf_info; 43938c2ecf20Sopenharmony_ci 43948c2ecf20Sopenharmony_ci vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 43958c2ecf20Sopenharmony_ci if (!vf_info) 43968c2ecf20Sopenharmony_ci return 0; 43978c2ecf20Sopenharmony_ci 43988c2ecf20Sopenharmony_ci vf_vp_wfq = &p_hwfn->qm_info.wfq_data[vf_info->vport_id]; 43998c2ecf20Sopenharmony_ci 44008c2ecf20Sopenharmony_ci if (vf_vp_wfq->configured) 44018c2ecf20Sopenharmony_ci return vf_vp_wfq->min_speed; 44028c2ecf20Sopenharmony_ci else 44038c2ecf20Sopenharmony_ci return 0; 44048c2ecf20Sopenharmony_ci} 44058c2ecf20Sopenharmony_ci 44068c2ecf20Sopenharmony_ci/** 44078c2ecf20Sopenharmony_ci * qed_schedule_iov - schedules IOV task for VF and PF 44088c2ecf20Sopenharmony_ci * @hwfn: hardware function pointer 44098c2ecf20Sopenharmony_ci * @flag: IOV flag for VF/PF 44108c2ecf20Sopenharmony_ci */ 44118c2ecf20Sopenharmony_civoid qed_schedule_iov(struct qed_hwfn *hwfn, enum qed_iov_wq_flag flag) 44128c2ecf20Sopenharmony_ci{ 44138c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 44148c2ecf20Sopenharmony_ci set_bit(flag, &hwfn->iov_task_flags); 44158c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 44168c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn, QED_MSG_IOV, "Scheduling iov task [Flag: %d]\n", flag); 44178c2ecf20Sopenharmony_ci queue_delayed_work(hwfn->iov_wq, &hwfn->iov_task, 0); 44188c2ecf20Sopenharmony_ci} 44198c2ecf20Sopenharmony_ci 44208c2ecf20Sopenharmony_civoid qed_vf_start_iov_wq(struct qed_dev *cdev) 44218c2ecf20Sopenharmony_ci{ 44228c2ecf20Sopenharmony_ci int i; 44238c2ecf20Sopenharmony_ci 44248c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) 44258c2ecf20Sopenharmony_ci queue_delayed_work(cdev->hwfns[i].iov_wq, 44268c2ecf20Sopenharmony_ci &cdev->hwfns[i].iov_task, 0); 44278c2ecf20Sopenharmony_ci} 44288c2ecf20Sopenharmony_ci 44298c2ecf20Sopenharmony_ciint qed_sriov_disable(struct qed_dev *cdev, bool pci_enabled) 44308c2ecf20Sopenharmony_ci{ 44318c2ecf20Sopenharmony_ci int i, j; 44328c2ecf20Sopenharmony_ci 44338c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) 44348c2ecf20Sopenharmony_ci if (cdev->hwfns[i].iov_wq) 44358c2ecf20Sopenharmony_ci flush_workqueue(cdev->hwfns[i].iov_wq); 44368c2ecf20Sopenharmony_ci 44378c2ecf20Sopenharmony_ci /* Mark VFs for disablement */ 44388c2ecf20Sopenharmony_ci qed_iov_set_vfs_to_disable(cdev, true); 44398c2ecf20Sopenharmony_ci 44408c2ecf20Sopenharmony_ci if (cdev->p_iov_info && cdev->p_iov_info->num_vfs && pci_enabled) 44418c2ecf20Sopenharmony_ci pci_disable_sriov(cdev->pdev); 44428c2ecf20Sopenharmony_ci 44438c2ecf20Sopenharmony_ci if (cdev->recov_in_prog) { 44448c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, 44458c2ecf20Sopenharmony_ci QED_MSG_IOV, 44468c2ecf20Sopenharmony_ci "Skip SRIOV disable operations in the device since a recovery is in progress\n"); 44478c2ecf20Sopenharmony_ci goto out; 44488c2ecf20Sopenharmony_ci } 44498c2ecf20Sopenharmony_ci 44508c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 44518c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = &cdev->hwfns[i]; 44528c2ecf20Sopenharmony_ci struct qed_ptt *ptt = qed_ptt_acquire(hwfn); 44538c2ecf20Sopenharmony_ci 44548c2ecf20Sopenharmony_ci /* Failure to acquire the ptt in 100g creates an odd error 44558c2ecf20Sopenharmony_ci * where the first engine has already relased IOV. 44568c2ecf20Sopenharmony_ci */ 44578c2ecf20Sopenharmony_ci if (!ptt) { 44588c2ecf20Sopenharmony_ci DP_ERR(hwfn, "Failed to acquire ptt\n"); 44598c2ecf20Sopenharmony_ci return -EBUSY; 44608c2ecf20Sopenharmony_ci } 44618c2ecf20Sopenharmony_ci 44628c2ecf20Sopenharmony_ci /* Clean WFQ db and configure equal weight for all vports */ 44638c2ecf20Sopenharmony_ci qed_clean_wfq_db(hwfn, ptt); 44648c2ecf20Sopenharmony_ci 44658c2ecf20Sopenharmony_ci qed_for_each_vf(hwfn, j) { 44668c2ecf20Sopenharmony_ci int k; 44678c2ecf20Sopenharmony_ci 44688c2ecf20Sopenharmony_ci if (!qed_iov_is_valid_vfid(hwfn, j, true, false)) 44698c2ecf20Sopenharmony_ci continue; 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_ci /* Wait until VF is disabled before releasing */ 44728c2ecf20Sopenharmony_ci for (k = 0; k < 100; k++) { 44738c2ecf20Sopenharmony_ci if (!qed_iov_is_vf_stopped(hwfn, j)) 44748c2ecf20Sopenharmony_ci msleep(20); 44758c2ecf20Sopenharmony_ci else 44768c2ecf20Sopenharmony_ci break; 44778c2ecf20Sopenharmony_ci } 44788c2ecf20Sopenharmony_ci 44798c2ecf20Sopenharmony_ci if (k < 100) 44808c2ecf20Sopenharmony_ci qed_iov_release_hw_for_vf(&cdev->hwfns[i], 44818c2ecf20Sopenharmony_ci ptt, j); 44828c2ecf20Sopenharmony_ci else 44838c2ecf20Sopenharmony_ci DP_ERR(hwfn, 44848c2ecf20Sopenharmony_ci "Timeout waiting for VF's FLR to end\n"); 44858c2ecf20Sopenharmony_ci } 44868c2ecf20Sopenharmony_ci 44878c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 44888c2ecf20Sopenharmony_ci } 44898c2ecf20Sopenharmony_ciout: 44908c2ecf20Sopenharmony_ci qed_iov_set_vfs_to_disable(cdev, false); 44918c2ecf20Sopenharmony_ci 44928c2ecf20Sopenharmony_ci return 0; 44938c2ecf20Sopenharmony_ci} 44948c2ecf20Sopenharmony_ci 44958c2ecf20Sopenharmony_cistatic void qed_sriov_enable_qid_config(struct qed_hwfn *hwfn, 44968c2ecf20Sopenharmony_ci u16 vfid, 44978c2ecf20Sopenharmony_ci struct qed_iov_vf_init_params *params) 44988c2ecf20Sopenharmony_ci{ 44998c2ecf20Sopenharmony_ci u16 base, i; 45008c2ecf20Sopenharmony_ci 45018c2ecf20Sopenharmony_ci /* Since we have an equal resource distribution per-VF, and we assume 45028c2ecf20Sopenharmony_ci * PF has acquired the QED_PF_L2_QUE first queues, we start setting 45038c2ecf20Sopenharmony_ci * sequentially from there. 45048c2ecf20Sopenharmony_ci */ 45058c2ecf20Sopenharmony_ci base = FEAT_NUM(hwfn, QED_PF_L2_QUE) + vfid * params->num_queues; 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci params->rel_vf_id = vfid; 45088c2ecf20Sopenharmony_ci for (i = 0; i < params->num_queues; i++) { 45098c2ecf20Sopenharmony_ci params->req_rx_queue[i] = base + i; 45108c2ecf20Sopenharmony_ci params->req_tx_queue[i] = base + i; 45118c2ecf20Sopenharmony_ci } 45128c2ecf20Sopenharmony_ci} 45138c2ecf20Sopenharmony_ci 45148c2ecf20Sopenharmony_cistatic int qed_sriov_enable(struct qed_dev *cdev, int num) 45158c2ecf20Sopenharmony_ci{ 45168c2ecf20Sopenharmony_ci struct qed_iov_vf_init_params params; 45178c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn; 45188c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 45198c2ecf20Sopenharmony_ci int i, j, rc; 45208c2ecf20Sopenharmony_ci 45218c2ecf20Sopenharmony_ci if (num >= RESC_NUM(&cdev->hwfns[0], QED_VPORT)) { 45228c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Can start at most %d VFs\n", 45238c2ecf20Sopenharmony_ci RESC_NUM(&cdev->hwfns[0], QED_VPORT) - 1); 45248c2ecf20Sopenharmony_ci return -EINVAL; 45258c2ecf20Sopenharmony_ci } 45268c2ecf20Sopenharmony_ci 45278c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 45288c2ecf20Sopenharmony_ci 45298c2ecf20Sopenharmony_ci /* Initialize HW for VF access */ 45308c2ecf20Sopenharmony_ci for_each_hwfn(cdev, j) { 45318c2ecf20Sopenharmony_ci hwfn = &cdev->hwfns[j]; 45328c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 45338c2ecf20Sopenharmony_ci 45348c2ecf20Sopenharmony_ci /* Make sure not to use more than 16 queues per VF */ 45358c2ecf20Sopenharmony_ci params.num_queues = min_t(int, 45368c2ecf20Sopenharmony_ci FEAT_NUM(hwfn, QED_VF_L2_QUE) / num, 45378c2ecf20Sopenharmony_ci 16); 45388c2ecf20Sopenharmony_ci 45398c2ecf20Sopenharmony_ci if (!ptt) { 45408c2ecf20Sopenharmony_ci DP_ERR(hwfn, "Failed to acquire ptt\n"); 45418c2ecf20Sopenharmony_ci rc = -EBUSY; 45428c2ecf20Sopenharmony_ci goto err; 45438c2ecf20Sopenharmony_ci } 45448c2ecf20Sopenharmony_ci 45458c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 45468c2ecf20Sopenharmony_ci if (!qed_iov_is_valid_vfid(hwfn, i, false, true)) 45478c2ecf20Sopenharmony_ci continue; 45488c2ecf20Sopenharmony_ci 45498c2ecf20Sopenharmony_ci qed_sriov_enable_qid_config(hwfn, i, ¶ms); 45508c2ecf20Sopenharmony_ci rc = qed_iov_init_hw_for_vf(hwfn, ptt, ¶ms); 45518c2ecf20Sopenharmony_ci if (rc) { 45528c2ecf20Sopenharmony_ci DP_ERR(cdev, "Failed to enable VF[%d]\n", i); 45538c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 45548c2ecf20Sopenharmony_ci goto err; 45558c2ecf20Sopenharmony_ci } 45568c2ecf20Sopenharmony_ci } 45578c2ecf20Sopenharmony_ci 45588c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 45598c2ecf20Sopenharmony_ci } 45608c2ecf20Sopenharmony_ci 45618c2ecf20Sopenharmony_ci /* Enable SRIOV PCIe functions */ 45628c2ecf20Sopenharmony_ci rc = pci_enable_sriov(cdev->pdev, num); 45638c2ecf20Sopenharmony_ci if (rc) { 45648c2ecf20Sopenharmony_ci DP_ERR(cdev, "Failed to enable sriov [%d]\n", rc); 45658c2ecf20Sopenharmony_ci goto err; 45668c2ecf20Sopenharmony_ci } 45678c2ecf20Sopenharmony_ci 45688c2ecf20Sopenharmony_ci hwfn = QED_LEADING_HWFN(cdev); 45698c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 45708c2ecf20Sopenharmony_ci if (!ptt) { 45718c2ecf20Sopenharmony_ci DP_ERR(hwfn, "Failed to acquire ptt\n"); 45728c2ecf20Sopenharmony_ci rc = -EBUSY; 45738c2ecf20Sopenharmony_ci goto err; 45748c2ecf20Sopenharmony_ci } 45758c2ecf20Sopenharmony_ci 45768c2ecf20Sopenharmony_ci rc = qed_mcp_ov_update_eswitch(hwfn, ptt, QED_OV_ESWITCH_VEB); 45778c2ecf20Sopenharmony_ci if (rc) 45788c2ecf20Sopenharmony_ci DP_INFO(cdev, "Failed to update eswitch mode\n"); 45798c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 45808c2ecf20Sopenharmony_ci 45818c2ecf20Sopenharmony_ci return num; 45828c2ecf20Sopenharmony_ci 45838c2ecf20Sopenharmony_cierr: 45848c2ecf20Sopenharmony_ci qed_sriov_disable(cdev, false); 45858c2ecf20Sopenharmony_ci return rc; 45868c2ecf20Sopenharmony_ci} 45878c2ecf20Sopenharmony_ci 45888c2ecf20Sopenharmony_cistatic int qed_sriov_configure(struct qed_dev *cdev, int num_vfs_param) 45898c2ecf20Sopenharmony_ci{ 45908c2ecf20Sopenharmony_ci if (!IS_QED_SRIOV(cdev)) { 45918c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_IOV, "SR-IOV is not supported\n"); 45928c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 45938c2ecf20Sopenharmony_ci } 45948c2ecf20Sopenharmony_ci 45958c2ecf20Sopenharmony_ci if (num_vfs_param) 45968c2ecf20Sopenharmony_ci return qed_sriov_enable(cdev, num_vfs_param); 45978c2ecf20Sopenharmony_ci else 45988c2ecf20Sopenharmony_ci return qed_sriov_disable(cdev, true); 45998c2ecf20Sopenharmony_ci} 46008c2ecf20Sopenharmony_ci 46018c2ecf20Sopenharmony_cistatic int qed_sriov_pf_set_mac(struct qed_dev *cdev, u8 *mac, int vfid) 46028c2ecf20Sopenharmony_ci{ 46038c2ecf20Sopenharmony_ci int i; 46048c2ecf20Sopenharmony_ci 46058c2ecf20Sopenharmony_ci if (!IS_QED_SRIOV(cdev) || !IS_PF_SRIOV_ALLOC(&cdev->hwfns[0])) { 46068c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_IOV, 46078c2ecf20Sopenharmony_ci "Cannot set a VF MAC; Sriov is not enabled\n"); 46088c2ecf20Sopenharmony_ci return -EINVAL; 46098c2ecf20Sopenharmony_ci } 46108c2ecf20Sopenharmony_ci 46118c2ecf20Sopenharmony_ci if (!qed_iov_is_valid_vfid(&cdev->hwfns[0], vfid, true, true)) { 46128c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_IOV, 46138c2ecf20Sopenharmony_ci "Cannot set VF[%d] MAC (VF is not active)\n", vfid); 46148c2ecf20Sopenharmony_ci return -EINVAL; 46158c2ecf20Sopenharmony_ci } 46168c2ecf20Sopenharmony_ci 46178c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 46188c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = &cdev->hwfns[i]; 46198c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf_info; 46208c2ecf20Sopenharmony_ci 46218c2ecf20Sopenharmony_ci vf_info = qed_iov_get_public_vf_info(hwfn, vfid, true); 46228c2ecf20Sopenharmony_ci if (!vf_info) 46238c2ecf20Sopenharmony_ci continue; 46248c2ecf20Sopenharmony_ci 46258c2ecf20Sopenharmony_ci /* Set the MAC, and schedule the IOV task */ 46268c2ecf20Sopenharmony_ci if (vf_info->is_trusted_configured) 46278c2ecf20Sopenharmony_ci ether_addr_copy(vf_info->mac, mac); 46288c2ecf20Sopenharmony_ci else 46298c2ecf20Sopenharmony_ci ether_addr_copy(vf_info->forced_mac, mac); 46308c2ecf20Sopenharmony_ci 46318c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_SET_UNICAST_FILTER_FLAG); 46328c2ecf20Sopenharmony_ci } 46338c2ecf20Sopenharmony_ci 46348c2ecf20Sopenharmony_ci return 0; 46358c2ecf20Sopenharmony_ci} 46368c2ecf20Sopenharmony_ci 46378c2ecf20Sopenharmony_cistatic int qed_sriov_pf_set_vlan(struct qed_dev *cdev, u16 vid, int vfid) 46388c2ecf20Sopenharmony_ci{ 46398c2ecf20Sopenharmony_ci int i; 46408c2ecf20Sopenharmony_ci 46418c2ecf20Sopenharmony_ci if (!IS_QED_SRIOV(cdev) || !IS_PF_SRIOV_ALLOC(&cdev->hwfns[0])) { 46428c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_IOV, 46438c2ecf20Sopenharmony_ci "Cannot set a VF MAC; Sriov is not enabled\n"); 46448c2ecf20Sopenharmony_ci return -EINVAL; 46458c2ecf20Sopenharmony_ci } 46468c2ecf20Sopenharmony_ci 46478c2ecf20Sopenharmony_ci if (!qed_iov_is_valid_vfid(&cdev->hwfns[0], vfid, true, true)) { 46488c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_IOV, 46498c2ecf20Sopenharmony_ci "Cannot set VF[%d] MAC (VF is not active)\n", vfid); 46508c2ecf20Sopenharmony_ci return -EINVAL; 46518c2ecf20Sopenharmony_ci } 46528c2ecf20Sopenharmony_ci 46538c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 46548c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = &cdev->hwfns[i]; 46558c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf_info; 46568c2ecf20Sopenharmony_ci 46578c2ecf20Sopenharmony_ci vf_info = qed_iov_get_public_vf_info(hwfn, vfid, true); 46588c2ecf20Sopenharmony_ci if (!vf_info) 46598c2ecf20Sopenharmony_ci continue; 46608c2ecf20Sopenharmony_ci 46618c2ecf20Sopenharmony_ci /* Set the forced vlan, and schedule the IOV task */ 46628c2ecf20Sopenharmony_ci vf_info->forced_vlan = vid; 46638c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_SET_UNICAST_FILTER_FLAG); 46648c2ecf20Sopenharmony_ci } 46658c2ecf20Sopenharmony_ci 46668c2ecf20Sopenharmony_ci return 0; 46678c2ecf20Sopenharmony_ci} 46688c2ecf20Sopenharmony_ci 46698c2ecf20Sopenharmony_cistatic int qed_get_vf_config(struct qed_dev *cdev, 46708c2ecf20Sopenharmony_ci int vf_id, struct ifla_vf_info *ivi) 46718c2ecf20Sopenharmony_ci{ 46728c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 46738c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf_info; 46748c2ecf20Sopenharmony_ci struct qed_mcp_link_state link; 46758c2ecf20Sopenharmony_ci u32 tx_rate; 46768c2ecf20Sopenharmony_ci int ret; 46778c2ecf20Sopenharmony_ci 46788c2ecf20Sopenharmony_ci /* Sanitize request */ 46798c2ecf20Sopenharmony_ci if (IS_VF(cdev)) 46808c2ecf20Sopenharmony_ci return -EINVAL; 46818c2ecf20Sopenharmony_ci 46828c2ecf20Sopenharmony_ci if (!qed_iov_is_valid_vfid(&cdev->hwfns[0], vf_id, true, false)) { 46838c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_IOV, 46848c2ecf20Sopenharmony_ci "VF index [%d] isn't active\n", vf_id); 46858c2ecf20Sopenharmony_ci return -EINVAL; 46868c2ecf20Sopenharmony_ci } 46878c2ecf20Sopenharmony_ci 46888c2ecf20Sopenharmony_ci vf_info = qed_iov_get_public_vf_info(hwfn, vf_id, true); 46898c2ecf20Sopenharmony_ci 46908c2ecf20Sopenharmony_ci ret = qed_iov_get_link(hwfn, vf_id, NULL, &link, NULL); 46918c2ecf20Sopenharmony_ci if (ret) 46928c2ecf20Sopenharmony_ci return ret; 46938c2ecf20Sopenharmony_ci 46948c2ecf20Sopenharmony_ci /* Fill information about VF */ 46958c2ecf20Sopenharmony_ci ivi->vf = vf_id; 46968c2ecf20Sopenharmony_ci 46978c2ecf20Sopenharmony_ci if (is_valid_ether_addr(vf_info->forced_mac)) 46988c2ecf20Sopenharmony_ci ether_addr_copy(ivi->mac, vf_info->forced_mac); 46998c2ecf20Sopenharmony_ci else 47008c2ecf20Sopenharmony_ci ether_addr_copy(ivi->mac, vf_info->mac); 47018c2ecf20Sopenharmony_ci 47028c2ecf20Sopenharmony_ci ivi->vlan = vf_info->forced_vlan; 47038c2ecf20Sopenharmony_ci ivi->spoofchk = qed_iov_spoofchk_get(hwfn, vf_id); 47048c2ecf20Sopenharmony_ci ivi->linkstate = vf_info->link_state; 47058c2ecf20Sopenharmony_ci tx_rate = vf_info->tx_rate; 47068c2ecf20Sopenharmony_ci ivi->max_tx_rate = tx_rate ? tx_rate : link.speed; 47078c2ecf20Sopenharmony_ci ivi->min_tx_rate = qed_iov_get_vf_min_rate(hwfn, vf_id); 47088c2ecf20Sopenharmony_ci ivi->trusted = vf_info->is_trusted_request; 47098c2ecf20Sopenharmony_ci 47108c2ecf20Sopenharmony_ci return 0; 47118c2ecf20Sopenharmony_ci} 47128c2ecf20Sopenharmony_ci 47138c2ecf20Sopenharmony_civoid qed_inform_vf_link_state(struct qed_hwfn *hwfn) 47148c2ecf20Sopenharmony_ci{ 47158c2ecf20Sopenharmony_ci struct qed_hwfn *lead_hwfn = QED_LEADING_HWFN(hwfn->cdev); 47168c2ecf20Sopenharmony_ci struct qed_mcp_link_capabilities caps; 47178c2ecf20Sopenharmony_ci struct qed_mcp_link_params params; 47188c2ecf20Sopenharmony_ci struct qed_mcp_link_state link; 47198c2ecf20Sopenharmony_ci int i; 47208c2ecf20Sopenharmony_ci 47218c2ecf20Sopenharmony_ci if (!hwfn->pf_iov_info) 47228c2ecf20Sopenharmony_ci return; 47238c2ecf20Sopenharmony_ci 47248c2ecf20Sopenharmony_ci /* Update bulletin of all future possible VFs with link configuration */ 47258c2ecf20Sopenharmony_ci for (i = 0; i < hwfn->cdev->p_iov_info->total_vfs; i++) { 47268c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf_info; 47278c2ecf20Sopenharmony_ci 47288c2ecf20Sopenharmony_ci vf_info = qed_iov_get_public_vf_info(hwfn, i, false); 47298c2ecf20Sopenharmony_ci if (!vf_info) 47308c2ecf20Sopenharmony_ci continue; 47318c2ecf20Sopenharmony_ci 47328c2ecf20Sopenharmony_ci /* Only hwfn0 is actually interested in the link speed. 47338c2ecf20Sopenharmony_ci * But since only it would receive an MFW indication of link, 47348c2ecf20Sopenharmony_ci * need to take configuration from it - otherwise things like 47358c2ecf20Sopenharmony_ci * rate limiting for hwfn1 VF would not work. 47368c2ecf20Sopenharmony_ci */ 47378c2ecf20Sopenharmony_ci memcpy(¶ms, qed_mcp_get_link_params(lead_hwfn), 47388c2ecf20Sopenharmony_ci sizeof(params)); 47398c2ecf20Sopenharmony_ci memcpy(&link, qed_mcp_get_link_state(lead_hwfn), sizeof(link)); 47408c2ecf20Sopenharmony_ci memcpy(&caps, qed_mcp_get_link_capabilities(lead_hwfn), 47418c2ecf20Sopenharmony_ci sizeof(caps)); 47428c2ecf20Sopenharmony_ci 47438c2ecf20Sopenharmony_ci /* Modify link according to the VF's configured link state */ 47448c2ecf20Sopenharmony_ci switch (vf_info->link_state) { 47458c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_DISABLE: 47468c2ecf20Sopenharmony_ci link.link_up = false; 47478c2ecf20Sopenharmony_ci break; 47488c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_ENABLE: 47498c2ecf20Sopenharmony_ci link.link_up = true; 47508c2ecf20Sopenharmony_ci /* Set speed according to maximum supported by HW. 47518c2ecf20Sopenharmony_ci * that is 40G for regular devices and 100G for CMT 47528c2ecf20Sopenharmony_ci * mode devices. 47538c2ecf20Sopenharmony_ci */ 47548c2ecf20Sopenharmony_ci link.speed = (hwfn->cdev->num_hwfns > 1) ? 47558c2ecf20Sopenharmony_ci 100000 : 40000; 47568c2ecf20Sopenharmony_ci default: 47578c2ecf20Sopenharmony_ci /* In auto mode pass PF link image to VF */ 47588c2ecf20Sopenharmony_ci break; 47598c2ecf20Sopenharmony_ci } 47608c2ecf20Sopenharmony_ci 47618c2ecf20Sopenharmony_ci if (link.link_up && vf_info->tx_rate) { 47628c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 47638c2ecf20Sopenharmony_ci int rate; 47648c2ecf20Sopenharmony_ci 47658c2ecf20Sopenharmony_ci rate = min_t(int, vf_info->tx_rate, link.speed); 47668c2ecf20Sopenharmony_ci 47678c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 47688c2ecf20Sopenharmony_ci if (!ptt) { 47698c2ecf20Sopenharmony_ci DP_NOTICE(hwfn, "Failed to acquire PTT\n"); 47708c2ecf20Sopenharmony_ci return; 47718c2ecf20Sopenharmony_ci } 47728c2ecf20Sopenharmony_ci 47738c2ecf20Sopenharmony_ci if (!qed_iov_configure_tx_rate(hwfn, ptt, i, rate)) { 47748c2ecf20Sopenharmony_ci vf_info->tx_rate = rate; 47758c2ecf20Sopenharmony_ci link.speed = rate; 47768c2ecf20Sopenharmony_ci } 47778c2ecf20Sopenharmony_ci 47788c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 47798c2ecf20Sopenharmony_ci } 47808c2ecf20Sopenharmony_ci 47818c2ecf20Sopenharmony_ci qed_iov_set_link(hwfn, i, ¶ms, &link, &caps); 47828c2ecf20Sopenharmony_ci } 47838c2ecf20Sopenharmony_ci 47848c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); 47858c2ecf20Sopenharmony_ci} 47868c2ecf20Sopenharmony_ci 47878c2ecf20Sopenharmony_cistatic int qed_set_vf_link_state(struct qed_dev *cdev, 47888c2ecf20Sopenharmony_ci int vf_id, int link_state) 47898c2ecf20Sopenharmony_ci{ 47908c2ecf20Sopenharmony_ci int i; 47918c2ecf20Sopenharmony_ci 47928c2ecf20Sopenharmony_ci /* Sanitize request */ 47938c2ecf20Sopenharmony_ci if (IS_VF(cdev)) 47948c2ecf20Sopenharmony_ci return -EINVAL; 47958c2ecf20Sopenharmony_ci 47968c2ecf20Sopenharmony_ci if (!qed_iov_is_valid_vfid(&cdev->hwfns[0], vf_id, true, true)) { 47978c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_IOV, 47988c2ecf20Sopenharmony_ci "VF index [%d] isn't active\n", vf_id); 47998c2ecf20Sopenharmony_ci return -EINVAL; 48008c2ecf20Sopenharmony_ci } 48018c2ecf20Sopenharmony_ci 48028c2ecf20Sopenharmony_ci /* Handle configuration of link state */ 48038c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 48048c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = &cdev->hwfns[i]; 48058c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf; 48068c2ecf20Sopenharmony_ci 48078c2ecf20Sopenharmony_ci vf = qed_iov_get_public_vf_info(hwfn, vf_id, true); 48088c2ecf20Sopenharmony_ci if (!vf) 48098c2ecf20Sopenharmony_ci continue; 48108c2ecf20Sopenharmony_ci 48118c2ecf20Sopenharmony_ci if (vf->link_state == link_state) 48128c2ecf20Sopenharmony_ci continue; 48138c2ecf20Sopenharmony_ci 48148c2ecf20Sopenharmony_ci vf->link_state = link_state; 48158c2ecf20Sopenharmony_ci qed_inform_vf_link_state(&cdev->hwfns[i]); 48168c2ecf20Sopenharmony_ci } 48178c2ecf20Sopenharmony_ci 48188c2ecf20Sopenharmony_ci return 0; 48198c2ecf20Sopenharmony_ci} 48208c2ecf20Sopenharmony_ci 48218c2ecf20Sopenharmony_cistatic int qed_spoof_configure(struct qed_dev *cdev, int vfid, bool val) 48228c2ecf20Sopenharmony_ci{ 48238c2ecf20Sopenharmony_ci int i, rc = -EINVAL; 48248c2ecf20Sopenharmony_ci 48258c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 48268c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 48278c2ecf20Sopenharmony_ci 48288c2ecf20Sopenharmony_ci rc = qed_iov_spoofchk_set(p_hwfn, vfid, val); 48298c2ecf20Sopenharmony_ci if (rc) 48308c2ecf20Sopenharmony_ci break; 48318c2ecf20Sopenharmony_ci } 48328c2ecf20Sopenharmony_ci 48338c2ecf20Sopenharmony_ci return rc; 48348c2ecf20Sopenharmony_ci} 48358c2ecf20Sopenharmony_ci 48368c2ecf20Sopenharmony_cistatic int qed_configure_max_vf_rate(struct qed_dev *cdev, int vfid, int rate) 48378c2ecf20Sopenharmony_ci{ 48388c2ecf20Sopenharmony_ci int i; 48398c2ecf20Sopenharmony_ci 48408c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 48418c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 48428c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf; 48438c2ecf20Sopenharmony_ci 48448c2ecf20Sopenharmony_ci if (!qed_iov_pf_sanity_check(p_hwfn, vfid)) { 48458c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 48468c2ecf20Sopenharmony_ci "SR-IOV sanity check failed, can't set tx rate\n"); 48478c2ecf20Sopenharmony_ci return -EINVAL; 48488c2ecf20Sopenharmony_ci } 48498c2ecf20Sopenharmony_ci 48508c2ecf20Sopenharmony_ci vf = qed_iov_get_public_vf_info(p_hwfn, vfid, true); 48518c2ecf20Sopenharmony_ci 48528c2ecf20Sopenharmony_ci vf->tx_rate = rate; 48538c2ecf20Sopenharmony_ci 48548c2ecf20Sopenharmony_ci qed_inform_vf_link_state(p_hwfn); 48558c2ecf20Sopenharmony_ci } 48568c2ecf20Sopenharmony_ci 48578c2ecf20Sopenharmony_ci return 0; 48588c2ecf20Sopenharmony_ci} 48598c2ecf20Sopenharmony_ci 48608c2ecf20Sopenharmony_cistatic int qed_set_vf_rate(struct qed_dev *cdev, 48618c2ecf20Sopenharmony_ci int vfid, u32 min_rate, u32 max_rate) 48628c2ecf20Sopenharmony_ci{ 48638c2ecf20Sopenharmony_ci int rc_min = 0, rc_max = 0; 48648c2ecf20Sopenharmony_ci 48658c2ecf20Sopenharmony_ci if (max_rate) 48668c2ecf20Sopenharmony_ci rc_max = qed_configure_max_vf_rate(cdev, vfid, max_rate); 48678c2ecf20Sopenharmony_ci 48688c2ecf20Sopenharmony_ci if (min_rate) 48698c2ecf20Sopenharmony_ci rc_min = qed_iov_configure_min_tx_rate(cdev, vfid, min_rate); 48708c2ecf20Sopenharmony_ci 48718c2ecf20Sopenharmony_ci if (rc_max | rc_min) 48728c2ecf20Sopenharmony_ci return -EINVAL; 48738c2ecf20Sopenharmony_ci 48748c2ecf20Sopenharmony_ci return 0; 48758c2ecf20Sopenharmony_ci} 48768c2ecf20Sopenharmony_ci 48778c2ecf20Sopenharmony_cistatic int qed_set_vf_trust(struct qed_dev *cdev, int vfid, bool trust) 48788c2ecf20Sopenharmony_ci{ 48798c2ecf20Sopenharmony_ci int i; 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 48828c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = &cdev->hwfns[i]; 48838c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf; 48848c2ecf20Sopenharmony_ci 48858c2ecf20Sopenharmony_ci if (!qed_iov_pf_sanity_check(hwfn, vfid)) { 48868c2ecf20Sopenharmony_ci DP_NOTICE(hwfn, 48878c2ecf20Sopenharmony_ci "SR-IOV sanity check failed, can't set trust\n"); 48888c2ecf20Sopenharmony_ci return -EINVAL; 48898c2ecf20Sopenharmony_ci } 48908c2ecf20Sopenharmony_ci 48918c2ecf20Sopenharmony_ci vf = qed_iov_get_public_vf_info(hwfn, vfid, true); 48928c2ecf20Sopenharmony_ci 48938c2ecf20Sopenharmony_ci if (vf->is_trusted_request == trust) 48948c2ecf20Sopenharmony_ci return 0; 48958c2ecf20Sopenharmony_ci vf->is_trusted_request = trust; 48968c2ecf20Sopenharmony_ci 48978c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_TRUST_FLAG); 48988c2ecf20Sopenharmony_ci } 48998c2ecf20Sopenharmony_ci 49008c2ecf20Sopenharmony_ci return 0; 49018c2ecf20Sopenharmony_ci} 49028c2ecf20Sopenharmony_ci 49038c2ecf20Sopenharmony_cistatic void qed_handle_vf_msg(struct qed_hwfn *hwfn) 49048c2ecf20Sopenharmony_ci{ 49058c2ecf20Sopenharmony_ci u64 events[QED_VF_ARRAY_LENGTH]; 49068c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 49078c2ecf20Sopenharmony_ci int i; 49088c2ecf20Sopenharmony_ci 49098c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 49108c2ecf20Sopenharmony_ci if (!ptt) { 49118c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn, QED_MSG_IOV, 49128c2ecf20Sopenharmony_ci "Can't acquire PTT; re-scheduling\n"); 49138c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_MSG_FLAG); 49148c2ecf20Sopenharmony_ci return; 49158c2ecf20Sopenharmony_ci } 49168c2ecf20Sopenharmony_ci 49178c2ecf20Sopenharmony_ci qed_iov_pf_get_pending_events(hwfn, events); 49188c2ecf20Sopenharmony_ci 49198c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn, QED_MSG_IOV, 49208c2ecf20Sopenharmony_ci "Event mask of VF events: 0x%llx 0x%llx 0x%llx\n", 49218c2ecf20Sopenharmony_ci events[0], events[1], events[2]); 49228c2ecf20Sopenharmony_ci 49238c2ecf20Sopenharmony_ci qed_for_each_vf(hwfn, i) { 49248c2ecf20Sopenharmony_ci /* Skip VFs with no pending messages */ 49258c2ecf20Sopenharmony_ci if (!(events[i / 64] & (1ULL << (i % 64)))) 49268c2ecf20Sopenharmony_ci continue; 49278c2ecf20Sopenharmony_ci 49288c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn, QED_MSG_IOV, 49298c2ecf20Sopenharmony_ci "Handling VF message from VF 0x%02x [Abs 0x%02x]\n", 49308c2ecf20Sopenharmony_ci i, hwfn->cdev->p_iov_info->first_vf_in_pf + i); 49318c2ecf20Sopenharmony_ci 49328c2ecf20Sopenharmony_ci /* Copy VF's message to PF's request buffer for that VF */ 49338c2ecf20Sopenharmony_ci if (qed_iov_copy_vf_msg(hwfn, ptt, i)) 49348c2ecf20Sopenharmony_ci continue; 49358c2ecf20Sopenharmony_ci 49368c2ecf20Sopenharmony_ci qed_iov_process_mbx_req(hwfn, ptt, i); 49378c2ecf20Sopenharmony_ci } 49388c2ecf20Sopenharmony_ci 49398c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 49408c2ecf20Sopenharmony_ci} 49418c2ecf20Sopenharmony_ci 49428c2ecf20Sopenharmony_cistatic bool qed_pf_validate_req_vf_mac(struct qed_hwfn *hwfn, 49438c2ecf20Sopenharmony_ci u8 *mac, 49448c2ecf20Sopenharmony_ci struct qed_public_vf_info *info) 49458c2ecf20Sopenharmony_ci{ 49468c2ecf20Sopenharmony_ci if (info->is_trusted_configured) { 49478c2ecf20Sopenharmony_ci if (is_valid_ether_addr(info->mac) && 49488c2ecf20Sopenharmony_ci (!mac || !ether_addr_equal(mac, info->mac))) 49498c2ecf20Sopenharmony_ci return true; 49508c2ecf20Sopenharmony_ci } else { 49518c2ecf20Sopenharmony_ci if (is_valid_ether_addr(info->forced_mac) && 49528c2ecf20Sopenharmony_ci (!mac || !ether_addr_equal(mac, info->forced_mac))) 49538c2ecf20Sopenharmony_ci return true; 49548c2ecf20Sopenharmony_ci } 49558c2ecf20Sopenharmony_ci 49568c2ecf20Sopenharmony_ci return false; 49578c2ecf20Sopenharmony_ci} 49588c2ecf20Sopenharmony_ci 49598c2ecf20Sopenharmony_cistatic void qed_set_bulletin_mac(struct qed_hwfn *hwfn, 49608c2ecf20Sopenharmony_ci struct qed_public_vf_info *info, 49618c2ecf20Sopenharmony_ci int vfid) 49628c2ecf20Sopenharmony_ci{ 49638c2ecf20Sopenharmony_ci if (info->is_trusted_configured) 49648c2ecf20Sopenharmony_ci qed_iov_bulletin_set_mac(hwfn, info->mac, vfid); 49658c2ecf20Sopenharmony_ci else 49668c2ecf20Sopenharmony_ci qed_iov_bulletin_set_forced_mac(hwfn, info->forced_mac, vfid); 49678c2ecf20Sopenharmony_ci} 49688c2ecf20Sopenharmony_ci 49698c2ecf20Sopenharmony_cistatic void qed_handle_pf_set_vf_unicast(struct qed_hwfn *hwfn) 49708c2ecf20Sopenharmony_ci{ 49718c2ecf20Sopenharmony_ci int i; 49728c2ecf20Sopenharmony_ci 49738c2ecf20Sopenharmony_ci qed_for_each_vf(hwfn, i) { 49748c2ecf20Sopenharmony_ci struct qed_public_vf_info *info; 49758c2ecf20Sopenharmony_ci bool update = false; 49768c2ecf20Sopenharmony_ci u8 *mac; 49778c2ecf20Sopenharmony_ci 49788c2ecf20Sopenharmony_ci info = qed_iov_get_public_vf_info(hwfn, i, true); 49798c2ecf20Sopenharmony_ci if (!info) 49808c2ecf20Sopenharmony_ci continue; 49818c2ecf20Sopenharmony_ci 49828c2ecf20Sopenharmony_ci /* Update data on bulletin board */ 49838c2ecf20Sopenharmony_ci if (info->is_trusted_configured) 49848c2ecf20Sopenharmony_ci mac = qed_iov_bulletin_get_mac(hwfn, i); 49858c2ecf20Sopenharmony_ci else 49868c2ecf20Sopenharmony_ci mac = qed_iov_bulletin_get_forced_mac(hwfn, i); 49878c2ecf20Sopenharmony_ci 49888c2ecf20Sopenharmony_ci if (qed_pf_validate_req_vf_mac(hwfn, mac, info)) { 49898c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn, 49908c2ecf20Sopenharmony_ci QED_MSG_IOV, 49918c2ecf20Sopenharmony_ci "Handling PF setting of VF MAC to VF 0x%02x [Abs 0x%02x]\n", 49928c2ecf20Sopenharmony_ci i, 49938c2ecf20Sopenharmony_ci hwfn->cdev->p_iov_info->first_vf_in_pf + i); 49948c2ecf20Sopenharmony_ci 49958c2ecf20Sopenharmony_ci /* Update bulletin board with MAC */ 49968c2ecf20Sopenharmony_ci qed_set_bulletin_mac(hwfn, info, i); 49978c2ecf20Sopenharmony_ci update = true; 49988c2ecf20Sopenharmony_ci } 49998c2ecf20Sopenharmony_ci 50008c2ecf20Sopenharmony_ci if (qed_iov_bulletin_get_forced_vlan(hwfn, i) ^ 50018c2ecf20Sopenharmony_ci info->forced_vlan) { 50028c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn, 50038c2ecf20Sopenharmony_ci QED_MSG_IOV, 50048c2ecf20Sopenharmony_ci "Handling PF setting of pvid [0x%04x] to VF 0x%02x [Abs 0x%02x]\n", 50058c2ecf20Sopenharmony_ci info->forced_vlan, 50068c2ecf20Sopenharmony_ci i, 50078c2ecf20Sopenharmony_ci hwfn->cdev->p_iov_info->first_vf_in_pf + i); 50088c2ecf20Sopenharmony_ci qed_iov_bulletin_set_forced_vlan(hwfn, 50098c2ecf20Sopenharmony_ci info->forced_vlan, i); 50108c2ecf20Sopenharmony_ci update = true; 50118c2ecf20Sopenharmony_ci } 50128c2ecf20Sopenharmony_ci 50138c2ecf20Sopenharmony_ci if (update) 50148c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); 50158c2ecf20Sopenharmony_ci } 50168c2ecf20Sopenharmony_ci} 50178c2ecf20Sopenharmony_ci 50188c2ecf20Sopenharmony_cistatic void qed_handle_bulletin_post(struct qed_hwfn *hwfn) 50198c2ecf20Sopenharmony_ci{ 50208c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 50218c2ecf20Sopenharmony_ci int i; 50228c2ecf20Sopenharmony_ci 50238c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 50248c2ecf20Sopenharmony_ci if (!ptt) { 50258c2ecf20Sopenharmony_ci DP_NOTICE(hwfn, "Failed allocating a ptt entry\n"); 50268c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); 50278c2ecf20Sopenharmony_ci return; 50288c2ecf20Sopenharmony_ci } 50298c2ecf20Sopenharmony_ci 50308c2ecf20Sopenharmony_ci qed_for_each_vf(hwfn, i) 50318c2ecf20Sopenharmony_ci qed_iov_post_vf_bulletin(hwfn, i, ptt); 50328c2ecf20Sopenharmony_ci 50338c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 50348c2ecf20Sopenharmony_ci} 50358c2ecf20Sopenharmony_ci 50368c2ecf20Sopenharmony_cistatic void qed_update_mac_for_vf_trust_change(struct qed_hwfn *hwfn, int vf_id) 50378c2ecf20Sopenharmony_ci{ 50388c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf_info; 50398c2ecf20Sopenharmony_ci struct qed_vf_info *vf; 50408c2ecf20Sopenharmony_ci u8 *force_mac; 50418c2ecf20Sopenharmony_ci int i; 50428c2ecf20Sopenharmony_ci 50438c2ecf20Sopenharmony_ci vf_info = qed_iov_get_public_vf_info(hwfn, vf_id, true); 50448c2ecf20Sopenharmony_ci vf = qed_iov_get_vf_info(hwfn, vf_id, true); 50458c2ecf20Sopenharmony_ci 50468c2ecf20Sopenharmony_ci if (!vf_info || !vf) 50478c2ecf20Sopenharmony_ci return; 50488c2ecf20Sopenharmony_ci 50498c2ecf20Sopenharmony_ci /* Force MAC converted to generic MAC in case of VF trust on */ 50508c2ecf20Sopenharmony_ci if (vf_info->is_trusted_configured && 50518c2ecf20Sopenharmony_ci (vf->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED))) { 50528c2ecf20Sopenharmony_ci force_mac = qed_iov_bulletin_get_forced_mac(hwfn, vf_id); 50538c2ecf20Sopenharmony_ci 50548c2ecf20Sopenharmony_ci if (force_mac) { 50558c2ecf20Sopenharmony_ci /* Clear existing shadow copy of MAC to have a clean 50568c2ecf20Sopenharmony_ci * slate. 50578c2ecf20Sopenharmony_ci */ 50588c2ecf20Sopenharmony_ci for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) { 50598c2ecf20Sopenharmony_ci if (ether_addr_equal(vf->shadow_config.macs[i], 50608c2ecf20Sopenharmony_ci vf_info->mac)) { 50618c2ecf20Sopenharmony_ci eth_zero_addr(vf->shadow_config.macs[i]); 50628c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn, QED_MSG_IOV, 50638c2ecf20Sopenharmony_ci "Shadow MAC %pM removed for VF 0x%02x, VF trust mode is ON\n", 50648c2ecf20Sopenharmony_ci vf_info->mac, vf_id); 50658c2ecf20Sopenharmony_ci break; 50668c2ecf20Sopenharmony_ci } 50678c2ecf20Sopenharmony_ci } 50688c2ecf20Sopenharmony_ci 50698c2ecf20Sopenharmony_ci ether_addr_copy(vf_info->mac, force_mac); 50708c2ecf20Sopenharmony_ci eth_zero_addr(vf_info->forced_mac); 50718c2ecf20Sopenharmony_ci vf->bulletin.p_virt->valid_bitmap &= 50728c2ecf20Sopenharmony_ci ~BIT(MAC_ADDR_FORCED); 50738c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); 50748c2ecf20Sopenharmony_ci } 50758c2ecf20Sopenharmony_ci } 50768c2ecf20Sopenharmony_ci 50778c2ecf20Sopenharmony_ci /* Update shadow copy with VF MAC when trust mode is turned off */ 50788c2ecf20Sopenharmony_ci if (!vf_info->is_trusted_configured) { 50798c2ecf20Sopenharmony_ci u8 empty_mac[ETH_ALEN]; 50808c2ecf20Sopenharmony_ci 50818c2ecf20Sopenharmony_ci eth_zero_addr(empty_mac); 50828c2ecf20Sopenharmony_ci for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) { 50838c2ecf20Sopenharmony_ci if (ether_addr_equal(vf->shadow_config.macs[i], 50848c2ecf20Sopenharmony_ci empty_mac)) { 50858c2ecf20Sopenharmony_ci ether_addr_copy(vf->shadow_config.macs[i], 50868c2ecf20Sopenharmony_ci vf_info->mac); 50878c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn, QED_MSG_IOV, 50888c2ecf20Sopenharmony_ci "Shadow is updated with %pM for VF 0x%02x, VF trust mode is OFF\n", 50898c2ecf20Sopenharmony_ci vf_info->mac, vf_id); 50908c2ecf20Sopenharmony_ci break; 50918c2ecf20Sopenharmony_ci } 50928c2ecf20Sopenharmony_ci } 50938c2ecf20Sopenharmony_ci /* Clear bulletin when trust mode is turned off, 50948c2ecf20Sopenharmony_ci * to have a clean slate for next (normal) operations. 50958c2ecf20Sopenharmony_ci */ 50968c2ecf20Sopenharmony_ci qed_iov_bulletin_set_mac(hwfn, empty_mac, vf_id); 50978c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); 50988c2ecf20Sopenharmony_ci } 50998c2ecf20Sopenharmony_ci} 51008c2ecf20Sopenharmony_ci 51018c2ecf20Sopenharmony_cistatic void qed_iov_handle_trust_change(struct qed_hwfn *hwfn) 51028c2ecf20Sopenharmony_ci{ 51038c2ecf20Sopenharmony_ci struct qed_sp_vport_update_params params; 51048c2ecf20Sopenharmony_ci struct qed_filter_accept_flags *flags; 51058c2ecf20Sopenharmony_ci struct qed_public_vf_info *vf_info; 51068c2ecf20Sopenharmony_ci struct qed_vf_info *vf; 51078c2ecf20Sopenharmony_ci u8 mask; 51088c2ecf20Sopenharmony_ci int i; 51098c2ecf20Sopenharmony_ci 51108c2ecf20Sopenharmony_ci mask = QED_ACCEPT_UCAST_UNMATCHED | QED_ACCEPT_MCAST_UNMATCHED; 51118c2ecf20Sopenharmony_ci flags = ¶ms.accept_flags; 51128c2ecf20Sopenharmony_ci 51138c2ecf20Sopenharmony_ci qed_for_each_vf(hwfn, i) { 51148c2ecf20Sopenharmony_ci /* Need to make sure current requested configuration didn't 51158c2ecf20Sopenharmony_ci * flip so that we'll end up configuring something that's not 51168c2ecf20Sopenharmony_ci * needed. 51178c2ecf20Sopenharmony_ci */ 51188c2ecf20Sopenharmony_ci vf_info = qed_iov_get_public_vf_info(hwfn, i, true); 51198c2ecf20Sopenharmony_ci if (vf_info->is_trusted_configured == 51208c2ecf20Sopenharmony_ci vf_info->is_trusted_request) 51218c2ecf20Sopenharmony_ci continue; 51228c2ecf20Sopenharmony_ci vf_info->is_trusted_configured = vf_info->is_trusted_request; 51238c2ecf20Sopenharmony_ci 51248c2ecf20Sopenharmony_ci /* Handle forced MAC mode */ 51258c2ecf20Sopenharmony_ci qed_update_mac_for_vf_trust_change(hwfn, i); 51268c2ecf20Sopenharmony_ci 51278c2ecf20Sopenharmony_ci /* Validate that the VF has a configured vport */ 51288c2ecf20Sopenharmony_ci vf = qed_iov_get_vf_info(hwfn, i, true); 51298c2ecf20Sopenharmony_ci if (!vf || !vf->vport_instance) 51308c2ecf20Sopenharmony_ci continue; 51318c2ecf20Sopenharmony_ci 51328c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 51338c2ecf20Sopenharmony_ci params.opaque_fid = vf->opaque_fid; 51348c2ecf20Sopenharmony_ci params.vport_id = vf->vport_id; 51358c2ecf20Sopenharmony_ci 51368c2ecf20Sopenharmony_ci params.update_ctl_frame_check = 1; 51378c2ecf20Sopenharmony_ci params.mac_chk_en = !vf_info->is_trusted_configured; 51388c2ecf20Sopenharmony_ci params.update_accept_any_vlan_flg = 0; 51398c2ecf20Sopenharmony_ci 51408c2ecf20Sopenharmony_ci if (vf_info->accept_any_vlan && vf_info->forced_vlan) { 51418c2ecf20Sopenharmony_ci params.update_accept_any_vlan_flg = 1; 51428c2ecf20Sopenharmony_ci params.accept_any_vlan = vf_info->accept_any_vlan; 51438c2ecf20Sopenharmony_ci } 51448c2ecf20Sopenharmony_ci 51458c2ecf20Sopenharmony_ci if (vf_info->rx_accept_mode & mask) { 51468c2ecf20Sopenharmony_ci flags->update_rx_mode_config = 1; 51478c2ecf20Sopenharmony_ci flags->rx_accept_filter = vf_info->rx_accept_mode; 51488c2ecf20Sopenharmony_ci } 51498c2ecf20Sopenharmony_ci 51508c2ecf20Sopenharmony_ci if (vf_info->tx_accept_mode & mask) { 51518c2ecf20Sopenharmony_ci flags->update_tx_mode_config = 1; 51528c2ecf20Sopenharmony_ci flags->tx_accept_filter = vf_info->tx_accept_mode; 51538c2ecf20Sopenharmony_ci } 51548c2ecf20Sopenharmony_ci 51558c2ecf20Sopenharmony_ci /* Remove if needed; Otherwise this would set the mask */ 51568c2ecf20Sopenharmony_ci if (!vf_info->is_trusted_configured) { 51578c2ecf20Sopenharmony_ci flags->rx_accept_filter &= ~mask; 51588c2ecf20Sopenharmony_ci flags->tx_accept_filter &= ~mask; 51598c2ecf20Sopenharmony_ci params.accept_any_vlan = false; 51608c2ecf20Sopenharmony_ci } 51618c2ecf20Sopenharmony_ci 51628c2ecf20Sopenharmony_ci if (flags->update_rx_mode_config || 51638c2ecf20Sopenharmony_ci flags->update_tx_mode_config || 51648c2ecf20Sopenharmony_ci params.update_ctl_frame_check || 51658c2ecf20Sopenharmony_ci params.update_accept_any_vlan_flg) { 51668c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn, QED_MSG_IOV, 51678c2ecf20Sopenharmony_ci "vport update config for %s VF[abs 0x%x rel 0x%x]\n", 51688c2ecf20Sopenharmony_ci vf_info->is_trusted_configured ? "trusted" : "untrusted", 51698c2ecf20Sopenharmony_ci vf->abs_vf_id, vf->relative_vf_id); 51708c2ecf20Sopenharmony_ci qed_sp_vport_update(hwfn, ¶ms, 51718c2ecf20Sopenharmony_ci QED_SPQ_MODE_EBLOCK, NULL); 51728c2ecf20Sopenharmony_ci } 51738c2ecf20Sopenharmony_ci } 51748c2ecf20Sopenharmony_ci} 51758c2ecf20Sopenharmony_ci 51768c2ecf20Sopenharmony_cistatic void qed_iov_pf_task(struct work_struct *work) 51778c2ecf20Sopenharmony_ci 51788c2ecf20Sopenharmony_ci{ 51798c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn, 51808c2ecf20Sopenharmony_ci iov_task.work); 51818c2ecf20Sopenharmony_ci int rc; 51828c2ecf20Sopenharmony_ci 51838c2ecf20Sopenharmony_ci if (test_and_clear_bit(QED_IOV_WQ_STOP_WQ_FLAG, &hwfn->iov_task_flags)) 51848c2ecf20Sopenharmony_ci return; 51858c2ecf20Sopenharmony_ci 51868c2ecf20Sopenharmony_ci if (test_and_clear_bit(QED_IOV_WQ_FLR_FLAG, &hwfn->iov_task_flags)) { 51878c2ecf20Sopenharmony_ci struct qed_ptt *ptt = qed_ptt_acquire(hwfn); 51888c2ecf20Sopenharmony_ci 51898c2ecf20Sopenharmony_ci if (!ptt) { 51908c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_FLR_FLAG); 51918c2ecf20Sopenharmony_ci return; 51928c2ecf20Sopenharmony_ci } 51938c2ecf20Sopenharmony_ci 51948c2ecf20Sopenharmony_ci rc = qed_iov_vf_flr_cleanup(hwfn, ptt); 51958c2ecf20Sopenharmony_ci if (rc) 51968c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_FLR_FLAG); 51978c2ecf20Sopenharmony_ci 51988c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 51998c2ecf20Sopenharmony_ci } 52008c2ecf20Sopenharmony_ci 52018c2ecf20Sopenharmony_ci if (test_and_clear_bit(QED_IOV_WQ_MSG_FLAG, &hwfn->iov_task_flags)) 52028c2ecf20Sopenharmony_ci qed_handle_vf_msg(hwfn); 52038c2ecf20Sopenharmony_ci 52048c2ecf20Sopenharmony_ci if (test_and_clear_bit(QED_IOV_WQ_SET_UNICAST_FILTER_FLAG, 52058c2ecf20Sopenharmony_ci &hwfn->iov_task_flags)) 52068c2ecf20Sopenharmony_ci qed_handle_pf_set_vf_unicast(hwfn); 52078c2ecf20Sopenharmony_ci 52088c2ecf20Sopenharmony_ci if (test_and_clear_bit(QED_IOV_WQ_BULLETIN_UPDATE_FLAG, 52098c2ecf20Sopenharmony_ci &hwfn->iov_task_flags)) 52108c2ecf20Sopenharmony_ci qed_handle_bulletin_post(hwfn); 52118c2ecf20Sopenharmony_ci 52128c2ecf20Sopenharmony_ci if (test_and_clear_bit(QED_IOV_WQ_TRUST_FLAG, &hwfn->iov_task_flags)) 52138c2ecf20Sopenharmony_ci qed_iov_handle_trust_change(hwfn); 52148c2ecf20Sopenharmony_ci} 52158c2ecf20Sopenharmony_ci 52168c2ecf20Sopenharmony_civoid qed_iov_wq_stop(struct qed_dev *cdev, bool schedule_first) 52178c2ecf20Sopenharmony_ci{ 52188c2ecf20Sopenharmony_ci int i; 52198c2ecf20Sopenharmony_ci 52208c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 52218c2ecf20Sopenharmony_ci if (!cdev->hwfns[i].iov_wq) 52228c2ecf20Sopenharmony_ci continue; 52238c2ecf20Sopenharmony_ci 52248c2ecf20Sopenharmony_ci if (schedule_first) { 52258c2ecf20Sopenharmony_ci qed_schedule_iov(&cdev->hwfns[i], 52268c2ecf20Sopenharmony_ci QED_IOV_WQ_STOP_WQ_FLAG); 52278c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&cdev->hwfns[i].iov_task); 52288c2ecf20Sopenharmony_ci } 52298c2ecf20Sopenharmony_ci 52308c2ecf20Sopenharmony_ci flush_workqueue(cdev->hwfns[i].iov_wq); 52318c2ecf20Sopenharmony_ci destroy_workqueue(cdev->hwfns[i].iov_wq); 52328c2ecf20Sopenharmony_ci } 52338c2ecf20Sopenharmony_ci} 52348c2ecf20Sopenharmony_ci 52358c2ecf20Sopenharmony_ciint qed_iov_wq_start(struct qed_dev *cdev) 52368c2ecf20Sopenharmony_ci{ 52378c2ecf20Sopenharmony_ci char name[NAME_SIZE]; 52388c2ecf20Sopenharmony_ci int i; 52398c2ecf20Sopenharmony_ci 52408c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 52418c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 52428c2ecf20Sopenharmony_ci 52438c2ecf20Sopenharmony_ci /* PFs needs a dedicated workqueue only if they support IOV. 52448c2ecf20Sopenharmony_ci * VFs always require one. 52458c2ecf20Sopenharmony_ci */ 52468c2ecf20Sopenharmony_ci if (IS_PF(p_hwfn->cdev) && !IS_PF_SRIOV(p_hwfn)) 52478c2ecf20Sopenharmony_ci continue; 52488c2ecf20Sopenharmony_ci 52498c2ecf20Sopenharmony_ci snprintf(name, NAME_SIZE, "iov-%02x:%02x.%02x", 52508c2ecf20Sopenharmony_ci cdev->pdev->bus->number, 52518c2ecf20Sopenharmony_ci PCI_SLOT(cdev->pdev->devfn), p_hwfn->abs_pf_id); 52528c2ecf20Sopenharmony_ci 52538c2ecf20Sopenharmony_ci p_hwfn->iov_wq = create_singlethread_workqueue(name); 52548c2ecf20Sopenharmony_ci if (!p_hwfn->iov_wq) { 52558c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Cannot create iov workqueue\n"); 52568c2ecf20Sopenharmony_ci return -ENOMEM; 52578c2ecf20Sopenharmony_ci } 52588c2ecf20Sopenharmony_ci 52598c2ecf20Sopenharmony_ci if (IS_PF(cdev)) 52608c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&p_hwfn->iov_task, qed_iov_pf_task); 52618c2ecf20Sopenharmony_ci else 52628c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&p_hwfn->iov_task, qed_iov_vf_task); 52638c2ecf20Sopenharmony_ci } 52648c2ecf20Sopenharmony_ci 52658c2ecf20Sopenharmony_ci return 0; 52668c2ecf20Sopenharmony_ci} 52678c2ecf20Sopenharmony_ci 52688c2ecf20Sopenharmony_ciconst struct qed_iov_hv_ops qed_iov_ops_pass = { 52698c2ecf20Sopenharmony_ci .configure = &qed_sriov_configure, 52708c2ecf20Sopenharmony_ci .set_mac = &qed_sriov_pf_set_mac, 52718c2ecf20Sopenharmony_ci .set_vlan = &qed_sriov_pf_set_vlan, 52728c2ecf20Sopenharmony_ci .get_config = &qed_get_vf_config, 52738c2ecf20Sopenharmony_ci .set_link_state = &qed_set_vf_link_state, 52748c2ecf20Sopenharmony_ci .set_spoof = &qed_spoof_configure, 52758c2ecf20Sopenharmony_ci .set_rate = &qed_set_vf_rate, 52768c2ecf20Sopenharmony_ci .set_trust = &qed_set_vf_trust, 52778c2ecf20Sopenharmony_ci}; 5278