132a47e72SYuval Mintz /* QLogic qed NIC Driver 232a47e72SYuval Mintz * Copyright (c) 2015 QLogic Corporation 332a47e72SYuval Mintz * 432a47e72SYuval Mintz * This software is available under the terms of the GNU General Public License 532a47e72SYuval Mintz * (GPL) Version 2, available from the file COPYING in the main directory of 632a47e72SYuval Mintz * this source tree. 732a47e72SYuval Mintz */ 832a47e72SYuval Mintz 9dacd88d6SYuval Mintz #include <linux/etherdevice.h> 1036558c3dSYuval Mintz #include <linux/crc32.h> 110b55e27dSYuval Mintz #include <linux/qed/qed_iov_if.h> 121408cc1fSYuval Mintz #include "qed_cxt.h" 131408cc1fSYuval Mintz #include "qed_hsi.h" 1432a47e72SYuval Mintz #include "qed_hw.h" 151408cc1fSYuval Mintz #include "qed_init_ops.h" 1632a47e72SYuval Mintz #include "qed_int.h" 171408cc1fSYuval Mintz #include "qed_mcp.h" 1832a47e72SYuval Mintz #include "qed_reg_addr.h" 191408cc1fSYuval Mintz #include "qed_sp.h" 2032a47e72SYuval Mintz #include "qed_sriov.h" 2132a47e72SYuval Mintz #include "qed_vf.h" 2232a47e72SYuval Mintz 231408cc1fSYuval Mintz /* IOV ramrods */ 241fe614d1SYuval Mintz static int qed_sp_vf_start(struct qed_hwfn *p_hwfn, struct qed_vf_info *p_vf) 251408cc1fSYuval Mintz { 261408cc1fSYuval Mintz struct vf_start_ramrod_data *p_ramrod = NULL; 271408cc1fSYuval Mintz struct qed_spq_entry *p_ent = NULL; 281408cc1fSYuval Mintz struct qed_sp_init_data init_data; 291408cc1fSYuval Mintz int rc = -EINVAL; 301fe614d1SYuval Mintz u8 fp_minor; 311408cc1fSYuval Mintz 321408cc1fSYuval Mintz /* Get SPQ entry */ 331408cc1fSYuval Mintz memset(&init_data, 0, sizeof(init_data)); 341408cc1fSYuval Mintz init_data.cid = qed_spq_get_cid(p_hwfn); 351fe614d1SYuval Mintz init_data.opaque_fid = p_vf->opaque_fid; 361408cc1fSYuval Mintz init_data.comp_mode = QED_SPQ_MODE_EBLOCK; 371408cc1fSYuval Mintz 381408cc1fSYuval Mintz rc = qed_sp_init_request(p_hwfn, &p_ent, 391408cc1fSYuval Mintz COMMON_RAMROD_VF_START, 401408cc1fSYuval Mintz PROTOCOLID_COMMON, &init_data); 411408cc1fSYuval Mintz if (rc) 421408cc1fSYuval Mintz return rc; 431408cc1fSYuval Mintz 441408cc1fSYuval Mintz p_ramrod = &p_ent->ramrod.vf_start; 451408cc1fSYuval Mintz 461fe614d1SYuval Mintz p_ramrod->vf_id = GET_FIELD(p_vf->concrete_fid, PXP_CONCRETE_FID_VFID); 471fe614d1SYuval Mintz p_ramrod->opaque_fid = cpu_to_le16(p_vf->opaque_fid); 481408cc1fSYuval Mintz 491fe614d1SYuval Mintz switch (p_hwfn->hw_info.personality) { 501fe614d1SYuval Mintz case QED_PCI_ETH: 511408cc1fSYuval Mintz p_ramrod->personality = PERSONALITY_ETH; 521fe614d1SYuval Mintz break; 531fe614d1SYuval Mintz case QED_PCI_ETH_ROCE: 541fe614d1SYuval Mintz p_ramrod->personality = PERSONALITY_RDMA_AND_ETH; 551fe614d1SYuval Mintz break; 561fe614d1SYuval Mintz default: 571fe614d1SYuval Mintz DP_NOTICE(p_hwfn, "Unknown VF personality %d\n", 581fe614d1SYuval Mintz p_hwfn->hw_info.personality); 591fe614d1SYuval Mintz return -EINVAL; 601fe614d1SYuval Mintz } 611fe614d1SYuval Mintz 621fe614d1SYuval Mintz fp_minor = p_vf->acquire.vfdev_info.eth_fp_hsi_minor; 63a044df83SYuval Mintz if (fp_minor > ETH_HSI_VER_MINOR && 64a044df83SYuval Mintz fp_minor != ETH_HSI_VER_NO_PKT_LEN_TUNN) { 651fe614d1SYuval Mintz DP_VERBOSE(p_hwfn, 661fe614d1SYuval Mintz QED_MSG_IOV, 671fe614d1SYuval Mintz "VF [%d] - Requested fp hsi %02x.%02x which is slightly newer than PF's %02x.%02x; Configuring PFs version\n", 681fe614d1SYuval Mintz p_vf->abs_vf_id, 691fe614d1SYuval Mintz ETH_HSI_VER_MAJOR, 701fe614d1SYuval Mintz fp_minor, ETH_HSI_VER_MAJOR, ETH_HSI_VER_MINOR); 711fe614d1SYuval Mintz fp_minor = ETH_HSI_VER_MINOR; 721fe614d1SYuval Mintz } 731fe614d1SYuval Mintz 74351a4dedSYuval Mintz p_ramrod->hsi_fp_ver.major_ver_arr[ETH_VER_KEY] = ETH_HSI_VER_MAJOR; 751fe614d1SYuval Mintz p_ramrod->hsi_fp_ver.minor_ver_arr[ETH_VER_KEY] = fp_minor; 761fe614d1SYuval Mintz 771fe614d1SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 781fe614d1SYuval Mintz "VF[%d] - Starting using HSI %02x.%02x\n", 791fe614d1SYuval Mintz p_vf->abs_vf_id, ETH_HSI_VER_MAJOR, fp_minor); 801408cc1fSYuval Mintz 811408cc1fSYuval Mintz return qed_spq_post(p_hwfn, p_ent, NULL); 821408cc1fSYuval Mintz } 831408cc1fSYuval Mintz 840b55e27dSYuval Mintz static int qed_sp_vf_stop(struct qed_hwfn *p_hwfn, 850b55e27dSYuval Mintz u32 concrete_vfid, u16 opaque_vfid) 860b55e27dSYuval Mintz { 870b55e27dSYuval Mintz struct vf_stop_ramrod_data *p_ramrod = NULL; 880b55e27dSYuval Mintz struct qed_spq_entry *p_ent = NULL; 890b55e27dSYuval Mintz struct qed_sp_init_data init_data; 900b55e27dSYuval Mintz int rc = -EINVAL; 910b55e27dSYuval Mintz 920b55e27dSYuval Mintz /* Get SPQ entry */ 930b55e27dSYuval Mintz memset(&init_data, 0, sizeof(init_data)); 940b55e27dSYuval Mintz init_data.cid = qed_spq_get_cid(p_hwfn); 950b55e27dSYuval Mintz init_data.opaque_fid = opaque_vfid; 960b55e27dSYuval Mintz init_data.comp_mode = QED_SPQ_MODE_EBLOCK; 970b55e27dSYuval Mintz 980b55e27dSYuval Mintz rc = qed_sp_init_request(p_hwfn, &p_ent, 990b55e27dSYuval Mintz COMMON_RAMROD_VF_STOP, 1000b55e27dSYuval Mintz PROTOCOLID_COMMON, &init_data); 1010b55e27dSYuval Mintz if (rc) 1020b55e27dSYuval Mintz return rc; 1030b55e27dSYuval Mintz 1040b55e27dSYuval Mintz p_ramrod = &p_ent->ramrod.vf_stop; 1050b55e27dSYuval Mintz 1060b55e27dSYuval Mintz p_ramrod->vf_id = GET_FIELD(concrete_vfid, PXP_CONCRETE_FID_VFID); 1070b55e27dSYuval Mintz 1080b55e27dSYuval Mintz return qed_spq_post(p_hwfn, p_ent, NULL); 1090b55e27dSYuval Mintz } 1100b55e27dSYuval Mintz 11132a47e72SYuval Mintz bool qed_iov_is_valid_vfid(struct qed_hwfn *p_hwfn, 11232a47e72SYuval Mintz int rel_vf_id, bool b_enabled_only) 11332a47e72SYuval Mintz { 11432a47e72SYuval Mintz if (!p_hwfn->pf_iov_info) { 11532a47e72SYuval Mintz DP_NOTICE(p_hwfn->cdev, "No iov info\n"); 11632a47e72SYuval Mintz return false; 11732a47e72SYuval Mintz } 11832a47e72SYuval Mintz 11932a47e72SYuval Mintz if ((rel_vf_id >= p_hwfn->cdev->p_iov_info->total_vfs) || 12032a47e72SYuval Mintz (rel_vf_id < 0)) 12132a47e72SYuval Mintz return false; 12232a47e72SYuval Mintz 12332a47e72SYuval Mintz if ((!p_hwfn->pf_iov_info->vfs_array[rel_vf_id].b_init) && 12432a47e72SYuval Mintz b_enabled_only) 12532a47e72SYuval Mintz return false; 12632a47e72SYuval Mintz 12732a47e72SYuval Mintz return true; 12832a47e72SYuval Mintz } 12932a47e72SYuval Mintz 13037bff2b9SYuval Mintz static struct qed_vf_info *qed_iov_get_vf_info(struct qed_hwfn *p_hwfn, 13137bff2b9SYuval Mintz u16 relative_vf_id, 13237bff2b9SYuval Mintz bool b_enabled_only) 13337bff2b9SYuval Mintz { 13437bff2b9SYuval Mintz struct qed_vf_info *vf = NULL; 13537bff2b9SYuval Mintz 13637bff2b9SYuval Mintz if (!p_hwfn->pf_iov_info) { 13737bff2b9SYuval Mintz DP_NOTICE(p_hwfn->cdev, "No iov info\n"); 13837bff2b9SYuval Mintz return NULL; 13937bff2b9SYuval Mintz } 14037bff2b9SYuval Mintz 14137bff2b9SYuval Mintz if (qed_iov_is_valid_vfid(p_hwfn, relative_vf_id, b_enabled_only)) 14237bff2b9SYuval Mintz vf = &p_hwfn->pf_iov_info->vfs_array[relative_vf_id]; 14337bff2b9SYuval Mintz else 14437bff2b9SYuval Mintz DP_ERR(p_hwfn, "qed_iov_get_vf_info: VF[%d] is not enabled\n", 14537bff2b9SYuval Mintz relative_vf_id); 14637bff2b9SYuval Mintz 14737bff2b9SYuval Mintz return vf; 14837bff2b9SYuval Mintz } 14937bff2b9SYuval Mintz 15041086467SYuval Mintz static bool qed_iov_validate_rxq(struct qed_hwfn *p_hwfn, 15141086467SYuval Mintz struct qed_vf_info *p_vf, u16 rx_qid) 15241086467SYuval Mintz { 15341086467SYuval Mintz if (rx_qid >= p_vf->num_rxqs) 15441086467SYuval Mintz DP_VERBOSE(p_hwfn, 15541086467SYuval Mintz QED_MSG_IOV, 15641086467SYuval Mintz "VF[0x%02x] - can't touch Rx queue[%04x]; Only 0x%04x are allocated\n", 15741086467SYuval Mintz p_vf->abs_vf_id, rx_qid, p_vf->num_rxqs); 15841086467SYuval Mintz return rx_qid < p_vf->num_rxqs; 15941086467SYuval Mintz } 16041086467SYuval Mintz 16141086467SYuval Mintz static bool qed_iov_validate_txq(struct qed_hwfn *p_hwfn, 16241086467SYuval Mintz struct qed_vf_info *p_vf, u16 tx_qid) 16341086467SYuval Mintz { 16441086467SYuval Mintz if (tx_qid >= p_vf->num_txqs) 16541086467SYuval Mintz DP_VERBOSE(p_hwfn, 16641086467SYuval Mintz QED_MSG_IOV, 16741086467SYuval Mintz "VF[0x%02x] - can't touch Tx queue[%04x]; Only 0x%04x are allocated\n", 16841086467SYuval Mintz p_vf->abs_vf_id, tx_qid, p_vf->num_txqs); 16941086467SYuval Mintz return tx_qid < p_vf->num_txqs; 17041086467SYuval Mintz } 17141086467SYuval Mintz 17241086467SYuval Mintz static bool qed_iov_validate_sb(struct qed_hwfn *p_hwfn, 17341086467SYuval Mintz struct qed_vf_info *p_vf, u16 sb_idx) 17441086467SYuval Mintz { 17541086467SYuval Mintz int i; 17641086467SYuval Mintz 17741086467SYuval Mintz for (i = 0; i < p_vf->num_sbs; i++) 17841086467SYuval Mintz if (p_vf->igu_sbs[i] == sb_idx) 17941086467SYuval Mintz return true; 18041086467SYuval Mintz 18141086467SYuval Mintz DP_VERBOSE(p_hwfn, 18241086467SYuval Mintz QED_MSG_IOV, 18341086467SYuval Mintz "VF[0%02x] - tried using sb_idx %04x which doesn't exist as one of its 0x%02x SBs\n", 18441086467SYuval Mintz p_vf->abs_vf_id, sb_idx, p_vf->num_sbs); 18541086467SYuval Mintz 18641086467SYuval Mintz return false; 18741086467SYuval Mintz } 18841086467SYuval Mintz 18936558c3dSYuval Mintz int qed_iov_post_vf_bulletin(struct qed_hwfn *p_hwfn, 19036558c3dSYuval Mintz int vfid, struct qed_ptt *p_ptt) 19136558c3dSYuval Mintz { 19236558c3dSYuval Mintz struct qed_bulletin_content *p_bulletin; 19336558c3dSYuval Mintz int crc_size = sizeof(p_bulletin->crc); 19436558c3dSYuval Mintz struct qed_dmae_params params; 19536558c3dSYuval Mintz struct qed_vf_info *p_vf; 19636558c3dSYuval Mintz 19736558c3dSYuval Mintz p_vf = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 19836558c3dSYuval Mintz if (!p_vf) 19936558c3dSYuval Mintz return -EINVAL; 20036558c3dSYuval Mintz 20136558c3dSYuval Mintz if (!p_vf->vf_bulletin) 20236558c3dSYuval Mintz return -EINVAL; 20336558c3dSYuval Mintz 20436558c3dSYuval Mintz p_bulletin = p_vf->bulletin.p_virt; 20536558c3dSYuval Mintz 20636558c3dSYuval Mintz /* Increment bulletin board version and compute crc */ 20736558c3dSYuval Mintz p_bulletin->version++; 20836558c3dSYuval Mintz p_bulletin->crc = crc32(0, (u8 *)p_bulletin + crc_size, 20936558c3dSYuval Mintz p_vf->bulletin.size - crc_size); 21036558c3dSYuval Mintz 21136558c3dSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 21236558c3dSYuval Mintz "Posting Bulletin 0x%08x to VF[%d] (CRC 0x%08x)\n", 21336558c3dSYuval Mintz p_bulletin->version, p_vf->relative_vf_id, p_bulletin->crc); 21436558c3dSYuval Mintz 21536558c3dSYuval Mintz /* propagate bulletin board via dmae to vm memory */ 21636558c3dSYuval Mintz memset(¶ms, 0, sizeof(params)); 21736558c3dSYuval Mintz params.flags = QED_DMAE_FLAG_VF_DST; 21836558c3dSYuval Mintz params.dst_vfid = p_vf->abs_vf_id; 21936558c3dSYuval Mintz return qed_dmae_host2host(p_hwfn, p_ptt, p_vf->bulletin.phys, 22036558c3dSYuval Mintz p_vf->vf_bulletin, p_vf->bulletin.size / 4, 22136558c3dSYuval Mintz ¶ms); 22236558c3dSYuval Mintz } 22336558c3dSYuval Mintz 22432a47e72SYuval Mintz static int qed_iov_pci_cfg_info(struct qed_dev *cdev) 22532a47e72SYuval Mintz { 22632a47e72SYuval Mintz struct qed_hw_sriov_info *iov = cdev->p_iov_info; 22732a47e72SYuval Mintz int pos = iov->pos; 22832a47e72SYuval Mintz 22932a47e72SYuval Mintz DP_VERBOSE(cdev, QED_MSG_IOV, "sriov ext pos %d\n", pos); 23032a47e72SYuval Mintz pci_read_config_word(cdev->pdev, pos + PCI_SRIOV_CTRL, &iov->ctrl); 23132a47e72SYuval Mintz 23232a47e72SYuval Mintz pci_read_config_word(cdev->pdev, 23332a47e72SYuval Mintz pos + PCI_SRIOV_TOTAL_VF, &iov->total_vfs); 23432a47e72SYuval Mintz pci_read_config_word(cdev->pdev, 23532a47e72SYuval Mintz pos + PCI_SRIOV_INITIAL_VF, &iov->initial_vfs); 23632a47e72SYuval Mintz 23732a47e72SYuval Mintz pci_read_config_word(cdev->pdev, pos + PCI_SRIOV_NUM_VF, &iov->num_vfs); 23832a47e72SYuval Mintz if (iov->num_vfs) { 23932a47e72SYuval Mintz DP_VERBOSE(cdev, 24032a47e72SYuval Mintz QED_MSG_IOV, 24132a47e72SYuval Mintz "Number of VFs are already set to non-zero value. Ignoring PCI configuration value\n"); 24232a47e72SYuval Mintz iov->num_vfs = 0; 24332a47e72SYuval Mintz } 24432a47e72SYuval Mintz 24532a47e72SYuval Mintz pci_read_config_word(cdev->pdev, 24632a47e72SYuval Mintz pos + PCI_SRIOV_VF_OFFSET, &iov->offset); 24732a47e72SYuval Mintz 24832a47e72SYuval Mintz pci_read_config_word(cdev->pdev, 24932a47e72SYuval Mintz pos + PCI_SRIOV_VF_STRIDE, &iov->stride); 25032a47e72SYuval Mintz 25132a47e72SYuval Mintz pci_read_config_word(cdev->pdev, 25232a47e72SYuval Mintz pos + PCI_SRIOV_VF_DID, &iov->vf_device_id); 25332a47e72SYuval Mintz 25432a47e72SYuval Mintz pci_read_config_dword(cdev->pdev, 25532a47e72SYuval Mintz pos + PCI_SRIOV_SUP_PGSIZE, &iov->pgsz); 25632a47e72SYuval Mintz 25732a47e72SYuval Mintz pci_read_config_dword(cdev->pdev, pos + PCI_SRIOV_CAP, &iov->cap); 25832a47e72SYuval Mintz 25932a47e72SYuval Mintz pci_read_config_byte(cdev->pdev, pos + PCI_SRIOV_FUNC_LINK, &iov->link); 26032a47e72SYuval Mintz 26132a47e72SYuval Mintz DP_VERBOSE(cdev, 26232a47e72SYuval Mintz QED_MSG_IOV, 26332a47e72SYuval Mintz "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", 26432a47e72SYuval Mintz iov->nres, 26532a47e72SYuval Mintz iov->cap, 26632a47e72SYuval Mintz iov->ctrl, 26732a47e72SYuval Mintz iov->total_vfs, 26832a47e72SYuval Mintz iov->initial_vfs, 26932a47e72SYuval Mintz iov->nr_virtfn, iov->offset, iov->stride, iov->pgsz); 27032a47e72SYuval Mintz 27132a47e72SYuval Mintz /* Some sanity checks */ 27232a47e72SYuval Mintz if (iov->num_vfs > NUM_OF_VFS(cdev) || 27332a47e72SYuval Mintz iov->total_vfs > NUM_OF_VFS(cdev)) { 27432a47e72SYuval Mintz /* This can happen only due to a bug. In this case we set 27532a47e72SYuval Mintz * num_vfs to zero to avoid memory corruption in the code that 27632a47e72SYuval Mintz * assumes max number of vfs 27732a47e72SYuval Mintz */ 27832a47e72SYuval Mintz DP_NOTICE(cdev, 27932a47e72SYuval Mintz "IOV: Unexpected number of vfs set: %d setting num_vf to zero\n", 28032a47e72SYuval Mintz iov->num_vfs); 28132a47e72SYuval Mintz 28232a47e72SYuval Mintz iov->num_vfs = 0; 28332a47e72SYuval Mintz iov->total_vfs = 0; 28432a47e72SYuval Mintz } 28532a47e72SYuval Mintz 28632a47e72SYuval Mintz return 0; 28732a47e72SYuval Mintz } 28832a47e72SYuval Mintz 28932a47e72SYuval Mintz static void qed_iov_clear_vf_igu_blocks(struct qed_hwfn *p_hwfn, 29032a47e72SYuval Mintz struct qed_ptt *p_ptt) 29132a47e72SYuval Mintz { 29232a47e72SYuval Mintz struct qed_igu_block *p_sb; 29332a47e72SYuval Mintz u16 sb_id; 29432a47e72SYuval Mintz u32 val; 29532a47e72SYuval Mintz 29632a47e72SYuval Mintz if (!p_hwfn->hw_info.p_igu_info) { 29732a47e72SYuval Mintz DP_ERR(p_hwfn, 29832a47e72SYuval Mintz "qed_iov_clear_vf_igu_blocks IGU Info not initialized\n"); 29932a47e72SYuval Mintz return; 30032a47e72SYuval Mintz } 30132a47e72SYuval Mintz 30232a47e72SYuval Mintz for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); 30332a47e72SYuval Mintz sb_id++) { 30432a47e72SYuval Mintz p_sb = &p_hwfn->hw_info.p_igu_info->igu_map.igu_blocks[sb_id]; 30532a47e72SYuval Mintz if ((p_sb->status & QED_IGU_STATUS_FREE) && 30632a47e72SYuval Mintz !(p_sb->status & QED_IGU_STATUS_PF)) { 30732a47e72SYuval Mintz val = qed_rd(p_hwfn, p_ptt, 30832a47e72SYuval Mintz IGU_REG_MAPPING_MEMORY + sb_id * 4); 30932a47e72SYuval Mintz SET_FIELD(val, IGU_MAPPING_LINE_VALID, 0); 31032a47e72SYuval Mintz qed_wr(p_hwfn, p_ptt, 31132a47e72SYuval Mintz IGU_REG_MAPPING_MEMORY + 4 * sb_id, val); 31232a47e72SYuval Mintz } 31332a47e72SYuval Mintz } 31432a47e72SYuval Mintz } 31532a47e72SYuval Mintz 31632a47e72SYuval Mintz static void qed_iov_setup_vfdb(struct qed_hwfn *p_hwfn) 31732a47e72SYuval Mintz { 31832a47e72SYuval Mintz struct qed_hw_sriov_info *p_iov = p_hwfn->cdev->p_iov_info; 31932a47e72SYuval Mintz struct qed_pf_iov *p_iov_info = p_hwfn->pf_iov_info; 32032a47e72SYuval Mintz struct qed_bulletin_content *p_bulletin_virt; 32132a47e72SYuval Mintz dma_addr_t req_p, rply_p, bulletin_p; 32232a47e72SYuval Mintz union pfvf_tlvs *p_reply_virt_addr; 32332a47e72SYuval Mintz union vfpf_tlvs *p_req_virt_addr; 32432a47e72SYuval Mintz u8 idx = 0; 32532a47e72SYuval Mintz 32632a47e72SYuval Mintz memset(p_iov_info->vfs_array, 0, sizeof(p_iov_info->vfs_array)); 32732a47e72SYuval Mintz 32832a47e72SYuval Mintz p_req_virt_addr = p_iov_info->mbx_msg_virt_addr; 32932a47e72SYuval Mintz req_p = p_iov_info->mbx_msg_phys_addr; 33032a47e72SYuval Mintz p_reply_virt_addr = p_iov_info->mbx_reply_virt_addr; 33132a47e72SYuval Mintz rply_p = p_iov_info->mbx_reply_phys_addr; 33232a47e72SYuval Mintz p_bulletin_virt = p_iov_info->p_bulletins; 33332a47e72SYuval Mintz bulletin_p = p_iov_info->bulletins_phys; 33432a47e72SYuval Mintz if (!p_req_virt_addr || !p_reply_virt_addr || !p_bulletin_virt) { 33532a47e72SYuval Mintz DP_ERR(p_hwfn, 33632a47e72SYuval Mintz "qed_iov_setup_vfdb called without allocating mem first\n"); 33732a47e72SYuval Mintz return; 33832a47e72SYuval Mintz } 33932a47e72SYuval Mintz 34032a47e72SYuval Mintz for (idx = 0; idx < p_iov->total_vfs; idx++) { 34132a47e72SYuval Mintz struct qed_vf_info *vf = &p_iov_info->vfs_array[idx]; 34232a47e72SYuval Mintz u32 concrete; 34332a47e72SYuval Mintz 34432a47e72SYuval Mintz vf->vf_mbx.req_virt = p_req_virt_addr + idx; 34532a47e72SYuval Mintz vf->vf_mbx.req_phys = req_p + idx * sizeof(union vfpf_tlvs); 34632a47e72SYuval Mintz vf->vf_mbx.reply_virt = p_reply_virt_addr + idx; 34732a47e72SYuval Mintz vf->vf_mbx.reply_phys = rply_p + idx * sizeof(union pfvf_tlvs); 34832a47e72SYuval Mintz 34932a47e72SYuval Mintz vf->state = VF_STOPPED; 35032a47e72SYuval Mintz vf->b_init = false; 35132a47e72SYuval Mintz 35232a47e72SYuval Mintz vf->bulletin.phys = idx * 35332a47e72SYuval Mintz sizeof(struct qed_bulletin_content) + 35432a47e72SYuval Mintz bulletin_p; 35532a47e72SYuval Mintz vf->bulletin.p_virt = p_bulletin_virt + idx; 35632a47e72SYuval Mintz vf->bulletin.size = sizeof(struct qed_bulletin_content); 35732a47e72SYuval Mintz 35832a47e72SYuval Mintz vf->relative_vf_id = idx; 35932a47e72SYuval Mintz vf->abs_vf_id = idx + p_iov->first_vf_in_pf; 36032a47e72SYuval Mintz concrete = qed_vfid_to_concrete(p_hwfn, vf->abs_vf_id); 36132a47e72SYuval Mintz vf->concrete_fid = concrete; 36232a47e72SYuval Mintz vf->opaque_fid = (p_hwfn->hw_info.opaque_fid & 0xff) | 36332a47e72SYuval Mintz (vf->abs_vf_id << 8); 36432a47e72SYuval Mintz vf->vport_id = idx + 1; 3651cf2b1a9SYuval Mintz 3661cf2b1a9SYuval Mintz vf->num_mac_filters = QED_ETH_VF_NUM_MAC_FILTERS; 3671cf2b1a9SYuval Mintz vf->num_vlan_filters = QED_ETH_VF_NUM_VLAN_FILTERS; 36832a47e72SYuval Mintz } 36932a47e72SYuval Mintz } 37032a47e72SYuval Mintz 37132a47e72SYuval Mintz static int qed_iov_allocate_vfdb(struct qed_hwfn *p_hwfn) 37232a47e72SYuval Mintz { 37332a47e72SYuval Mintz struct qed_pf_iov *p_iov_info = p_hwfn->pf_iov_info; 37432a47e72SYuval Mintz void **p_v_addr; 37532a47e72SYuval Mintz u16 num_vfs = 0; 37632a47e72SYuval Mintz 37732a47e72SYuval Mintz num_vfs = p_hwfn->cdev->p_iov_info->total_vfs; 37832a47e72SYuval Mintz 37932a47e72SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 38032a47e72SYuval Mintz "qed_iov_allocate_vfdb for %d VFs\n", num_vfs); 38132a47e72SYuval Mintz 38232a47e72SYuval Mintz /* Allocate PF Mailbox buffer (per-VF) */ 38332a47e72SYuval Mintz p_iov_info->mbx_msg_size = sizeof(union vfpf_tlvs) * num_vfs; 38432a47e72SYuval Mintz p_v_addr = &p_iov_info->mbx_msg_virt_addr; 38532a47e72SYuval Mintz *p_v_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 38632a47e72SYuval Mintz p_iov_info->mbx_msg_size, 38732a47e72SYuval Mintz &p_iov_info->mbx_msg_phys_addr, 38832a47e72SYuval Mintz GFP_KERNEL); 38932a47e72SYuval Mintz if (!*p_v_addr) 39032a47e72SYuval Mintz return -ENOMEM; 39132a47e72SYuval Mintz 39232a47e72SYuval Mintz /* Allocate PF Mailbox Reply buffer (per-VF) */ 39332a47e72SYuval Mintz p_iov_info->mbx_reply_size = sizeof(union pfvf_tlvs) * num_vfs; 39432a47e72SYuval Mintz p_v_addr = &p_iov_info->mbx_reply_virt_addr; 39532a47e72SYuval Mintz *p_v_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 39632a47e72SYuval Mintz p_iov_info->mbx_reply_size, 39732a47e72SYuval Mintz &p_iov_info->mbx_reply_phys_addr, 39832a47e72SYuval Mintz GFP_KERNEL); 39932a47e72SYuval Mintz if (!*p_v_addr) 40032a47e72SYuval Mintz return -ENOMEM; 40132a47e72SYuval Mintz 40232a47e72SYuval Mintz p_iov_info->bulletins_size = sizeof(struct qed_bulletin_content) * 40332a47e72SYuval Mintz num_vfs; 40432a47e72SYuval Mintz p_v_addr = &p_iov_info->p_bulletins; 40532a47e72SYuval Mintz *p_v_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 40632a47e72SYuval Mintz p_iov_info->bulletins_size, 40732a47e72SYuval Mintz &p_iov_info->bulletins_phys, 40832a47e72SYuval Mintz GFP_KERNEL); 40932a47e72SYuval Mintz if (!*p_v_addr) 41032a47e72SYuval Mintz return -ENOMEM; 41132a47e72SYuval Mintz 41232a47e72SYuval Mintz DP_VERBOSE(p_hwfn, 41332a47e72SYuval Mintz QED_MSG_IOV, 41432a47e72SYuval Mintz "PF's Requests mailbox [%p virt 0x%llx phys], Response mailbox [%p virt 0x%llx phys] Bulletins [%p virt 0x%llx phys]\n", 41532a47e72SYuval Mintz p_iov_info->mbx_msg_virt_addr, 41632a47e72SYuval Mintz (u64) p_iov_info->mbx_msg_phys_addr, 41732a47e72SYuval Mintz p_iov_info->mbx_reply_virt_addr, 41832a47e72SYuval Mintz (u64) p_iov_info->mbx_reply_phys_addr, 41932a47e72SYuval Mintz p_iov_info->p_bulletins, (u64) p_iov_info->bulletins_phys); 42032a47e72SYuval Mintz 42132a47e72SYuval Mintz return 0; 42232a47e72SYuval Mintz } 42332a47e72SYuval Mintz 42432a47e72SYuval Mintz static void qed_iov_free_vfdb(struct qed_hwfn *p_hwfn) 42532a47e72SYuval Mintz { 42632a47e72SYuval Mintz struct qed_pf_iov *p_iov_info = p_hwfn->pf_iov_info; 42732a47e72SYuval Mintz 42832a47e72SYuval Mintz if (p_hwfn->pf_iov_info->mbx_msg_virt_addr) 42932a47e72SYuval Mintz dma_free_coherent(&p_hwfn->cdev->pdev->dev, 43032a47e72SYuval Mintz p_iov_info->mbx_msg_size, 43132a47e72SYuval Mintz p_iov_info->mbx_msg_virt_addr, 43232a47e72SYuval Mintz p_iov_info->mbx_msg_phys_addr); 43332a47e72SYuval Mintz 43432a47e72SYuval Mintz if (p_hwfn->pf_iov_info->mbx_reply_virt_addr) 43532a47e72SYuval Mintz dma_free_coherent(&p_hwfn->cdev->pdev->dev, 43632a47e72SYuval Mintz p_iov_info->mbx_reply_size, 43732a47e72SYuval Mintz p_iov_info->mbx_reply_virt_addr, 43832a47e72SYuval Mintz p_iov_info->mbx_reply_phys_addr); 43932a47e72SYuval Mintz 44032a47e72SYuval Mintz if (p_iov_info->p_bulletins) 44132a47e72SYuval Mintz dma_free_coherent(&p_hwfn->cdev->pdev->dev, 44232a47e72SYuval Mintz p_iov_info->bulletins_size, 44332a47e72SYuval Mintz p_iov_info->p_bulletins, 44432a47e72SYuval Mintz p_iov_info->bulletins_phys); 44532a47e72SYuval Mintz } 44632a47e72SYuval Mintz 44732a47e72SYuval Mintz int qed_iov_alloc(struct qed_hwfn *p_hwfn) 44832a47e72SYuval Mintz { 44932a47e72SYuval Mintz struct qed_pf_iov *p_sriov; 45032a47e72SYuval Mintz 45132a47e72SYuval Mintz if (!IS_PF_SRIOV(p_hwfn)) { 45232a47e72SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 45332a47e72SYuval Mintz "No SR-IOV - no need for IOV db\n"); 45432a47e72SYuval Mintz return 0; 45532a47e72SYuval Mintz } 45632a47e72SYuval Mintz 45732a47e72SYuval Mintz p_sriov = kzalloc(sizeof(*p_sriov), GFP_KERNEL); 45832a47e72SYuval Mintz if (!p_sriov) { 45932a47e72SYuval Mintz DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_sriov'\n"); 46032a47e72SYuval Mintz return -ENOMEM; 46132a47e72SYuval Mintz } 46232a47e72SYuval Mintz 46332a47e72SYuval Mintz p_hwfn->pf_iov_info = p_sriov; 46432a47e72SYuval Mintz 46532a47e72SYuval Mintz return qed_iov_allocate_vfdb(p_hwfn); 46632a47e72SYuval Mintz } 46732a47e72SYuval Mintz 46832a47e72SYuval Mintz void qed_iov_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 46932a47e72SYuval Mintz { 47032a47e72SYuval Mintz if (!IS_PF_SRIOV(p_hwfn) || !IS_PF_SRIOV_ALLOC(p_hwfn)) 47132a47e72SYuval Mintz return; 47232a47e72SYuval Mintz 47332a47e72SYuval Mintz qed_iov_setup_vfdb(p_hwfn); 47432a47e72SYuval Mintz qed_iov_clear_vf_igu_blocks(p_hwfn, p_ptt); 47532a47e72SYuval Mintz } 47632a47e72SYuval Mintz 47732a47e72SYuval Mintz void qed_iov_free(struct qed_hwfn *p_hwfn) 47832a47e72SYuval Mintz { 47932a47e72SYuval Mintz if (IS_PF_SRIOV_ALLOC(p_hwfn)) { 48032a47e72SYuval Mintz qed_iov_free_vfdb(p_hwfn); 48132a47e72SYuval Mintz kfree(p_hwfn->pf_iov_info); 48232a47e72SYuval Mintz } 48332a47e72SYuval Mintz } 48432a47e72SYuval Mintz 48532a47e72SYuval Mintz void qed_iov_free_hw_info(struct qed_dev *cdev) 48632a47e72SYuval Mintz { 48732a47e72SYuval Mintz kfree(cdev->p_iov_info); 48832a47e72SYuval Mintz cdev->p_iov_info = NULL; 48932a47e72SYuval Mintz } 49032a47e72SYuval Mintz 49132a47e72SYuval Mintz int qed_iov_hw_info(struct qed_hwfn *p_hwfn) 49232a47e72SYuval Mintz { 49332a47e72SYuval Mintz struct qed_dev *cdev = p_hwfn->cdev; 49432a47e72SYuval Mintz int pos; 49532a47e72SYuval Mintz int rc; 49632a47e72SYuval Mintz 4971408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) 4981408cc1fSYuval Mintz return 0; 4991408cc1fSYuval Mintz 50032a47e72SYuval Mintz /* Learn the PCI configuration */ 50132a47e72SYuval Mintz pos = pci_find_ext_capability(p_hwfn->cdev->pdev, 50232a47e72SYuval Mintz PCI_EXT_CAP_ID_SRIOV); 50332a47e72SYuval Mintz if (!pos) { 50432a47e72SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, "No PCIe IOV support\n"); 50532a47e72SYuval Mintz return 0; 50632a47e72SYuval Mintz } 50732a47e72SYuval Mintz 50832a47e72SYuval Mintz /* Allocate a new struct for IOV information */ 50932a47e72SYuval Mintz cdev->p_iov_info = kzalloc(sizeof(*cdev->p_iov_info), GFP_KERNEL); 51032a47e72SYuval Mintz if (!cdev->p_iov_info) { 51132a47e72SYuval Mintz DP_NOTICE(p_hwfn, "Can't support IOV due to lack of memory\n"); 51232a47e72SYuval Mintz return -ENOMEM; 51332a47e72SYuval Mintz } 51432a47e72SYuval Mintz cdev->p_iov_info->pos = pos; 51532a47e72SYuval Mintz 51632a47e72SYuval Mintz rc = qed_iov_pci_cfg_info(cdev); 51732a47e72SYuval Mintz if (rc) 51832a47e72SYuval Mintz return rc; 51932a47e72SYuval Mintz 52032a47e72SYuval Mintz /* We want PF IOV to be synonemous with the existance of p_iov_info; 52132a47e72SYuval Mintz * In case the capability is published but there are no VFs, simply 52232a47e72SYuval Mintz * de-allocate the struct. 52332a47e72SYuval Mintz */ 52432a47e72SYuval Mintz if (!cdev->p_iov_info->total_vfs) { 52532a47e72SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 52632a47e72SYuval Mintz "IOV capabilities, but no VFs are published\n"); 52732a47e72SYuval Mintz kfree(cdev->p_iov_info); 52832a47e72SYuval Mintz cdev->p_iov_info = NULL; 52932a47e72SYuval Mintz return 0; 53032a47e72SYuval Mintz } 53132a47e72SYuval Mintz 53232a47e72SYuval Mintz /* Calculate the first VF index - this is a bit tricky; Basically, 53332a47e72SYuval Mintz * VFs start at offset 16 relative to PF0, and 2nd engine VFs begin 53432a47e72SYuval Mintz * after the first engine's VFs. 53532a47e72SYuval Mintz */ 53632a47e72SYuval Mintz cdev->p_iov_info->first_vf_in_pf = p_hwfn->cdev->p_iov_info->offset + 53732a47e72SYuval Mintz p_hwfn->abs_pf_id - 16; 53832a47e72SYuval Mintz if (QED_PATH_ID(p_hwfn)) 53932a47e72SYuval Mintz cdev->p_iov_info->first_vf_in_pf -= MAX_NUM_VFS_BB; 54032a47e72SYuval Mintz 54132a47e72SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 54232a47e72SYuval Mintz "First VF in hwfn 0x%08x\n", 54332a47e72SYuval Mintz cdev->p_iov_info->first_vf_in_pf); 54432a47e72SYuval Mintz 54532a47e72SYuval Mintz return 0; 54632a47e72SYuval Mintz } 54732a47e72SYuval Mintz 54837bff2b9SYuval Mintz static bool qed_iov_pf_sanity_check(struct qed_hwfn *p_hwfn, int vfid) 54937bff2b9SYuval Mintz { 55037bff2b9SYuval Mintz /* Check PF supports sriov */ 551b0409fa0SYuval Mintz if (IS_VF(p_hwfn->cdev) || !IS_QED_SRIOV(p_hwfn->cdev) || 552b0409fa0SYuval Mintz !IS_PF_SRIOV_ALLOC(p_hwfn)) 55337bff2b9SYuval Mintz return false; 55437bff2b9SYuval Mintz 55537bff2b9SYuval Mintz /* Check VF validity */ 556b0409fa0SYuval Mintz if (!qed_iov_is_valid_vfid(p_hwfn, vfid, true)) 55737bff2b9SYuval Mintz return false; 55837bff2b9SYuval Mintz 55937bff2b9SYuval Mintz return true; 56037bff2b9SYuval Mintz } 56137bff2b9SYuval Mintz 5620b55e27dSYuval Mintz static void qed_iov_set_vf_to_disable(struct qed_dev *cdev, 5630b55e27dSYuval Mintz u16 rel_vf_id, u8 to_disable) 5640b55e27dSYuval Mintz { 5650b55e27dSYuval Mintz struct qed_vf_info *vf; 5660b55e27dSYuval Mintz int i; 5670b55e27dSYuval Mintz 5680b55e27dSYuval Mintz for_each_hwfn(cdev, i) { 5690b55e27dSYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 5700b55e27dSYuval Mintz 5710b55e27dSYuval Mintz vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, false); 5720b55e27dSYuval Mintz if (!vf) 5730b55e27dSYuval Mintz continue; 5740b55e27dSYuval Mintz 5750b55e27dSYuval Mintz vf->to_disable = to_disable; 5760b55e27dSYuval Mintz } 5770b55e27dSYuval Mintz } 5780b55e27dSYuval Mintz 5790b55e27dSYuval Mintz void qed_iov_set_vfs_to_disable(struct qed_dev *cdev, u8 to_disable) 5800b55e27dSYuval Mintz { 5810b55e27dSYuval Mintz u16 i; 5820b55e27dSYuval Mintz 5830b55e27dSYuval Mintz if (!IS_QED_SRIOV(cdev)) 5840b55e27dSYuval Mintz return; 5850b55e27dSYuval Mintz 5860b55e27dSYuval Mintz for (i = 0; i < cdev->p_iov_info->total_vfs; i++) 5870b55e27dSYuval Mintz qed_iov_set_vf_to_disable(cdev, i, to_disable); 5880b55e27dSYuval Mintz } 5890b55e27dSYuval Mintz 5901408cc1fSYuval Mintz static void qed_iov_vf_pglue_clear_err(struct qed_hwfn *p_hwfn, 5911408cc1fSYuval Mintz struct qed_ptt *p_ptt, u8 abs_vfid) 5921408cc1fSYuval Mintz { 5931408cc1fSYuval Mintz qed_wr(p_hwfn, p_ptt, 5941408cc1fSYuval Mintz PGLUE_B_REG_WAS_ERROR_VF_31_0_CLR + (abs_vfid >> 5) * 4, 5951408cc1fSYuval Mintz 1 << (abs_vfid & 0x1f)); 5961408cc1fSYuval Mintz } 5971408cc1fSYuval Mintz 598dacd88d6SYuval Mintz static void qed_iov_vf_igu_reset(struct qed_hwfn *p_hwfn, 599dacd88d6SYuval Mintz struct qed_ptt *p_ptt, struct qed_vf_info *vf) 600dacd88d6SYuval Mintz { 601dacd88d6SYuval Mintz int i; 602dacd88d6SYuval Mintz 603dacd88d6SYuval Mintz /* Set VF masks and configuration - pretend */ 604dacd88d6SYuval Mintz qed_fid_pretend(p_hwfn, p_ptt, (u16) vf->concrete_fid); 605dacd88d6SYuval Mintz 606dacd88d6SYuval Mintz qed_wr(p_hwfn, p_ptt, IGU_REG_STATISTIC_NUM_VF_MSG_SENT, 0); 607dacd88d6SYuval Mintz 608dacd88d6SYuval Mintz /* unpretend */ 609dacd88d6SYuval Mintz qed_fid_pretend(p_hwfn, p_ptt, (u16) p_hwfn->hw_info.concrete_fid); 610dacd88d6SYuval Mintz 611dacd88d6SYuval Mintz /* iterate over all queues, clear sb consumer */ 612b2b897ebSYuval Mintz for (i = 0; i < vf->num_sbs; i++) 613b2b897ebSYuval Mintz qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, 614b2b897ebSYuval Mintz vf->igu_sbs[i], 615b2b897ebSYuval Mintz vf->opaque_fid, true); 616dacd88d6SYuval Mintz } 617dacd88d6SYuval Mintz 6180b55e27dSYuval Mintz static void qed_iov_vf_igu_set_int(struct qed_hwfn *p_hwfn, 6190b55e27dSYuval Mintz struct qed_ptt *p_ptt, 6200b55e27dSYuval Mintz struct qed_vf_info *vf, bool enable) 6210b55e27dSYuval Mintz { 6220b55e27dSYuval Mintz u32 igu_vf_conf; 6230b55e27dSYuval Mintz 6240b55e27dSYuval Mintz qed_fid_pretend(p_hwfn, p_ptt, (u16) vf->concrete_fid); 6250b55e27dSYuval Mintz 6260b55e27dSYuval Mintz igu_vf_conf = qed_rd(p_hwfn, p_ptt, IGU_REG_VF_CONFIGURATION); 6270b55e27dSYuval Mintz 6280b55e27dSYuval Mintz if (enable) 6290b55e27dSYuval Mintz igu_vf_conf |= IGU_VF_CONF_MSI_MSIX_EN; 6300b55e27dSYuval Mintz else 6310b55e27dSYuval Mintz igu_vf_conf &= ~IGU_VF_CONF_MSI_MSIX_EN; 6320b55e27dSYuval Mintz 6330b55e27dSYuval Mintz qed_wr(p_hwfn, p_ptt, IGU_REG_VF_CONFIGURATION, igu_vf_conf); 6340b55e27dSYuval Mintz 6350b55e27dSYuval Mintz /* unpretend */ 6360b55e27dSYuval Mintz qed_fid_pretend(p_hwfn, p_ptt, (u16) p_hwfn->hw_info.concrete_fid); 6370b55e27dSYuval Mintz } 6380b55e27dSYuval Mintz 6391408cc1fSYuval Mintz static int qed_iov_enable_vf_access(struct qed_hwfn *p_hwfn, 6401408cc1fSYuval Mintz struct qed_ptt *p_ptt, 6411408cc1fSYuval Mintz struct qed_vf_info *vf) 6421408cc1fSYuval Mintz { 6431408cc1fSYuval Mintz u32 igu_vf_conf = IGU_VF_CONF_FUNC_EN; 6441408cc1fSYuval Mintz int rc; 6451408cc1fSYuval Mintz 6460b55e27dSYuval Mintz if (vf->to_disable) 6470b55e27dSYuval Mintz return 0; 6480b55e27dSYuval Mintz 6491408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, 6501408cc1fSYuval Mintz QED_MSG_IOV, 6511408cc1fSYuval Mintz "Enable internal access for vf %x [abs %x]\n", 6521408cc1fSYuval Mintz vf->abs_vf_id, QED_VF_ABS_ID(p_hwfn, vf)); 6531408cc1fSYuval Mintz 6541408cc1fSYuval Mintz qed_iov_vf_pglue_clear_err(p_hwfn, p_ptt, QED_VF_ABS_ID(p_hwfn, vf)); 6551408cc1fSYuval Mintz 656b2b897ebSYuval Mintz qed_iov_vf_igu_reset(p_hwfn, p_ptt, vf); 657b2b897ebSYuval Mintz 6581408cc1fSYuval Mintz rc = qed_mcp_config_vf_msix(p_hwfn, p_ptt, vf->abs_vf_id, vf->num_sbs); 6591408cc1fSYuval Mintz if (rc) 6601408cc1fSYuval Mintz return rc; 6611408cc1fSYuval Mintz 6621408cc1fSYuval Mintz qed_fid_pretend(p_hwfn, p_ptt, (u16) vf->concrete_fid); 6631408cc1fSYuval Mintz 6641408cc1fSYuval Mintz SET_FIELD(igu_vf_conf, IGU_VF_CONF_PARENT, p_hwfn->rel_pf_id); 6651408cc1fSYuval Mintz STORE_RT_REG(p_hwfn, IGU_REG_VF_CONFIGURATION_RT_OFFSET, igu_vf_conf); 6661408cc1fSYuval Mintz 6671408cc1fSYuval Mintz qed_init_run(p_hwfn, p_ptt, PHASE_VF, vf->abs_vf_id, 6681408cc1fSYuval Mintz p_hwfn->hw_info.hw_mode); 6691408cc1fSYuval Mintz 6701408cc1fSYuval Mintz /* unpretend */ 6711408cc1fSYuval Mintz qed_fid_pretend(p_hwfn, p_ptt, (u16) p_hwfn->hw_info.concrete_fid); 6721408cc1fSYuval Mintz 6731408cc1fSYuval Mintz vf->state = VF_FREE; 6741408cc1fSYuval Mintz 6751408cc1fSYuval Mintz return rc; 6761408cc1fSYuval Mintz } 6771408cc1fSYuval Mintz 6780b55e27dSYuval Mintz /** 6790b55e27dSYuval Mintz * @brief qed_iov_config_perm_table - configure the permission 6800b55e27dSYuval Mintz * zone table. 6810b55e27dSYuval Mintz * In E4, queue zone permission table size is 320x9. There 6820b55e27dSYuval Mintz * are 320 VF queues for single engine device (256 for dual 6830b55e27dSYuval Mintz * engine device), and each entry has the following format: 6840b55e27dSYuval Mintz * {Valid, VF[7:0]} 6850b55e27dSYuval Mintz * @param p_hwfn 6860b55e27dSYuval Mintz * @param p_ptt 6870b55e27dSYuval Mintz * @param vf 6880b55e27dSYuval Mintz * @param enable 6890b55e27dSYuval Mintz */ 6900b55e27dSYuval Mintz static void qed_iov_config_perm_table(struct qed_hwfn *p_hwfn, 6910b55e27dSYuval Mintz struct qed_ptt *p_ptt, 6920b55e27dSYuval Mintz struct qed_vf_info *vf, u8 enable) 6930b55e27dSYuval Mintz { 6940b55e27dSYuval Mintz u32 reg_addr, val; 6950b55e27dSYuval Mintz u16 qzone_id = 0; 6960b55e27dSYuval Mintz int qid; 6970b55e27dSYuval Mintz 6980b55e27dSYuval Mintz for (qid = 0; qid < vf->num_rxqs; qid++) { 6990b55e27dSYuval Mintz qed_fw_l2_queue(p_hwfn, vf->vf_queues[qid].fw_rx_qid, 7000b55e27dSYuval Mintz &qzone_id); 7010b55e27dSYuval Mintz 7020b55e27dSYuval Mintz reg_addr = PSWHST_REG_ZONE_PERMISSION_TABLE + qzone_id * 4; 7031a635e48SYuval Mintz val = enable ? (vf->abs_vf_id | BIT(8)) : 0; 7040b55e27dSYuval Mintz qed_wr(p_hwfn, p_ptt, reg_addr, val); 7050b55e27dSYuval Mintz } 7060b55e27dSYuval Mintz } 7070b55e27dSYuval Mintz 708dacd88d6SYuval Mintz static void qed_iov_enable_vf_traffic(struct qed_hwfn *p_hwfn, 709dacd88d6SYuval Mintz struct qed_ptt *p_ptt, 710dacd88d6SYuval Mintz struct qed_vf_info *vf) 711dacd88d6SYuval Mintz { 712dacd88d6SYuval Mintz /* Reset vf in IGU - interrupts are still disabled */ 713dacd88d6SYuval Mintz qed_iov_vf_igu_reset(p_hwfn, p_ptt, vf); 714dacd88d6SYuval Mintz 715dacd88d6SYuval Mintz qed_iov_vf_igu_set_int(p_hwfn, p_ptt, vf, 1); 716dacd88d6SYuval Mintz 717dacd88d6SYuval Mintz /* Permission Table */ 718dacd88d6SYuval Mintz qed_iov_config_perm_table(p_hwfn, p_ptt, vf, true); 719dacd88d6SYuval Mintz } 720dacd88d6SYuval Mintz 7211408cc1fSYuval Mintz static u8 qed_iov_alloc_vf_igu_sbs(struct qed_hwfn *p_hwfn, 7221408cc1fSYuval Mintz struct qed_ptt *p_ptt, 7231408cc1fSYuval Mintz struct qed_vf_info *vf, u16 num_rx_queues) 7241408cc1fSYuval Mintz { 7251408cc1fSYuval Mintz struct qed_igu_block *igu_blocks; 7261408cc1fSYuval Mintz int qid = 0, igu_id = 0; 7271408cc1fSYuval Mintz u32 val = 0; 7281408cc1fSYuval Mintz 7291408cc1fSYuval Mintz igu_blocks = p_hwfn->hw_info.p_igu_info->igu_map.igu_blocks; 7301408cc1fSYuval Mintz 7311408cc1fSYuval Mintz if (num_rx_queues > p_hwfn->hw_info.p_igu_info->free_blks) 7321408cc1fSYuval Mintz num_rx_queues = p_hwfn->hw_info.p_igu_info->free_blks; 7331408cc1fSYuval Mintz p_hwfn->hw_info.p_igu_info->free_blks -= num_rx_queues; 7341408cc1fSYuval Mintz 7351408cc1fSYuval Mintz SET_FIELD(val, IGU_MAPPING_LINE_FUNCTION_NUMBER, vf->abs_vf_id); 7361408cc1fSYuval Mintz SET_FIELD(val, IGU_MAPPING_LINE_VALID, 1); 7371408cc1fSYuval Mintz SET_FIELD(val, IGU_MAPPING_LINE_PF_VALID, 0); 7381408cc1fSYuval Mintz 7391408cc1fSYuval Mintz while ((qid < num_rx_queues) && 7401408cc1fSYuval Mintz (igu_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev))) { 7411408cc1fSYuval Mintz if (igu_blocks[igu_id].status & QED_IGU_STATUS_FREE) { 7421408cc1fSYuval Mintz struct cau_sb_entry sb_entry; 7431408cc1fSYuval Mintz 7441408cc1fSYuval Mintz vf->igu_sbs[qid] = (u16)igu_id; 7451408cc1fSYuval Mintz igu_blocks[igu_id].status &= ~QED_IGU_STATUS_FREE; 7461408cc1fSYuval Mintz 7471408cc1fSYuval Mintz SET_FIELD(val, IGU_MAPPING_LINE_VECTOR_NUMBER, qid); 7481408cc1fSYuval Mintz 7491408cc1fSYuval Mintz qed_wr(p_hwfn, p_ptt, 7501408cc1fSYuval Mintz IGU_REG_MAPPING_MEMORY + sizeof(u32) * igu_id, 7511408cc1fSYuval Mintz val); 7521408cc1fSYuval Mintz 7531408cc1fSYuval Mintz /* Configure igu sb in CAU which were marked valid */ 7541408cc1fSYuval Mintz qed_init_cau_sb_entry(p_hwfn, &sb_entry, 7551408cc1fSYuval Mintz p_hwfn->rel_pf_id, 7561408cc1fSYuval Mintz vf->abs_vf_id, 1); 7571408cc1fSYuval Mintz qed_dmae_host2grc(p_hwfn, p_ptt, 7581408cc1fSYuval Mintz (u64)(uintptr_t)&sb_entry, 7591408cc1fSYuval Mintz CAU_REG_SB_VAR_MEMORY + 7601408cc1fSYuval Mintz igu_id * sizeof(u64), 2, 0); 7611408cc1fSYuval Mintz qid++; 7621408cc1fSYuval Mintz } 7631408cc1fSYuval Mintz igu_id++; 7641408cc1fSYuval Mintz } 7651408cc1fSYuval Mintz 7661408cc1fSYuval Mintz vf->num_sbs = (u8) num_rx_queues; 7671408cc1fSYuval Mintz 7681408cc1fSYuval Mintz return vf->num_sbs; 7691408cc1fSYuval Mintz } 7701408cc1fSYuval Mintz 7710b55e27dSYuval Mintz static void qed_iov_free_vf_igu_sbs(struct qed_hwfn *p_hwfn, 7720b55e27dSYuval Mintz struct qed_ptt *p_ptt, 7730b55e27dSYuval Mintz struct qed_vf_info *vf) 7740b55e27dSYuval Mintz { 7750b55e27dSYuval Mintz struct qed_igu_info *p_info = p_hwfn->hw_info.p_igu_info; 7760b55e27dSYuval Mintz int idx, igu_id; 7770b55e27dSYuval Mintz u32 addr, val; 7780b55e27dSYuval Mintz 7790b55e27dSYuval Mintz /* Invalidate igu CAM lines and mark them as free */ 7800b55e27dSYuval Mintz for (idx = 0; idx < vf->num_sbs; idx++) { 7810b55e27dSYuval Mintz igu_id = vf->igu_sbs[idx]; 7820b55e27dSYuval Mintz addr = IGU_REG_MAPPING_MEMORY + sizeof(u32) * igu_id; 7830b55e27dSYuval Mintz 7840b55e27dSYuval Mintz val = qed_rd(p_hwfn, p_ptt, addr); 7850b55e27dSYuval Mintz SET_FIELD(val, IGU_MAPPING_LINE_VALID, 0); 7860b55e27dSYuval Mintz qed_wr(p_hwfn, p_ptt, addr, val); 7870b55e27dSYuval Mintz 7880b55e27dSYuval Mintz p_info->igu_map.igu_blocks[igu_id].status |= 7890b55e27dSYuval Mintz QED_IGU_STATUS_FREE; 7900b55e27dSYuval Mintz 7910b55e27dSYuval Mintz p_hwfn->hw_info.p_igu_info->free_blks++; 7920b55e27dSYuval Mintz } 7930b55e27dSYuval Mintz 7940b55e27dSYuval Mintz vf->num_sbs = 0; 7950b55e27dSYuval Mintz } 7960b55e27dSYuval Mintz 7971408cc1fSYuval Mintz static int qed_iov_init_hw_for_vf(struct qed_hwfn *p_hwfn, 7981408cc1fSYuval Mintz struct qed_ptt *p_ptt, 7991408cc1fSYuval Mintz u16 rel_vf_id, u16 num_rx_queues) 8001408cc1fSYuval Mintz { 8011408cc1fSYuval Mintz u8 num_of_vf_avaiable_chains = 0; 8021408cc1fSYuval Mintz struct qed_vf_info *vf = NULL; 8031408cc1fSYuval Mintz int rc = 0; 8041408cc1fSYuval Mintz u32 cids; 8051408cc1fSYuval Mintz u8 i; 8061408cc1fSYuval Mintz 8071408cc1fSYuval Mintz vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, false); 8081408cc1fSYuval Mintz if (!vf) { 8091408cc1fSYuval Mintz DP_ERR(p_hwfn, "qed_iov_init_hw_for_vf : vf is NULL\n"); 8101408cc1fSYuval Mintz return -EINVAL; 8111408cc1fSYuval Mintz } 8121408cc1fSYuval Mintz 8131408cc1fSYuval Mintz if (vf->b_init) { 8141408cc1fSYuval Mintz DP_NOTICE(p_hwfn, "VF[%d] is already active.\n", rel_vf_id); 8151408cc1fSYuval Mintz return -EINVAL; 8161408cc1fSYuval Mintz } 8171408cc1fSYuval Mintz 8181408cc1fSYuval Mintz /* Limit number of queues according to number of CIDs */ 8191408cc1fSYuval Mintz qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ETH, &cids); 8201408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, 8211408cc1fSYuval Mintz QED_MSG_IOV, 8221408cc1fSYuval Mintz "VF[%d] - requesting to initialize for 0x%04x queues [0x%04x CIDs available]\n", 8231408cc1fSYuval Mintz vf->relative_vf_id, num_rx_queues, (u16) cids); 8241408cc1fSYuval Mintz num_rx_queues = min_t(u16, num_rx_queues, ((u16) cids)); 8251408cc1fSYuval Mintz 8261408cc1fSYuval Mintz num_of_vf_avaiable_chains = qed_iov_alloc_vf_igu_sbs(p_hwfn, 8271408cc1fSYuval Mintz p_ptt, 8281408cc1fSYuval Mintz vf, 8291408cc1fSYuval Mintz num_rx_queues); 8301408cc1fSYuval Mintz if (!num_of_vf_avaiable_chains) { 8311408cc1fSYuval Mintz DP_ERR(p_hwfn, "no available igu sbs\n"); 8321408cc1fSYuval Mintz return -ENOMEM; 8331408cc1fSYuval Mintz } 8341408cc1fSYuval Mintz 8351408cc1fSYuval Mintz /* Choose queue number and index ranges */ 8361408cc1fSYuval Mintz vf->num_rxqs = num_of_vf_avaiable_chains; 8371408cc1fSYuval Mintz vf->num_txqs = num_of_vf_avaiable_chains; 8381408cc1fSYuval Mintz 8391408cc1fSYuval Mintz for (i = 0; i < vf->num_rxqs; i++) { 8401408cc1fSYuval Mintz u16 queue_id = qed_int_queue_id_from_sb_id(p_hwfn, 8411408cc1fSYuval Mintz vf->igu_sbs[i]); 8421408cc1fSYuval Mintz 8431408cc1fSYuval Mintz if (queue_id > RESC_NUM(p_hwfn, QED_L2_QUEUE)) { 8441408cc1fSYuval Mintz DP_NOTICE(p_hwfn, 8451408cc1fSYuval Mintz "VF[%d] will require utilizing of out-of-bounds queues - %04x\n", 8461408cc1fSYuval Mintz vf->relative_vf_id, queue_id); 8471408cc1fSYuval Mintz return -EINVAL; 8481408cc1fSYuval Mintz } 8491408cc1fSYuval Mintz 8501408cc1fSYuval Mintz /* CIDs are per-VF, so no problem having them 0-based. */ 8511408cc1fSYuval Mintz vf->vf_queues[i].fw_rx_qid = queue_id; 8521408cc1fSYuval Mintz vf->vf_queues[i].fw_tx_qid = queue_id; 8531408cc1fSYuval Mintz vf->vf_queues[i].fw_cid = i; 8541408cc1fSYuval Mintz 8551408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 8561408cc1fSYuval Mintz "VF[%d] - [%d] SB %04x, Tx/Rx queue %04x CID %04x\n", 8571408cc1fSYuval Mintz vf->relative_vf_id, i, vf->igu_sbs[i], queue_id, i); 8581408cc1fSYuval Mintz } 8591408cc1fSYuval Mintz rc = qed_iov_enable_vf_access(p_hwfn, p_ptt, vf); 8601408cc1fSYuval Mintz if (!rc) { 8611408cc1fSYuval Mintz vf->b_init = true; 8621408cc1fSYuval Mintz 8631408cc1fSYuval Mintz if (IS_LEAD_HWFN(p_hwfn)) 8641408cc1fSYuval Mintz p_hwfn->cdev->p_iov_info->num_vfs++; 8651408cc1fSYuval Mintz } 8661408cc1fSYuval Mintz 8671408cc1fSYuval Mintz return rc; 8681408cc1fSYuval Mintz } 8691408cc1fSYuval Mintz 870079d20a6SManish Chopra static void qed_iov_set_link(struct qed_hwfn *p_hwfn, 871079d20a6SManish Chopra u16 vfid, 872079d20a6SManish Chopra struct qed_mcp_link_params *params, 873079d20a6SManish Chopra struct qed_mcp_link_state *link, 874079d20a6SManish Chopra struct qed_mcp_link_capabilities *p_caps) 875079d20a6SManish Chopra { 876079d20a6SManish Chopra struct qed_vf_info *p_vf = qed_iov_get_vf_info(p_hwfn, 877079d20a6SManish Chopra vfid, 878079d20a6SManish Chopra false); 879079d20a6SManish Chopra struct qed_bulletin_content *p_bulletin; 880079d20a6SManish Chopra 881079d20a6SManish Chopra if (!p_vf) 882079d20a6SManish Chopra return; 883079d20a6SManish Chopra 884079d20a6SManish Chopra p_bulletin = p_vf->bulletin.p_virt; 885079d20a6SManish Chopra p_bulletin->req_autoneg = params->speed.autoneg; 886079d20a6SManish Chopra p_bulletin->req_adv_speed = params->speed.advertised_speeds; 887079d20a6SManish Chopra p_bulletin->req_forced_speed = params->speed.forced_speed; 888079d20a6SManish Chopra p_bulletin->req_autoneg_pause = params->pause.autoneg; 889079d20a6SManish Chopra p_bulletin->req_forced_rx = params->pause.forced_rx; 890079d20a6SManish Chopra p_bulletin->req_forced_tx = params->pause.forced_tx; 891079d20a6SManish Chopra p_bulletin->req_loopback = params->loopback_mode; 892079d20a6SManish Chopra 893079d20a6SManish Chopra p_bulletin->link_up = link->link_up; 894079d20a6SManish Chopra p_bulletin->speed = link->speed; 895079d20a6SManish Chopra p_bulletin->full_duplex = link->full_duplex; 896079d20a6SManish Chopra p_bulletin->autoneg = link->an; 897079d20a6SManish Chopra p_bulletin->autoneg_complete = link->an_complete; 898079d20a6SManish Chopra p_bulletin->parallel_detection = link->parallel_detection; 899079d20a6SManish Chopra p_bulletin->pfc_enabled = link->pfc_enabled; 900079d20a6SManish Chopra p_bulletin->partner_adv_speed = link->partner_adv_speed; 901079d20a6SManish Chopra p_bulletin->partner_tx_flow_ctrl_en = link->partner_tx_flow_ctrl_en; 902079d20a6SManish Chopra p_bulletin->partner_rx_flow_ctrl_en = link->partner_rx_flow_ctrl_en; 903079d20a6SManish Chopra p_bulletin->partner_adv_pause = link->partner_adv_pause; 904079d20a6SManish Chopra p_bulletin->sfp_tx_fault = link->sfp_tx_fault; 905079d20a6SManish Chopra 906079d20a6SManish Chopra p_bulletin->capability_speed = p_caps->speed_capabilities; 907079d20a6SManish Chopra } 908079d20a6SManish Chopra 9090b55e27dSYuval Mintz static int qed_iov_release_hw_for_vf(struct qed_hwfn *p_hwfn, 9100b55e27dSYuval Mintz struct qed_ptt *p_ptt, u16 rel_vf_id) 9110b55e27dSYuval Mintz { 912079d20a6SManish Chopra struct qed_mcp_link_capabilities caps; 913079d20a6SManish Chopra struct qed_mcp_link_params params; 914079d20a6SManish Chopra struct qed_mcp_link_state link; 9150b55e27dSYuval Mintz struct qed_vf_info *vf = NULL; 9160b55e27dSYuval Mintz 9170b55e27dSYuval Mintz vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, true); 9180b55e27dSYuval Mintz if (!vf) { 9190b55e27dSYuval Mintz DP_ERR(p_hwfn, "qed_iov_release_hw_for_vf : vf is NULL\n"); 9200b55e27dSYuval Mintz return -EINVAL; 9210b55e27dSYuval Mintz } 9220b55e27dSYuval Mintz 92336558c3dSYuval Mintz if (vf->bulletin.p_virt) 92436558c3dSYuval Mintz memset(vf->bulletin.p_virt, 0, sizeof(*vf->bulletin.p_virt)); 92536558c3dSYuval Mintz 92636558c3dSYuval Mintz memset(&vf->p_vf_info, 0, sizeof(vf->p_vf_info)); 92736558c3dSYuval Mintz 928079d20a6SManish Chopra /* Get the link configuration back in bulletin so 929079d20a6SManish Chopra * that when VFs are re-enabled they get the actual 930079d20a6SManish Chopra * link configuration. 931079d20a6SManish Chopra */ 932079d20a6SManish Chopra memcpy(¶ms, qed_mcp_get_link_params(p_hwfn), sizeof(params)); 933079d20a6SManish Chopra memcpy(&link, qed_mcp_get_link_state(p_hwfn), sizeof(link)); 934079d20a6SManish Chopra memcpy(&caps, qed_mcp_get_link_capabilities(p_hwfn), sizeof(caps)); 935079d20a6SManish Chopra qed_iov_set_link(p_hwfn, rel_vf_id, ¶ms, &link, &caps); 936079d20a6SManish Chopra 9371fe614d1SYuval Mintz /* Forget the VF's acquisition message */ 9381fe614d1SYuval Mintz memset(&vf->acquire, 0, sizeof(vf->acquire)); 9390b55e27dSYuval Mintz 9400b55e27dSYuval Mintz /* disablng interrupts and resetting permission table was done during 9410b55e27dSYuval Mintz * vf-close, however, we could get here without going through vf_close 9420b55e27dSYuval Mintz */ 9430b55e27dSYuval Mintz /* Disable Interrupts for VF */ 9440b55e27dSYuval Mintz qed_iov_vf_igu_set_int(p_hwfn, p_ptt, vf, 0); 9450b55e27dSYuval Mintz 9460b55e27dSYuval Mintz /* Reset Permission table */ 9470b55e27dSYuval Mintz qed_iov_config_perm_table(p_hwfn, p_ptt, vf, 0); 9480b55e27dSYuval Mintz 9490b55e27dSYuval Mintz vf->num_rxqs = 0; 9500b55e27dSYuval Mintz vf->num_txqs = 0; 9510b55e27dSYuval Mintz qed_iov_free_vf_igu_sbs(p_hwfn, p_ptt, vf); 9520b55e27dSYuval Mintz 9530b55e27dSYuval Mintz if (vf->b_init) { 9540b55e27dSYuval Mintz vf->b_init = false; 9550b55e27dSYuval Mintz 9560b55e27dSYuval Mintz if (IS_LEAD_HWFN(p_hwfn)) 9570b55e27dSYuval Mintz p_hwfn->cdev->p_iov_info->num_vfs--; 9580b55e27dSYuval Mintz } 9590b55e27dSYuval Mintz 9600b55e27dSYuval Mintz return 0; 9610b55e27dSYuval Mintz } 9620b55e27dSYuval Mintz 96337bff2b9SYuval Mintz static bool qed_iov_tlv_supported(u16 tlvtype) 96437bff2b9SYuval Mintz { 96537bff2b9SYuval Mintz return CHANNEL_TLV_NONE < tlvtype && tlvtype < CHANNEL_TLV_MAX; 96637bff2b9SYuval Mintz } 96737bff2b9SYuval Mintz 96837bff2b9SYuval Mintz /* place a given tlv on the tlv buffer, continuing current tlv list */ 96937bff2b9SYuval Mintz void *qed_add_tlv(struct qed_hwfn *p_hwfn, u8 **offset, u16 type, u16 length) 97037bff2b9SYuval Mintz { 97137bff2b9SYuval Mintz struct channel_tlv *tl = (struct channel_tlv *)*offset; 97237bff2b9SYuval Mintz 97337bff2b9SYuval Mintz tl->type = type; 97437bff2b9SYuval Mintz tl->length = length; 97537bff2b9SYuval Mintz 97637bff2b9SYuval Mintz /* Offset should keep pointing to next TLV (the end of the last) */ 97737bff2b9SYuval Mintz *offset += length; 97837bff2b9SYuval Mintz 97937bff2b9SYuval Mintz /* Return a pointer to the start of the added tlv */ 98037bff2b9SYuval Mintz return *offset - length; 98137bff2b9SYuval Mintz } 98237bff2b9SYuval Mintz 98337bff2b9SYuval Mintz /* list the types and lengths of the tlvs on the buffer */ 98437bff2b9SYuval Mintz void qed_dp_tlv_list(struct qed_hwfn *p_hwfn, void *tlvs_list) 98537bff2b9SYuval Mintz { 98637bff2b9SYuval Mintz u16 i = 1, total_length = 0; 98737bff2b9SYuval Mintz struct channel_tlv *tlv; 98837bff2b9SYuval Mintz 98937bff2b9SYuval Mintz do { 99037bff2b9SYuval Mintz tlv = (struct channel_tlv *)((u8 *)tlvs_list + total_length); 99137bff2b9SYuval Mintz 99237bff2b9SYuval Mintz /* output tlv */ 99337bff2b9SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 99437bff2b9SYuval Mintz "TLV number %d: type %d, length %d\n", 99537bff2b9SYuval Mintz i, tlv->type, tlv->length); 99637bff2b9SYuval Mintz 99737bff2b9SYuval Mintz if (tlv->type == CHANNEL_TLV_LIST_END) 99837bff2b9SYuval Mintz return; 99937bff2b9SYuval Mintz 100037bff2b9SYuval Mintz /* Validate entry - protect against malicious VFs */ 100137bff2b9SYuval Mintz if (!tlv->length) { 100237bff2b9SYuval Mintz DP_NOTICE(p_hwfn, "TLV of length 0 found\n"); 100337bff2b9SYuval Mintz return; 100437bff2b9SYuval Mintz } 100537bff2b9SYuval Mintz 100637bff2b9SYuval Mintz total_length += tlv->length; 100737bff2b9SYuval Mintz 100837bff2b9SYuval Mintz if (total_length >= sizeof(struct tlv_buffer_size)) { 100937bff2b9SYuval Mintz DP_NOTICE(p_hwfn, "TLV ==> Buffer overflow\n"); 101037bff2b9SYuval Mintz return; 101137bff2b9SYuval Mintz } 101237bff2b9SYuval Mintz 101337bff2b9SYuval Mintz i++; 101437bff2b9SYuval Mintz } while (1); 101537bff2b9SYuval Mintz } 101637bff2b9SYuval Mintz 101737bff2b9SYuval Mintz static void qed_iov_send_response(struct qed_hwfn *p_hwfn, 101837bff2b9SYuval Mintz struct qed_ptt *p_ptt, 101937bff2b9SYuval Mintz struct qed_vf_info *p_vf, 102037bff2b9SYuval Mintz u16 length, u8 status) 102137bff2b9SYuval Mintz { 102237bff2b9SYuval Mintz struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx; 102337bff2b9SYuval Mintz struct qed_dmae_params params; 102437bff2b9SYuval Mintz u8 eng_vf_id; 102537bff2b9SYuval Mintz 102637bff2b9SYuval Mintz mbx->reply_virt->default_resp.hdr.status = status; 102737bff2b9SYuval Mintz 102837bff2b9SYuval Mintz qed_dp_tlv_list(p_hwfn, mbx->reply_virt); 102937bff2b9SYuval Mintz 103037bff2b9SYuval Mintz eng_vf_id = p_vf->abs_vf_id; 103137bff2b9SYuval Mintz 103237bff2b9SYuval Mintz memset(¶ms, 0, sizeof(struct qed_dmae_params)); 103337bff2b9SYuval Mintz params.flags = QED_DMAE_FLAG_VF_DST; 103437bff2b9SYuval Mintz params.dst_vfid = eng_vf_id; 103537bff2b9SYuval Mintz 103637bff2b9SYuval Mintz qed_dmae_host2host(p_hwfn, p_ptt, mbx->reply_phys + sizeof(u64), 103737bff2b9SYuval Mintz mbx->req_virt->first_tlv.reply_address + 103837bff2b9SYuval Mintz sizeof(u64), 103937bff2b9SYuval Mintz (sizeof(union pfvf_tlvs) - sizeof(u64)) / 4, 104037bff2b9SYuval Mintz ¶ms); 104137bff2b9SYuval Mintz 104237bff2b9SYuval Mintz qed_dmae_host2host(p_hwfn, p_ptt, mbx->reply_phys, 104337bff2b9SYuval Mintz mbx->req_virt->first_tlv.reply_address, 104437bff2b9SYuval Mintz sizeof(u64) / 4, ¶ms); 104537bff2b9SYuval Mintz 104637bff2b9SYuval Mintz REG_WR(p_hwfn, 104737bff2b9SYuval Mintz GTT_BAR0_MAP_REG_USDM_RAM + 104837bff2b9SYuval Mintz USTORM_VF_PF_CHANNEL_READY_OFFSET(eng_vf_id), 1); 104937bff2b9SYuval Mintz } 105037bff2b9SYuval Mintz 1051dacd88d6SYuval Mintz static u16 qed_iov_vport_to_tlv(struct qed_hwfn *p_hwfn, 1052dacd88d6SYuval Mintz enum qed_iov_vport_update_flag flag) 1053dacd88d6SYuval Mintz { 1054dacd88d6SYuval Mintz switch (flag) { 1055dacd88d6SYuval Mintz case QED_IOV_VP_UPDATE_ACTIVATE: 1056dacd88d6SYuval Mintz return CHANNEL_TLV_VPORT_UPDATE_ACTIVATE; 105717b235c1SYuval Mintz case QED_IOV_VP_UPDATE_VLAN_STRIP: 105817b235c1SYuval Mintz return CHANNEL_TLV_VPORT_UPDATE_VLAN_STRIP; 105917b235c1SYuval Mintz case QED_IOV_VP_UPDATE_TX_SWITCH: 106017b235c1SYuval Mintz return CHANNEL_TLV_VPORT_UPDATE_TX_SWITCH; 1061dacd88d6SYuval Mintz case QED_IOV_VP_UPDATE_MCAST: 1062dacd88d6SYuval Mintz return CHANNEL_TLV_VPORT_UPDATE_MCAST; 1063dacd88d6SYuval Mintz case QED_IOV_VP_UPDATE_ACCEPT_PARAM: 1064dacd88d6SYuval Mintz return CHANNEL_TLV_VPORT_UPDATE_ACCEPT_PARAM; 1065dacd88d6SYuval Mintz case QED_IOV_VP_UPDATE_RSS: 1066dacd88d6SYuval Mintz return CHANNEL_TLV_VPORT_UPDATE_RSS; 106717b235c1SYuval Mintz case QED_IOV_VP_UPDATE_ACCEPT_ANY_VLAN: 106817b235c1SYuval Mintz return CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN; 106917b235c1SYuval Mintz case QED_IOV_VP_UPDATE_SGE_TPA: 107017b235c1SYuval Mintz return CHANNEL_TLV_VPORT_UPDATE_SGE_TPA; 1071dacd88d6SYuval Mintz default: 1072dacd88d6SYuval Mintz return 0; 1073dacd88d6SYuval Mintz } 1074dacd88d6SYuval Mintz } 1075dacd88d6SYuval Mintz 1076dacd88d6SYuval Mintz static u16 qed_iov_prep_vp_update_resp_tlvs(struct qed_hwfn *p_hwfn, 1077dacd88d6SYuval Mintz struct qed_vf_info *p_vf, 1078dacd88d6SYuval Mintz struct qed_iov_vf_mbx *p_mbx, 1079dacd88d6SYuval Mintz u8 status, 1080dacd88d6SYuval Mintz u16 tlvs_mask, u16 tlvs_accepted) 1081dacd88d6SYuval Mintz { 1082dacd88d6SYuval Mintz struct pfvf_def_resp_tlv *resp; 1083dacd88d6SYuval Mintz u16 size, total_len, i; 1084dacd88d6SYuval Mintz 1085dacd88d6SYuval Mintz memset(p_mbx->reply_virt, 0, sizeof(union pfvf_tlvs)); 1086dacd88d6SYuval Mintz p_mbx->offset = (u8 *)p_mbx->reply_virt; 1087dacd88d6SYuval Mintz size = sizeof(struct pfvf_def_resp_tlv); 1088dacd88d6SYuval Mintz total_len = size; 1089dacd88d6SYuval Mintz 1090dacd88d6SYuval Mintz qed_add_tlv(p_hwfn, &p_mbx->offset, CHANNEL_TLV_VPORT_UPDATE, size); 1091dacd88d6SYuval Mintz 1092dacd88d6SYuval Mintz /* Prepare response for all extended tlvs if they are found by PF */ 1093dacd88d6SYuval Mintz for (i = 0; i < QED_IOV_VP_UPDATE_MAX; i++) { 10941a635e48SYuval Mintz if (!(tlvs_mask & BIT(i))) 1095dacd88d6SYuval Mintz continue; 1096dacd88d6SYuval Mintz 1097dacd88d6SYuval Mintz resp = qed_add_tlv(p_hwfn, &p_mbx->offset, 1098dacd88d6SYuval Mintz qed_iov_vport_to_tlv(p_hwfn, i), size); 1099dacd88d6SYuval Mintz 11001a635e48SYuval Mintz if (tlvs_accepted & BIT(i)) 1101dacd88d6SYuval Mintz resp->hdr.status = status; 1102dacd88d6SYuval Mintz else 1103dacd88d6SYuval Mintz resp->hdr.status = PFVF_STATUS_NOT_SUPPORTED; 1104dacd88d6SYuval Mintz 1105dacd88d6SYuval Mintz DP_VERBOSE(p_hwfn, 1106dacd88d6SYuval Mintz QED_MSG_IOV, 1107dacd88d6SYuval Mintz "VF[%d] - vport_update response: TLV %d, status %02x\n", 1108dacd88d6SYuval Mintz p_vf->relative_vf_id, 1109dacd88d6SYuval Mintz qed_iov_vport_to_tlv(p_hwfn, i), resp->hdr.status); 1110dacd88d6SYuval Mintz 1111dacd88d6SYuval Mintz total_len += size; 1112dacd88d6SYuval Mintz } 1113dacd88d6SYuval Mintz 1114dacd88d6SYuval Mintz qed_add_tlv(p_hwfn, &p_mbx->offset, CHANNEL_TLV_LIST_END, 1115dacd88d6SYuval Mintz sizeof(struct channel_list_end_tlv)); 1116dacd88d6SYuval Mintz 1117dacd88d6SYuval Mintz return total_len; 1118dacd88d6SYuval Mintz } 1119dacd88d6SYuval Mintz 112037bff2b9SYuval Mintz static void qed_iov_prepare_resp(struct qed_hwfn *p_hwfn, 112137bff2b9SYuval Mintz struct qed_ptt *p_ptt, 112237bff2b9SYuval Mintz struct qed_vf_info *vf_info, 112337bff2b9SYuval Mintz u16 type, u16 length, u8 status) 112437bff2b9SYuval Mintz { 112537bff2b9SYuval Mintz struct qed_iov_vf_mbx *mbx = &vf_info->vf_mbx; 112637bff2b9SYuval Mintz 112737bff2b9SYuval Mintz mbx->offset = (u8 *)mbx->reply_virt; 112837bff2b9SYuval Mintz 112937bff2b9SYuval Mintz qed_add_tlv(p_hwfn, &mbx->offset, type, length); 113037bff2b9SYuval Mintz qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_LIST_END, 113137bff2b9SYuval Mintz sizeof(struct channel_list_end_tlv)); 113237bff2b9SYuval Mintz 113337bff2b9SYuval Mintz qed_iov_send_response(p_hwfn, p_ptt, vf_info, length, status); 113437bff2b9SYuval Mintz } 113537bff2b9SYuval Mintz 11360b55e27dSYuval Mintz struct qed_public_vf_info *qed_iov_get_public_vf_info(struct qed_hwfn *p_hwfn, 11370b55e27dSYuval Mintz u16 relative_vf_id, 11380b55e27dSYuval Mintz bool b_enabled_only) 11390b55e27dSYuval Mintz { 11400b55e27dSYuval Mintz struct qed_vf_info *vf = NULL; 11410b55e27dSYuval Mintz 11420b55e27dSYuval Mintz vf = qed_iov_get_vf_info(p_hwfn, relative_vf_id, b_enabled_only); 11430b55e27dSYuval Mintz if (!vf) 11440b55e27dSYuval Mintz return NULL; 11450b55e27dSYuval Mintz 11460b55e27dSYuval Mintz return &vf->p_vf_info; 11470b55e27dSYuval Mintz } 11480b55e27dSYuval Mintz 11490b55e27dSYuval Mintz void qed_iov_clean_vf(struct qed_hwfn *p_hwfn, u8 vfid) 11500b55e27dSYuval Mintz { 11510b55e27dSYuval Mintz struct qed_public_vf_info *vf_info; 11520b55e27dSYuval Mintz 11530b55e27dSYuval Mintz vf_info = qed_iov_get_public_vf_info(p_hwfn, vfid, false); 11540b55e27dSYuval Mintz 11550b55e27dSYuval Mintz if (!vf_info) 11560b55e27dSYuval Mintz return; 11570b55e27dSYuval Mintz 11580b55e27dSYuval Mintz /* Clear the VF mac */ 11590b55e27dSYuval Mintz memset(vf_info->mac, 0, ETH_ALEN); 11600b55e27dSYuval Mintz } 11610b55e27dSYuval Mintz 11620b55e27dSYuval Mintz static void qed_iov_vf_cleanup(struct qed_hwfn *p_hwfn, 11630b55e27dSYuval Mintz struct qed_vf_info *p_vf) 11640b55e27dSYuval Mintz { 11650b55e27dSYuval Mintz u32 i; 11660b55e27dSYuval Mintz 11670b55e27dSYuval Mintz p_vf->vf_bulletin = 0; 1168dacd88d6SYuval Mintz p_vf->vport_instance = 0; 116908feecd7SYuval Mintz p_vf->configured_features = 0; 11700b55e27dSYuval Mintz 11710b55e27dSYuval Mintz /* If VF previously requested less resources, go back to default */ 11720b55e27dSYuval Mintz p_vf->num_rxqs = p_vf->num_sbs; 11730b55e27dSYuval Mintz p_vf->num_txqs = p_vf->num_sbs; 11740b55e27dSYuval Mintz 1175dacd88d6SYuval Mintz p_vf->num_active_rxqs = 0; 1176dacd88d6SYuval Mintz 11770b55e27dSYuval Mintz for (i = 0; i < QED_MAX_VF_CHAINS_PER_PF; i++) 11780b55e27dSYuval Mintz p_vf->vf_queues[i].rxq_active = 0; 11790b55e27dSYuval Mintz 118008feecd7SYuval Mintz memset(&p_vf->shadow_config, 0, sizeof(p_vf->shadow_config)); 11811fe614d1SYuval Mintz memset(&p_vf->acquire, 0, sizeof(p_vf->acquire)); 11820b55e27dSYuval Mintz qed_iov_clean_vf(p_hwfn, p_vf->relative_vf_id); 11830b55e27dSYuval Mintz } 11840b55e27dSYuval Mintz 11851cf2b1a9SYuval Mintz static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, 11861cf2b1a9SYuval Mintz struct qed_ptt *p_ptt, 11871cf2b1a9SYuval Mintz struct qed_vf_info *p_vf, 11881cf2b1a9SYuval Mintz struct vf_pf_resc_request *p_req, 11891cf2b1a9SYuval Mintz struct pf_vf_resc *p_resp) 11901cf2b1a9SYuval Mintz { 11911cf2b1a9SYuval Mintz int i; 11921cf2b1a9SYuval Mintz 11931cf2b1a9SYuval Mintz /* Queue related information */ 11941cf2b1a9SYuval Mintz p_resp->num_rxqs = p_vf->num_rxqs; 11951cf2b1a9SYuval Mintz p_resp->num_txqs = p_vf->num_txqs; 11961cf2b1a9SYuval Mintz p_resp->num_sbs = p_vf->num_sbs; 11971cf2b1a9SYuval Mintz 11981cf2b1a9SYuval Mintz for (i = 0; i < p_resp->num_sbs; i++) { 11991cf2b1a9SYuval Mintz p_resp->hw_sbs[i].hw_sb_id = p_vf->igu_sbs[i]; 12001cf2b1a9SYuval Mintz p_resp->hw_sbs[i].sb_qid = 0; 12011cf2b1a9SYuval Mintz } 12021cf2b1a9SYuval Mintz 12031cf2b1a9SYuval Mintz /* These fields are filled for backward compatibility. 12041cf2b1a9SYuval Mintz * Unused by modern vfs. 12051cf2b1a9SYuval Mintz */ 12061cf2b1a9SYuval Mintz for (i = 0; i < p_resp->num_rxqs; i++) { 12071cf2b1a9SYuval Mintz qed_fw_l2_queue(p_hwfn, p_vf->vf_queues[i].fw_rx_qid, 12081cf2b1a9SYuval Mintz (u16 *)&p_resp->hw_qid[i]); 12091cf2b1a9SYuval Mintz p_resp->cid[i] = p_vf->vf_queues[i].fw_cid; 12101cf2b1a9SYuval Mintz } 12111cf2b1a9SYuval Mintz 12121cf2b1a9SYuval Mintz /* Filter related information */ 12131cf2b1a9SYuval Mintz p_resp->num_mac_filters = min_t(u8, p_vf->num_mac_filters, 12141cf2b1a9SYuval Mintz p_req->num_mac_filters); 12151cf2b1a9SYuval Mintz p_resp->num_vlan_filters = min_t(u8, p_vf->num_vlan_filters, 12161cf2b1a9SYuval Mintz p_req->num_vlan_filters); 12171cf2b1a9SYuval Mintz 12181cf2b1a9SYuval Mintz /* This isn't really needed/enforced, but some legacy VFs might depend 12191cf2b1a9SYuval Mintz * on the correct filling of this field. 12201cf2b1a9SYuval Mintz */ 12211cf2b1a9SYuval Mintz p_resp->num_mc_filters = QED_MAX_MC_ADDRS; 12221cf2b1a9SYuval Mintz 12231cf2b1a9SYuval Mintz /* Validate sufficient resources for VF */ 12241cf2b1a9SYuval Mintz if (p_resp->num_rxqs < p_req->num_rxqs || 12251cf2b1a9SYuval Mintz p_resp->num_txqs < p_req->num_txqs || 12261cf2b1a9SYuval Mintz p_resp->num_sbs < p_req->num_sbs || 12271cf2b1a9SYuval Mintz p_resp->num_mac_filters < p_req->num_mac_filters || 12281cf2b1a9SYuval Mintz p_resp->num_vlan_filters < p_req->num_vlan_filters || 12291cf2b1a9SYuval Mintz p_resp->num_mc_filters < p_req->num_mc_filters) { 12301cf2b1a9SYuval Mintz DP_VERBOSE(p_hwfn, 12311cf2b1a9SYuval Mintz QED_MSG_IOV, 12321cf2b1a9SYuval Mintz "VF[%d] - Insufficient resources: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x]\n", 12331cf2b1a9SYuval Mintz p_vf->abs_vf_id, 12341cf2b1a9SYuval Mintz p_req->num_rxqs, 12351cf2b1a9SYuval Mintz p_resp->num_rxqs, 12361cf2b1a9SYuval Mintz p_req->num_rxqs, 12371cf2b1a9SYuval Mintz p_resp->num_txqs, 12381cf2b1a9SYuval Mintz p_req->num_sbs, 12391cf2b1a9SYuval Mintz p_resp->num_sbs, 12401cf2b1a9SYuval Mintz p_req->num_mac_filters, 12411cf2b1a9SYuval Mintz p_resp->num_mac_filters, 12421cf2b1a9SYuval Mintz p_req->num_vlan_filters, 12431cf2b1a9SYuval Mintz p_resp->num_vlan_filters, 12441cf2b1a9SYuval Mintz p_req->num_mc_filters, p_resp->num_mc_filters); 1245a044df83SYuval Mintz 1246a044df83SYuval Mintz /* Some legacy OSes are incapable of correctly handling this 1247a044df83SYuval Mintz * failure. 1248a044df83SYuval Mintz */ 1249a044df83SYuval Mintz if ((p_vf->acquire.vfdev_info.eth_fp_hsi_minor == 1250a044df83SYuval Mintz ETH_HSI_VER_NO_PKT_LEN_TUNN) && 1251a044df83SYuval Mintz (p_vf->acquire.vfdev_info.os_type == 1252a044df83SYuval Mintz VFPF_ACQUIRE_OS_WINDOWS)) 1253a044df83SYuval Mintz return PFVF_STATUS_SUCCESS; 1254a044df83SYuval Mintz 12551cf2b1a9SYuval Mintz return PFVF_STATUS_NO_RESOURCE; 12561cf2b1a9SYuval Mintz } 12571cf2b1a9SYuval Mintz 12581cf2b1a9SYuval Mintz return PFVF_STATUS_SUCCESS; 12591cf2b1a9SYuval Mintz } 12601cf2b1a9SYuval Mintz 12611cf2b1a9SYuval Mintz static void qed_iov_vf_mbx_acquire_stats(struct qed_hwfn *p_hwfn, 12621cf2b1a9SYuval Mintz struct pfvf_stats_info *p_stats) 12631cf2b1a9SYuval Mintz { 12641cf2b1a9SYuval Mintz p_stats->mstats.address = PXP_VF_BAR0_START_MSDM_ZONE_B + 12651cf2b1a9SYuval Mintz offsetof(struct mstorm_vf_zone, 12661cf2b1a9SYuval Mintz non_trigger.eth_queue_stat); 12671cf2b1a9SYuval Mintz p_stats->mstats.len = sizeof(struct eth_mstorm_per_queue_stat); 12681cf2b1a9SYuval Mintz p_stats->ustats.address = PXP_VF_BAR0_START_USDM_ZONE_B + 12691cf2b1a9SYuval Mintz offsetof(struct ustorm_vf_zone, 12701cf2b1a9SYuval Mintz non_trigger.eth_queue_stat); 12711cf2b1a9SYuval Mintz p_stats->ustats.len = sizeof(struct eth_ustorm_per_queue_stat); 12721cf2b1a9SYuval Mintz p_stats->pstats.address = PXP_VF_BAR0_START_PSDM_ZONE_B + 12731cf2b1a9SYuval Mintz offsetof(struct pstorm_vf_zone, 12741cf2b1a9SYuval Mintz non_trigger.eth_queue_stat); 12751cf2b1a9SYuval Mintz p_stats->pstats.len = sizeof(struct eth_pstorm_per_queue_stat); 12761cf2b1a9SYuval Mintz p_stats->tstats.address = 0; 12771cf2b1a9SYuval Mintz p_stats->tstats.len = 0; 12781cf2b1a9SYuval Mintz } 12791cf2b1a9SYuval Mintz 12801408cc1fSYuval Mintz static void qed_iov_vf_mbx_acquire(struct qed_hwfn *p_hwfn, 128137bff2b9SYuval Mintz struct qed_ptt *p_ptt, 12821408cc1fSYuval Mintz struct qed_vf_info *vf) 128337bff2b9SYuval Mintz { 12841408cc1fSYuval Mintz struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 12851408cc1fSYuval Mintz struct pfvf_acquire_resp_tlv *resp = &mbx->reply_virt->acquire_resp; 12861408cc1fSYuval Mintz struct pf_vf_pfdev_info *pfdev_info = &resp->pfdev_info; 12871408cc1fSYuval Mintz struct vfpf_acquire_tlv *req = &mbx->req_virt->acquire; 12881cf2b1a9SYuval Mintz u8 vfpf_status = PFVF_STATUS_NOT_SUPPORTED; 12891408cc1fSYuval Mintz struct pf_vf_resc *resc = &resp->resc; 12901fe614d1SYuval Mintz int rc; 12911fe614d1SYuval Mintz 12921fe614d1SYuval Mintz memset(resp, 0, sizeof(*resp)); 12931408cc1fSYuval Mintz 129405fafbfbSYuval Mintz /* Write the PF version so that VF would know which version 129505fafbfbSYuval Mintz * is supported - might be later overriden. This guarantees that 129605fafbfbSYuval Mintz * VF could recognize legacy PF based on lack of versions in reply. 129705fafbfbSYuval Mintz */ 129805fafbfbSYuval Mintz pfdev_info->major_fp_hsi = ETH_HSI_VER_MAJOR; 129905fafbfbSYuval Mintz pfdev_info->minor_fp_hsi = ETH_HSI_VER_MINOR; 130005fafbfbSYuval Mintz 1301a044df83SYuval Mintz if (vf->state != VF_FREE && vf->state != VF_STOPPED) { 1302a044df83SYuval Mintz DP_VERBOSE(p_hwfn, 1303a044df83SYuval Mintz QED_MSG_IOV, 1304a044df83SYuval Mintz "VF[%d] sent ACQUIRE but is already in state %d - fail request\n", 1305a044df83SYuval Mintz vf->abs_vf_id, vf->state); 1306a044df83SYuval Mintz goto out; 1307a044df83SYuval Mintz } 1308a044df83SYuval Mintz 13091408cc1fSYuval Mintz /* Validate FW compatibility */ 13101fe614d1SYuval Mintz if (req->vfdev_info.eth_fp_hsi_major != ETH_HSI_VER_MAJOR) { 1311a044df83SYuval Mintz if (req->vfdev_info.capabilities & 1312a044df83SYuval Mintz VFPF_ACQUIRE_CAP_PRE_FP_HSI) { 1313a044df83SYuval Mintz struct vf_pf_vfdev_info *p_vfdev = &req->vfdev_info; 1314a044df83SYuval Mintz 1315a044df83SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 1316a044df83SYuval Mintz "VF[%d] is pre-fastpath HSI\n", 1317a044df83SYuval Mintz vf->abs_vf_id); 1318a044df83SYuval Mintz p_vfdev->eth_fp_hsi_major = ETH_HSI_VER_MAJOR; 1319a044df83SYuval Mintz p_vfdev->eth_fp_hsi_minor = ETH_HSI_VER_NO_PKT_LEN_TUNN; 1320a044df83SYuval Mintz } else { 13211408cc1fSYuval Mintz DP_INFO(p_hwfn, 13221fe614d1SYuval Mintz "VF[%d] needs fastpath HSI %02x.%02x, which is incompatible with loaded FW's faspath HSI %02x.%02x\n", 13231408cc1fSYuval Mintz vf->abs_vf_id, 13241fe614d1SYuval Mintz req->vfdev_info.eth_fp_hsi_major, 13251fe614d1SYuval Mintz req->vfdev_info.eth_fp_hsi_minor, 13261fe614d1SYuval Mintz ETH_HSI_VER_MAJOR, ETH_HSI_VER_MINOR); 13271fe614d1SYuval Mintz 13281408cc1fSYuval Mintz goto out; 13291408cc1fSYuval Mintz } 1330a044df83SYuval Mintz } 13311408cc1fSYuval Mintz 13321408cc1fSYuval Mintz /* On 100g PFs, prevent old VFs from loading */ 13331408cc1fSYuval Mintz if ((p_hwfn->cdev->num_hwfns > 1) && 13341408cc1fSYuval Mintz !(req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_100G)) { 13351408cc1fSYuval Mintz DP_INFO(p_hwfn, 13361408cc1fSYuval Mintz "VF[%d] is running an old driver that doesn't support 100g\n", 13371408cc1fSYuval Mintz vf->abs_vf_id); 13381408cc1fSYuval Mintz goto out; 13391408cc1fSYuval Mintz } 13401408cc1fSYuval Mintz 13411fe614d1SYuval Mintz /* Store the acquire message */ 13421fe614d1SYuval Mintz memcpy(&vf->acquire, req, sizeof(vf->acquire)); 13431408cc1fSYuval Mintz 13441408cc1fSYuval Mintz vf->opaque_fid = req->vfdev_info.opaque_fid; 13451408cc1fSYuval Mintz 13461408cc1fSYuval Mintz vf->vf_bulletin = req->bulletin_addr; 13471408cc1fSYuval Mintz vf->bulletin.size = (vf->bulletin.size < req->bulletin_size) ? 13481408cc1fSYuval Mintz vf->bulletin.size : req->bulletin_size; 13491408cc1fSYuval Mintz 13501408cc1fSYuval Mintz /* fill in pfdev info */ 13511408cc1fSYuval Mintz pfdev_info->chip_num = p_hwfn->cdev->chip_num; 13521408cc1fSYuval Mintz pfdev_info->db_size = 0; 13531408cc1fSYuval Mintz pfdev_info->indices_per_sb = PIS_PER_SB; 13541408cc1fSYuval Mintz 13551408cc1fSYuval Mintz pfdev_info->capabilities = PFVF_ACQUIRE_CAP_DEFAULT_UNTAGGED | 13561408cc1fSYuval Mintz PFVF_ACQUIRE_CAP_POST_FW_OVERRIDE; 13571408cc1fSYuval Mintz if (p_hwfn->cdev->num_hwfns > 1) 13581408cc1fSYuval Mintz pfdev_info->capabilities |= PFVF_ACQUIRE_CAP_100G; 13591408cc1fSYuval Mintz 13601cf2b1a9SYuval Mintz qed_iov_vf_mbx_acquire_stats(p_hwfn, &pfdev_info->stats_info); 13611408cc1fSYuval Mintz 13621408cc1fSYuval Mintz memcpy(pfdev_info->port_mac, p_hwfn->hw_info.hw_mac_addr, ETH_ALEN); 13631408cc1fSYuval Mintz 13641408cc1fSYuval Mintz pfdev_info->fw_major = FW_MAJOR_VERSION; 13651408cc1fSYuval Mintz pfdev_info->fw_minor = FW_MINOR_VERSION; 13661408cc1fSYuval Mintz pfdev_info->fw_rev = FW_REVISION_VERSION; 13671408cc1fSYuval Mintz pfdev_info->fw_eng = FW_ENGINEERING_VERSION; 1368a044df83SYuval Mintz 1369a044df83SYuval Mintz /* Incorrect when legacy, but doesn't matter as legacy isn't reading 1370a044df83SYuval Mintz * this field. 1371a044df83SYuval Mintz */ 13721a635e48SYuval Mintz pfdev_info->minor_fp_hsi = min_t(u8, ETH_HSI_VER_MINOR, 13731fe614d1SYuval Mintz req->vfdev_info.eth_fp_hsi_minor); 13741408cc1fSYuval Mintz pfdev_info->os_type = VFPF_ACQUIRE_OS_LINUX; 13751408cc1fSYuval Mintz qed_mcp_get_mfw_ver(p_hwfn, p_ptt, &pfdev_info->mfw_ver, NULL); 13761408cc1fSYuval Mintz 13771408cc1fSYuval Mintz pfdev_info->dev_type = p_hwfn->cdev->type; 13781408cc1fSYuval Mintz pfdev_info->chip_rev = p_hwfn->cdev->chip_rev; 13791408cc1fSYuval Mintz 13801cf2b1a9SYuval Mintz /* Fill resources available to VF; Make sure there are enough to 13811cf2b1a9SYuval Mintz * satisfy the VF's request. 13821408cc1fSYuval Mintz */ 13831cf2b1a9SYuval Mintz vfpf_status = qed_iov_vf_mbx_acquire_resc(p_hwfn, p_ptt, vf, 13841cf2b1a9SYuval Mintz &req->resc_request, resc); 13851cf2b1a9SYuval Mintz if (vfpf_status != PFVF_STATUS_SUCCESS) 13861cf2b1a9SYuval Mintz goto out; 13871408cc1fSYuval Mintz 13881fe614d1SYuval Mintz /* Start the VF in FW */ 13891fe614d1SYuval Mintz rc = qed_sp_vf_start(p_hwfn, vf); 13901fe614d1SYuval Mintz if (rc) { 13911fe614d1SYuval Mintz DP_NOTICE(p_hwfn, "Failed to start VF[%02x]\n", vf->abs_vf_id); 13921fe614d1SYuval Mintz vfpf_status = PFVF_STATUS_FAILURE; 13931fe614d1SYuval Mintz goto out; 13941fe614d1SYuval Mintz } 13951fe614d1SYuval Mintz 13961408cc1fSYuval Mintz /* Fill agreed size of bulletin board in response */ 13971408cc1fSYuval Mintz resp->bulletin_size = vf->bulletin.size; 139836558c3dSYuval Mintz qed_iov_post_vf_bulletin(p_hwfn, vf->relative_vf_id, p_ptt); 13991408cc1fSYuval Mintz 14001408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, 14011408cc1fSYuval Mintz QED_MSG_IOV, 14021408cc1fSYuval Mintz "VF[%d] ACQUIRE_RESPONSE: pfdev_info- chip_num=0x%x, db_size=%d, idx_per_sb=%d, pf_cap=0x%llx\n" 14031408cc1fSYuval Mintz "resources- n_rxq-%d, n_txq-%d, n_sbs-%d, n_macs-%d, n_vlans-%d\n", 14041408cc1fSYuval Mintz vf->abs_vf_id, 14051408cc1fSYuval Mintz resp->pfdev_info.chip_num, 14061408cc1fSYuval Mintz resp->pfdev_info.db_size, 14071408cc1fSYuval Mintz resp->pfdev_info.indices_per_sb, 14081408cc1fSYuval Mintz resp->pfdev_info.capabilities, 14091408cc1fSYuval Mintz resc->num_rxqs, 14101408cc1fSYuval Mintz resc->num_txqs, 14111408cc1fSYuval Mintz resc->num_sbs, 14121408cc1fSYuval Mintz resc->num_mac_filters, 14131408cc1fSYuval Mintz resc->num_vlan_filters); 14141408cc1fSYuval Mintz vf->state = VF_ACQUIRED; 14151408cc1fSYuval Mintz 14161408cc1fSYuval Mintz /* Prepare Response */ 14171408cc1fSYuval Mintz out: 14181408cc1fSYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_ACQUIRE, 14191408cc1fSYuval Mintz sizeof(struct pfvf_acquire_resp_tlv), vfpf_status); 142037bff2b9SYuval Mintz } 142137bff2b9SYuval Mintz 14226ddc7608SYuval Mintz static int __qed_iov_spoofchk_set(struct qed_hwfn *p_hwfn, 14236ddc7608SYuval Mintz struct qed_vf_info *p_vf, bool val) 14246ddc7608SYuval Mintz { 14256ddc7608SYuval Mintz struct qed_sp_vport_update_params params; 14266ddc7608SYuval Mintz int rc; 14276ddc7608SYuval Mintz 14286ddc7608SYuval Mintz if (val == p_vf->spoof_chk) { 14296ddc7608SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 14306ddc7608SYuval Mintz "Spoofchk value[%d] is already configured\n", val); 14316ddc7608SYuval Mintz return 0; 14326ddc7608SYuval Mintz } 14336ddc7608SYuval Mintz 14346ddc7608SYuval Mintz memset(¶ms, 0, sizeof(struct qed_sp_vport_update_params)); 14356ddc7608SYuval Mintz params.opaque_fid = p_vf->opaque_fid; 14366ddc7608SYuval Mintz params.vport_id = p_vf->vport_id; 14376ddc7608SYuval Mintz params.update_anti_spoofing_en_flg = 1; 14386ddc7608SYuval Mintz params.anti_spoofing_en = val; 14396ddc7608SYuval Mintz 14406ddc7608SYuval Mintz rc = qed_sp_vport_update(p_hwfn, ¶ms, QED_SPQ_MODE_EBLOCK, NULL); 1441cb1fa088SYuval Mintz if (!rc) { 14426ddc7608SYuval Mintz p_vf->spoof_chk = val; 14436ddc7608SYuval Mintz p_vf->req_spoofchk_val = p_vf->spoof_chk; 14446ddc7608SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 14456ddc7608SYuval Mintz "Spoofchk val[%d] configured\n", val); 14466ddc7608SYuval Mintz } else { 14476ddc7608SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 14486ddc7608SYuval Mintz "Spoofchk configuration[val:%d] failed for VF[%d]\n", 14496ddc7608SYuval Mintz val, p_vf->relative_vf_id); 14506ddc7608SYuval Mintz } 14516ddc7608SYuval Mintz 14526ddc7608SYuval Mintz return rc; 14536ddc7608SYuval Mintz } 14546ddc7608SYuval Mintz 145508feecd7SYuval Mintz static int qed_iov_reconfigure_unicast_vlan(struct qed_hwfn *p_hwfn, 145608feecd7SYuval Mintz struct qed_vf_info *p_vf) 145708feecd7SYuval Mintz { 145808feecd7SYuval Mintz struct qed_filter_ucast filter; 145908feecd7SYuval Mintz int rc = 0; 146008feecd7SYuval Mintz int i; 146108feecd7SYuval Mintz 146208feecd7SYuval Mintz memset(&filter, 0, sizeof(filter)); 146308feecd7SYuval Mintz filter.is_rx_filter = 1; 146408feecd7SYuval Mintz filter.is_tx_filter = 1; 146508feecd7SYuval Mintz filter.vport_to_add_to = p_vf->vport_id; 146608feecd7SYuval Mintz filter.opcode = QED_FILTER_ADD; 146708feecd7SYuval Mintz 146808feecd7SYuval Mintz /* Reconfigure vlans */ 146908feecd7SYuval Mintz for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++) { 147008feecd7SYuval Mintz if (!p_vf->shadow_config.vlans[i].used) 147108feecd7SYuval Mintz continue; 147208feecd7SYuval Mintz 147308feecd7SYuval Mintz filter.type = QED_FILTER_VLAN; 147408feecd7SYuval Mintz filter.vlan = p_vf->shadow_config.vlans[i].vid; 14751a635e48SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 147608feecd7SYuval Mintz "Reconfiguring VLAN [0x%04x] for VF [%04x]\n", 147708feecd7SYuval Mintz filter.vlan, p_vf->relative_vf_id); 14781a635e48SYuval Mintz rc = qed_sp_eth_filter_ucast(p_hwfn, p_vf->opaque_fid, 14791a635e48SYuval Mintz &filter, QED_SPQ_MODE_CB, NULL); 148008feecd7SYuval Mintz if (rc) { 148108feecd7SYuval Mintz DP_NOTICE(p_hwfn, 148208feecd7SYuval Mintz "Failed to configure VLAN [%04x] to VF [%04x]\n", 148308feecd7SYuval Mintz filter.vlan, p_vf->relative_vf_id); 148408feecd7SYuval Mintz break; 148508feecd7SYuval Mintz } 148608feecd7SYuval Mintz } 148708feecd7SYuval Mintz 148808feecd7SYuval Mintz return rc; 148908feecd7SYuval Mintz } 149008feecd7SYuval Mintz 149108feecd7SYuval Mintz static int 149208feecd7SYuval Mintz qed_iov_reconfigure_unicast_shadow(struct qed_hwfn *p_hwfn, 149308feecd7SYuval Mintz struct qed_vf_info *p_vf, u64 events) 149408feecd7SYuval Mintz { 149508feecd7SYuval Mintz int rc = 0; 149608feecd7SYuval Mintz 14971a635e48SYuval Mintz if ((events & BIT(VLAN_ADDR_FORCED)) && 149808feecd7SYuval Mintz !(p_vf->configured_features & (1 << VLAN_ADDR_FORCED))) 149908feecd7SYuval Mintz rc = qed_iov_reconfigure_unicast_vlan(p_hwfn, p_vf); 150008feecd7SYuval Mintz 150108feecd7SYuval Mintz return rc; 150208feecd7SYuval Mintz } 150308feecd7SYuval Mintz 150408feecd7SYuval Mintz static int qed_iov_configure_vport_forced(struct qed_hwfn *p_hwfn, 150508feecd7SYuval Mintz struct qed_vf_info *p_vf, u64 events) 150608feecd7SYuval Mintz { 150708feecd7SYuval Mintz int rc = 0; 150808feecd7SYuval Mintz struct qed_filter_ucast filter; 150908feecd7SYuval Mintz 151008feecd7SYuval Mintz if (!p_vf->vport_instance) 151108feecd7SYuval Mintz return -EINVAL; 151208feecd7SYuval Mintz 15131a635e48SYuval Mintz if (events & BIT(MAC_ADDR_FORCED)) { 1514eff16960SYuval Mintz /* Since there's no way [currently] of removing the MAC, 1515eff16960SYuval Mintz * we can always assume this means we need to force it. 1516eff16960SYuval Mintz */ 1517eff16960SYuval Mintz memset(&filter, 0, sizeof(filter)); 1518eff16960SYuval Mintz filter.type = QED_FILTER_MAC; 1519eff16960SYuval Mintz filter.opcode = QED_FILTER_REPLACE; 1520eff16960SYuval Mintz filter.is_rx_filter = 1; 1521eff16960SYuval Mintz filter.is_tx_filter = 1; 1522eff16960SYuval Mintz filter.vport_to_add_to = p_vf->vport_id; 1523eff16960SYuval Mintz ether_addr_copy(filter.mac, p_vf->bulletin.p_virt->mac); 1524eff16960SYuval Mintz 1525eff16960SYuval Mintz rc = qed_sp_eth_filter_ucast(p_hwfn, p_vf->opaque_fid, 1526eff16960SYuval Mintz &filter, QED_SPQ_MODE_CB, NULL); 1527eff16960SYuval Mintz if (rc) { 1528eff16960SYuval Mintz DP_NOTICE(p_hwfn, 1529eff16960SYuval Mintz "PF failed to configure MAC for VF\n"); 1530eff16960SYuval Mintz return rc; 1531eff16960SYuval Mintz } 1532eff16960SYuval Mintz 1533eff16960SYuval Mintz p_vf->configured_features |= 1 << MAC_ADDR_FORCED; 1534eff16960SYuval Mintz } 1535eff16960SYuval Mintz 15361a635e48SYuval Mintz if (events & BIT(VLAN_ADDR_FORCED)) { 153708feecd7SYuval Mintz struct qed_sp_vport_update_params vport_update; 153808feecd7SYuval Mintz u8 removal; 153908feecd7SYuval Mintz int i; 154008feecd7SYuval Mintz 154108feecd7SYuval Mintz memset(&filter, 0, sizeof(filter)); 154208feecd7SYuval Mintz filter.type = QED_FILTER_VLAN; 154308feecd7SYuval Mintz filter.is_rx_filter = 1; 154408feecd7SYuval Mintz filter.is_tx_filter = 1; 154508feecd7SYuval Mintz filter.vport_to_add_to = p_vf->vport_id; 154608feecd7SYuval Mintz filter.vlan = p_vf->bulletin.p_virt->pvid; 154708feecd7SYuval Mintz filter.opcode = filter.vlan ? QED_FILTER_REPLACE : 154808feecd7SYuval Mintz QED_FILTER_FLUSH; 154908feecd7SYuval Mintz 155008feecd7SYuval Mintz /* Send the ramrod */ 155108feecd7SYuval Mintz rc = qed_sp_eth_filter_ucast(p_hwfn, p_vf->opaque_fid, 155208feecd7SYuval Mintz &filter, QED_SPQ_MODE_CB, NULL); 155308feecd7SYuval Mintz if (rc) { 155408feecd7SYuval Mintz DP_NOTICE(p_hwfn, 155508feecd7SYuval Mintz "PF failed to configure VLAN for VF\n"); 155608feecd7SYuval Mintz return rc; 155708feecd7SYuval Mintz } 155808feecd7SYuval Mintz 155908feecd7SYuval Mintz /* Update the default-vlan & silent vlan stripping */ 156008feecd7SYuval Mintz memset(&vport_update, 0, sizeof(vport_update)); 156108feecd7SYuval Mintz vport_update.opaque_fid = p_vf->opaque_fid; 156208feecd7SYuval Mintz vport_update.vport_id = p_vf->vport_id; 156308feecd7SYuval Mintz vport_update.update_default_vlan_enable_flg = 1; 156408feecd7SYuval Mintz vport_update.default_vlan_enable_flg = filter.vlan ? 1 : 0; 156508feecd7SYuval Mintz vport_update.update_default_vlan_flg = 1; 156608feecd7SYuval Mintz vport_update.default_vlan = filter.vlan; 156708feecd7SYuval Mintz 156808feecd7SYuval Mintz vport_update.update_inner_vlan_removal_flg = 1; 156908feecd7SYuval Mintz removal = filter.vlan ? 1 157008feecd7SYuval Mintz : p_vf->shadow_config.inner_vlan_removal; 157108feecd7SYuval Mintz vport_update.inner_vlan_removal_flg = removal; 157208feecd7SYuval Mintz vport_update.silent_vlan_removal_flg = filter.vlan ? 1 : 0; 157308feecd7SYuval Mintz rc = qed_sp_vport_update(p_hwfn, 157408feecd7SYuval Mintz &vport_update, 157508feecd7SYuval Mintz QED_SPQ_MODE_EBLOCK, NULL); 157608feecd7SYuval Mintz if (rc) { 157708feecd7SYuval Mintz DP_NOTICE(p_hwfn, 157808feecd7SYuval Mintz "PF failed to configure VF vport for vlan\n"); 157908feecd7SYuval Mintz return rc; 158008feecd7SYuval Mintz } 158108feecd7SYuval Mintz 158208feecd7SYuval Mintz /* Update all the Rx queues */ 158308feecd7SYuval Mintz for (i = 0; i < QED_MAX_VF_CHAINS_PER_PF; i++) { 158408feecd7SYuval Mintz u16 qid; 158508feecd7SYuval Mintz 158608feecd7SYuval Mintz if (!p_vf->vf_queues[i].rxq_active) 158708feecd7SYuval Mintz continue; 158808feecd7SYuval Mintz 158908feecd7SYuval Mintz qid = p_vf->vf_queues[i].fw_rx_qid; 159008feecd7SYuval Mintz 159108feecd7SYuval Mintz rc = qed_sp_eth_rx_queues_update(p_hwfn, qid, 159208feecd7SYuval Mintz 1, 0, 1, 159308feecd7SYuval Mintz QED_SPQ_MODE_EBLOCK, 159408feecd7SYuval Mintz NULL); 159508feecd7SYuval Mintz if (rc) { 159608feecd7SYuval Mintz DP_NOTICE(p_hwfn, 159708feecd7SYuval Mintz "Failed to send Rx update fo queue[0x%04x]\n", 159808feecd7SYuval Mintz qid); 159908feecd7SYuval Mintz return rc; 160008feecd7SYuval Mintz } 160108feecd7SYuval Mintz } 160208feecd7SYuval Mintz 160308feecd7SYuval Mintz if (filter.vlan) 160408feecd7SYuval Mintz p_vf->configured_features |= 1 << VLAN_ADDR_FORCED; 160508feecd7SYuval Mintz else 16061a635e48SYuval Mintz p_vf->configured_features &= ~BIT(VLAN_ADDR_FORCED); 160708feecd7SYuval Mintz } 160808feecd7SYuval Mintz 160908feecd7SYuval Mintz /* If forced features are terminated, we need to configure the shadow 161008feecd7SYuval Mintz * configuration back again. 161108feecd7SYuval Mintz */ 161208feecd7SYuval Mintz if (events) 161308feecd7SYuval Mintz qed_iov_reconfigure_unicast_shadow(p_hwfn, p_vf, events); 161408feecd7SYuval Mintz 161508feecd7SYuval Mintz return rc; 161608feecd7SYuval Mintz } 161708feecd7SYuval Mintz 1618dacd88d6SYuval Mintz static void qed_iov_vf_mbx_start_vport(struct qed_hwfn *p_hwfn, 1619dacd88d6SYuval Mintz struct qed_ptt *p_ptt, 1620dacd88d6SYuval Mintz struct qed_vf_info *vf) 1621dacd88d6SYuval Mintz { 1622dacd88d6SYuval Mintz struct qed_sp_vport_start_params params = { 0 }; 1623dacd88d6SYuval Mintz struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 1624dacd88d6SYuval Mintz struct vfpf_vport_start_tlv *start; 1625dacd88d6SYuval Mintz u8 status = PFVF_STATUS_SUCCESS; 1626dacd88d6SYuval Mintz struct qed_vf_info *vf_info; 162708feecd7SYuval Mintz u64 *p_bitmap; 1628dacd88d6SYuval Mintz int sb_id; 1629dacd88d6SYuval Mintz int rc; 1630dacd88d6SYuval Mintz 1631dacd88d6SYuval Mintz vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vf->relative_vf_id, true); 1632dacd88d6SYuval Mintz if (!vf_info) { 1633dacd88d6SYuval Mintz DP_NOTICE(p_hwfn->cdev, 1634dacd88d6SYuval Mintz "Failed to get VF info, invalid vfid [%d]\n", 1635dacd88d6SYuval Mintz vf->relative_vf_id); 1636dacd88d6SYuval Mintz return; 1637dacd88d6SYuval Mintz } 1638dacd88d6SYuval Mintz 1639dacd88d6SYuval Mintz vf->state = VF_ENABLED; 1640dacd88d6SYuval Mintz start = &mbx->req_virt->start_vport; 1641dacd88d6SYuval Mintz 1642dacd88d6SYuval Mintz /* Initialize Status block in CAU */ 1643dacd88d6SYuval Mintz for (sb_id = 0; sb_id < vf->num_sbs; sb_id++) { 1644dacd88d6SYuval Mintz if (!start->sb_addr[sb_id]) { 1645dacd88d6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 1646dacd88d6SYuval Mintz "VF[%d] did not fill the address of SB %d\n", 1647dacd88d6SYuval Mintz vf->relative_vf_id, sb_id); 1648dacd88d6SYuval Mintz break; 1649dacd88d6SYuval Mintz } 1650dacd88d6SYuval Mintz 1651dacd88d6SYuval Mintz qed_int_cau_conf_sb(p_hwfn, p_ptt, 1652dacd88d6SYuval Mintz start->sb_addr[sb_id], 16531a635e48SYuval Mintz vf->igu_sbs[sb_id], vf->abs_vf_id, 1); 1654dacd88d6SYuval Mintz } 1655dacd88d6SYuval Mintz qed_iov_enable_vf_traffic(p_hwfn, p_ptt, vf); 1656dacd88d6SYuval Mintz 1657dacd88d6SYuval Mintz vf->mtu = start->mtu; 165808feecd7SYuval Mintz vf->shadow_config.inner_vlan_removal = start->inner_vlan_removal; 165908feecd7SYuval Mintz 166008feecd7SYuval Mintz /* Take into consideration configuration forced by hypervisor; 166108feecd7SYuval Mintz * If none is configured, use the supplied VF values [for old 166208feecd7SYuval Mintz * vfs that would still be fine, since they passed '0' as padding]. 166308feecd7SYuval Mintz */ 166408feecd7SYuval Mintz p_bitmap = &vf_info->bulletin.p_virt->valid_bitmap; 16651a635e48SYuval Mintz if (!(*p_bitmap & BIT(VFPF_BULLETIN_UNTAGGED_DEFAULT_FORCED))) { 166608feecd7SYuval Mintz u8 vf_req = start->only_untagged; 166708feecd7SYuval Mintz 166808feecd7SYuval Mintz vf_info->bulletin.p_virt->default_only_untagged = vf_req; 166908feecd7SYuval Mintz *p_bitmap |= 1 << VFPF_BULLETIN_UNTAGGED_DEFAULT; 167008feecd7SYuval Mintz } 1671dacd88d6SYuval Mintz 1672dacd88d6SYuval Mintz params.tpa_mode = start->tpa_mode; 1673dacd88d6SYuval Mintz params.remove_inner_vlan = start->inner_vlan_removal; 1674831bfb0eSYuval Mintz params.tx_switching = true; 1675dacd88d6SYuval Mintz 167608feecd7SYuval Mintz params.only_untagged = vf_info->bulletin.p_virt->default_only_untagged; 1677dacd88d6SYuval Mintz params.drop_ttl0 = false; 1678dacd88d6SYuval Mintz params.concrete_fid = vf->concrete_fid; 1679dacd88d6SYuval Mintz params.opaque_fid = vf->opaque_fid; 1680dacd88d6SYuval Mintz params.vport_id = vf->vport_id; 1681dacd88d6SYuval Mintz params.max_buffers_per_cqe = start->max_buffers_per_cqe; 1682dacd88d6SYuval Mintz params.mtu = vf->mtu; 1683dacd88d6SYuval Mintz 1684dacd88d6SYuval Mintz rc = qed_sp_eth_vport_start(p_hwfn, ¶ms); 16851a635e48SYuval Mintz if (rc) { 1686dacd88d6SYuval Mintz DP_ERR(p_hwfn, 1687dacd88d6SYuval Mintz "qed_iov_vf_mbx_start_vport returned error %d\n", rc); 1688dacd88d6SYuval Mintz status = PFVF_STATUS_FAILURE; 1689dacd88d6SYuval Mintz } else { 1690dacd88d6SYuval Mintz vf->vport_instance++; 169108feecd7SYuval Mintz 169208feecd7SYuval Mintz /* Force configuration if needed on the newly opened vport */ 169308feecd7SYuval Mintz qed_iov_configure_vport_forced(p_hwfn, vf, *p_bitmap); 16946ddc7608SYuval Mintz 16956ddc7608SYuval Mintz __qed_iov_spoofchk_set(p_hwfn, vf, vf->req_spoofchk_val); 1696dacd88d6SYuval Mintz } 1697dacd88d6SYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_VPORT_START, 1698dacd88d6SYuval Mintz sizeof(struct pfvf_def_resp_tlv), status); 1699dacd88d6SYuval Mintz } 1700dacd88d6SYuval Mintz 1701dacd88d6SYuval Mintz static void qed_iov_vf_mbx_stop_vport(struct qed_hwfn *p_hwfn, 1702dacd88d6SYuval Mintz struct qed_ptt *p_ptt, 1703dacd88d6SYuval Mintz struct qed_vf_info *vf) 1704dacd88d6SYuval Mintz { 1705dacd88d6SYuval Mintz u8 status = PFVF_STATUS_SUCCESS; 1706dacd88d6SYuval Mintz int rc; 1707dacd88d6SYuval Mintz 1708dacd88d6SYuval Mintz vf->vport_instance--; 17096ddc7608SYuval Mintz vf->spoof_chk = false; 1710dacd88d6SYuval Mintz 1711dacd88d6SYuval Mintz rc = qed_sp_vport_stop(p_hwfn, vf->opaque_fid, vf->vport_id); 17121a635e48SYuval Mintz if (rc) { 1713dacd88d6SYuval Mintz DP_ERR(p_hwfn, "qed_iov_vf_mbx_stop_vport returned error %d\n", 1714dacd88d6SYuval Mintz rc); 1715dacd88d6SYuval Mintz status = PFVF_STATUS_FAILURE; 1716dacd88d6SYuval Mintz } 1717dacd88d6SYuval Mintz 171808feecd7SYuval Mintz /* Forget the configuration on the vport */ 171908feecd7SYuval Mintz vf->configured_features = 0; 172008feecd7SYuval Mintz memset(&vf->shadow_config, 0, sizeof(vf->shadow_config)); 172108feecd7SYuval Mintz 1722dacd88d6SYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_VPORT_TEARDOWN, 1723dacd88d6SYuval Mintz sizeof(struct pfvf_def_resp_tlv), status); 1724dacd88d6SYuval Mintz } 1725dacd88d6SYuval Mintz 1726dacd88d6SYuval Mintz static void qed_iov_vf_mbx_start_rxq_resp(struct qed_hwfn *p_hwfn, 1727dacd88d6SYuval Mintz struct qed_ptt *p_ptt, 1728a044df83SYuval Mintz struct qed_vf_info *vf, 1729a044df83SYuval Mintz u8 status, bool b_legacy) 1730dacd88d6SYuval Mintz { 1731dacd88d6SYuval Mintz struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 1732dacd88d6SYuval Mintz struct pfvf_start_queue_resp_tlv *p_tlv; 1733dacd88d6SYuval Mintz struct vfpf_start_rxq_tlv *req; 1734a044df83SYuval Mintz u16 length; 1735dacd88d6SYuval Mintz 1736dacd88d6SYuval Mintz mbx->offset = (u8 *)mbx->reply_virt; 1737dacd88d6SYuval Mintz 1738a044df83SYuval Mintz /* Taking a bigger struct instead of adding a TLV to list was a 1739a044df83SYuval Mintz * mistake, but one which we're now stuck with, as some older 1740a044df83SYuval Mintz * clients assume the size of the previous response. 1741a044df83SYuval Mintz */ 1742a044df83SYuval Mintz if (!b_legacy) 1743a044df83SYuval Mintz length = sizeof(*p_tlv); 1744a044df83SYuval Mintz else 1745a044df83SYuval Mintz length = sizeof(struct pfvf_def_resp_tlv); 1746a044df83SYuval Mintz 1747dacd88d6SYuval Mintz p_tlv = qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_START_RXQ, 1748a044df83SYuval Mintz length); 1749dacd88d6SYuval Mintz qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_LIST_END, 1750dacd88d6SYuval Mintz sizeof(struct channel_list_end_tlv)); 1751dacd88d6SYuval Mintz 1752dacd88d6SYuval Mintz /* Update the TLV with the response */ 1753a044df83SYuval Mintz if ((status == PFVF_STATUS_SUCCESS) && !b_legacy) { 1754dacd88d6SYuval Mintz req = &mbx->req_virt->start_rxq; 1755351a4dedSYuval Mintz p_tlv->offset = PXP_VF_BAR0_START_MSDM_ZONE_B + 1756351a4dedSYuval Mintz offsetof(struct mstorm_vf_zone, 1757351a4dedSYuval Mintz non_trigger.eth_rx_queue_producers) + 1758351a4dedSYuval Mintz sizeof(struct eth_rx_prod_data) * req->rx_qid; 1759dacd88d6SYuval Mintz } 1760dacd88d6SYuval Mintz 1761a044df83SYuval Mintz qed_iov_send_response(p_hwfn, p_ptt, vf, length, status); 1762dacd88d6SYuval Mintz } 1763dacd88d6SYuval Mintz 1764dacd88d6SYuval Mintz static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, 1765dacd88d6SYuval Mintz struct qed_ptt *p_ptt, 1766dacd88d6SYuval Mintz struct qed_vf_info *vf) 1767dacd88d6SYuval Mintz { 1768dacd88d6SYuval Mintz struct qed_queue_start_common_params params; 1769dacd88d6SYuval Mintz struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 177041086467SYuval Mintz u8 status = PFVF_STATUS_NO_RESOURCE; 1771dacd88d6SYuval Mintz struct vfpf_start_rxq_tlv *req; 1772a044df83SYuval Mintz bool b_legacy_vf = false; 1773dacd88d6SYuval Mintz int rc; 1774dacd88d6SYuval Mintz 1775dacd88d6SYuval Mintz memset(¶ms, 0, sizeof(params)); 1776dacd88d6SYuval Mintz req = &mbx->req_virt->start_rxq; 177741086467SYuval Mintz 177841086467SYuval Mintz if (!qed_iov_validate_rxq(p_hwfn, vf, req->rx_qid) || 177941086467SYuval Mintz !qed_iov_validate_sb(p_hwfn, vf, req->hw_sb)) 178041086467SYuval Mintz goto out; 178141086467SYuval Mintz 1782dacd88d6SYuval Mintz params.queue_id = vf->vf_queues[req->rx_qid].fw_rx_qid; 1783351a4dedSYuval Mintz params.vf_qid = req->rx_qid; 1784dacd88d6SYuval Mintz params.vport_id = vf->vport_id; 1785dacd88d6SYuval Mintz params.sb = req->hw_sb; 1786dacd88d6SYuval Mintz params.sb_idx = req->sb_index; 1787dacd88d6SYuval Mintz 1788a044df83SYuval Mintz /* Legacy VFs have their Producers in a different location, which they 1789a044df83SYuval Mintz * calculate on their own and clean the producer prior to this. 1790a044df83SYuval Mintz */ 1791a044df83SYuval Mintz if (vf->acquire.vfdev_info.eth_fp_hsi_minor == 1792a044df83SYuval Mintz ETH_HSI_VER_NO_PKT_LEN_TUNN) { 1793a044df83SYuval Mintz b_legacy_vf = true; 1794a044df83SYuval Mintz } else { 1795a044df83SYuval Mintz REG_WR(p_hwfn, 1796a044df83SYuval Mintz GTT_BAR0_MAP_REG_MSDM_RAM + 1797a044df83SYuval Mintz MSTORM_ETH_VF_PRODS_OFFSET(vf->abs_vf_id, req->rx_qid), 1798a044df83SYuval Mintz 0); 1799a044df83SYuval Mintz } 1800a044df83SYuval Mintz 1801dacd88d6SYuval Mintz rc = qed_sp_eth_rxq_start_ramrod(p_hwfn, vf->opaque_fid, 1802dacd88d6SYuval Mintz vf->vf_queues[req->rx_qid].fw_cid, 1803dacd88d6SYuval Mintz ¶ms, 1804dacd88d6SYuval Mintz vf->abs_vf_id + 0x10, 1805dacd88d6SYuval Mintz req->bd_max_bytes, 1806dacd88d6SYuval Mintz req->rxq_addr, 1807a044df83SYuval Mintz req->cqe_pbl_addr, req->cqe_pbl_size, 1808a044df83SYuval Mintz b_legacy_vf); 1809dacd88d6SYuval Mintz 1810dacd88d6SYuval Mintz if (rc) { 1811dacd88d6SYuval Mintz status = PFVF_STATUS_FAILURE; 1812dacd88d6SYuval Mintz } else { 181341086467SYuval Mintz status = PFVF_STATUS_SUCCESS; 1814dacd88d6SYuval Mintz vf->vf_queues[req->rx_qid].rxq_active = true; 1815dacd88d6SYuval Mintz vf->num_active_rxqs++; 1816dacd88d6SYuval Mintz } 1817dacd88d6SYuval Mintz 181841086467SYuval Mintz out: 1819a044df83SYuval Mintz qed_iov_vf_mbx_start_rxq_resp(p_hwfn, p_ptt, vf, status, b_legacy_vf); 1820dacd88d6SYuval Mintz } 1821dacd88d6SYuval Mintz 18225040acf5SYuval Mintz static void qed_iov_vf_mbx_start_txq_resp(struct qed_hwfn *p_hwfn, 18235040acf5SYuval Mintz struct qed_ptt *p_ptt, 18245040acf5SYuval Mintz struct qed_vf_info *p_vf, u8 status) 18255040acf5SYuval Mintz { 18265040acf5SYuval Mintz struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx; 18275040acf5SYuval Mintz struct pfvf_start_queue_resp_tlv *p_tlv; 1828a044df83SYuval Mintz bool b_legacy = false; 1829a044df83SYuval Mintz u16 length; 18305040acf5SYuval Mintz 18315040acf5SYuval Mintz mbx->offset = (u8 *)mbx->reply_virt; 18325040acf5SYuval Mintz 1833a044df83SYuval Mintz /* Taking a bigger struct instead of adding a TLV to list was a 1834a044df83SYuval Mintz * mistake, but one which we're now stuck with, as some older 1835a044df83SYuval Mintz * clients assume the size of the previous response. 1836a044df83SYuval Mintz */ 1837a044df83SYuval Mintz if (p_vf->acquire.vfdev_info.eth_fp_hsi_minor == 1838a044df83SYuval Mintz ETH_HSI_VER_NO_PKT_LEN_TUNN) 1839a044df83SYuval Mintz b_legacy = true; 1840a044df83SYuval Mintz 1841a044df83SYuval Mintz if (!b_legacy) 1842a044df83SYuval Mintz length = sizeof(*p_tlv); 1843a044df83SYuval Mintz else 1844a044df83SYuval Mintz length = sizeof(struct pfvf_def_resp_tlv); 1845a044df83SYuval Mintz 18465040acf5SYuval Mintz p_tlv = qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_START_TXQ, 1847a044df83SYuval Mintz length); 18485040acf5SYuval Mintz qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_LIST_END, 18495040acf5SYuval Mintz sizeof(struct channel_list_end_tlv)); 18505040acf5SYuval Mintz 18515040acf5SYuval Mintz /* Update the TLV with the response */ 1852a044df83SYuval Mintz if ((status == PFVF_STATUS_SUCCESS) && !b_legacy) { 18535040acf5SYuval Mintz u16 qid = mbx->req_virt->start_txq.tx_qid; 18545040acf5SYuval Mintz 18555040acf5SYuval Mintz p_tlv->offset = qed_db_addr(p_vf->vf_queues[qid].fw_cid, 18565040acf5SYuval Mintz DQ_DEMS_LEGACY); 18575040acf5SYuval Mintz } 18585040acf5SYuval Mintz 1859a044df83SYuval Mintz qed_iov_send_response(p_hwfn, p_ptt, p_vf, length, status); 18605040acf5SYuval Mintz } 18615040acf5SYuval Mintz 1862dacd88d6SYuval Mintz static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, 1863dacd88d6SYuval Mintz struct qed_ptt *p_ptt, 1864dacd88d6SYuval Mintz struct qed_vf_info *vf) 1865dacd88d6SYuval Mintz { 1866dacd88d6SYuval Mintz struct qed_queue_start_common_params params; 1867dacd88d6SYuval Mintz struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 186841086467SYuval Mintz u8 status = PFVF_STATUS_NO_RESOURCE; 1869dacd88d6SYuval Mintz union qed_qm_pq_params pq_params; 1870dacd88d6SYuval Mintz struct vfpf_start_txq_tlv *req; 1871dacd88d6SYuval Mintz int rc; 1872dacd88d6SYuval Mintz 1873dacd88d6SYuval Mintz /* Prepare the parameters which would choose the right PQ */ 1874dacd88d6SYuval Mintz memset(&pq_params, 0, sizeof(pq_params)); 1875dacd88d6SYuval Mintz pq_params.eth.is_vf = 1; 1876dacd88d6SYuval Mintz pq_params.eth.vf_id = vf->relative_vf_id; 1877dacd88d6SYuval Mintz 1878dacd88d6SYuval Mintz memset(¶ms, 0, sizeof(params)); 1879dacd88d6SYuval Mintz req = &mbx->req_virt->start_txq; 188041086467SYuval Mintz 188141086467SYuval Mintz if (!qed_iov_validate_txq(p_hwfn, vf, req->tx_qid) || 188241086467SYuval Mintz !qed_iov_validate_sb(p_hwfn, vf, req->hw_sb)) 188341086467SYuval Mintz goto out; 188441086467SYuval Mintz 1885dacd88d6SYuval Mintz params.queue_id = vf->vf_queues[req->tx_qid].fw_tx_qid; 1886dacd88d6SYuval Mintz params.vport_id = vf->vport_id; 1887dacd88d6SYuval Mintz params.sb = req->hw_sb; 1888dacd88d6SYuval Mintz params.sb_idx = req->sb_index; 1889dacd88d6SYuval Mintz 1890dacd88d6SYuval Mintz rc = qed_sp_eth_txq_start_ramrod(p_hwfn, 1891dacd88d6SYuval Mintz vf->opaque_fid, 1892dacd88d6SYuval Mintz vf->vf_queues[req->tx_qid].fw_cid, 1893dacd88d6SYuval Mintz ¶ms, 1894dacd88d6SYuval Mintz vf->abs_vf_id + 0x10, 1895dacd88d6SYuval Mintz req->pbl_addr, 1896dacd88d6SYuval Mintz req->pbl_size, &pq_params); 1897dacd88d6SYuval Mintz 189841086467SYuval Mintz if (rc) { 1899dacd88d6SYuval Mintz status = PFVF_STATUS_FAILURE; 190041086467SYuval Mintz } else { 190141086467SYuval Mintz status = PFVF_STATUS_SUCCESS; 1902dacd88d6SYuval Mintz vf->vf_queues[req->tx_qid].txq_active = true; 190341086467SYuval Mintz } 1904dacd88d6SYuval Mintz 190541086467SYuval Mintz out: 19065040acf5SYuval Mintz qed_iov_vf_mbx_start_txq_resp(p_hwfn, p_ptt, vf, status); 1907dacd88d6SYuval Mintz } 1908dacd88d6SYuval Mintz 1909dacd88d6SYuval Mintz static int qed_iov_vf_stop_rxqs(struct qed_hwfn *p_hwfn, 1910dacd88d6SYuval Mintz struct qed_vf_info *vf, 1911dacd88d6SYuval Mintz u16 rxq_id, u8 num_rxqs, bool cqe_completion) 1912dacd88d6SYuval Mintz { 1913dacd88d6SYuval Mintz int rc = 0; 1914dacd88d6SYuval Mintz int qid; 1915dacd88d6SYuval Mintz 1916dacd88d6SYuval Mintz if (rxq_id + num_rxqs > ARRAY_SIZE(vf->vf_queues)) 1917dacd88d6SYuval Mintz return -EINVAL; 1918dacd88d6SYuval Mintz 1919dacd88d6SYuval Mintz for (qid = rxq_id; qid < rxq_id + num_rxqs; qid++) { 1920dacd88d6SYuval Mintz if (vf->vf_queues[qid].rxq_active) { 1921dacd88d6SYuval Mintz rc = qed_sp_eth_rx_queue_stop(p_hwfn, 1922dacd88d6SYuval Mintz vf->vf_queues[qid]. 1923dacd88d6SYuval Mintz fw_rx_qid, false, 1924dacd88d6SYuval Mintz cqe_completion); 1925dacd88d6SYuval Mintz 1926dacd88d6SYuval Mintz if (rc) 1927dacd88d6SYuval Mintz return rc; 1928dacd88d6SYuval Mintz } 1929dacd88d6SYuval Mintz vf->vf_queues[qid].rxq_active = false; 1930dacd88d6SYuval Mintz vf->num_active_rxqs--; 1931dacd88d6SYuval Mintz } 1932dacd88d6SYuval Mintz 1933dacd88d6SYuval Mintz return rc; 1934dacd88d6SYuval Mintz } 1935dacd88d6SYuval Mintz 1936dacd88d6SYuval Mintz static int qed_iov_vf_stop_txqs(struct qed_hwfn *p_hwfn, 1937dacd88d6SYuval Mintz struct qed_vf_info *vf, u16 txq_id, u8 num_txqs) 1938dacd88d6SYuval Mintz { 1939dacd88d6SYuval Mintz int rc = 0; 1940dacd88d6SYuval Mintz int qid; 1941dacd88d6SYuval Mintz 1942dacd88d6SYuval Mintz if (txq_id + num_txqs > ARRAY_SIZE(vf->vf_queues)) 1943dacd88d6SYuval Mintz return -EINVAL; 1944dacd88d6SYuval Mintz 1945dacd88d6SYuval Mintz for (qid = txq_id; qid < txq_id + num_txqs; qid++) { 1946dacd88d6SYuval Mintz if (vf->vf_queues[qid].txq_active) { 1947dacd88d6SYuval Mintz rc = qed_sp_eth_tx_queue_stop(p_hwfn, 1948dacd88d6SYuval Mintz vf->vf_queues[qid]. 1949dacd88d6SYuval Mintz fw_tx_qid); 1950dacd88d6SYuval Mintz 1951dacd88d6SYuval Mintz if (rc) 1952dacd88d6SYuval Mintz return rc; 1953dacd88d6SYuval Mintz } 1954dacd88d6SYuval Mintz vf->vf_queues[qid].txq_active = false; 1955dacd88d6SYuval Mintz } 1956dacd88d6SYuval Mintz return rc; 1957dacd88d6SYuval Mintz } 1958dacd88d6SYuval Mintz 1959dacd88d6SYuval Mintz static void qed_iov_vf_mbx_stop_rxqs(struct qed_hwfn *p_hwfn, 1960dacd88d6SYuval Mintz struct qed_ptt *p_ptt, 1961dacd88d6SYuval Mintz struct qed_vf_info *vf) 1962dacd88d6SYuval Mintz { 1963dacd88d6SYuval Mintz u16 length = sizeof(struct pfvf_def_resp_tlv); 1964dacd88d6SYuval Mintz struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 1965dacd88d6SYuval Mintz u8 status = PFVF_STATUS_SUCCESS; 1966dacd88d6SYuval Mintz struct vfpf_stop_rxqs_tlv *req; 1967dacd88d6SYuval Mintz int rc; 1968dacd88d6SYuval Mintz 1969dacd88d6SYuval Mintz /* We give the option of starting from qid != 0, in this case we 1970dacd88d6SYuval Mintz * need to make sure that qid + num_qs doesn't exceed the actual 1971dacd88d6SYuval Mintz * amount of queues that exist. 1972dacd88d6SYuval Mintz */ 1973dacd88d6SYuval Mintz req = &mbx->req_virt->stop_rxqs; 1974dacd88d6SYuval Mintz rc = qed_iov_vf_stop_rxqs(p_hwfn, vf, req->rx_qid, 1975dacd88d6SYuval Mintz req->num_rxqs, req->cqe_completion); 1976dacd88d6SYuval Mintz if (rc) 1977dacd88d6SYuval Mintz status = PFVF_STATUS_FAILURE; 1978dacd88d6SYuval Mintz 1979dacd88d6SYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_STOP_RXQS, 1980dacd88d6SYuval Mintz length, status); 1981dacd88d6SYuval Mintz } 1982dacd88d6SYuval Mintz 1983dacd88d6SYuval Mintz static void qed_iov_vf_mbx_stop_txqs(struct qed_hwfn *p_hwfn, 1984dacd88d6SYuval Mintz struct qed_ptt *p_ptt, 1985dacd88d6SYuval Mintz struct qed_vf_info *vf) 1986dacd88d6SYuval Mintz { 1987dacd88d6SYuval Mintz u16 length = sizeof(struct pfvf_def_resp_tlv); 1988dacd88d6SYuval Mintz struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 1989dacd88d6SYuval Mintz u8 status = PFVF_STATUS_SUCCESS; 1990dacd88d6SYuval Mintz struct vfpf_stop_txqs_tlv *req; 1991dacd88d6SYuval Mintz int rc; 1992dacd88d6SYuval Mintz 1993dacd88d6SYuval Mintz /* We give the option of starting from qid != 0, in this case we 1994dacd88d6SYuval Mintz * need to make sure that qid + num_qs doesn't exceed the actual 1995dacd88d6SYuval Mintz * amount of queues that exist. 1996dacd88d6SYuval Mintz */ 1997dacd88d6SYuval Mintz req = &mbx->req_virt->stop_txqs; 1998dacd88d6SYuval Mintz rc = qed_iov_vf_stop_txqs(p_hwfn, vf, req->tx_qid, req->num_txqs); 1999dacd88d6SYuval Mintz if (rc) 2000dacd88d6SYuval Mintz status = PFVF_STATUS_FAILURE; 2001dacd88d6SYuval Mintz 2002dacd88d6SYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_STOP_TXQS, 2003dacd88d6SYuval Mintz length, status); 2004dacd88d6SYuval Mintz } 2005dacd88d6SYuval Mintz 200617b235c1SYuval Mintz static void qed_iov_vf_mbx_update_rxqs(struct qed_hwfn *p_hwfn, 200717b235c1SYuval Mintz struct qed_ptt *p_ptt, 200817b235c1SYuval Mintz struct qed_vf_info *vf) 200917b235c1SYuval Mintz { 201017b235c1SYuval Mintz u16 length = sizeof(struct pfvf_def_resp_tlv); 201117b235c1SYuval Mintz struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 201217b235c1SYuval Mintz struct vfpf_update_rxq_tlv *req; 201317b235c1SYuval Mintz u8 status = PFVF_STATUS_SUCCESS; 201417b235c1SYuval Mintz u8 complete_event_flg; 201517b235c1SYuval Mintz u8 complete_cqe_flg; 201617b235c1SYuval Mintz u16 qid; 201717b235c1SYuval Mintz int rc; 201817b235c1SYuval Mintz u8 i; 201917b235c1SYuval Mintz 202017b235c1SYuval Mintz req = &mbx->req_virt->update_rxq; 202117b235c1SYuval Mintz complete_cqe_flg = !!(req->flags & VFPF_RXQ_UPD_COMPLETE_CQE_FLAG); 202217b235c1SYuval Mintz complete_event_flg = !!(req->flags & VFPF_RXQ_UPD_COMPLETE_EVENT_FLAG); 202317b235c1SYuval Mintz 202417b235c1SYuval Mintz for (i = 0; i < req->num_rxqs; i++) { 202517b235c1SYuval Mintz qid = req->rx_qid + i; 202617b235c1SYuval Mintz 202717b235c1SYuval Mintz if (!vf->vf_queues[qid].rxq_active) { 202817b235c1SYuval Mintz DP_NOTICE(p_hwfn, "VF rx_qid = %d isn`t active!\n", 202917b235c1SYuval Mintz qid); 203017b235c1SYuval Mintz status = PFVF_STATUS_FAILURE; 203117b235c1SYuval Mintz break; 203217b235c1SYuval Mintz } 203317b235c1SYuval Mintz 203417b235c1SYuval Mintz rc = qed_sp_eth_rx_queues_update(p_hwfn, 203517b235c1SYuval Mintz vf->vf_queues[qid].fw_rx_qid, 203617b235c1SYuval Mintz 1, 203717b235c1SYuval Mintz complete_cqe_flg, 203817b235c1SYuval Mintz complete_event_flg, 203917b235c1SYuval Mintz QED_SPQ_MODE_EBLOCK, NULL); 204017b235c1SYuval Mintz 204117b235c1SYuval Mintz if (rc) { 204217b235c1SYuval Mintz status = PFVF_STATUS_FAILURE; 204317b235c1SYuval Mintz break; 204417b235c1SYuval Mintz } 204517b235c1SYuval Mintz } 204617b235c1SYuval Mintz 204717b235c1SYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_UPDATE_RXQ, 204817b235c1SYuval Mintz length, status); 204917b235c1SYuval Mintz } 205017b235c1SYuval Mintz 2051dacd88d6SYuval Mintz void *qed_iov_search_list_tlvs(struct qed_hwfn *p_hwfn, 2052dacd88d6SYuval Mintz void *p_tlvs_list, u16 req_type) 2053dacd88d6SYuval Mintz { 2054dacd88d6SYuval Mintz struct channel_tlv *p_tlv = (struct channel_tlv *)p_tlvs_list; 2055dacd88d6SYuval Mintz int len = 0; 2056dacd88d6SYuval Mintz 2057dacd88d6SYuval Mintz do { 2058dacd88d6SYuval Mintz if (!p_tlv->length) { 2059dacd88d6SYuval Mintz DP_NOTICE(p_hwfn, "Zero length TLV found\n"); 2060dacd88d6SYuval Mintz return NULL; 2061dacd88d6SYuval Mintz } 2062dacd88d6SYuval Mintz 2063dacd88d6SYuval Mintz if (p_tlv->type == req_type) { 2064dacd88d6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 2065dacd88d6SYuval Mintz "Extended tlv type %d, length %d found\n", 2066dacd88d6SYuval Mintz p_tlv->type, p_tlv->length); 2067dacd88d6SYuval Mintz return p_tlv; 2068dacd88d6SYuval Mintz } 2069dacd88d6SYuval Mintz 2070dacd88d6SYuval Mintz len += p_tlv->length; 2071dacd88d6SYuval Mintz p_tlv = (struct channel_tlv *)((u8 *)p_tlv + p_tlv->length); 2072dacd88d6SYuval Mintz 2073dacd88d6SYuval Mintz if ((len + p_tlv->length) > TLV_BUFFER_SIZE) { 2074dacd88d6SYuval Mintz DP_NOTICE(p_hwfn, "TLVs has overrun the buffer size\n"); 2075dacd88d6SYuval Mintz return NULL; 2076dacd88d6SYuval Mintz } 2077dacd88d6SYuval Mintz } while (p_tlv->type != CHANNEL_TLV_LIST_END); 2078dacd88d6SYuval Mintz 2079dacd88d6SYuval Mintz return NULL; 2080dacd88d6SYuval Mintz } 2081dacd88d6SYuval Mintz 2082dacd88d6SYuval Mintz static void 2083dacd88d6SYuval Mintz qed_iov_vp_update_act_param(struct qed_hwfn *p_hwfn, 2084dacd88d6SYuval Mintz struct qed_sp_vport_update_params *p_data, 2085dacd88d6SYuval Mintz struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 2086dacd88d6SYuval Mintz { 2087dacd88d6SYuval Mintz struct vfpf_vport_update_activate_tlv *p_act_tlv; 2088dacd88d6SYuval Mintz u16 tlv = CHANNEL_TLV_VPORT_UPDATE_ACTIVATE; 2089dacd88d6SYuval Mintz 2090dacd88d6SYuval Mintz p_act_tlv = (struct vfpf_vport_update_activate_tlv *) 2091dacd88d6SYuval Mintz qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 2092dacd88d6SYuval Mintz if (!p_act_tlv) 2093dacd88d6SYuval Mintz return; 2094dacd88d6SYuval Mintz 2095dacd88d6SYuval Mintz p_data->update_vport_active_rx_flg = p_act_tlv->update_rx; 2096dacd88d6SYuval Mintz p_data->vport_active_rx_flg = p_act_tlv->active_rx; 2097dacd88d6SYuval Mintz p_data->update_vport_active_tx_flg = p_act_tlv->update_tx; 2098dacd88d6SYuval Mintz p_data->vport_active_tx_flg = p_act_tlv->active_tx; 2099dacd88d6SYuval Mintz *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_ACTIVATE; 2100dacd88d6SYuval Mintz } 2101dacd88d6SYuval Mintz 2102dacd88d6SYuval Mintz static void 210317b235c1SYuval Mintz qed_iov_vp_update_vlan_param(struct qed_hwfn *p_hwfn, 210417b235c1SYuval Mintz struct qed_sp_vport_update_params *p_data, 210517b235c1SYuval Mintz struct qed_vf_info *p_vf, 210617b235c1SYuval Mintz struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 210717b235c1SYuval Mintz { 210817b235c1SYuval Mintz struct vfpf_vport_update_vlan_strip_tlv *p_vlan_tlv; 210917b235c1SYuval Mintz u16 tlv = CHANNEL_TLV_VPORT_UPDATE_VLAN_STRIP; 211017b235c1SYuval Mintz 211117b235c1SYuval Mintz p_vlan_tlv = (struct vfpf_vport_update_vlan_strip_tlv *) 211217b235c1SYuval Mintz qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 211317b235c1SYuval Mintz if (!p_vlan_tlv) 211417b235c1SYuval Mintz return; 211517b235c1SYuval Mintz 211608feecd7SYuval Mintz p_vf->shadow_config.inner_vlan_removal = p_vlan_tlv->remove_vlan; 211708feecd7SYuval Mintz 211808feecd7SYuval Mintz /* Ignore the VF request if we're forcing a vlan */ 21191a635e48SYuval Mintz if (!(p_vf->configured_features & BIT(VLAN_ADDR_FORCED))) { 212017b235c1SYuval Mintz p_data->update_inner_vlan_removal_flg = 1; 212117b235c1SYuval Mintz p_data->inner_vlan_removal_flg = p_vlan_tlv->remove_vlan; 212208feecd7SYuval Mintz } 212317b235c1SYuval Mintz 212417b235c1SYuval Mintz *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_VLAN_STRIP; 212517b235c1SYuval Mintz } 212617b235c1SYuval Mintz 212717b235c1SYuval Mintz static void 212817b235c1SYuval Mintz qed_iov_vp_update_tx_switch(struct qed_hwfn *p_hwfn, 212917b235c1SYuval Mintz struct qed_sp_vport_update_params *p_data, 213017b235c1SYuval Mintz struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 213117b235c1SYuval Mintz { 213217b235c1SYuval Mintz struct vfpf_vport_update_tx_switch_tlv *p_tx_switch_tlv; 213317b235c1SYuval Mintz u16 tlv = CHANNEL_TLV_VPORT_UPDATE_TX_SWITCH; 213417b235c1SYuval Mintz 213517b235c1SYuval Mintz p_tx_switch_tlv = (struct vfpf_vport_update_tx_switch_tlv *) 213617b235c1SYuval Mintz qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, 213717b235c1SYuval Mintz tlv); 213817b235c1SYuval Mintz if (!p_tx_switch_tlv) 213917b235c1SYuval Mintz return; 214017b235c1SYuval Mintz 214117b235c1SYuval Mintz p_data->update_tx_switching_flg = 1; 214217b235c1SYuval Mintz p_data->tx_switching_flg = p_tx_switch_tlv->tx_switching; 214317b235c1SYuval Mintz *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_TX_SWITCH; 214417b235c1SYuval Mintz } 214517b235c1SYuval Mintz 214617b235c1SYuval Mintz static void 2147dacd88d6SYuval Mintz qed_iov_vp_update_mcast_bin_param(struct qed_hwfn *p_hwfn, 2148dacd88d6SYuval Mintz struct qed_sp_vport_update_params *p_data, 2149dacd88d6SYuval Mintz struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 2150dacd88d6SYuval Mintz { 2151dacd88d6SYuval Mintz struct vfpf_vport_update_mcast_bin_tlv *p_mcast_tlv; 2152dacd88d6SYuval Mintz u16 tlv = CHANNEL_TLV_VPORT_UPDATE_MCAST; 2153dacd88d6SYuval Mintz 2154dacd88d6SYuval Mintz p_mcast_tlv = (struct vfpf_vport_update_mcast_bin_tlv *) 2155dacd88d6SYuval Mintz qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 2156dacd88d6SYuval Mintz if (!p_mcast_tlv) 2157dacd88d6SYuval Mintz return; 2158dacd88d6SYuval Mintz 2159dacd88d6SYuval Mintz p_data->update_approx_mcast_flg = 1; 2160dacd88d6SYuval Mintz memcpy(p_data->bins, p_mcast_tlv->bins, 2161dacd88d6SYuval Mintz sizeof(unsigned long) * ETH_MULTICAST_MAC_BINS_IN_REGS); 2162dacd88d6SYuval Mintz *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_MCAST; 2163dacd88d6SYuval Mintz } 2164dacd88d6SYuval Mintz 2165dacd88d6SYuval Mintz static void 2166dacd88d6SYuval Mintz qed_iov_vp_update_accept_flag(struct qed_hwfn *p_hwfn, 2167dacd88d6SYuval Mintz struct qed_sp_vport_update_params *p_data, 2168dacd88d6SYuval Mintz struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 2169dacd88d6SYuval Mintz { 2170dacd88d6SYuval Mintz struct qed_filter_accept_flags *p_flags = &p_data->accept_flags; 2171dacd88d6SYuval Mintz struct vfpf_vport_update_accept_param_tlv *p_accept_tlv; 2172dacd88d6SYuval Mintz u16 tlv = CHANNEL_TLV_VPORT_UPDATE_ACCEPT_PARAM; 2173dacd88d6SYuval Mintz 2174dacd88d6SYuval Mintz p_accept_tlv = (struct vfpf_vport_update_accept_param_tlv *) 2175dacd88d6SYuval Mintz qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 2176dacd88d6SYuval Mintz if (!p_accept_tlv) 2177dacd88d6SYuval Mintz return; 2178dacd88d6SYuval Mintz 2179dacd88d6SYuval Mintz p_flags->update_rx_mode_config = p_accept_tlv->update_rx_mode; 2180dacd88d6SYuval Mintz p_flags->rx_accept_filter = p_accept_tlv->rx_accept_filter; 2181dacd88d6SYuval Mintz p_flags->update_tx_mode_config = p_accept_tlv->update_tx_mode; 2182dacd88d6SYuval Mintz p_flags->tx_accept_filter = p_accept_tlv->tx_accept_filter; 2183dacd88d6SYuval Mintz *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_ACCEPT_PARAM; 2184dacd88d6SYuval Mintz } 2185dacd88d6SYuval Mintz 2186dacd88d6SYuval Mintz static void 218717b235c1SYuval Mintz qed_iov_vp_update_accept_any_vlan(struct qed_hwfn *p_hwfn, 218817b235c1SYuval Mintz struct qed_sp_vport_update_params *p_data, 218917b235c1SYuval Mintz struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 219017b235c1SYuval Mintz { 219117b235c1SYuval Mintz struct vfpf_vport_update_accept_any_vlan_tlv *p_accept_any_vlan; 219217b235c1SYuval Mintz u16 tlv = CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN; 219317b235c1SYuval Mintz 219417b235c1SYuval Mintz p_accept_any_vlan = (struct vfpf_vport_update_accept_any_vlan_tlv *) 219517b235c1SYuval Mintz qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, 219617b235c1SYuval Mintz tlv); 219717b235c1SYuval Mintz if (!p_accept_any_vlan) 219817b235c1SYuval Mintz return; 219917b235c1SYuval Mintz 220017b235c1SYuval Mintz p_data->accept_any_vlan = p_accept_any_vlan->accept_any_vlan; 220117b235c1SYuval Mintz p_data->update_accept_any_vlan_flg = 220217b235c1SYuval Mintz p_accept_any_vlan->update_accept_any_vlan_flg; 220317b235c1SYuval Mintz *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_ACCEPT_ANY_VLAN; 220417b235c1SYuval Mintz } 220517b235c1SYuval Mintz 220617b235c1SYuval Mintz static void 2207dacd88d6SYuval Mintz qed_iov_vp_update_rss_param(struct qed_hwfn *p_hwfn, 2208dacd88d6SYuval Mintz struct qed_vf_info *vf, 2209dacd88d6SYuval Mintz struct qed_sp_vport_update_params *p_data, 2210dacd88d6SYuval Mintz struct qed_rss_params *p_rss, 2211dacd88d6SYuval Mintz struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 2212dacd88d6SYuval Mintz { 2213dacd88d6SYuval Mintz struct vfpf_vport_update_rss_tlv *p_rss_tlv; 2214dacd88d6SYuval Mintz u16 tlv = CHANNEL_TLV_VPORT_UPDATE_RSS; 2215dacd88d6SYuval Mintz u16 i, q_idx, max_q_idx; 2216dacd88d6SYuval Mintz u16 table_size; 2217dacd88d6SYuval Mintz 2218dacd88d6SYuval Mintz p_rss_tlv = (struct vfpf_vport_update_rss_tlv *) 2219dacd88d6SYuval Mintz qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 2220dacd88d6SYuval Mintz if (!p_rss_tlv) { 2221dacd88d6SYuval Mintz p_data->rss_params = NULL; 2222dacd88d6SYuval Mintz return; 2223dacd88d6SYuval Mintz } 2224dacd88d6SYuval Mintz 2225dacd88d6SYuval Mintz memset(p_rss, 0, sizeof(struct qed_rss_params)); 2226dacd88d6SYuval Mintz 2227dacd88d6SYuval Mintz p_rss->update_rss_config = !!(p_rss_tlv->update_rss_flags & 2228dacd88d6SYuval Mintz VFPF_UPDATE_RSS_CONFIG_FLAG); 2229dacd88d6SYuval Mintz p_rss->update_rss_capabilities = !!(p_rss_tlv->update_rss_flags & 2230dacd88d6SYuval Mintz VFPF_UPDATE_RSS_CAPS_FLAG); 2231dacd88d6SYuval Mintz p_rss->update_rss_ind_table = !!(p_rss_tlv->update_rss_flags & 2232dacd88d6SYuval Mintz VFPF_UPDATE_RSS_IND_TABLE_FLAG); 2233dacd88d6SYuval Mintz p_rss->update_rss_key = !!(p_rss_tlv->update_rss_flags & 2234dacd88d6SYuval Mintz VFPF_UPDATE_RSS_KEY_FLAG); 2235dacd88d6SYuval Mintz 2236dacd88d6SYuval Mintz p_rss->rss_enable = p_rss_tlv->rss_enable; 2237dacd88d6SYuval Mintz p_rss->rss_eng_id = vf->relative_vf_id + 1; 2238dacd88d6SYuval Mintz p_rss->rss_caps = p_rss_tlv->rss_caps; 2239dacd88d6SYuval Mintz p_rss->rss_table_size_log = p_rss_tlv->rss_table_size_log; 2240dacd88d6SYuval Mintz memcpy(p_rss->rss_ind_table, p_rss_tlv->rss_ind_table, 2241dacd88d6SYuval Mintz sizeof(p_rss->rss_ind_table)); 2242dacd88d6SYuval Mintz memcpy(p_rss->rss_key, p_rss_tlv->rss_key, sizeof(p_rss->rss_key)); 2243dacd88d6SYuval Mintz 2244dacd88d6SYuval Mintz table_size = min_t(u16, ARRAY_SIZE(p_rss->rss_ind_table), 2245dacd88d6SYuval Mintz (1 << p_rss_tlv->rss_table_size_log)); 2246dacd88d6SYuval Mintz 2247dacd88d6SYuval Mintz max_q_idx = ARRAY_SIZE(vf->vf_queues); 2248dacd88d6SYuval Mintz 2249dacd88d6SYuval Mintz for (i = 0; i < table_size; i++) { 2250dacd88d6SYuval Mintz u16 index = vf->vf_queues[0].fw_rx_qid; 2251dacd88d6SYuval Mintz 2252dacd88d6SYuval Mintz q_idx = p_rss->rss_ind_table[i]; 2253dacd88d6SYuval Mintz if (q_idx >= max_q_idx) 2254dacd88d6SYuval Mintz DP_NOTICE(p_hwfn, 2255dacd88d6SYuval Mintz "rss_ind_table[%d] = %d, rxq is out of range\n", 2256dacd88d6SYuval Mintz i, q_idx); 2257dacd88d6SYuval Mintz else if (!vf->vf_queues[q_idx].rxq_active) 2258dacd88d6SYuval Mintz DP_NOTICE(p_hwfn, 2259dacd88d6SYuval Mintz "rss_ind_table[%d] = %d, rxq is not active\n", 2260dacd88d6SYuval Mintz i, q_idx); 2261dacd88d6SYuval Mintz else 2262dacd88d6SYuval Mintz index = vf->vf_queues[q_idx].fw_rx_qid; 2263dacd88d6SYuval Mintz p_rss->rss_ind_table[i] = index; 2264dacd88d6SYuval Mintz } 2265dacd88d6SYuval Mintz 2266dacd88d6SYuval Mintz p_data->rss_params = p_rss; 2267dacd88d6SYuval Mintz *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_RSS; 2268dacd88d6SYuval Mintz } 2269dacd88d6SYuval Mintz 227017b235c1SYuval Mintz static void 227117b235c1SYuval Mintz qed_iov_vp_update_sge_tpa_param(struct qed_hwfn *p_hwfn, 227217b235c1SYuval Mintz struct qed_vf_info *vf, 227317b235c1SYuval Mintz struct qed_sp_vport_update_params *p_data, 227417b235c1SYuval Mintz struct qed_sge_tpa_params *p_sge_tpa, 227517b235c1SYuval Mintz struct qed_iov_vf_mbx *p_mbx, u16 *tlvs_mask) 227617b235c1SYuval Mintz { 227717b235c1SYuval Mintz struct vfpf_vport_update_sge_tpa_tlv *p_sge_tpa_tlv; 227817b235c1SYuval Mintz u16 tlv = CHANNEL_TLV_VPORT_UPDATE_SGE_TPA; 227917b235c1SYuval Mintz 228017b235c1SYuval Mintz p_sge_tpa_tlv = (struct vfpf_vport_update_sge_tpa_tlv *) 228117b235c1SYuval Mintz qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, tlv); 228217b235c1SYuval Mintz 228317b235c1SYuval Mintz if (!p_sge_tpa_tlv) { 228417b235c1SYuval Mintz p_data->sge_tpa_params = NULL; 228517b235c1SYuval Mintz return; 228617b235c1SYuval Mintz } 228717b235c1SYuval Mintz 228817b235c1SYuval Mintz memset(p_sge_tpa, 0, sizeof(struct qed_sge_tpa_params)); 228917b235c1SYuval Mintz 229017b235c1SYuval Mintz p_sge_tpa->update_tpa_en_flg = 229117b235c1SYuval Mintz !!(p_sge_tpa_tlv->update_sge_tpa_flags & VFPF_UPDATE_TPA_EN_FLAG); 229217b235c1SYuval Mintz p_sge_tpa->update_tpa_param_flg = 229317b235c1SYuval Mintz !!(p_sge_tpa_tlv->update_sge_tpa_flags & 229417b235c1SYuval Mintz VFPF_UPDATE_TPA_PARAM_FLAG); 229517b235c1SYuval Mintz 229617b235c1SYuval Mintz p_sge_tpa->tpa_ipv4_en_flg = 229717b235c1SYuval Mintz !!(p_sge_tpa_tlv->sge_tpa_flags & VFPF_TPA_IPV4_EN_FLAG); 229817b235c1SYuval Mintz p_sge_tpa->tpa_ipv6_en_flg = 229917b235c1SYuval Mintz !!(p_sge_tpa_tlv->sge_tpa_flags & VFPF_TPA_IPV6_EN_FLAG); 230017b235c1SYuval Mintz p_sge_tpa->tpa_pkt_split_flg = 230117b235c1SYuval Mintz !!(p_sge_tpa_tlv->sge_tpa_flags & VFPF_TPA_PKT_SPLIT_FLAG); 230217b235c1SYuval Mintz p_sge_tpa->tpa_hdr_data_split_flg = 230317b235c1SYuval Mintz !!(p_sge_tpa_tlv->sge_tpa_flags & VFPF_TPA_HDR_DATA_SPLIT_FLAG); 230417b235c1SYuval Mintz p_sge_tpa->tpa_gro_consistent_flg = 230517b235c1SYuval Mintz !!(p_sge_tpa_tlv->sge_tpa_flags & VFPF_TPA_GRO_CONSIST_FLAG); 230617b235c1SYuval Mintz 230717b235c1SYuval Mintz p_sge_tpa->tpa_max_aggs_num = p_sge_tpa_tlv->tpa_max_aggs_num; 230817b235c1SYuval Mintz p_sge_tpa->tpa_max_size = p_sge_tpa_tlv->tpa_max_size; 230917b235c1SYuval Mintz p_sge_tpa->tpa_min_size_to_start = p_sge_tpa_tlv->tpa_min_size_to_start; 231017b235c1SYuval Mintz p_sge_tpa->tpa_min_size_to_cont = p_sge_tpa_tlv->tpa_min_size_to_cont; 231117b235c1SYuval Mintz p_sge_tpa->max_buffers_per_cqe = p_sge_tpa_tlv->max_buffers_per_cqe; 231217b235c1SYuval Mintz 231317b235c1SYuval Mintz p_data->sge_tpa_params = p_sge_tpa; 231417b235c1SYuval Mintz 231517b235c1SYuval Mintz *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_SGE_TPA; 231617b235c1SYuval Mintz } 231717b235c1SYuval Mintz 2318dacd88d6SYuval Mintz static void qed_iov_vf_mbx_vport_update(struct qed_hwfn *p_hwfn, 2319dacd88d6SYuval Mintz struct qed_ptt *p_ptt, 2320dacd88d6SYuval Mintz struct qed_vf_info *vf) 2321dacd88d6SYuval Mintz { 2322dacd88d6SYuval Mintz struct qed_sp_vport_update_params params; 2323dacd88d6SYuval Mintz struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 232417b235c1SYuval Mintz struct qed_sge_tpa_params sge_tpa_params; 2325dacd88d6SYuval Mintz struct qed_rss_params rss_params; 2326dacd88d6SYuval Mintz u8 status = PFVF_STATUS_SUCCESS; 2327dacd88d6SYuval Mintz u16 tlvs_mask = 0; 2328dacd88d6SYuval Mintz u16 length; 2329dacd88d6SYuval Mintz int rc; 2330dacd88d6SYuval Mintz 233141086467SYuval Mintz /* Valiate PF can send such a request */ 233241086467SYuval Mintz if (!vf->vport_instance) { 233341086467SYuval Mintz DP_VERBOSE(p_hwfn, 233441086467SYuval Mintz QED_MSG_IOV, 233541086467SYuval Mintz "No VPORT instance available for VF[%d], failing vport update\n", 233641086467SYuval Mintz vf->abs_vf_id); 233741086467SYuval Mintz status = PFVF_STATUS_FAILURE; 233841086467SYuval Mintz goto out; 233941086467SYuval Mintz } 234041086467SYuval Mintz 2341dacd88d6SYuval Mintz memset(¶ms, 0, sizeof(params)); 2342dacd88d6SYuval Mintz params.opaque_fid = vf->opaque_fid; 2343dacd88d6SYuval Mintz params.vport_id = vf->vport_id; 2344dacd88d6SYuval Mintz params.rss_params = NULL; 2345dacd88d6SYuval Mintz 2346dacd88d6SYuval Mintz /* Search for extended tlvs list and update values 2347dacd88d6SYuval Mintz * from VF in struct qed_sp_vport_update_params. 2348dacd88d6SYuval Mintz */ 2349dacd88d6SYuval Mintz qed_iov_vp_update_act_param(p_hwfn, ¶ms, mbx, &tlvs_mask); 235017b235c1SYuval Mintz qed_iov_vp_update_vlan_param(p_hwfn, ¶ms, vf, mbx, &tlvs_mask); 235117b235c1SYuval Mintz qed_iov_vp_update_tx_switch(p_hwfn, ¶ms, mbx, &tlvs_mask); 2352dacd88d6SYuval Mintz qed_iov_vp_update_mcast_bin_param(p_hwfn, ¶ms, mbx, &tlvs_mask); 2353dacd88d6SYuval Mintz qed_iov_vp_update_accept_flag(p_hwfn, ¶ms, mbx, &tlvs_mask); 2354dacd88d6SYuval Mintz qed_iov_vp_update_rss_param(p_hwfn, vf, ¶ms, &rss_params, 2355dacd88d6SYuval Mintz mbx, &tlvs_mask); 235617b235c1SYuval Mintz qed_iov_vp_update_accept_any_vlan(p_hwfn, ¶ms, mbx, &tlvs_mask); 235717b235c1SYuval Mintz qed_iov_vp_update_sge_tpa_param(p_hwfn, vf, ¶ms, 235817b235c1SYuval Mintz &sge_tpa_params, mbx, &tlvs_mask); 2359dacd88d6SYuval Mintz 2360dacd88d6SYuval Mintz /* Just log a message if there is no single extended tlv in buffer. 2361dacd88d6SYuval Mintz * When all features of vport update ramrod would be requested by VF 2362dacd88d6SYuval Mintz * as extended TLVs in buffer then an error can be returned in response 2363dacd88d6SYuval Mintz * if there is no extended TLV present in buffer. 2364dacd88d6SYuval Mintz */ 2365dacd88d6SYuval Mintz if (!tlvs_mask) { 2366dacd88d6SYuval Mintz DP_NOTICE(p_hwfn, 2367dacd88d6SYuval Mintz "No feature tlvs found for vport update\n"); 2368dacd88d6SYuval Mintz status = PFVF_STATUS_NOT_SUPPORTED; 2369dacd88d6SYuval Mintz goto out; 2370dacd88d6SYuval Mintz } 2371dacd88d6SYuval Mintz 2372dacd88d6SYuval Mintz rc = qed_sp_vport_update(p_hwfn, ¶ms, QED_SPQ_MODE_EBLOCK, NULL); 2373dacd88d6SYuval Mintz 2374dacd88d6SYuval Mintz if (rc) 2375dacd88d6SYuval Mintz status = PFVF_STATUS_FAILURE; 2376dacd88d6SYuval Mintz 2377dacd88d6SYuval Mintz out: 2378dacd88d6SYuval Mintz length = qed_iov_prep_vp_update_resp_tlvs(p_hwfn, vf, mbx, status, 2379dacd88d6SYuval Mintz tlvs_mask, tlvs_mask); 2380dacd88d6SYuval Mintz qed_iov_send_response(p_hwfn, p_ptt, vf, length, status); 2381dacd88d6SYuval Mintz } 2382dacd88d6SYuval Mintz 23838246d0b4SYuval Mintz static int qed_iov_vf_update_vlan_shadow(struct qed_hwfn *p_hwfn, 238408feecd7SYuval Mintz struct qed_vf_info *p_vf, 238508feecd7SYuval Mintz struct qed_filter_ucast *p_params) 238608feecd7SYuval Mintz { 238708feecd7SYuval Mintz int i; 238808feecd7SYuval Mintz 238908feecd7SYuval Mintz /* First remove entries and then add new ones */ 239008feecd7SYuval Mintz if (p_params->opcode == QED_FILTER_REMOVE) { 239108feecd7SYuval Mintz for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++) 239208feecd7SYuval Mintz if (p_vf->shadow_config.vlans[i].used && 239308feecd7SYuval Mintz p_vf->shadow_config.vlans[i].vid == 239408feecd7SYuval Mintz p_params->vlan) { 239508feecd7SYuval Mintz p_vf->shadow_config.vlans[i].used = false; 239608feecd7SYuval Mintz break; 239708feecd7SYuval Mintz } 239808feecd7SYuval Mintz if (i == QED_ETH_VF_NUM_VLAN_FILTERS + 1) { 239908feecd7SYuval Mintz DP_VERBOSE(p_hwfn, 240008feecd7SYuval Mintz QED_MSG_IOV, 240108feecd7SYuval Mintz "VF [%d] - Tries to remove a non-existing vlan\n", 240208feecd7SYuval Mintz p_vf->relative_vf_id); 240308feecd7SYuval Mintz return -EINVAL; 240408feecd7SYuval Mintz } 240508feecd7SYuval Mintz } else if (p_params->opcode == QED_FILTER_REPLACE || 240608feecd7SYuval Mintz p_params->opcode == QED_FILTER_FLUSH) { 240708feecd7SYuval Mintz for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++) 240808feecd7SYuval Mintz p_vf->shadow_config.vlans[i].used = false; 240908feecd7SYuval Mintz } 241008feecd7SYuval Mintz 241108feecd7SYuval Mintz /* In forced mode, we're willing to remove entries - but we don't add 241208feecd7SYuval Mintz * new ones. 241308feecd7SYuval Mintz */ 24141a635e48SYuval Mintz if (p_vf->bulletin.p_virt->valid_bitmap & BIT(VLAN_ADDR_FORCED)) 241508feecd7SYuval Mintz return 0; 241608feecd7SYuval Mintz 241708feecd7SYuval Mintz if (p_params->opcode == QED_FILTER_ADD || 241808feecd7SYuval Mintz p_params->opcode == QED_FILTER_REPLACE) { 241908feecd7SYuval Mintz for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++) { 242008feecd7SYuval Mintz if (p_vf->shadow_config.vlans[i].used) 242108feecd7SYuval Mintz continue; 242208feecd7SYuval Mintz 242308feecd7SYuval Mintz p_vf->shadow_config.vlans[i].used = true; 242408feecd7SYuval Mintz p_vf->shadow_config.vlans[i].vid = p_params->vlan; 242508feecd7SYuval Mintz break; 242608feecd7SYuval Mintz } 242708feecd7SYuval Mintz 242808feecd7SYuval Mintz if (i == QED_ETH_VF_NUM_VLAN_FILTERS + 1) { 242908feecd7SYuval Mintz DP_VERBOSE(p_hwfn, 243008feecd7SYuval Mintz QED_MSG_IOV, 243108feecd7SYuval Mintz "VF [%d] - Tries to configure more than %d vlan filters\n", 243208feecd7SYuval Mintz p_vf->relative_vf_id, 243308feecd7SYuval Mintz QED_ETH_VF_NUM_VLAN_FILTERS + 1); 243408feecd7SYuval Mintz return -EINVAL; 243508feecd7SYuval Mintz } 243608feecd7SYuval Mintz } 243708feecd7SYuval Mintz 243808feecd7SYuval Mintz return 0; 243908feecd7SYuval Mintz } 244008feecd7SYuval Mintz 24418246d0b4SYuval Mintz static int qed_iov_vf_update_mac_shadow(struct qed_hwfn *p_hwfn, 24428246d0b4SYuval Mintz struct qed_vf_info *p_vf, 24438246d0b4SYuval Mintz struct qed_filter_ucast *p_params) 24448246d0b4SYuval Mintz { 24458246d0b4SYuval Mintz int i; 24468246d0b4SYuval Mintz 24478246d0b4SYuval Mintz /* If we're in forced-mode, we don't allow any change */ 24481a635e48SYuval Mintz if (p_vf->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED)) 24498246d0b4SYuval Mintz return 0; 24508246d0b4SYuval Mintz 24518246d0b4SYuval Mintz /* First remove entries and then add new ones */ 24528246d0b4SYuval Mintz if (p_params->opcode == QED_FILTER_REMOVE) { 24538246d0b4SYuval Mintz for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) { 24548246d0b4SYuval Mintz if (ether_addr_equal(p_vf->shadow_config.macs[i], 24558246d0b4SYuval Mintz p_params->mac)) { 24568246d0b4SYuval Mintz memset(p_vf->shadow_config.macs[i], 0, 24578246d0b4SYuval Mintz ETH_ALEN); 24588246d0b4SYuval Mintz break; 24598246d0b4SYuval Mintz } 24608246d0b4SYuval Mintz } 24618246d0b4SYuval Mintz 24628246d0b4SYuval Mintz if (i == QED_ETH_VF_NUM_MAC_FILTERS) { 24638246d0b4SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 24648246d0b4SYuval Mintz "MAC isn't configured\n"); 24658246d0b4SYuval Mintz return -EINVAL; 24668246d0b4SYuval Mintz } 24678246d0b4SYuval Mintz } else if (p_params->opcode == QED_FILTER_REPLACE || 24688246d0b4SYuval Mintz p_params->opcode == QED_FILTER_FLUSH) { 24698246d0b4SYuval Mintz for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) 24708246d0b4SYuval Mintz memset(p_vf->shadow_config.macs[i], 0, ETH_ALEN); 24718246d0b4SYuval Mintz } 24728246d0b4SYuval Mintz 24738246d0b4SYuval Mintz /* List the new MAC address */ 24748246d0b4SYuval Mintz if (p_params->opcode != QED_FILTER_ADD && 24758246d0b4SYuval Mintz p_params->opcode != QED_FILTER_REPLACE) 24768246d0b4SYuval Mintz return 0; 24778246d0b4SYuval Mintz 24788246d0b4SYuval Mintz for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) { 24798246d0b4SYuval Mintz if (is_zero_ether_addr(p_vf->shadow_config.macs[i])) { 24808246d0b4SYuval Mintz ether_addr_copy(p_vf->shadow_config.macs[i], 24818246d0b4SYuval Mintz p_params->mac); 24828246d0b4SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 24838246d0b4SYuval Mintz "Added MAC at %d entry in shadow\n", i); 24848246d0b4SYuval Mintz break; 24858246d0b4SYuval Mintz } 24868246d0b4SYuval Mintz } 24878246d0b4SYuval Mintz 24888246d0b4SYuval Mintz if (i == QED_ETH_VF_NUM_MAC_FILTERS) { 24898246d0b4SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, "No available place for MAC\n"); 24908246d0b4SYuval Mintz return -EINVAL; 24918246d0b4SYuval Mintz } 24928246d0b4SYuval Mintz 24938246d0b4SYuval Mintz return 0; 24948246d0b4SYuval Mintz } 24958246d0b4SYuval Mintz 24968246d0b4SYuval Mintz static int 24978246d0b4SYuval Mintz qed_iov_vf_update_unicast_shadow(struct qed_hwfn *p_hwfn, 24988246d0b4SYuval Mintz struct qed_vf_info *p_vf, 24998246d0b4SYuval Mintz struct qed_filter_ucast *p_params) 25008246d0b4SYuval Mintz { 25018246d0b4SYuval Mintz int rc = 0; 25028246d0b4SYuval Mintz 25038246d0b4SYuval Mintz if (p_params->type == QED_FILTER_MAC) { 25048246d0b4SYuval Mintz rc = qed_iov_vf_update_mac_shadow(p_hwfn, p_vf, p_params); 25058246d0b4SYuval Mintz if (rc) 25068246d0b4SYuval Mintz return rc; 25078246d0b4SYuval Mintz } 25088246d0b4SYuval Mintz 25098246d0b4SYuval Mintz if (p_params->type == QED_FILTER_VLAN) 25108246d0b4SYuval Mintz rc = qed_iov_vf_update_vlan_shadow(p_hwfn, p_vf, p_params); 25118246d0b4SYuval Mintz 25128246d0b4SYuval Mintz return rc; 25138246d0b4SYuval Mintz } 25148246d0b4SYuval Mintz 2515dacd88d6SYuval Mintz int qed_iov_chk_ucast(struct qed_hwfn *hwfn, 2516dacd88d6SYuval Mintz int vfid, struct qed_filter_ucast *params) 2517dacd88d6SYuval Mintz { 2518dacd88d6SYuval Mintz struct qed_public_vf_info *vf; 2519dacd88d6SYuval Mintz 2520dacd88d6SYuval Mintz vf = qed_iov_get_public_vf_info(hwfn, vfid, true); 2521dacd88d6SYuval Mintz if (!vf) 2522dacd88d6SYuval Mintz return -EINVAL; 2523dacd88d6SYuval Mintz 2524dacd88d6SYuval Mintz /* No real decision to make; Store the configured MAC */ 2525dacd88d6SYuval Mintz if (params->type == QED_FILTER_MAC || 2526dacd88d6SYuval Mintz params->type == QED_FILTER_MAC_VLAN) 2527dacd88d6SYuval Mintz ether_addr_copy(vf->mac, params->mac); 2528dacd88d6SYuval Mintz 2529dacd88d6SYuval Mintz return 0; 2530dacd88d6SYuval Mintz } 2531dacd88d6SYuval Mintz 2532dacd88d6SYuval Mintz static void qed_iov_vf_mbx_ucast_filter(struct qed_hwfn *p_hwfn, 2533dacd88d6SYuval Mintz struct qed_ptt *p_ptt, 2534dacd88d6SYuval Mintz struct qed_vf_info *vf) 2535dacd88d6SYuval Mintz { 253608feecd7SYuval Mintz struct qed_bulletin_content *p_bulletin = vf->bulletin.p_virt; 2537dacd88d6SYuval Mintz struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; 2538dacd88d6SYuval Mintz struct vfpf_ucast_filter_tlv *req; 2539dacd88d6SYuval Mintz u8 status = PFVF_STATUS_SUCCESS; 2540dacd88d6SYuval Mintz struct qed_filter_ucast params; 2541dacd88d6SYuval Mintz int rc; 2542dacd88d6SYuval Mintz 2543dacd88d6SYuval Mintz /* Prepare the unicast filter params */ 2544dacd88d6SYuval Mintz memset(¶ms, 0, sizeof(struct qed_filter_ucast)); 2545dacd88d6SYuval Mintz req = &mbx->req_virt->ucast_filter; 2546dacd88d6SYuval Mintz params.opcode = (enum qed_filter_opcode)req->opcode; 2547dacd88d6SYuval Mintz params.type = (enum qed_filter_ucast_type)req->type; 2548dacd88d6SYuval Mintz 2549dacd88d6SYuval Mintz params.is_rx_filter = 1; 2550dacd88d6SYuval Mintz params.is_tx_filter = 1; 2551dacd88d6SYuval Mintz params.vport_to_remove_from = vf->vport_id; 2552dacd88d6SYuval Mintz params.vport_to_add_to = vf->vport_id; 2553dacd88d6SYuval Mintz memcpy(params.mac, req->mac, ETH_ALEN); 2554dacd88d6SYuval Mintz params.vlan = req->vlan; 2555dacd88d6SYuval Mintz 2556dacd88d6SYuval Mintz DP_VERBOSE(p_hwfn, 2557dacd88d6SYuval Mintz QED_MSG_IOV, 2558dacd88d6SYuval Mintz "VF[%d]: opcode 0x%02x type 0x%02x [%s %s] [vport 0x%02x] MAC %02x:%02x:%02x:%02x:%02x:%02x, vlan 0x%04x\n", 2559dacd88d6SYuval Mintz vf->abs_vf_id, params.opcode, params.type, 2560dacd88d6SYuval Mintz params.is_rx_filter ? "RX" : "", 2561dacd88d6SYuval Mintz params.is_tx_filter ? "TX" : "", 2562dacd88d6SYuval Mintz params.vport_to_add_to, 2563dacd88d6SYuval Mintz params.mac[0], params.mac[1], 2564dacd88d6SYuval Mintz params.mac[2], params.mac[3], 2565dacd88d6SYuval Mintz params.mac[4], params.mac[5], params.vlan); 2566dacd88d6SYuval Mintz 2567dacd88d6SYuval Mintz if (!vf->vport_instance) { 2568dacd88d6SYuval Mintz DP_VERBOSE(p_hwfn, 2569dacd88d6SYuval Mintz QED_MSG_IOV, 2570dacd88d6SYuval Mintz "No VPORT instance available for VF[%d], failing ucast MAC configuration\n", 2571dacd88d6SYuval Mintz vf->abs_vf_id); 2572dacd88d6SYuval Mintz status = PFVF_STATUS_FAILURE; 2573dacd88d6SYuval Mintz goto out; 2574dacd88d6SYuval Mintz } 2575dacd88d6SYuval Mintz 257608feecd7SYuval Mintz /* Update shadow copy of the VF configuration */ 257708feecd7SYuval Mintz if (qed_iov_vf_update_unicast_shadow(p_hwfn, vf, ¶ms)) { 257808feecd7SYuval Mintz status = PFVF_STATUS_FAILURE; 257908feecd7SYuval Mintz goto out; 258008feecd7SYuval Mintz } 258108feecd7SYuval Mintz 258208feecd7SYuval Mintz /* Determine if the unicast filtering is acceptible by PF */ 25831a635e48SYuval Mintz if ((p_bulletin->valid_bitmap & BIT(VLAN_ADDR_FORCED)) && 258408feecd7SYuval Mintz (params.type == QED_FILTER_VLAN || 258508feecd7SYuval Mintz params.type == QED_FILTER_MAC_VLAN)) { 258608feecd7SYuval Mintz /* Once VLAN is forced or PVID is set, do not allow 258708feecd7SYuval Mintz * to add/replace any further VLANs. 258808feecd7SYuval Mintz */ 258908feecd7SYuval Mintz if (params.opcode == QED_FILTER_ADD || 259008feecd7SYuval Mintz params.opcode == QED_FILTER_REPLACE) 259108feecd7SYuval Mintz status = PFVF_STATUS_FORCED; 259208feecd7SYuval Mintz goto out; 259308feecd7SYuval Mintz } 259408feecd7SYuval Mintz 25951a635e48SYuval Mintz if ((p_bulletin->valid_bitmap & BIT(MAC_ADDR_FORCED)) && 2596eff16960SYuval Mintz (params.type == QED_FILTER_MAC || 2597eff16960SYuval Mintz params.type == QED_FILTER_MAC_VLAN)) { 2598eff16960SYuval Mintz if (!ether_addr_equal(p_bulletin->mac, params.mac) || 2599eff16960SYuval Mintz (params.opcode != QED_FILTER_ADD && 2600eff16960SYuval Mintz params.opcode != QED_FILTER_REPLACE)) 2601eff16960SYuval Mintz status = PFVF_STATUS_FORCED; 2602eff16960SYuval Mintz goto out; 2603eff16960SYuval Mintz } 2604eff16960SYuval Mintz 2605dacd88d6SYuval Mintz rc = qed_iov_chk_ucast(p_hwfn, vf->relative_vf_id, ¶ms); 2606dacd88d6SYuval Mintz if (rc) { 2607dacd88d6SYuval Mintz status = PFVF_STATUS_FAILURE; 2608dacd88d6SYuval Mintz goto out; 2609dacd88d6SYuval Mintz } 2610dacd88d6SYuval Mintz 2611dacd88d6SYuval Mintz rc = qed_sp_eth_filter_ucast(p_hwfn, vf->opaque_fid, ¶ms, 2612dacd88d6SYuval Mintz QED_SPQ_MODE_CB, NULL); 2613dacd88d6SYuval Mintz if (rc) 2614dacd88d6SYuval Mintz status = PFVF_STATUS_FAILURE; 2615dacd88d6SYuval Mintz 2616dacd88d6SYuval Mintz out: 2617dacd88d6SYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_UCAST_FILTER, 2618dacd88d6SYuval Mintz sizeof(struct pfvf_def_resp_tlv), status); 2619dacd88d6SYuval Mintz } 2620dacd88d6SYuval Mintz 26210b55e27dSYuval Mintz static void qed_iov_vf_mbx_int_cleanup(struct qed_hwfn *p_hwfn, 26220b55e27dSYuval Mintz struct qed_ptt *p_ptt, 26230b55e27dSYuval Mintz struct qed_vf_info *vf) 26240b55e27dSYuval Mintz { 26250b55e27dSYuval Mintz int i; 26260b55e27dSYuval Mintz 26270b55e27dSYuval Mintz /* Reset the SBs */ 26280b55e27dSYuval Mintz for (i = 0; i < vf->num_sbs; i++) 26290b55e27dSYuval Mintz qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, 26300b55e27dSYuval Mintz vf->igu_sbs[i], 26310b55e27dSYuval Mintz vf->opaque_fid, false); 26320b55e27dSYuval Mintz 26330b55e27dSYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_INT_CLEANUP, 26340b55e27dSYuval Mintz sizeof(struct pfvf_def_resp_tlv), 26350b55e27dSYuval Mintz PFVF_STATUS_SUCCESS); 26360b55e27dSYuval Mintz } 26370b55e27dSYuval Mintz 26380b55e27dSYuval Mintz static void qed_iov_vf_mbx_close(struct qed_hwfn *p_hwfn, 26390b55e27dSYuval Mintz struct qed_ptt *p_ptt, struct qed_vf_info *vf) 26400b55e27dSYuval Mintz { 26410b55e27dSYuval Mintz u16 length = sizeof(struct pfvf_def_resp_tlv); 26420b55e27dSYuval Mintz u8 status = PFVF_STATUS_SUCCESS; 26430b55e27dSYuval Mintz 26440b55e27dSYuval Mintz /* Disable Interrupts for VF */ 26450b55e27dSYuval Mintz qed_iov_vf_igu_set_int(p_hwfn, p_ptt, vf, 0); 26460b55e27dSYuval Mintz 26470b55e27dSYuval Mintz /* Reset Permission table */ 26480b55e27dSYuval Mintz qed_iov_config_perm_table(p_hwfn, p_ptt, vf, 0); 26490b55e27dSYuval Mintz 26500b55e27dSYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_CLOSE, 26510b55e27dSYuval Mintz length, status); 26520b55e27dSYuval Mintz } 26530b55e27dSYuval Mintz 26540b55e27dSYuval Mintz static void qed_iov_vf_mbx_release(struct qed_hwfn *p_hwfn, 26550b55e27dSYuval Mintz struct qed_ptt *p_ptt, 26560b55e27dSYuval Mintz struct qed_vf_info *p_vf) 26570b55e27dSYuval Mintz { 26580b55e27dSYuval Mintz u16 length = sizeof(struct pfvf_def_resp_tlv); 26591fe614d1SYuval Mintz u8 status = PFVF_STATUS_SUCCESS; 26601fe614d1SYuval Mintz int rc = 0; 26610b55e27dSYuval Mintz 26620b55e27dSYuval Mintz qed_iov_vf_cleanup(p_hwfn, p_vf); 26630b55e27dSYuval Mintz 26641fe614d1SYuval Mintz if (p_vf->state != VF_STOPPED && p_vf->state != VF_FREE) { 26651fe614d1SYuval Mintz /* Stopping the VF */ 26661fe614d1SYuval Mintz rc = qed_sp_vf_stop(p_hwfn, p_vf->concrete_fid, 26671fe614d1SYuval Mintz p_vf->opaque_fid); 26681fe614d1SYuval Mintz 26691fe614d1SYuval Mintz if (rc) { 26701fe614d1SYuval Mintz DP_ERR(p_hwfn, "qed_sp_vf_stop returned error %d\n", 26711fe614d1SYuval Mintz rc); 26721fe614d1SYuval Mintz status = PFVF_STATUS_FAILURE; 26731fe614d1SYuval Mintz } 26741fe614d1SYuval Mintz 26751fe614d1SYuval Mintz p_vf->state = VF_STOPPED; 26761fe614d1SYuval Mintz } 26771fe614d1SYuval Mintz 26780b55e27dSYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, p_vf, CHANNEL_TLV_RELEASE, 26791fe614d1SYuval Mintz length, status); 26800b55e27dSYuval Mintz } 26810b55e27dSYuval Mintz 26820b55e27dSYuval Mintz static int 26830b55e27dSYuval Mintz qed_iov_vf_flr_poll_dorq(struct qed_hwfn *p_hwfn, 26840b55e27dSYuval Mintz struct qed_vf_info *p_vf, struct qed_ptt *p_ptt) 26850b55e27dSYuval Mintz { 26860b55e27dSYuval Mintz int cnt; 26870b55e27dSYuval Mintz u32 val; 26880b55e27dSYuval Mintz 26890b55e27dSYuval Mintz qed_fid_pretend(p_hwfn, p_ptt, (u16) p_vf->concrete_fid); 26900b55e27dSYuval Mintz 26910b55e27dSYuval Mintz for (cnt = 0; cnt < 50; cnt++) { 26920b55e27dSYuval Mintz val = qed_rd(p_hwfn, p_ptt, DORQ_REG_VF_USAGE_CNT); 26930b55e27dSYuval Mintz if (!val) 26940b55e27dSYuval Mintz break; 26950b55e27dSYuval Mintz msleep(20); 26960b55e27dSYuval Mintz } 26970b55e27dSYuval Mintz qed_fid_pretend(p_hwfn, p_ptt, (u16) p_hwfn->hw_info.concrete_fid); 26980b55e27dSYuval Mintz 26990b55e27dSYuval Mintz if (cnt == 50) { 27000b55e27dSYuval Mintz DP_ERR(p_hwfn, 27010b55e27dSYuval Mintz "VF[%d] - dorq failed to cleanup [usage 0x%08x]\n", 27020b55e27dSYuval Mintz p_vf->abs_vf_id, val); 27030b55e27dSYuval Mintz return -EBUSY; 27040b55e27dSYuval Mintz } 27050b55e27dSYuval Mintz 27060b55e27dSYuval Mintz return 0; 27070b55e27dSYuval Mintz } 27080b55e27dSYuval Mintz 27090b55e27dSYuval Mintz static int 27100b55e27dSYuval Mintz qed_iov_vf_flr_poll_pbf(struct qed_hwfn *p_hwfn, 27110b55e27dSYuval Mintz struct qed_vf_info *p_vf, struct qed_ptt *p_ptt) 27120b55e27dSYuval Mintz { 27130b55e27dSYuval Mintz u32 cons[MAX_NUM_VOQS], distance[MAX_NUM_VOQS]; 27140b55e27dSYuval Mintz int i, cnt; 27150b55e27dSYuval Mintz 27160b55e27dSYuval Mintz /* Read initial consumers & producers */ 27170b55e27dSYuval Mintz for (i = 0; i < MAX_NUM_VOQS; i++) { 27180b55e27dSYuval Mintz u32 prod; 27190b55e27dSYuval Mintz 27200b55e27dSYuval Mintz cons[i] = qed_rd(p_hwfn, p_ptt, 27210b55e27dSYuval Mintz PBF_REG_NUM_BLOCKS_ALLOCATED_CONS_VOQ0 + 27220b55e27dSYuval Mintz i * 0x40); 27230b55e27dSYuval Mintz prod = qed_rd(p_hwfn, p_ptt, 27240b55e27dSYuval Mintz PBF_REG_NUM_BLOCKS_ALLOCATED_PROD_VOQ0 + 27250b55e27dSYuval Mintz i * 0x40); 27260b55e27dSYuval Mintz distance[i] = prod - cons[i]; 27270b55e27dSYuval Mintz } 27280b55e27dSYuval Mintz 27290b55e27dSYuval Mintz /* Wait for consumers to pass the producers */ 27300b55e27dSYuval Mintz i = 0; 27310b55e27dSYuval Mintz for (cnt = 0; cnt < 50; cnt++) { 27320b55e27dSYuval Mintz for (; i < MAX_NUM_VOQS; i++) { 27330b55e27dSYuval Mintz u32 tmp; 27340b55e27dSYuval Mintz 27350b55e27dSYuval Mintz tmp = qed_rd(p_hwfn, p_ptt, 27360b55e27dSYuval Mintz PBF_REG_NUM_BLOCKS_ALLOCATED_CONS_VOQ0 + 27370b55e27dSYuval Mintz i * 0x40); 27380b55e27dSYuval Mintz if (distance[i] > tmp - cons[i]) 27390b55e27dSYuval Mintz break; 27400b55e27dSYuval Mintz } 27410b55e27dSYuval Mintz 27420b55e27dSYuval Mintz if (i == MAX_NUM_VOQS) 27430b55e27dSYuval Mintz break; 27440b55e27dSYuval Mintz 27450b55e27dSYuval Mintz msleep(20); 27460b55e27dSYuval Mintz } 27470b55e27dSYuval Mintz 27480b55e27dSYuval Mintz if (cnt == 50) { 27490b55e27dSYuval Mintz DP_ERR(p_hwfn, "VF[%d] - pbf polling failed on VOQ %d\n", 27500b55e27dSYuval Mintz p_vf->abs_vf_id, i); 27510b55e27dSYuval Mintz return -EBUSY; 27520b55e27dSYuval Mintz } 27530b55e27dSYuval Mintz 27540b55e27dSYuval Mintz return 0; 27550b55e27dSYuval Mintz } 27560b55e27dSYuval Mintz 27570b55e27dSYuval Mintz static int qed_iov_vf_flr_poll(struct qed_hwfn *p_hwfn, 27580b55e27dSYuval Mintz struct qed_vf_info *p_vf, struct qed_ptt *p_ptt) 27590b55e27dSYuval Mintz { 27600b55e27dSYuval Mintz int rc; 27610b55e27dSYuval Mintz 27620b55e27dSYuval Mintz rc = qed_iov_vf_flr_poll_dorq(p_hwfn, p_vf, p_ptt); 27630b55e27dSYuval Mintz if (rc) 27640b55e27dSYuval Mintz return rc; 27650b55e27dSYuval Mintz 27660b55e27dSYuval Mintz rc = qed_iov_vf_flr_poll_pbf(p_hwfn, p_vf, p_ptt); 27670b55e27dSYuval Mintz if (rc) 27680b55e27dSYuval Mintz return rc; 27690b55e27dSYuval Mintz 27700b55e27dSYuval Mintz return 0; 27710b55e27dSYuval Mintz } 27720b55e27dSYuval Mintz 27730b55e27dSYuval Mintz static int 27740b55e27dSYuval Mintz qed_iov_execute_vf_flr_cleanup(struct qed_hwfn *p_hwfn, 27750b55e27dSYuval Mintz struct qed_ptt *p_ptt, 27760b55e27dSYuval Mintz u16 rel_vf_id, u32 *ack_vfs) 27770b55e27dSYuval Mintz { 27780b55e27dSYuval Mintz struct qed_vf_info *p_vf; 27790b55e27dSYuval Mintz int rc = 0; 27800b55e27dSYuval Mintz 27810b55e27dSYuval Mintz p_vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, false); 27820b55e27dSYuval Mintz if (!p_vf) 27830b55e27dSYuval Mintz return 0; 27840b55e27dSYuval Mintz 27850b55e27dSYuval Mintz if (p_hwfn->pf_iov_info->pending_flr[rel_vf_id / 64] & 27860b55e27dSYuval Mintz (1ULL << (rel_vf_id % 64))) { 27870b55e27dSYuval Mintz u16 vfid = p_vf->abs_vf_id; 27880b55e27dSYuval Mintz 27890b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 27900b55e27dSYuval Mintz "VF[%d] - Handling FLR\n", vfid); 27910b55e27dSYuval Mintz 27920b55e27dSYuval Mintz qed_iov_vf_cleanup(p_hwfn, p_vf); 27930b55e27dSYuval Mintz 27940b55e27dSYuval Mintz /* If VF isn't active, no need for anything but SW */ 27950b55e27dSYuval Mintz if (!p_vf->b_init) 27960b55e27dSYuval Mintz goto cleanup; 27970b55e27dSYuval Mintz 27980b55e27dSYuval Mintz rc = qed_iov_vf_flr_poll(p_hwfn, p_vf, p_ptt); 27990b55e27dSYuval Mintz if (rc) 28000b55e27dSYuval Mintz goto cleanup; 28010b55e27dSYuval Mintz 28020b55e27dSYuval Mintz rc = qed_final_cleanup(p_hwfn, p_ptt, vfid, true); 28030b55e27dSYuval Mintz if (rc) { 28040b55e27dSYuval Mintz DP_ERR(p_hwfn, "Failed handle FLR of VF[%d]\n", vfid); 28050b55e27dSYuval Mintz return rc; 28060b55e27dSYuval Mintz } 28070b55e27dSYuval Mintz 28080b55e27dSYuval Mintz /* VF_STOPPED has to be set only after final cleanup 28090b55e27dSYuval Mintz * but prior to re-enabling the VF. 28100b55e27dSYuval Mintz */ 28110b55e27dSYuval Mintz p_vf->state = VF_STOPPED; 28120b55e27dSYuval Mintz 28130b55e27dSYuval Mintz rc = qed_iov_enable_vf_access(p_hwfn, p_ptt, p_vf); 28140b55e27dSYuval Mintz if (rc) { 28150b55e27dSYuval Mintz DP_ERR(p_hwfn, "Failed to re-enable VF[%d] acces\n", 28160b55e27dSYuval Mintz vfid); 28170b55e27dSYuval Mintz return rc; 28180b55e27dSYuval Mintz } 28190b55e27dSYuval Mintz cleanup: 28200b55e27dSYuval Mintz /* Mark VF for ack and clean pending state */ 28210b55e27dSYuval Mintz if (p_vf->state == VF_RESET) 28220b55e27dSYuval Mintz p_vf->state = VF_STOPPED; 28231a635e48SYuval Mintz ack_vfs[vfid / 32] |= BIT((vfid % 32)); 28240b55e27dSYuval Mintz p_hwfn->pf_iov_info->pending_flr[rel_vf_id / 64] &= 28250b55e27dSYuval Mintz ~(1ULL << (rel_vf_id % 64)); 28260b55e27dSYuval Mintz p_hwfn->pf_iov_info->pending_events[rel_vf_id / 64] &= 28270b55e27dSYuval Mintz ~(1ULL << (rel_vf_id % 64)); 28280b55e27dSYuval Mintz } 28290b55e27dSYuval Mintz 28300b55e27dSYuval Mintz return rc; 28310b55e27dSYuval Mintz } 28320b55e27dSYuval Mintz 28330b55e27dSYuval Mintz int qed_iov_vf_flr_cleanup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 28340b55e27dSYuval Mintz { 28350b55e27dSYuval Mintz u32 ack_vfs[VF_MAX_STATIC / 32]; 28360b55e27dSYuval Mintz int rc = 0; 28370b55e27dSYuval Mintz u16 i; 28380b55e27dSYuval Mintz 28390b55e27dSYuval Mintz memset(ack_vfs, 0, sizeof(u32) * (VF_MAX_STATIC / 32)); 28400b55e27dSYuval Mintz 28410b55e27dSYuval Mintz /* Since BRB <-> PRS interface can't be tested as part of the flr 28420b55e27dSYuval Mintz * polling due to HW limitations, simply sleep a bit. And since 28430b55e27dSYuval Mintz * there's no need to wait per-vf, do it before looping. 28440b55e27dSYuval Mintz */ 28450b55e27dSYuval Mintz msleep(100); 28460b55e27dSYuval Mintz 28470b55e27dSYuval Mintz for (i = 0; i < p_hwfn->cdev->p_iov_info->total_vfs; i++) 28480b55e27dSYuval Mintz qed_iov_execute_vf_flr_cleanup(p_hwfn, p_ptt, i, ack_vfs); 28490b55e27dSYuval Mintz 28500b55e27dSYuval Mintz rc = qed_mcp_ack_vf_flr(p_hwfn, p_ptt, ack_vfs); 28510b55e27dSYuval Mintz return rc; 28520b55e27dSYuval Mintz } 28530b55e27dSYuval Mintz 28540b55e27dSYuval Mintz int qed_iov_mark_vf_flr(struct qed_hwfn *p_hwfn, u32 *p_disabled_vfs) 28550b55e27dSYuval Mintz { 28560b55e27dSYuval Mintz u16 i, found = 0; 28570b55e27dSYuval Mintz 28580b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, "Marking FLR-ed VFs\n"); 28590b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 28600b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 28610b55e27dSYuval Mintz "[%08x,...,%08x]: %08x\n", 28620b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, p_disabled_vfs[i]); 28630b55e27dSYuval Mintz 28640b55e27dSYuval Mintz if (!p_hwfn->cdev->p_iov_info) { 28650b55e27dSYuval Mintz DP_NOTICE(p_hwfn, "VF flr but no IOV\n"); 28660b55e27dSYuval Mintz return 0; 28670b55e27dSYuval Mintz } 28680b55e27dSYuval Mintz 28690b55e27dSYuval Mintz /* Mark VFs */ 28700b55e27dSYuval Mintz for (i = 0; i < p_hwfn->cdev->p_iov_info->total_vfs; i++) { 28710b55e27dSYuval Mintz struct qed_vf_info *p_vf; 28720b55e27dSYuval Mintz u8 vfid; 28730b55e27dSYuval Mintz 28740b55e27dSYuval Mintz p_vf = qed_iov_get_vf_info(p_hwfn, i, false); 28750b55e27dSYuval Mintz if (!p_vf) 28760b55e27dSYuval Mintz continue; 28770b55e27dSYuval Mintz 28780b55e27dSYuval Mintz vfid = p_vf->abs_vf_id; 28791a635e48SYuval Mintz if (BIT((vfid % 32)) & p_disabled_vfs[vfid / 32]) { 28800b55e27dSYuval Mintz u64 *p_flr = p_hwfn->pf_iov_info->pending_flr; 28810b55e27dSYuval Mintz u16 rel_vf_id = p_vf->relative_vf_id; 28820b55e27dSYuval Mintz 28830b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 28840b55e27dSYuval Mintz "VF[%d] [rel %d] got FLR-ed\n", 28850b55e27dSYuval Mintz vfid, rel_vf_id); 28860b55e27dSYuval Mintz 28870b55e27dSYuval Mintz p_vf->state = VF_RESET; 28880b55e27dSYuval Mintz 28890b55e27dSYuval Mintz /* No need to lock here, since pending_flr should 28900b55e27dSYuval Mintz * only change here and before ACKing MFw. Since 28910b55e27dSYuval Mintz * MFW will not trigger an additional attention for 28920b55e27dSYuval Mintz * VF flr until ACKs, we're safe. 28930b55e27dSYuval Mintz */ 28940b55e27dSYuval Mintz p_flr[rel_vf_id / 64] |= 1ULL << (rel_vf_id % 64); 28950b55e27dSYuval Mintz found = 1; 28960b55e27dSYuval Mintz } 28970b55e27dSYuval Mintz } 28980b55e27dSYuval Mintz 28990b55e27dSYuval Mintz return found; 29000b55e27dSYuval Mintz } 29010b55e27dSYuval Mintz 290273390ac9SYuval Mintz static void qed_iov_get_link(struct qed_hwfn *p_hwfn, 290373390ac9SYuval Mintz u16 vfid, 290473390ac9SYuval Mintz struct qed_mcp_link_params *p_params, 290573390ac9SYuval Mintz struct qed_mcp_link_state *p_link, 290673390ac9SYuval Mintz struct qed_mcp_link_capabilities *p_caps) 290773390ac9SYuval Mintz { 290873390ac9SYuval Mintz struct qed_vf_info *p_vf = qed_iov_get_vf_info(p_hwfn, 290973390ac9SYuval Mintz vfid, 291073390ac9SYuval Mintz false); 291173390ac9SYuval Mintz struct qed_bulletin_content *p_bulletin; 291273390ac9SYuval Mintz 291373390ac9SYuval Mintz if (!p_vf) 291473390ac9SYuval Mintz return; 291573390ac9SYuval Mintz 291673390ac9SYuval Mintz p_bulletin = p_vf->bulletin.p_virt; 291773390ac9SYuval Mintz 291873390ac9SYuval Mintz if (p_params) 291973390ac9SYuval Mintz __qed_vf_get_link_params(p_hwfn, p_params, p_bulletin); 292073390ac9SYuval Mintz if (p_link) 292173390ac9SYuval Mintz __qed_vf_get_link_state(p_hwfn, p_link, p_bulletin); 292273390ac9SYuval Mintz if (p_caps) 292373390ac9SYuval Mintz __qed_vf_get_link_caps(p_hwfn, p_caps, p_bulletin); 292473390ac9SYuval Mintz } 292573390ac9SYuval Mintz 292637bff2b9SYuval Mintz static void qed_iov_process_mbx_req(struct qed_hwfn *p_hwfn, 292737bff2b9SYuval Mintz struct qed_ptt *p_ptt, int vfid) 292837bff2b9SYuval Mintz { 292937bff2b9SYuval Mintz struct qed_iov_vf_mbx *mbx; 293037bff2b9SYuval Mintz struct qed_vf_info *p_vf; 293137bff2b9SYuval Mintz 293237bff2b9SYuval Mintz p_vf = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 293337bff2b9SYuval Mintz if (!p_vf) 293437bff2b9SYuval Mintz return; 293537bff2b9SYuval Mintz 293637bff2b9SYuval Mintz mbx = &p_vf->vf_mbx; 293737bff2b9SYuval Mintz 293837bff2b9SYuval Mintz /* qed_iov_process_mbx_request */ 293954fdd80fSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 294054fdd80fSYuval Mintz "VF[%02x]: Processing mailbox message\n", p_vf->abs_vf_id); 294137bff2b9SYuval Mintz 294237bff2b9SYuval Mintz mbx->first_tlv = mbx->req_virt->first_tlv; 294337bff2b9SYuval Mintz 294437bff2b9SYuval Mintz /* check if tlv type is known */ 294537bff2b9SYuval Mintz if (qed_iov_tlv_supported(mbx->first_tlv.tl.type)) { 29461408cc1fSYuval Mintz switch (mbx->first_tlv.tl.type) { 29471408cc1fSYuval Mintz case CHANNEL_TLV_ACQUIRE: 29481408cc1fSYuval Mintz qed_iov_vf_mbx_acquire(p_hwfn, p_ptt, p_vf); 29491408cc1fSYuval Mintz break; 2950dacd88d6SYuval Mintz case CHANNEL_TLV_VPORT_START: 2951dacd88d6SYuval Mintz qed_iov_vf_mbx_start_vport(p_hwfn, p_ptt, p_vf); 2952dacd88d6SYuval Mintz break; 2953dacd88d6SYuval Mintz case CHANNEL_TLV_VPORT_TEARDOWN: 2954dacd88d6SYuval Mintz qed_iov_vf_mbx_stop_vport(p_hwfn, p_ptt, p_vf); 2955dacd88d6SYuval Mintz break; 2956dacd88d6SYuval Mintz case CHANNEL_TLV_START_RXQ: 2957dacd88d6SYuval Mintz qed_iov_vf_mbx_start_rxq(p_hwfn, p_ptt, p_vf); 2958dacd88d6SYuval Mintz break; 2959dacd88d6SYuval Mintz case CHANNEL_TLV_START_TXQ: 2960dacd88d6SYuval Mintz qed_iov_vf_mbx_start_txq(p_hwfn, p_ptt, p_vf); 2961dacd88d6SYuval Mintz break; 2962dacd88d6SYuval Mintz case CHANNEL_TLV_STOP_RXQS: 2963dacd88d6SYuval Mintz qed_iov_vf_mbx_stop_rxqs(p_hwfn, p_ptt, p_vf); 2964dacd88d6SYuval Mintz break; 2965dacd88d6SYuval Mintz case CHANNEL_TLV_STOP_TXQS: 2966dacd88d6SYuval Mintz qed_iov_vf_mbx_stop_txqs(p_hwfn, p_ptt, p_vf); 2967dacd88d6SYuval Mintz break; 296817b235c1SYuval Mintz case CHANNEL_TLV_UPDATE_RXQ: 296917b235c1SYuval Mintz qed_iov_vf_mbx_update_rxqs(p_hwfn, p_ptt, p_vf); 297017b235c1SYuval Mintz break; 2971dacd88d6SYuval Mintz case CHANNEL_TLV_VPORT_UPDATE: 2972dacd88d6SYuval Mintz qed_iov_vf_mbx_vport_update(p_hwfn, p_ptt, p_vf); 2973dacd88d6SYuval Mintz break; 2974dacd88d6SYuval Mintz case CHANNEL_TLV_UCAST_FILTER: 2975dacd88d6SYuval Mintz qed_iov_vf_mbx_ucast_filter(p_hwfn, p_ptt, p_vf); 2976dacd88d6SYuval Mintz break; 29770b55e27dSYuval Mintz case CHANNEL_TLV_CLOSE: 29780b55e27dSYuval Mintz qed_iov_vf_mbx_close(p_hwfn, p_ptt, p_vf); 29790b55e27dSYuval Mintz break; 29800b55e27dSYuval Mintz case CHANNEL_TLV_INT_CLEANUP: 29810b55e27dSYuval Mintz qed_iov_vf_mbx_int_cleanup(p_hwfn, p_ptt, p_vf); 29820b55e27dSYuval Mintz break; 29830b55e27dSYuval Mintz case CHANNEL_TLV_RELEASE: 29840b55e27dSYuval Mintz qed_iov_vf_mbx_release(p_hwfn, p_ptt, p_vf); 29850b55e27dSYuval Mintz break; 29861408cc1fSYuval Mintz } 298737bff2b9SYuval Mintz } else { 298837bff2b9SYuval Mintz /* unknown TLV - this may belong to a VF driver from the future 298937bff2b9SYuval Mintz * - a version written after this PF driver was written, which 299037bff2b9SYuval Mintz * supports features unknown as of yet. Too bad since we don't 299137bff2b9SYuval Mintz * support them. Or this may be because someone wrote a crappy 299237bff2b9SYuval Mintz * VF driver and is sending garbage over the channel. 299337bff2b9SYuval Mintz */ 299454fdd80fSYuval Mintz DP_NOTICE(p_hwfn, 299554fdd80fSYuval Mintz "VF[%02x]: unknown TLV. type %04x length %04x padding %08x reply address %llu\n", 299654fdd80fSYuval Mintz p_vf->abs_vf_id, 299754fdd80fSYuval Mintz mbx->first_tlv.tl.type, 299854fdd80fSYuval Mintz mbx->first_tlv.tl.length, 299954fdd80fSYuval Mintz mbx->first_tlv.padding, mbx->first_tlv.reply_address); 300037bff2b9SYuval Mintz 300154fdd80fSYuval Mintz /* Try replying in case reply address matches the acquisition's 300254fdd80fSYuval Mintz * posted address. 300354fdd80fSYuval Mintz */ 300454fdd80fSYuval Mintz if (p_vf->acquire.first_tlv.reply_address && 300554fdd80fSYuval Mintz (mbx->first_tlv.reply_address == 300654fdd80fSYuval Mintz p_vf->acquire.first_tlv.reply_address)) { 300754fdd80fSYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, p_vf, 300854fdd80fSYuval Mintz mbx->first_tlv.tl.type, 300954fdd80fSYuval Mintz sizeof(struct pfvf_def_resp_tlv), 301054fdd80fSYuval Mintz PFVF_STATUS_NOT_SUPPORTED); 301154fdd80fSYuval Mintz } else { 301237bff2b9SYuval Mintz DP_VERBOSE(p_hwfn, 301337bff2b9SYuval Mintz QED_MSG_IOV, 301454fdd80fSYuval Mintz "VF[%02x]: Can't respond to TLV - no valid reply address\n", 301554fdd80fSYuval Mintz p_vf->abs_vf_id); 301637bff2b9SYuval Mintz } 301737bff2b9SYuval Mintz } 301837bff2b9SYuval Mintz } 301937bff2b9SYuval Mintz 302037bff2b9SYuval Mintz void qed_iov_pf_add_pending_events(struct qed_hwfn *p_hwfn, u8 vfid) 302137bff2b9SYuval Mintz { 302237bff2b9SYuval Mintz u64 add_bit = 1ULL << (vfid % 64); 302337bff2b9SYuval Mintz 302437bff2b9SYuval Mintz p_hwfn->pf_iov_info->pending_events[vfid / 64] |= add_bit; 302537bff2b9SYuval Mintz } 302637bff2b9SYuval Mintz 302737bff2b9SYuval Mintz static void qed_iov_pf_get_and_clear_pending_events(struct qed_hwfn *p_hwfn, 302837bff2b9SYuval Mintz u64 *events) 302937bff2b9SYuval Mintz { 303037bff2b9SYuval Mintz u64 *p_pending_events = p_hwfn->pf_iov_info->pending_events; 303137bff2b9SYuval Mintz 303237bff2b9SYuval Mintz memcpy(events, p_pending_events, sizeof(u64) * QED_VF_ARRAY_LENGTH); 303337bff2b9SYuval Mintz memset(p_pending_events, 0, sizeof(u64) * QED_VF_ARRAY_LENGTH); 303437bff2b9SYuval Mintz } 303537bff2b9SYuval Mintz 303637bff2b9SYuval Mintz static int qed_sriov_vfpf_msg(struct qed_hwfn *p_hwfn, 303737bff2b9SYuval Mintz u16 abs_vfid, struct regpair *vf_msg) 303837bff2b9SYuval Mintz { 303937bff2b9SYuval Mintz u8 min = (u8)p_hwfn->cdev->p_iov_info->first_vf_in_pf; 304037bff2b9SYuval Mintz struct qed_vf_info *p_vf; 304137bff2b9SYuval Mintz 304237bff2b9SYuval Mintz if (!qed_iov_pf_sanity_check(p_hwfn, (int)abs_vfid - min)) { 304337bff2b9SYuval Mintz DP_VERBOSE(p_hwfn, 304437bff2b9SYuval Mintz QED_MSG_IOV, 304537bff2b9SYuval Mintz "Got a message from VF [abs 0x%08x] that cannot be handled by PF\n", 304637bff2b9SYuval Mintz abs_vfid); 304737bff2b9SYuval Mintz return 0; 304837bff2b9SYuval Mintz } 304937bff2b9SYuval Mintz p_vf = &p_hwfn->pf_iov_info->vfs_array[(u8)abs_vfid - min]; 305037bff2b9SYuval Mintz 305137bff2b9SYuval Mintz /* List the physical address of the request so that handler 305237bff2b9SYuval Mintz * could later on copy the message from it. 305337bff2b9SYuval Mintz */ 305437bff2b9SYuval Mintz p_vf->vf_mbx.pending_req = (((u64)vf_msg->hi) << 32) | vf_msg->lo; 305537bff2b9SYuval Mintz 305637bff2b9SYuval Mintz /* Mark the event and schedule the workqueue */ 305737bff2b9SYuval Mintz qed_iov_pf_add_pending_events(p_hwfn, p_vf->relative_vf_id); 305837bff2b9SYuval Mintz qed_schedule_iov(p_hwfn, QED_IOV_WQ_MSG_FLAG); 305937bff2b9SYuval Mintz 306037bff2b9SYuval Mintz return 0; 306137bff2b9SYuval Mintz } 306237bff2b9SYuval Mintz 306337bff2b9SYuval Mintz int qed_sriov_eqe_event(struct qed_hwfn *p_hwfn, 306437bff2b9SYuval Mintz u8 opcode, __le16 echo, union event_ring_data *data) 306537bff2b9SYuval Mintz { 306637bff2b9SYuval Mintz switch (opcode) { 306737bff2b9SYuval Mintz case COMMON_EVENT_VF_PF_CHANNEL: 306837bff2b9SYuval Mintz return qed_sriov_vfpf_msg(p_hwfn, le16_to_cpu(echo), 306937bff2b9SYuval Mintz &data->vf_pf_channel.msg_addr); 307037bff2b9SYuval Mintz default: 307137bff2b9SYuval Mintz DP_INFO(p_hwfn->cdev, "Unknown sriov eqe event 0x%02x\n", 307237bff2b9SYuval Mintz opcode); 307337bff2b9SYuval Mintz return -EINVAL; 307437bff2b9SYuval Mintz } 307537bff2b9SYuval Mintz } 307637bff2b9SYuval Mintz 307732a47e72SYuval Mintz u16 qed_iov_get_next_active_vf(struct qed_hwfn *p_hwfn, u16 rel_vf_id) 307832a47e72SYuval Mintz { 307932a47e72SYuval Mintz struct qed_hw_sriov_info *p_iov = p_hwfn->cdev->p_iov_info; 308032a47e72SYuval Mintz u16 i; 308132a47e72SYuval Mintz 308232a47e72SYuval Mintz if (!p_iov) 308332a47e72SYuval Mintz goto out; 308432a47e72SYuval Mintz 308532a47e72SYuval Mintz for (i = rel_vf_id; i < p_iov->total_vfs; i++) 308632a47e72SYuval Mintz if (qed_iov_is_valid_vfid(p_hwfn, rel_vf_id, true)) 308732a47e72SYuval Mintz return i; 308832a47e72SYuval Mintz 308932a47e72SYuval Mintz out: 309032a47e72SYuval Mintz return MAX_NUM_VFS; 309132a47e72SYuval Mintz } 309237bff2b9SYuval Mintz 309337bff2b9SYuval Mintz static int qed_iov_copy_vf_msg(struct qed_hwfn *p_hwfn, struct qed_ptt *ptt, 309437bff2b9SYuval Mintz int vfid) 309537bff2b9SYuval Mintz { 309637bff2b9SYuval Mintz struct qed_dmae_params params; 309737bff2b9SYuval Mintz struct qed_vf_info *vf_info; 309837bff2b9SYuval Mintz 309937bff2b9SYuval Mintz vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 310037bff2b9SYuval Mintz if (!vf_info) 310137bff2b9SYuval Mintz return -EINVAL; 310237bff2b9SYuval Mintz 310337bff2b9SYuval Mintz memset(¶ms, 0, sizeof(struct qed_dmae_params)); 310437bff2b9SYuval Mintz params.flags = QED_DMAE_FLAG_VF_SRC | QED_DMAE_FLAG_COMPLETION_DST; 310537bff2b9SYuval Mintz params.src_vfid = vf_info->abs_vf_id; 310637bff2b9SYuval Mintz 310737bff2b9SYuval Mintz if (qed_dmae_host2host(p_hwfn, ptt, 310837bff2b9SYuval Mintz vf_info->vf_mbx.pending_req, 310937bff2b9SYuval Mintz vf_info->vf_mbx.req_phys, 311037bff2b9SYuval Mintz sizeof(union vfpf_tlvs) / 4, ¶ms)) { 311137bff2b9SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 311237bff2b9SYuval Mintz "Failed to copy message from VF 0x%02x\n", vfid); 311337bff2b9SYuval Mintz 311437bff2b9SYuval Mintz return -EIO; 311537bff2b9SYuval Mintz } 311637bff2b9SYuval Mintz 311737bff2b9SYuval Mintz return 0; 311837bff2b9SYuval Mintz } 311937bff2b9SYuval Mintz 3120eff16960SYuval Mintz static void qed_iov_bulletin_set_forced_mac(struct qed_hwfn *p_hwfn, 3121eff16960SYuval Mintz u8 *mac, int vfid) 3122eff16960SYuval Mintz { 3123eff16960SYuval Mintz struct qed_vf_info *vf_info; 3124eff16960SYuval Mintz u64 feature; 3125eff16960SYuval Mintz 3126eff16960SYuval Mintz vf_info = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true); 3127eff16960SYuval Mintz if (!vf_info) { 3128eff16960SYuval Mintz DP_NOTICE(p_hwfn->cdev, 3129eff16960SYuval Mintz "Can not set forced MAC, invalid vfid [%d]\n", vfid); 3130eff16960SYuval Mintz return; 3131eff16960SYuval Mintz } 3132eff16960SYuval Mintz 3133eff16960SYuval Mintz feature = 1 << MAC_ADDR_FORCED; 3134eff16960SYuval Mintz memcpy(vf_info->bulletin.p_virt->mac, mac, ETH_ALEN); 3135eff16960SYuval Mintz 3136eff16960SYuval Mintz vf_info->bulletin.p_virt->valid_bitmap |= feature; 3137eff16960SYuval Mintz /* Forced MAC will disable MAC_ADDR */ 31381a635e48SYuval Mintz vf_info->bulletin.p_virt->valid_bitmap &= ~BIT(VFPF_BULLETIN_MAC_ADDR); 3139eff16960SYuval Mintz 3140eff16960SYuval Mintz qed_iov_configure_vport_forced(p_hwfn, vf_info, feature); 3141eff16960SYuval Mintz } 3142eff16960SYuval Mintz 314308feecd7SYuval Mintz void qed_iov_bulletin_set_forced_vlan(struct qed_hwfn *p_hwfn, 314408feecd7SYuval Mintz u16 pvid, int vfid) 314508feecd7SYuval Mintz { 314608feecd7SYuval Mintz struct qed_vf_info *vf_info; 314708feecd7SYuval Mintz u64 feature; 314808feecd7SYuval Mintz 314908feecd7SYuval Mintz vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 315008feecd7SYuval Mintz if (!vf_info) { 315108feecd7SYuval Mintz DP_NOTICE(p_hwfn->cdev, 315208feecd7SYuval Mintz "Can not set forced MAC, invalid vfid [%d]\n", vfid); 315308feecd7SYuval Mintz return; 315408feecd7SYuval Mintz } 315508feecd7SYuval Mintz 315608feecd7SYuval Mintz feature = 1 << VLAN_ADDR_FORCED; 315708feecd7SYuval Mintz vf_info->bulletin.p_virt->pvid = pvid; 315808feecd7SYuval Mintz if (pvid) 315908feecd7SYuval Mintz vf_info->bulletin.p_virt->valid_bitmap |= feature; 316008feecd7SYuval Mintz else 316108feecd7SYuval Mintz vf_info->bulletin.p_virt->valid_bitmap &= ~feature; 316208feecd7SYuval Mintz 316308feecd7SYuval Mintz qed_iov_configure_vport_forced(p_hwfn, vf_info, feature); 316408feecd7SYuval Mintz } 316508feecd7SYuval Mintz 31666ddc7608SYuval Mintz static bool qed_iov_vf_has_vport_instance(struct qed_hwfn *p_hwfn, int vfid) 31676ddc7608SYuval Mintz { 31686ddc7608SYuval Mintz struct qed_vf_info *p_vf_info; 31696ddc7608SYuval Mintz 31706ddc7608SYuval Mintz p_vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 31716ddc7608SYuval Mintz if (!p_vf_info) 31726ddc7608SYuval Mintz return false; 31736ddc7608SYuval Mintz 31746ddc7608SYuval Mintz return !!p_vf_info->vport_instance; 31756ddc7608SYuval Mintz } 31766ddc7608SYuval Mintz 31770b55e27dSYuval Mintz bool qed_iov_is_vf_stopped(struct qed_hwfn *p_hwfn, int vfid) 31780b55e27dSYuval Mintz { 31790b55e27dSYuval Mintz struct qed_vf_info *p_vf_info; 31800b55e27dSYuval Mintz 31810b55e27dSYuval Mintz p_vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 31820b55e27dSYuval Mintz if (!p_vf_info) 31830b55e27dSYuval Mintz return true; 31840b55e27dSYuval Mintz 31850b55e27dSYuval Mintz return p_vf_info->state == VF_STOPPED; 31860b55e27dSYuval Mintz } 31870b55e27dSYuval Mintz 318873390ac9SYuval Mintz static bool qed_iov_spoofchk_get(struct qed_hwfn *p_hwfn, int vfid) 318973390ac9SYuval Mintz { 319073390ac9SYuval Mintz struct qed_vf_info *vf_info; 319173390ac9SYuval Mintz 319273390ac9SYuval Mintz vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 319373390ac9SYuval Mintz if (!vf_info) 319473390ac9SYuval Mintz return false; 319573390ac9SYuval Mintz 319673390ac9SYuval Mintz return vf_info->spoof_chk; 319773390ac9SYuval Mintz } 319873390ac9SYuval Mintz 31996ddc7608SYuval Mintz int qed_iov_spoofchk_set(struct qed_hwfn *p_hwfn, int vfid, bool val) 32006ddc7608SYuval Mintz { 32016ddc7608SYuval Mintz struct qed_vf_info *vf; 32026ddc7608SYuval Mintz int rc = -EINVAL; 32036ddc7608SYuval Mintz 32046ddc7608SYuval Mintz if (!qed_iov_pf_sanity_check(p_hwfn, vfid)) { 32056ddc7608SYuval Mintz DP_NOTICE(p_hwfn, 32066ddc7608SYuval Mintz "SR-IOV sanity check failed, can't set spoofchk\n"); 32076ddc7608SYuval Mintz goto out; 32086ddc7608SYuval Mintz } 32096ddc7608SYuval Mintz 32106ddc7608SYuval Mintz vf = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 32116ddc7608SYuval Mintz if (!vf) 32126ddc7608SYuval Mintz goto out; 32136ddc7608SYuval Mintz 32146ddc7608SYuval Mintz if (!qed_iov_vf_has_vport_instance(p_hwfn, vfid)) { 32156ddc7608SYuval Mintz /* After VF VPORT start PF will configure spoof check */ 32166ddc7608SYuval Mintz vf->req_spoofchk_val = val; 32176ddc7608SYuval Mintz rc = 0; 32186ddc7608SYuval Mintz goto out; 32196ddc7608SYuval Mintz } 32206ddc7608SYuval Mintz 32216ddc7608SYuval Mintz rc = __qed_iov_spoofchk_set(p_hwfn, vf, val); 32226ddc7608SYuval Mintz 32236ddc7608SYuval Mintz out: 32246ddc7608SYuval Mintz return rc; 32256ddc7608SYuval Mintz } 32266ddc7608SYuval Mintz 3227eff16960SYuval Mintz static u8 *qed_iov_bulletin_get_forced_mac(struct qed_hwfn *p_hwfn, 3228eff16960SYuval Mintz u16 rel_vf_id) 3229eff16960SYuval Mintz { 3230eff16960SYuval Mintz struct qed_vf_info *p_vf; 3231eff16960SYuval Mintz 3232eff16960SYuval Mintz p_vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, true); 3233eff16960SYuval Mintz if (!p_vf || !p_vf->bulletin.p_virt) 3234eff16960SYuval Mintz return NULL; 3235eff16960SYuval Mintz 32361a635e48SYuval Mintz if (!(p_vf->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED))) 3237eff16960SYuval Mintz return NULL; 3238eff16960SYuval Mintz 3239eff16960SYuval Mintz return p_vf->bulletin.p_virt->mac; 3240eff16960SYuval Mintz } 3241eff16960SYuval Mintz 324208feecd7SYuval Mintz u16 qed_iov_bulletin_get_forced_vlan(struct qed_hwfn *p_hwfn, u16 rel_vf_id) 324308feecd7SYuval Mintz { 324408feecd7SYuval Mintz struct qed_vf_info *p_vf; 324508feecd7SYuval Mintz 324608feecd7SYuval Mintz p_vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, true); 324708feecd7SYuval Mintz if (!p_vf || !p_vf->bulletin.p_virt) 324808feecd7SYuval Mintz return 0; 324908feecd7SYuval Mintz 32501a635e48SYuval Mintz if (!(p_vf->bulletin.p_virt->valid_bitmap & BIT(VLAN_ADDR_FORCED))) 325108feecd7SYuval Mintz return 0; 325208feecd7SYuval Mintz 325308feecd7SYuval Mintz return p_vf->bulletin.p_virt->pvid; 325408feecd7SYuval Mintz } 325508feecd7SYuval Mintz 3256733def6aSYuval Mintz static int qed_iov_configure_tx_rate(struct qed_hwfn *p_hwfn, 3257733def6aSYuval Mintz struct qed_ptt *p_ptt, int vfid, int val) 3258733def6aSYuval Mintz { 3259733def6aSYuval Mintz struct qed_vf_info *vf; 3260733def6aSYuval Mintz u8 abs_vp_id = 0; 3261733def6aSYuval Mintz int rc; 3262733def6aSYuval Mintz 3263733def6aSYuval Mintz vf = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true); 3264733def6aSYuval Mintz if (!vf) 3265733def6aSYuval Mintz return -EINVAL; 3266733def6aSYuval Mintz 3267733def6aSYuval Mintz rc = qed_fw_vport(p_hwfn, vf->vport_id, &abs_vp_id); 3268733def6aSYuval Mintz if (rc) 3269733def6aSYuval Mintz return rc; 3270733def6aSYuval Mintz 3271733def6aSYuval Mintz return qed_init_vport_rl(p_hwfn, p_ptt, abs_vp_id, (u32)val); 3272733def6aSYuval Mintz } 3273733def6aSYuval Mintz 3274733def6aSYuval Mintz int qed_iov_configure_min_tx_rate(struct qed_dev *cdev, int vfid, u32 rate) 3275733def6aSYuval Mintz { 3276733def6aSYuval Mintz struct qed_vf_info *vf; 3277733def6aSYuval Mintz u8 vport_id; 3278733def6aSYuval Mintz int i; 3279733def6aSYuval Mintz 3280733def6aSYuval Mintz for_each_hwfn(cdev, i) { 3281733def6aSYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 3282733def6aSYuval Mintz 3283733def6aSYuval Mintz if (!qed_iov_pf_sanity_check(p_hwfn, vfid)) { 3284733def6aSYuval Mintz DP_NOTICE(p_hwfn, 3285733def6aSYuval Mintz "SR-IOV sanity check failed, can't set min rate\n"); 3286733def6aSYuval Mintz return -EINVAL; 3287733def6aSYuval Mintz } 3288733def6aSYuval Mintz } 3289733def6aSYuval Mintz 3290733def6aSYuval Mintz vf = qed_iov_get_vf_info(QED_LEADING_HWFN(cdev), (u16)vfid, true); 3291733def6aSYuval Mintz vport_id = vf->vport_id; 3292733def6aSYuval Mintz 3293733def6aSYuval Mintz return qed_configure_vport_wfq(cdev, vport_id, rate); 3294733def6aSYuval Mintz } 3295733def6aSYuval Mintz 329673390ac9SYuval Mintz static int qed_iov_get_vf_min_rate(struct qed_hwfn *p_hwfn, int vfid) 329773390ac9SYuval Mintz { 329873390ac9SYuval Mintz struct qed_wfq_data *vf_vp_wfq; 329973390ac9SYuval Mintz struct qed_vf_info *vf_info; 330073390ac9SYuval Mintz 330173390ac9SYuval Mintz vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 330273390ac9SYuval Mintz if (!vf_info) 330373390ac9SYuval Mintz return 0; 330473390ac9SYuval Mintz 330573390ac9SYuval Mintz vf_vp_wfq = &p_hwfn->qm_info.wfq_data[vf_info->vport_id]; 330673390ac9SYuval Mintz 330773390ac9SYuval Mintz if (vf_vp_wfq->configured) 330873390ac9SYuval Mintz return vf_vp_wfq->min_speed; 330973390ac9SYuval Mintz else 331073390ac9SYuval Mintz return 0; 331173390ac9SYuval Mintz } 331273390ac9SYuval Mintz 331337bff2b9SYuval Mintz /** 331437bff2b9SYuval Mintz * qed_schedule_iov - schedules IOV task for VF and PF 331537bff2b9SYuval Mintz * @hwfn: hardware function pointer 331637bff2b9SYuval Mintz * @flag: IOV flag for VF/PF 331737bff2b9SYuval Mintz */ 331837bff2b9SYuval Mintz void qed_schedule_iov(struct qed_hwfn *hwfn, enum qed_iov_wq_flag flag) 331937bff2b9SYuval Mintz { 332037bff2b9SYuval Mintz smp_mb__before_atomic(); 332137bff2b9SYuval Mintz set_bit(flag, &hwfn->iov_task_flags); 332237bff2b9SYuval Mintz smp_mb__after_atomic(); 332337bff2b9SYuval Mintz DP_VERBOSE(hwfn, QED_MSG_IOV, "Scheduling iov task [Flag: %d]\n", flag); 332437bff2b9SYuval Mintz queue_delayed_work(hwfn->iov_wq, &hwfn->iov_task, 0); 332537bff2b9SYuval Mintz } 332637bff2b9SYuval Mintz 33271408cc1fSYuval Mintz void qed_vf_start_iov_wq(struct qed_dev *cdev) 33281408cc1fSYuval Mintz { 33291408cc1fSYuval Mintz int i; 33301408cc1fSYuval Mintz 33311408cc1fSYuval Mintz for_each_hwfn(cdev, i) 33321408cc1fSYuval Mintz queue_delayed_work(cdev->hwfns[i].iov_wq, 33331408cc1fSYuval Mintz &cdev->hwfns[i].iov_task, 0); 33341408cc1fSYuval Mintz } 33351408cc1fSYuval Mintz 33360b55e27dSYuval Mintz int qed_sriov_disable(struct qed_dev *cdev, bool pci_enabled) 33370b55e27dSYuval Mintz { 33380b55e27dSYuval Mintz int i, j; 33390b55e27dSYuval Mintz 33400b55e27dSYuval Mintz for_each_hwfn(cdev, i) 33410b55e27dSYuval Mintz if (cdev->hwfns[i].iov_wq) 33420b55e27dSYuval Mintz flush_workqueue(cdev->hwfns[i].iov_wq); 33430b55e27dSYuval Mintz 33440b55e27dSYuval Mintz /* Mark VFs for disablement */ 33450b55e27dSYuval Mintz qed_iov_set_vfs_to_disable(cdev, true); 33460b55e27dSYuval Mintz 33470b55e27dSYuval Mintz if (cdev->p_iov_info && cdev->p_iov_info->num_vfs && pci_enabled) 33480b55e27dSYuval Mintz pci_disable_sriov(cdev->pdev); 33490b55e27dSYuval Mintz 33500b55e27dSYuval Mintz for_each_hwfn(cdev, i) { 33510b55e27dSYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[i]; 33520b55e27dSYuval Mintz struct qed_ptt *ptt = qed_ptt_acquire(hwfn); 33530b55e27dSYuval Mintz 33540b55e27dSYuval Mintz /* Failure to acquire the ptt in 100g creates an odd error 33550b55e27dSYuval Mintz * where the first engine has already relased IOV. 33560b55e27dSYuval Mintz */ 33570b55e27dSYuval Mintz if (!ptt) { 33580b55e27dSYuval Mintz DP_ERR(hwfn, "Failed to acquire ptt\n"); 33590b55e27dSYuval Mintz return -EBUSY; 33600b55e27dSYuval Mintz } 33610b55e27dSYuval Mintz 3362733def6aSYuval Mintz /* Clean WFQ db and configure equal weight for all vports */ 3363733def6aSYuval Mintz qed_clean_wfq_db(hwfn, ptt); 3364733def6aSYuval Mintz 33650b55e27dSYuval Mintz qed_for_each_vf(hwfn, j) { 33660b55e27dSYuval Mintz int k; 33670b55e27dSYuval Mintz 33680b55e27dSYuval Mintz if (!qed_iov_is_valid_vfid(hwfn, j, true)) 33690b55e27dSYuval Mintz continue; 33700b55e27dSYuval Mintz 33710b55e27dSYuval Mintz /* Wait until VF is disabled before releasing */ 33720b55e27dSYuval Mintz for (k = 0; k < 100; k++) { 33730b55e27dSYuval Mintz if (!qed_iov_is_vf_stopped(hwfn, j)) 33740b55e27dSYuval Mintz msleep(20); 33750b55e27dSYuval Mintz else 33760b55e27dSYuval Mintz break; 33770b55e27dSYuval Mintz } 33780b55e27dSYuval Mintz 33790b55e27dSYuval Mintz if (k < 100) 33800b55e27dSYuval Mintz qed_iov_release_hw_for_vf(&cdev->hwfns[i], 33810b55e27dSYuval Mintz ptt, j); 33820b55e27dSYuval Mintz else 33830b55e27dSYuval Mintz DP_ERR(hwfn, 33840b55e27dSYuval Mintz "Timeout waiting for VF's FLR to end\n"); 33850b55e27dSYuval Mintz } 33860b55e27dSYuval Mintz 33870b55e27dSYuval Mintz qed_ptt_release(hwfn, ptt); 33880b55e27dSYuval Mintz } 33890b55e27dSYuval Mintz 33900b55e27dSYuval Mintz qed_iov_set_vfs_to_disable(cdev, false); 33910b55e27dSYuval Mintz 33920b55e27dSYuval Mintz return 0; 33930b55e27dSYuval Mintz } 33940b55e27dSYuval Mintz 33950b55e27dSYuval Mintz static int qed_sriov_enable(struct qed_dev *cdev, int num) 33960b55e27dSYuval Mintz { 33970b55e27dSYuval Mintz struct qed_sb_cnt_info sb_cnt_info; 33980b55e27dSYuval Mintz int i, j, rc; 33990b55e27dSYuval Mintz 34000b55e27dSYuval Mintz if (num >= RESC_NUM(&cdev->hwfns[0], QED_VPORT)) { 34010b55e27dSYuval Mintz DP_NOTICE(cdev, "Can start at most %d VFs\n", 34020b55e27dSYuval Mintz RESC_NUM(&cdev->hwfns[0], QED_VPORT) - 1); 34030b55e27dSYuval Mintz return -EINVAL; 34040b55e27dSYuval Mintz } 34050b55e27dSYuval Mintz 34060b55e27dSYuval Mintz /* Initialize HW for VF access */ 34070b55e27dSYuval Mintz for_each_hwfn(cdev, j) { 34080b55e27dSYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[j]; 34090b55e27dSYuval Mintz struct qed_ptt *ptt = qed_ptt_acquire(hwfn); 34100b55e27dSYuval Mintz int num_sbs = 0, limit = 16; 34110b55e27dSYuval Mintz 34120b55e27dSYuval Mintz if (!ptt) { 34130b55e27dSYuval Mintz DP_ERR(hwfn, "Failed to acquire ptt\n"); 34140b55e27dSYuval Mintz rc = -EBUSY; 34150b55e27dSYuval Mintz goto err; 34160b55e27dSYuval Mintz } 34170b55e27dSYuval Mintz 341883f34bd4SYuval Mintz if (IS_MF_DEFAULT(hwfn)) 341983f34bd4SYuval Mintz limit = MAX_NUM_VFS_BB / hwfn->num_funcs_on_engine; 342083f34bd4SYuval Mintz 34210b55e27dSYuval Mintz memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); 34220b55e27dSYuval Mintz qed_int_get_num_sbs(hwfn, &sb_cnt_info); 34230b55e27dSYuval Mintz num_sbs = min_t(int, sb_cnt_info.sb_free_blk, limit); 34240b55e27dSYuval Mintz 34250b55e27dSYuval Mintz for (i = 0; i < num; i++) { 34260b55e27dSYuval Mintz if (!qed_iov_is_valid_vfid(hwfn, i, false)) 34270b55e27dSYuval Mintz continue; 34280b55e27dSYuval Mintz 34290b55e27dSYuval Mintz rc = qed_iov_init_hw_for_vf(hwfn, 34300b55e27dSYuval Mintz ptt, i, num_sbs / num); 34310b55e27dSYuval Mintz if (rc) { 34320b55e27dSYuval Mintz DP_ERR(cdev, "Failed to enable VF[%d]\n", i); 34330b55e27dSYuval Mintz qed_ptt_release(hwfn, ptt); 34340b55e27dSYuval Mintz goto err; 34350b55e27dSYuval Mintz } 34360b55e27dSYuval Mintz } 34370b55e27dSYuval Mintz 34380b55e27dSYuval Mintz qed_ptt_release(hwfn, ptt); 34390b55e27dSYuval Mintz } 34400b55e27dSYuval Mintz 34410b55e27dSYuval Mintz /* Enable SRIOV PCIe functions */ 34420b55e27dSYuval Mintz rc = pci_enable_sriov(cdev->pdev, num); 34430b55e27dSYuval Mintz if (rc) { 34440b55e27dSYuval Mintz DP_ERR(cdev, "Failed to enable sriov [%d]\n", rc); 34450b55e27dSYuval Mintz goto err; 34460b55e27dSYuval Mintz } 34470b55e27dSYuval Mintz 34480b55e27dSYuval Mintz return num; 34490b55e27dSYuval Mintz 34500b55e27dSYuval Mintz err: 34510b55e27dSYuval Mintz qed_sriov_disable(cdev, false); 34520b55e27dSYuval Mintz return rc; 34530b55e27dSYuval Mintz } 34540b55e27dSYuval Mintz 34550b55e27dSYuval Mintz static int qed_sriov_configure(struct qed_dev *cdev, int num_vfs_param) 34560b55e27dSYuval Mintz { 34570b55e27dSYuval Mintz if (!IS_QED_SRIOV(cdev)) { 34580b55e27dSYuval Mintz DP_VERBOSE(cdev, QED_MSG_IOV, "SR-IOV is not supported\n"); 34590b55e27dSYuval Mintz return -EOPNOTSUPP; 34600b55e27dSYuval Mintz } 34610b55e27dSYuval Mintz 34620b55e27dSYuval Mintz if (num_vfs_param) 34630b55e27dSYuval Mintz return qed_sriov_enable(cdev, num_vfs_param); 34640b55e27dSYuval Mintz else 34650b55e27dSYuval Mintz return qed_sriov_disable(cdev, true); 34660b55e27dSYuval Mintz } 34670b55e27dSYuval Mintz 3468eff16960SYuval Mintz static int qed_sriov_pf_set_mac(struct qed_dev *cdev, u8 *mac, int vfid) 3469eff16960SYuval Mintz { 3470eff16960SYuval Mintz int i; 3471eff16960SYuval Mintz 3472eff16960SYuval Mintz if (!IS_QED_SRIOV(cdev) || !IS_PF_SRIOV_ALLOC(&cdev->hwfns[0])) { 3473eff16960SYuval Mintz DP_VERBOSE(cdev, QED_MSG_IOV, 3474eff16960SYuval Mintz "Cannot set a VF MAC; Sriov is not enabled\n"); 3475eff16960SYuval Mintz return -EINVAL; 3476eff16960SYuval Mintz } 3477eff16960SYuval Mintz 3478eff16960SYuval Mintz if (!qed_iov_is_valid_vfid(&cdev->hwfns[0], vfid, true)) { 3479eff16960SYuval Mintz DP_VERBOSE(cdev, QED_MSG_IOV, 3480eff16960SYuval Mintz "Cannot set VF[%d] MAC (VF is not active)\n", vfid); 3481eff16960SYuval Mintz return -EINVAL; 3482eff16960SYuval Mintz } 3483eff16960SYuval Mintz 3484eff16960SYuval Mintz for_each_hwfn(cdev, i) { 3485eff16960SYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[i]; 3486eff16960SYuval Mintz struct qed_public_vf_info *vf_info; 3487eff16960SYuval Mintz 3488eff16960SYuval Mintz vf_info = qed_iov_get_public_vf_info(hwfn, vfid, true); 3489eff16960SYuval Mintz if (!vf_info) 3490eff16960SYuval Mintz continue; 3491eff16960SYuval Mintz 3492eff16960SYuval Mintz /* Set the forced MAC, and schedule the IOV task */ 3493eff16960SYuval Mintz ether_addr_copy(vf_info->forced_mac, mac); 3494eff16960SYuval Mintz qed_schedule_iov(hwfn, QED_IOV_WQ_SET_UNICAST_FILTER_FLAG); 3495eff16960SYuval Mintz } 3496eff16960SYuval Mintz 3497eff16960SYuval Mintz return 0; 3498eff16960SYuval Mintz } 3499eff16960SYuval Mintz 350008feecd7SYuval Mintz static int qed_sriov_pf_set_vlan(struct qed_dev *cdev, u16 vid, int vfid) 350108feecd7SYuval Mintz { 350208feecd7SYuval Mintz int i; 350308feecd7SYuval Mintz 350408feecd7SYuval Mintz if (!IS_QED_SRIOV(cdev) || !IS_PF_SRIOV_ALLOC(&cdev->hwfns[0])) { 350508feecd7SYuval Mintz DP_VERBOSE(cdev, QED_MSG_IOV, 350608feecd7SYuval Mintz "Cannot set a VF MAC; Sriov is not enabled\n"); 350708feecd7SYuval Mintz return -EINVAL; 350808feecd7SYuval Mintz } 350908feecd7SYuval Mintz 351008feecd7SYuval Mintz if (!qed_iov_is_valid_vfid(&cdev->hwfns[0], vfid, true)) { 351108feecd7SYuval Mintz DP_VERBOSE(cdev, QED_MSG_IOV, 351208feecd7SYuval Mintz "Cannot set VF[%d] MAC (VF is not active)\n", vfid); 351308feecd7SYuval Mintz return -EINVAL; 351408feecd7SYuval Mintz } 351508feecd7SYuval Mintz 351608feecd7SYuval Mintz for_each_hwfn(cdev, i) { 351708feecd7SYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[i]; 351808feecd7SYuval Mintz struct qed_public_vf_info *vf_info; 351908feecd7SYuval Mintz 352008feecd7SYuval Mintz vf_info = qed_iov_get_public_vf_info(hwfn, vfid, true); 352108feecd7SYuval Mintz if (!vf_info) 352208feecd7SYuval Mintz continue; 352308feecd7SYuval Mintz 352408feecd7SYuval Mintz /* Set the forced vlan, and schedule the IOV task */ 352508feecd7SYuval Mintz vf_info->forced_vlan = vid; 352608feecd7SYuval Mintz qed_schedule_iov(hwfn, QED_IOV_WQ_SET_UNICAST_FILTER_FLAG); 352708feecd7SYuval Mintz } 352808feecd7SYuval Mintz 352908feecd7SYuval Mintz return 0; 353008feecd7SYuval Mintz } 353108feecd7SYuval Mintz 353273390ac9SYuval Mintz static int qed_get_vf_config(struct qed_dev *cdev, 353373390ac9SYuval Mintz int vf_id, struct ifla_vf_info *ivi) 353473390ac9SYuval Mintz { 353573390ac9SYuval Mintz struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 353673390ac9SYuval Mintz struct qed_public_vf_info *vf_info; 353773390ac9SYuval Mintz struct qed_mcp_link_state link; 353873390ac9SYuval Mintz u32 tx_rate; 353973390ac9SYuval Mintz 354073390ac9SYuval Mintz /* Sanitize request */ 354173390ac9SYuval Mintz if (IS_VF(cdev)) 354273390ac9SYuval Mintz return -EINVAL; 354373390ac9SYuval Mintz 354473390ac9SYuval Mintz if (!qed_iov_is_valid_vfid(&cdev->hwfns[0], vf_id, true)) { 354573390ac9SYuval Mintz DP_VERBOSE(cdev, QED_MSG_IOV, 354673390ac9SYuval Mintz "VF index [%d] isn't active\n", vf_id); 354773390ac9SYuval Mintz return -EINVAL; 354873390ac9SYuval Mintz } 354973390ac9SYuval Mintz 355073390ac9SYuval Mintz vf_info = qed_iov_get_public_vf_info(hwfn, vf_id, true); 355173390ac9SYuval Mintz 355273390ac9SYuval Mintz qed_iov_get_link(hwfn, vf_id, NULL, &link, NULL); 355373390ac9SYuval Mintz 355473390ac9SYuval Mintz /* Fill information about VF */ 355573390ac9SYuval Mintz ivi->vf = vf_id; 355673390ac9SYuval Mintz 355773390ac9SYuval Mintz if (is_valid_ether_addr(vf_info->forced_mac)) 355873390ac9SYuval Mintz ether_addr_copy(ivi->mac, vf_info->forced_mac); 355973390ac9SYuval Mintz else 356073390ac9SYuval Mintz ether_addr_copy(ivi->mac, vf_info->mac); 356173390ac9SYuval Mintz 356273390ac9SYuval Mintz ivi->vlan = vf_info->forced_vlan; 356373390ac9SYuval Mintz ivi->spoofchk = qed_iov_spoofchk_get(hwfn, vf_id); 356473390ac9SYuval Mintz ivi->linkstate = vf_info->link_state; 356573390ac9SYuval Mintz tx_rate = vf_info->tx_rate; 356673390ac9SYuval Mintz ivi->max_tx_rate = tx_rate ? tx_rate : link.speed; 356773390ac9SYuval Mintz ivi->min_tx_rate = qed_iov_get_vf_min_rate(hwfn, vf_id); 356873390ac9SYuval Mintz 356973390ac9SYuval Mintz return 0; 357073390ac9SYuval Mintz } 357173390ac9SYuval Mintz 357236558c3dSYuval Mintz void qed_inform_vf_link_state(struct qed_hwfn *hwfn) 357336558c3dSYuval Mintz { 357436558c3dSYuval Mintz struct qed_mcp_link_capabilities caps; 357536558c3dSYuval Mintz struct qed_mcp_link_params params; 357636558c3dSYuval Mintz struct qed_mcp_link_state link; 357736558c3dSYuval Mintz int i; 357836558c3dSYuval Mintz 357936558c3dSYuval Mintz if (!hwfn->pf_iov_info) 358036558c3dSYuval Mintz return; 358136558c3dSYuval Mintz 358236558c3dSYuval Mintz /* Update bulletin of all future possible VFs with link configuration */ 358336558c3dSYuval Mintz for (i = 0; i < hwfn->cdev->p_iov_info->total_vfs; i++) { 3584733def6aSYuval Mintz struct qed_public_vf_info *vf_info; 3585733def6aSYuval Mintz 3586733def6aSYuval Mintz vf_info = qed_iov_get_public_vf_info(hwfn, i, false); 3587733def6aSYuval Mintz if (!vf_info) 3588733def6aSYuval Mintz continue; 3589733def6aSYuval Mintz 359036558c3dSYuval Mintz memcpy(¶ms, qed_mcp_get_link_params(hwfn), sizeof(params)); 359136558c3dSYuval Mintz memcpy(&link, qed_mcp_get_link_state(hwfn), sizeof(link)); 359236558c3dSYuval Mintz memcpy(&caps, qed_mcp_get_link_capabilities(hwfn), 359336558c3dSYuval Mintz sizeof(caps)); 359436558c3dSYuval Mintz 3595733def6aSYuval Mintz /* Modify link according to the VF's configured link state */ 3596733def6aSYuval Mintz switch (vf_info->link_state) { 3597733def6aSYuval Mintz case IFLA_VF_LINK_STATE_DISABLE: 3598733def6aSYuval Mintz link.link_up = false; 3599733def6aSYuval Mintz break; 3600733def6aSYuval Mintz case IFLA_VF_LINK_STATE_ENABLE: 3601733def6aSYuval Mintz link.link_up = true; 3602733def6aSYuval Mintz /* Set speed according to maximum supported by HW. 3603733def6aSYuval Mintz * that is 40G for regular devices and 100G for CMT 3604733def6aSYuval Mintz * mode devices. 3605733def6aSYuval Mintz */ 3606733def6aSYuval Mintz link.speed = (hwfn->cdev->num_hwfns > 1) ? 3607733def6aSYuval Mintz 100000 : 40000; 3608733def6aSYuval Mintz default: 3609733def6aSYuval Mintz /* In auto mode pass PF link image to VF */ 3610733def6aSYuval Mintz break; 3611733def6aSYuval Mintz } 3612733def6aSYuval Mintz 3613733def6aSYuval Mintz if (link.link_up && vf_info->tx_rate) { 3614733def6aSYuval Mintz struct qed_ptt *ptt; 3615733def6aSYuval Mintz int rate; 3616733def6aSYuval Mintz 3617733def6aSYuval Mintz rate = min_t(int, vf_info->tx_rate, link.speed); 3618733def6aSYuval Mintz 3619733def6aSYuval Mintz ptt = qed_ptt_acquire(hwfn); 3620733def6aSYuval Mintz if (!ptt) { 3621733def6aSYuval Mintz DP_NOTICE(hwfn, "Failed to acquire PTT\n"); 3622733def6aSYuval Mintz return; 3623733def6aSYuval Mintz } 3624733def6aSYuval Mintz 3625733def6aSYuval Mintz if (!qed_iov_configure_tx_rate(hwfn, ptt, i, rate)) { 3626733def6aSYuval Mintz vf_info->tx_rate = rate; 3627733def6aSYuval Mintz link.speed = rate; 3628733def6aSYuval Mintz } 3629733def6aSYuval Mintz 3630733def6aSYuval Mintz qed_ptt_release(hwfn, ptt); 3631733def6aSYuval Mintz } 3632733def6aSYuval Mintz 363336558c3dSYuval Mintz qed_iov_set_link(hwfn, i, ¶ms, &link, &caps); 363436558c3dSYuval Mintz } 363536558c3dSYuval Mintz 363636558c3dSYuval Mintz qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); 363736558c3dSYuval Mintz } 363836558c3dSYuval Mintz 3639733def6aSYuval Mintz static int qed_set_vf_link_state(struct qed_dev *cdev, 3640733def6aSYuval Mintz int vf_id, int link_state) 3641733def6aSYuval Mintz { 3642733def6aSYuval Mintz int i; 3643733def6aSYuval Mintz 3644733def6aSYuval Mintz /* Sanitize request */ 3645733def6aSYuval Mintz if (IS_VF(cdev)) 3646733def6aSYuval Mintz return -EINVAL; 3647733def6aSYuval Mintz 3648733def6aSYuval Mintz if (!qed_iov_is_valid_vfid(&cdev->hwfns[0], vf_id, true)) { 3649733def6aSYuval Mintz DP_VERBOSE(cdev, QED_MSG_IOV, 3650733def6aSYuval Mintz "VF index [%d] isn't active\n", vf_id); 3651733def6aSYuval Mintz return -EINVAL; 3652733def6aSYuval Mintz } 3653733def6aSYuval Mintz 3654733def6aSYuval Mintz /* Handle configuration of link state */ 3655733def6aSYuval Mintz for_each_hwfn(cdev, i) { 3656733def6aSYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[i]; 3657733def6aSYuval Mintz struct qed_public_vf_info *vf; 3658733def6aSYuval Mintz 3659733def6aSYuval Mintz vf = qed_iov_get_public_vf_info(hwfn, vf_id, true); 3660733def6aSYuval Mintz if (!vf) 3661733def6aSYuval Mintz continue; 3662733def6aSYuval Mintz 3663733def6aSYuval Mintz if (vf->link_state == link_state) 3664733def6aSYuval Mintz continue; 3665733def6aSYuval Mintz 3666733def6aSYuval Mintz vf->link_state = link_state; 3667733def6aSYuval Mintz qed_inform_vf_link_state(&cdev->hwfns[i]); 3668733def6aSYuval Mintz } 3669733def6aSYuval Mintz 3670733def6aSYuval Mintz return 0; 3671733def6aSYuval Mintz } 3672733def6aSYuval Mintz 36736ddc7608SYuval Mintz static int qed_spoof_configure(struct qed_dev *cdev, int vfid, bool val) 36746ddc7608SYuval Mintz { 36756ddc7608SYuval Mintz int i, rc = -EINVAL; 36766ddc7608SYuval Mintz 36776ddc7608SYuval Mintz for_each_hwfn(cdev, i) { 36786ddc7608SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 36796ddc7608SYuval Mintz 36806ddc7608SYuval Mintz rc = qed_iov_spoofchk_set(p_hwfn, vfid, val); 36816ddc7608SYuval Mintz if (rc) 36826ddc7608SYuval Mintz break; 36836ddc7608SYuval Mintz } 36846ddc7608SYuval Mintz 36856ddc7608SYuval Mintz return rc; 36866ddc7608SYuval Mintz } 36876ddc7608SYuval Mintz 3688733def6aSYuval Mintz static int qed_configure_max_vf_rate(struct qed_dev *cdev, int vfid, int rate) 3689733def6aSYuval Mintz { 3690733def6aSYuval Mintz int i; 3691733def6aSYuval Mintz 3692733def6aSYuval Mintz for_each_hwfn(cdev, i) { 3693733def6aSYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 3694733def6aSYuval Mintz struct qed_public_vf_info *vf; 3695733def6aSYuval Mintz 3696733def6aSYuval Mintz if (!qed_iov_pf_sanity_check(p_hwfn, vfid)) { 3697733def6aSYuval Mintz DP_NOTICE(p_hwfn, 3698733def6aSYuval Mintz "SR-IOV sanity check failed, can't set tx rate\n"); 3699733def6aSYuval Mintz return -EINVAL; 3700733def6aSYuval Mintz } 3701733def6aSYuval Mintz 3702733def6aSYuval Mintz vf = qed_iov_get_public_vf_info(p_hwfn, vfid, true); 3703733def6aSYuval Mintz 3704733def6aSYuval Mintz vf->tx_rate = rate; 3705733def6aSYuval Mintz 3706733def6aSYuval Mintz qed_inform_vf_link_state(p_hwfn); 3707733def6aSYuval Mintz } 3708733def6aSYuval Mintz 3709733def6aSYuval Mintz return 0; 3710733def6aSYuval Mintz } 3711733def6aSYuval Mintz 3712733def6aSYuval Mintz static int qed_set_vf_rate(struct qed_dev *cdev, 3713733def6aSYuval Mintz int vfid, u32 min_rate, u32 max_rate) 3714733def6aSYuval Mintz { 3715733def6aSYuval Mintz int rc_min = 0, rc_max = 0; 3716733def6aSYuval Mintz 3717733def6aSYuval Mintz if (max_rate) 3718733def6aSYuval Mintz rc_max = qed_configure_max_vf_rate(cdev, vfid, max_rate); 3719733def6aSYuval Mintz 3720733def6aSYuval Mintz if (min_rate) 3721733def6aSYuval Mintz rc_min = qed_iov_configure_min_tx_rate(cdev, vfid, min_rate); 3722733def6aSYuval Mintz 3723733def6aSYuval Mintz if (rc_max | rc_min) 3724733def6aSYuval Mintz return -EINVAL; 3725733def6aSYuval Mintz 3726733def6aSYuval Mintz return 0; 3727733def6aSYuval Mintz } 3728733def6aSYuval Mintz 372937bff2b9SYuval Mintz static void qed_handle_vf_msg(struct qed_hwfn *hwfn) 373037bff2b9SYuval Mintz { 373137bff2b9SYuval Mintz u64 events[QED_VF_ARRAY_LENGTH]; 373237bff2b9SYuval Mintz struct qed_ptt *ptt; 373337bff2b9SYuval Mintz int i; 373437bff2b9SYuval Mintz 373537bff2b9SYuval Mintz ptt = qed_ptt_acquire(hwfn); 373637bff2b9SYuval Mintz if (!ptt) { 373737bff2b9SYuval Mintz DP_VERBOSE(hwfn, QED_MSG_IOV, 373837bff2b9SYuval Mintz "Can't acquire PTT; re-scheduling\n"); 373937bff2b9SYuval Mintz qed_schedule_iov(hwfn, QED_IOV_WQ_MSG_FLAG); 374037bff2b9SYuval Mintz return; 374137bff2b9SYuval Mintz } 374237bff2b9SYuval Mintz 374337bff2b9SYuval Mintz qed_iov_pf_get_and_clear_pending_events(hwfn, events); 374437bff2b9SYuval Mintz 374537bff2b9SYuval Mintz DP_VERBOSE(hwfn, QED_MSG_IOV, 374637bff2b9SYuval Mintz "Event mask of VF events: 0x%llx 0x%llx 0x%llx\n", 374737bff2b9SYuval Mintz events[0], events[1], events[2]); 374837bff2b9SYuval Mintz 374937bff2b9SYuval Mintz qed_for_each_vf(hwfn, i) { 375037bff2b9SYuval Mintz /* Skip VFs with no pending messages */ 375137bff2b9SYuval Mintz if (!(events[i / 64] & (1ULL << (i % 64)))) 375237bff2b9SYuval Mintz continue; 375337bff2b9SYuval Mintz 375437bff2b9SYuval Mintz DP_VERBOSE(hwfn, QED_MSG_IOV, 375537bff2b9SYuval Mintz "Handling VF message from VF 0x%02x [Abs 0x%02x]\n", 375637bff2b9SYuval Mintz i, hwfn->cdev->p_iov_info->first_vf_in_pf + i); 375737bff2b9SYuval Mintz 375837bff2b9SYuval Mintz /* Copy VF's message to PF's request buffer for that VF */ 375937bff2b9SYuval Mintz if (qed_iov_copy_vf_msg(hwfn, ptt, i)) 376037bff2b9SYuval Mintz continue; 376137bff2b9SYuval Mintz 376237bff2b9SYuval Mintz qed_iov_process_mbx_req(hwfn, ptt, i); 376337bff2b9SYuval Mintz } 376437bff2b9SYuval Mintz 376537bff2b9SYuval Mintz qed_ptt_release(hwfn, ptt); 376637bff2b9SYuval Mintz } 376737bff2b9SYuval Mintz 376808feecd7SYuval Mintz static void qed_handle_pf_set_vf_unicast(struct qed_hwfn *hwfn) 376908feecd7SYuval Mintz { 377008feecd7SYuval Mintz int i; 377108feecd7SYuval Mintz 377208feecd7SYuval Mintz qed_for_each_vf(hwfn, i) { 377308feecd7SYuval Mintz struct qed_public_vf_info *info; 377408feecd7SYuval Mintz bool update = false; 3775eff16960SYuval Mintz u8 *mac; 377608feecd7SYuval Mintz 377708feecd7SYuval Mintz info = qed_iov_get_public_vf_info(hwfn, i, true); 377808feecd7SYuval Mintz if (!info) 377908feecd7SYuval Mintz continue; 378008feecd7SYuval Mintz 378108feecd7SYuval Mintz /* Update data on bulletin board */ 3782eff16960SYuval Mintz mac = qed_iov_bulletin_get_forced_mac(hwfn, i); 3783eff16960SYuval Mintz if (is_valid_ether_addr(info->forced_mac) && 3784eff16960SYuval Mintz (!mac || !ether_addr_equal(mac, info->forced_mac))) { 3785eff16960SYuval Mintz DP_VERBOSE(hwfn, 3786eff16960SYuval Mintz QED_MSG_IOV, 3787eff16960SYuval Mintz "Handling PF setting of VF MAC to VF 0x%02x [Abs 0x%02x]\n", 3788eff16960SYuval Mintz i, 3789eff16960SYuval Mintz hwfn->cdev->p_iov_info->first_vf_in_pf + i); 3790eff16960SYuval Mintz 3791eff16960SYuval Mintz /* Update bulletin board with forced MAC */ 3792eff16960SYuval Mintz qed_iov_bulletin_set_forced_mac(hwfn, 3793eff16960SYuval Mintz info->forced_mac, i); 3794eff16960SYuval Mintz update = true; 3795eff16960SYuval Mintz } 379608feecd7SYuval Mintz 379708feecd7SYuval Mintz if (qed_iov_bulletin_get_forced_vlan(hwfn, i) ^ 379808feecd7SYuval Mintz info->forced_vlan) { 379908feecd7SYuval Mintz DP_VERBOSE(hwfn, 380008feecd7SYuval Mintz QED_MSG_IOV, 380108feecd7SYuval Mintz "Handling PF setting of pvid [0x%04x] to VF 0x%02x [Abs 0x%02x]\n", 380208feecd7SYuval Mintz info->forced_vlan, 380308feecd7SYuval Mintz i, 380408feecd7SYuval Mintz hwfn->cdev->p_iov_info->first_vf_in_pf + i); 380508feecd7SYuval Mintz qed_iov_bulletin_set_forced_vlan(hwfn, 380608feecd7SYuval Mintz info->forced_vlan, i); 380708feecd7SYuval Mintz update = true; 380808feecd7SYuval Mintz } 380908feecd7SYuval Mintz 381008feecd7SYuval Mintz if (update) 381108feecd7SYuval Mintz qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); 381208feecd7SYuval Mintz } 381308feecd7SYuval Mintz } 381408feecd7SYuval Mintz 381536558c3dSYuval Mintz static void qed_handle_bulletin_post(struct qed_hwfn *hwfn) 381636558c3dSYuval Mintz { 381736558c3dSYuval Mintz struct qed_ptt *ptt; 381836558c3dSYuval Mintz int i; 381936558c3dSYuval Mintz 382036558c3dSYuval Mintz ptt = qed_ptt_acquire(hwfn); 382136558c3dSYuval Mintz if (!ptt) { 382236558c3dSYuval Mintz DP_NOTICE(hwfn, "Failed allocating a ptt entry\n"); 382336558c3dSYuval Mintz qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); 382436558c3dSYuval Mintz return; 382536558c3dSYuval Mintz } 382636558c3dSYuval Mintz 382736558c3dSYuval Mintz qed_for_each_vf(hwfn, i) 382836558c3dSYuval Mintz qed_iov_post_vf_bulletin(hwfn, i, ptt); 382936558c3dSYuval Mintz 383036558c3dSYuval Mintz qed_ptt_release(hwfn, ptt); 383136558c3dSYuval Mintz } 383236558c3dSYuval Mintz 383337bff2b9SYuval Mintz void qed_iov_pf_task(struct work_struct *work) 383437bff2b9SYuval Mintz { 383537bff2b9SYuval Mintz struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn, 383637bff2b9SYuval Mintz iov_task.work); 38370b55e27dSYuval Mintz int rc; 383837bff2b9SYuval Mintz 383937bff2b9SYuval Mintz if (test_and_clear_bit(QED_IOV_WQ_STOP_WQ_FLAG, &hwfn->iov_task_flags)) 384037bff2b9SYuval Mintz return; 384137bff2b9SYuval Mintz 38420b55e27dSYuval Mintz if (test_and_clear_bit(QED_IOV_WQ_FLR_FLAG, &hwfn->iov_task_flags)) { 38430b55e27dSYuval Mintz struct qed_ptt *ptt = qed_ptt_acquire(hwfn); 38440b55e27dSYuval Mintz 38450b55e27dSYuval Mintz if (!ptt) { 38460b55e27dSYuval Mintz qed_schedule_iov(hwfn, QED_IOV_WQ_FLR_FLAG); 38470b55e27dSYuval Mintz return; 38480b55e27dSYuval Mintz } 38490b55e27dSYuval Mintz 38500b55e27dSYuval Mintz rc = qed_iov_vf_flr_cleanup(hwfn, ptt); 38510b55e27dSYuval Mintz if (rc) 38520b55e27dSYuval Mintz qed_schedule_iov(hwfn, QED_IOV_WQ_FLR_FLAG); 38530b55e27dSYuval Mintz 38540b55e27dSYuval Mintz qed_ptt_release(hwfn, ptt); 38550b55e27dSYuval Mintz } 38560b55e27dSYuval Mintz 385737bff2b9SYuval Mintz if (test_and_clear_bit(QED_IOV_WQ_MSG_FLAG, &hwfn->iov_task_flags)) 385837bff2b9SYuval Mintz qed_handle_vf_msg(hwfn); 385908feecd7SYuval Mintz 386008feecd7SYuval Mintz if (test_and_clear_bit(QED_IOV_WQ_SET_UNICAST_FILTER_FLAG, 386108feecd7SYuval Mintz &hwfn->iov_task_flags)) 386208feecd7SYuval Mintz qed_handle_pf_set_vf_unicast(hwfn); 386308feecd7SYuval Mintz 386436558c3dSYuval Mintz if (test_and_clear_bit(QED_IOV_WQ_BULLETIN_UPDATE_FLAG, 386536558c3dSYuval Mintz &hwfn->iov_task_flags)) 386636558c3dSYuval Mintz qed_handle_bulletin_post(hwfn); 386737bff2b9SYuval Mintz } 386837bff2b9SYuval Mintz 386937bff2b9SYuval Mintz void qed_iov_wq_stop(struct qed_dev *cdev, bool schedule_first) 387037bff2b9SYuval Mintz { 387137bff2b9SYuval Mintz int i; 387237bff2b9SYuval Mintz 387337bff2b9SYuval Mintz for_each_hwfn(cdev, i) { 387437bff2b9SYuval Mintz if (!cdev->hwfns[i].iov_wq) 387537bff2b9SYuval Mintz continue; 387637bff2b9SYuval Mintz 387737bff2b9SYuval Mintz if (schedule_first) { 387837bff2b9SYuval Mintz qed_schedule_iov(&cdev->hwfns[i], 387937bff2b9SYuval Mintz QED_IOV_WQ_STOP_WQ_FLAG); 388037bff2b9SYuval Mintz cancel_delayed_work_sync(&cdev->hwfns[i].iov_task); 388137bff2b9SYuval Mintz } 388237bff2b9SYuval Mintz 388337bff2b9SYuval Mintz flush_workqueue(cdev->hwfns[i].iov_wq); 388437bff2b9SYuval Mintz destroy_workqueue(cdev->hwfns[i].iov_wq); 388537bff2b9SYuval Mintz } 388637bff2b9SYuval Mintz } 388737bff2b9SYuval Mintz 388837bff2b9SYuval Mintz int qed_iov_wq_start(struct qed_dev *cdev) 388937bff2b9SYuval Mintz { 389037bff2b9SYuval Mintz char name[NAME_SIZE]; 389137bff2b9SYuval Mintz int i; 389237bff2b9SYuval Mintz 389337bff2b9SYuval Mintz for_each_hwfn(cdev, i) { 389437bff2b9SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 389537bff2b9SYuval Mintz 389636558c3dSYuval Mintz /* PFs needs a dedicated workqueue only if they support IOV. 389736558c3dSYuval Mintz * VFs always require one. 389836558c3dSYuval Mintz */ 389936558c3dSYuval Mintz if (IS_PF(p_hwfn->cdev) && !IS_PF_SRIOV(p_hwfn)) 390037bff2b9SYuval Mintz continue; 390137bff2b9SYuval Mintz 390237bff2b9SYuval Mintz snprintf(name, NAME_SIZE, "iov-%02x:%02x.%02x", 390337bff2b9SYuval Mintz cdev->pdev->bus->number, 390437bff2b9SYuval Mintz PCI_SLOT(cdev->pdev->devfn), p_hwfn->abs_pf_id); 390537bff2b9SYuval Mintz 390637bff2b9SYuval Mintz p_hwfn->iov_wq = create_singlethread_workqueue(name); 390737bff2b9SYuval Mintz if (!p_hwfn->iov_wq) { 390837bff2b9SYuval Mintz DP_NOTICE(p_hwfn, "Cannot create iov workqueue\n"); 390937bff2b9SYuval Mintz return -ENOMEM; 391037bff2b9SYuval Mintz } 391137bff2b9SYuval Mintz 391236558c3dSYuval Mintz if (IS_PF(cdev)) 391337bff2b9SYuval Mintz INIT_DELAYED_WORK(&p_hwfn->iov_task, qed_iov_pf_task); 391436558c3dSYuval Mintz else 391536558c3dSYuval Mintz INIT_DELAYED_WORK(&p_hwfn->iov_task, qed_iov_vf_task); 391637bff2b9SYuval Mintz } 391737bff2b9SYuval Mintz 391837bff2b9SYuval Mintz return 0; 391937bff2b9SYuval Mintz } 39200b55e27dSYuval Mintz 39210b55e27dSYuval Mintz const struct qed_iov_hv_ops qed_iov_ops_pass = { 39220b55e27dSYuval Mintz .configure = &qed_sriov_configure, 3923eff16960SYuval Mintz .set_mac = &qed_sriov_pf_set_mac, 392408feecd7SYuval Mintz .set_vlan = &qed_sriov_pf_set_vlan, 392573390ac9SYuval Mintz .get_config = &qed_get_vf_config, 3926733def6aSYuval Mintz .set_link_state = &qed_set_vf_link_state, 39276ddc7608SYuval Mintz .set_spoof = &qed_spoof_configure, 3928733def6aSYuval Mintz .set_rate = &qed_set_vf_rate, 39290b55e27dSYuval Mintz }; 3930