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 932a47e72SYuval Mintz #include "qed_hw.h" 1032a47e72SYuval Mintz #include "qed_int.h" 1132a47e72SYuval Mintz #include "qed_reg_addr.h" 1232a47e72SYuval Mintz #include "qed_sriov.h" 1332a47e72SYuval Mintz #include "qed_vf.h" 1432a47e72SYuval Mintz 1532a47e72SYuval Mintz bool qed_iov_is_valid_vfid(struct qed_hwfn *p_hwfn, 1632a47e72SYuval Mintz int rel_vf_id, bool b_enabled_only) 1732a47e72SYuval Mintz { 1832a47e72SYuval Mintz if (!p_hwfn->pf_iov_info) { 1932a47e72SYuval Mintz DP_NOTICE(p_hwfn->cdev, "No iov info\n"); 2032a47e72SYuval Mintz return false; 2132a47e72SYuval Mintz } 2232a47e72SYuval Mintz 2332a47e72SYuval Mintz if ((rel_vf_id >= p_hwfn->cdev->p_iov_info->total_vfs) || 2432a47e72SYuval Mintz (rel_vf_id < 0)) 2532a47e72SYuval Mintz return false; 2632a47e72SYuval Mintz 2732a47e72SYuval Mintz if ((!p_hwfn->pf_iov_info->vfs_array[rel_vf_id].b_init) && 2832a47e72SYuval Mintz b_enabled_only) 2932a47e72SYuval Mintz return false; 3032a47e72SYuval Mintz 3132a47e72SYuval Mintz return true; 3232a47e72SYuval Mintz } 3332a47e72SYuval Mintz 3437bff2b9SYuval Mintz static struct qed_vf_info *qed_iov_get_vf_info(struct qed_hwfn *p_hwfn, 3537bff2b9SYuval Mintz u16 relative_vf_id, 3637bff2b9SYuval Mintz bool b_enabled_only) 3737bff2b9SYuval Mintz { 3837bff2b9SYuval Mintz struct qed_vf_info *vf = NULL; 3937bff2b9SYuval Mintz 4037bff2b9SYuval Mintz if (!p_hwfn->pf_iov_info) { 4137bff2b9SYuval Mintz DP_NOTICE(p_hwfn->cdev, "No iov info\n"); 4237bff2b9SYuval Mintz return NULL; 4337bff2b9SYuval Mintz } 4437bff2b9SYuval Mintz 4537bff2b9SYuval Mintz if (qed_iov_is_valid_vfid(p_hwfn, relative_vf_id, b_enabled_only)) 4637bff2b9SYuval Mintz vf = &p_hwfn->pf_iov_info->vfs_array[relative_vf_id]; 4737bff2b9SYuval Mintz else 4837bff2b9SYuval Mintz DP_ERR(p_hwfn, "qed_iov_get_vf_info: VF[%d] is not enabled\n", 4937bff2b9SYuval Mintz relative_vf_id); 5037bff2b9SYuval Mintz 5137bff2b9SYuval Mintz return vf; 5237bff2b9SYuval Mintz } 5337bff2b9SYuval Mintz 5432a47e72SYuval Mintz static int qed_iov_pci_cfg_info(struct qed_dev *cdev) 5532a47e72SYuval Mintz { 5632a47e72SYuval Mintz struct qed_hw_sriov_info *iov = cdev->p_iov_info; 5732a47e72SYuval Mintz int pos = iov->pos; 5832a47e72SYuval Mintz 5932a47e72SYuval Mintz DP_VERBOSE(cdev, QED_MSG_IOV, "sriov ext pos %d\n", pos); 6032a47e72SYuval Mintz pci_read_config_word(cdev->pdev, pos + PCI_SRIOV_CTRL, &iov->ctrl); 6132a47e72SYuval Mintz 6232a47e72SYuval Mintz pci_read_config_word(cdev->pdev, 6332a47e72SYuval Mintz pos + PCI_SRIOV_TOTAL_VF, &iov->total_vfs); 6432a47e72SYuval Mintz pci_read_config_word(cdev->pdev, 6532a47e72SYuval Mintz pos + PCI_SRIOV_INITIAL_VF, &iov->initial_vfs); 6632a47e72SYuval Mintz 6732a47e72SYuval Mintz pci_read_config_word(cdev->pdev, pos + PCI_SRIOV_NUM_VF, &iov->num_vfs); 6832a47e72SYuval Mintz if (iov->num_vfs) { 6932a47e72SYuval Mintz DP_VERBOSE(cdev, 7032a47e72SYuval Mintz QED_MSG_IOV, 7132a47e72SYuval Mintz "Number of VFs are already set to non-zero value. Ignoring PCI configuration value\n"); 7232a47e72SYuval Mintz iov->num_vfs = 0; 7332a47e72SYuval Mintz } 7432a47e72SYuval Mintz 7532a47e72SYuval Mintz pci_read_config_word(cdev->pdev, 7632a47e72SYuval Mintz pos + PCI_SRIOV_VF_OFFSET, &iov->offset); 7732a47e72SYuval Mintz 7832a47e72SYuval Mintz pci_read_config_word(cdev->pdev, 7932a47e72SYuval Mintz pos + PCI_SRIOV_VF_STRIDE, &iov->stride); 8032a47e72SYuval Mintz 8132a47e72SYuval Mintz pci_read_config_word(cdev->pdev, 8232a47e72SYuval Mintz pos + PCI_SRIOV_VF_DID, &iov->vf_device_id); 8332a47e72SYuval Mintz 8432a47e72SYuval Mintz pci_read_config_dword(cdev->pdev, 8532a47e72SYuval Mintz pos + PCI_SRIOV_SUP_PGSIZE, &iov->pgsz); 8632a47e72SYuval Mintz 8732a47e72SYuval Mintz pci_read_config_dword(cdev->pdev, pos + PCI_SRIOV_CAP, &iov->cap); 8832a47e72SYuval Mintz 8932a47e72SYuval Mintz pci_read_config_byte(cdev->pdev, pos + PCI_SRIOV_FUNC_LINK, &iov->link); 9032a47e72SYuval Mintz 9132a47e72SYuval Mintz DP_VERBOSE(cdev, 9232a47e72SYuval Mintz QED_MSG_IOV, 9332a47e72SYuval 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", 9432a47e72SYuval Mintz iov->nres, 9532a47e72SYuval Mintz iov->cap, 9632a47e72SYuval Mintz iov->ctrl, 9732a47e72SYuval Mintz iov->total_vfs, 9832a47e72SYuval Mintz iov->initial_vfs, 9932a47e72SYuval Mintz iov->nr_virtfn, iov->offset, iov->stride, iov->pgsz); 10032a47e72SYuval Mintz 10132a47e72SYuval Mintz /* Some sanity checks */ 10232a47e72SYuval Mintz if (iov->num_vfs > NUM_OF_VFS(cdev) || 10332a47e72SYuval Mintz iov->total_vfs > NUM_OF_VFS(cdev)) { 10432a47e72SYuval Mintz /* This can happen only due to a bug. In this case we set 10532a47e72SYuval Mintz * num_vfs to zero to avoid memory corruption in the code that 10632a47e72SYuval Mintz * assumes max number of vfs 10732a47e72SYuval Mintz */ 10832a47e72SYuval Mintz DP_NOTICE(cdev, 10932a47e72SYuval Mintz "IOV: Unexpected number of vfs set: %d setting num_vf to zero\n", 11032a47e72SYuval Mintz iov->num_vfs); 11132a47e72SYuval Mintz 11232a47e72SYuval Mintz iov->num_vfs = 0; 11332a47e72SYuval Mintz iov->total_vfs = 0; 11432a47e72SYuval Mintz } 11532a47e72SYuval Mintz 11632a47e72SYuval Mintz return 0; 11732a47e72SYuval Mintz } 11832a47e72SYuval Mintz 11932a47e72SYuval Mintz static void qed_iov_clear_vf_igu_blocks(struct qed_hwfn *p_hwfn, 12032a47e72SYuval Mintz struct qed_ptt *p_ptt) 12132a47e72SYuval Mintz { 12232a47e72SYuval Mintz struct qed_igu_block *p_sb; 12332a47e72SYuval Mintz u16 sb_id; 12432a47e72SYuval Mintz u32 val; 12532a47e72SYuval Mintz 12632a47e72SYuval Mintz if (!p_hwfn->hw_info.p_igu_info) { 12732a47e72SYuval Mintz DP_ERR(p_hwfn, 12832a47e72SYuval Mintz "qed_iov_clear_vf_igu_blocks IGU Info not initialized\n"); 12932a47e72SYuval Mintz return; 13032a47e72SYuval Mintz } 13132a47e72SYuval Mintz 13232a47e72SYuval Mintz for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); 13332a47e72SYuval Mintz sb_id++) { 13432a47e72SYuval Mintz p_sb = &p_hwfn->hw_info.p_igu_info->igu_map.igu_blocks[sb_id]; 13532a47e72SYuval Mintz if ((p_sb->status & QED_IGU_STATUS_FREE) && 13632a47e72SYuval Mintz !(p_sb->status & QED_IGU_STATUS_PF)) { 13732a47e72SYuval Mintz val = qed_rd(p_hwfn, p_ptt, 13832a47e72SYuval Mintz IGU_REG_MAPPING_MEMORY + sb_id * 4); 13932a47e72SYuval Mintz SET_FIELD(val, IGU_MAPPING_LINE_VALID, 0); 14032a47e72SYuval Mintz qed_wr(p_hwfn, p_ptt, 14132a47e72SYuval Mintz IGU_REG_MAPPING_MEMORY + 4 * sb_id, val); 14232a47e72SYuval Mintz } 14332a47e72SYuval Mintz } 14432a47e72SYuval Mintz } 14532a47e72SYuval Mintz 14632a47e72SYuval Mintz static void qed_iov_setup_vfdb(struct qed_hwfn *p_hwfn) 14732a47e72SYuval Mintz { 14832a47e72SYuval Mintz struct qed_hw_sriov_info *p_iov = p_hwfn->cdev->p_iov_info; 14932a47e72SYuval Mintz struct qed_pf_iov *p_iov_info = p_hwfn->pf_iov_info; 15032a47e72SYuval Mintz struct qed_bulletin_content *p_bulletin_virt; 15132a47e72SYuval Mintz dma_addr_t req_p, rply_p, bulletin_p; 15232a47e72SYuval Mintz union pfvf_tlvs *p_reply_virt_addr; 15332a47e72SYuval Mintz union vfpf_tlvs *p_req_virt_addr; 15432a47e72SYuval Mintz u8 idx = 0; 15532a47e72SYuval Mintz 15632a47e72SYuval Mintz memset(p_iov_info->vfs_array, 0, sizeof(p_iov_info->vfs_array)); 15732a47e72SYuval Mintz 15832a47e72SYuval Mintz p_req_virt_addr = p_iov_info->mbx_msg_virt_addr; 15932a47e72SYuval Mintz req_p = p_iov_info->mbx_msg_phys_addr; 16032a47e72SYuval Mintz p_reply_virt_addr = p_iov_info->mbx_reply_virt_addr; 16132a47e72SYuval Mintz rply_p = p_iov_info->mbx_reply_phys_addr; 16232a47e72SYuval Mintz p_bulletin_virt = p_iov_info->p_bulletins; 16332a47e72SYuval Mintz bulletin_p = p_iov_info->bulletins_phys; 16432a47e72SYuval Mintz if (!p_req_virt_addr || !p_reply_virt_addr || !p_bulletin_virt) { 16532a47e72SYuval Mintz DP_ERR(p_hwfn, 16632a47e72SYuval Mintz "qed_iov_setup_vfdb called without allocating mem first\n"); 16732a47e72SYuval Mintz return; 16832a47e72SYuval Mintz } 16932a47e72SYuval Mintz 17032a47e72SYuval Mintz for (idx = 0; idx < p_iov->total_vfs; idx++) { 17132a47e72SYuval Mintz struct qed_vf_info *vf = &p_iov_info->vfs_array[idx]; 17232a47e72SYuval Mintz u32 concrete; 17332a47e72SYuval Mintz 17432a47e72SYuval Mintz vf->vf_mbx.req_virt = p_req_virt_addr + idx; 17532a47e72SYuval Mintz vf->vf_mbx.req_phys = req_p + idx * sizeof(union vfpf_tlvs); 17632a47e72SYuval Mintz vf->vf_mbx.reply_virt = p_reply_virt_addr + idx; 17732a47e72SYuval Mintz vf->vf_mbx.reply_phys = rply_p + idx * sizeof(union pfvf_tlvs); 17832a47e72SYuval Mintz 17932a47e72SYuval Mintz vf->state = VF_STOPPED; 18032a47e72SYuval Mintz vf->b_init = false; 18132a47e72SYuval Mintz 18232a47e72SYuval Mintz vf->bulletin.phys = idx * 18332a47e72SYuval Mintz sizeof(struct qed_bulletin_content) + 18432a47e72SYuval Mintz bulletin_p; 18532a47e72SYuval Mintz vf->bulletin.p_virt = p_bulletin_virt + idx; 18632a47e72SYuval Mintz vf->bulletin.size = sizeof(struct qed_bulletin_content); 18732a47e72SYuval Mintz 18832a47e72SYuval Mintz vf->relative_vf_id = idx; 18932a47e72SYuval Mintz vf->abs_vf_id = idx + p_iov->first_vf_in_pf; 19032a47e72SYuval Mintz concrete = qed_vfid_to_concrete(p_hwfn, vf->abs_vf_id); 19132a47e72SYuval Mintz vf->concrete_fid = concrete; 19232a47e72SYuval Mintz vf->opaque_fid = (p_hwfn->hw_info.opaque_fid & 0xff) | 19332a47e72SYuval Mintz (vf->abs_vf_id << 8); 19432a47e72SYuval Mintz vf->vport_id = idx + 1; 19532a47e72SYuval Mintz } 19632a47e72SYuval Mintz } 19732a47e72SYuval Mintz 19832a47e72SYuval Mintz static int qed_iov_allocate_vfdb(struct qed_hwfn *p_hwfn) 19932a47e72SYuval Mintz { 20032a47e72SYuval Mintz struct qed_pf_iov *p_iov_info = p_hwfn->pf_iov_info; 20132a47e72SYuval Mintz void **p_v_addr; 20232a47e72SYuval Mintz u16 num_vfs = 0; 20332a47e72SYuval Mintz 20432a47e72SYuval Mintz num_vfs = p_hwfn->cdev->p_iov_info->total_vfs; 20532a47e72SYuval Mintz 20632a47e72SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 20732a47e72SYuval Mintz "qed_iov_allocate_vfdb for %d VFs\n", num_vfs); 20832a47e72SYuval Mintz 20932a47e72SYuval Mintz /* Allocate PF Mailbox buffer (per-VF) */ 21032a47e72SYuval Mintz p_iov_info->mbx_msg_size = sizeof(union vfpf_tlvs) * num_vfs; 21132a47e72SYuval Mintz p_v_addr = &p_iov_info->mbx_msg_virt_addr; 21232a47e72SYuval Mintz *p_v_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 21332a47e72SYuval Mintz p_iov_info->mbx_msg_size, 21432a47e72SYuval Mintz &p_iov_info->mbx_msg_phys_addr, 21532a47e72SYuval Mintz GFP_KERNEL); 21632a47e72SYuval Mintz if (!*p_v_addr) 21732a47e72SYuval Mintz return -ENOMEM; 21832a47e72SYuval Mintz 21932a47e72SYuval Mintz /* Allocate PF Mailbox Reply buffer (per-VF) */ 22032a47e72SYuval Mintz p_iov_info->mbx_reply_size = sizeof(union pfvf_tlvs) * num_vfs; 22132a47e72SYuval Mintz p_v_addr = &p_iov_info->mbx_reply_virt_addr; 22232a47e72SYuval Mintz *p_v_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 22332a47e72SYuval Mintz p_iov_info->mbx_reply_size, 22432a47e72SYuval Mintz &p_iov_info->mbx_reply_phys_addr, 22532a47e72SYuval Mintz GFP_KERNEL); 22632a47e72SYuval Mintz if (!*p_v_addr) 22732a47e72SYuval Mintz return -ENOMEM; 22832a47e72SYuval Mintz 22932a47e72SYuval Mintz p_iov_info->bulletins_size = sizeof(struct qed_bulletin_content) * 23032a47e72SYuval Mintz num_vfs; 23132a47e72SYuval Mintz p_v_addr = &p_iov_info->p_bulletins; 23232a47e72SYuval Mintz *p_v_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 23332a47e72SYuval Mintz p_iov_info->bulletins_size, 23432a47e72SYuval Mintz &p_iov_info->bulletins_phys, 23532a47e72SYuval Mintz GFP_KERNEL); 23632a47e72SYuval Mintz if (!*p_v_addr) 23732a47e72SYuval Mintz return -ENOMEM; 23832a47e72SYuval Mintz 23932a47e72SYuval Mintz DP_VERBOSE(p_hwfn, 24032a47e72SYuval Mintz QED_MSG_IOV, 24132a47e72SYuval Mintz "PF's Requests mailbox [%p virt 0x%llx phys], Response mailbox [%p virt 0x%llx phys] Bulletins [%p virt 0x%llx phys]\n", 24232a47e72SYuval Mintz p_iov_info->mbx_msg_virt_addr, 24332a47e72SYuval Mintz (u64) p_iov_info->mbx_msg_phys_addr, 24432a47e72SYuval Mintz p_iov_info->mbx_reply_virt_addr, 24532a47e72SYuval Mintz (u64) p_iov_info->mbx_reply_phys_addr, 24632a47e72SYuval Mintz p_iov_info->p_bulletins, (u64) p_iov_info->bulletins_phys); 24732a47e72SYuval Mintz 24832a47e72SYuval Mintz return 0; 24932a47e72SYuval Mintz } 25032a47e72SYuval Mintz 25132a47e72SYuval Mintz static void qed_iov_free_vfdb(struct qed_hwfn *p_hwfn) 25232a47e72SYuval Mintz { 25332a47e72SYuval Mintz struct qed_pf_iov *p_iov_info = p_hwfn->pf_iov_info; 25432a47e72SYuval Mintz 25532a47e72SYuval Mintz if (p_hwfn->pf_iov_info->mbx_msg_virt_addr) 25632a47e72SYuval Mintz dma_free_coherent(&p_hwfn->cdev->pdev->dev, 25732a47e72SYuval Mintz p_iov_info->mbx_msg_size, 25832a47e72SYuval Mintz p_iov_info->mbx_msg_virt_addr, 25932a47e72SYuval Mintz p_iov_info->mbx_msg_phys_addr); 26032a47e72SYuval Mintz 26132a47e72SYuval Mintz if (p_hwfn->pf_iov_info->mbx_reply_virt_addr) 26232a47e72SYuval Mintz dma_free_coherent(&p_hwfn->cdev->pdev->dev, 26332a47e72SYuval Mintz p_iov_info->mbx_reply_size, 26432a47e72SYuval Mintz p_iov_info->mbx_reply_virt_addr, 26532a47e72SYuval Mintz p_iov_info->mbx_reply_phys_addr); 26632a47e72SYuval Mintz 26732a47e72SYuval Mintz if (p_iov_info->p_bulletins) 26832a47e72SYuval Mintz dma_free_coherent(&p_hwfn->cdev->pdev->dev, 26932a47e72SYuval Mintz p_iov_info->bulletins_size, 27032a47e72SYuval Mintz p_iov_info->p_bulletins, 27132a47e72SYuval Mintz p_iov_info->bulletins_phys); 27232a47e72SYuval Mintz } 27332a47e72SYuval Mintz 27432a47e72SYuval Mintz int qed_iov_alloc(struct qed_hwfn *p_hwfn) 27532a47e72SYuval Mintz { 27632a47e72SYuval Mintz struct qed_pf_iov *p_sriov; 27732a47e72SYuval Mintz 27832a47e72SYuval Mintz if (!IS_PF_SRIOV(p_hwfn)) { 27932a47e72SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 28032a47e72SYuval Mintz "No SR-IOV - no need for IOV db\n"); 28132a47e72SYuval Mintz return 0; 28232a47e72SYuval Mintz } 28332a47e72SYuval Mintz 28432a47e72SYuval Mintz p_sriov = kzalloc(sizeof(*p_sriov), GFP_KERNEL); 28532a47e72SYuval Mintz if (!p_sriov) { 28632a47e72SYuval Mintz DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_sriov'\n"); 28732a47e72SYuval Mintz return -ENOMEM; 28832a47e72SYuval Mintz } 28932a47e72SYuval Mintz 29032a47e72SYuval Mintz p_hwfn->pf_iov_info = p_sriov; 29132a47e72SYuval Mintz 29232a47e72SYuval Mintz return qed_iov_allocate_vfdb(p_hwfn); 29332a47e72SYuval Mintz } 29432a47e72SYuval Mintz 29532a47e72SYuval Mintz void qed_iov_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 29632a47e72SYuval Mintz { 29732a47e72SYuval Mintz if (!IS_PF_SRIOV(p_hwfn) || !IS_PF_SRIOV_ALLOC(p_hwfn)) 29832a47e72SYuval Mintz return; 29932a47e72SYuval Mintz 30032a47e72SYuval Mintz qed_iov_setup_vfdb(p_hwfn); 30132a47e72SYuval Mintz qed_iov_clear_vf_igu_blocks(p_hwfn, p_ptt); 30232a47e72SYuval Mintz } 30332a47e72SYuval Mintz 30432a47e72SYuval Mintz void qed_iov_free(struct qed_hwfn *p_hwfn) 30532a47e72SYuval Mintz { 30632a47e72SYuval Mintz if (IS_PF_SRIOV_ALLOC(p_hwfn)) { 30732a47e72SYuval Mintz qed_iov_free_vfdb(p_hwfn); 30832a47e72SYuval Mintz kfree(p_hwfn->pf_iov_info); 30932a47e72SYuval Mintz } 31032a47e72SYuval Mintz } 31132a47e72SYuval Mintz 31232a47e72SYuval Mintz void qed_iov_free_hw_info(struct qed_dev *cdev) 31332a47e72SYuval Mintz { 31432a47e72SYuval Mintz kfree(cdev->p_iov_info); 31532a47e72SYuval Mintz cdev->p_iov_info = NULL; 31632a47e72SYuval Mintz } 31732a47e72SYuval Mintz 31832a47e72SYuval Mintz int qed_iov_hw_info(struct qed_hwfn *p_hwfn) 31932a47e72SYuval Mintz { 32032a47e72SYuval Mintz struct qed_dev *cdev = p_hwfn->cdev; 32132a47e72SYuval Mintz int pos; 32232a47e72SYuval Mintz int rc; 32332a47e72SYuval Mintz 32432a47e72SYuval Mintz /* Learn the PCI configuration */ 32532a47e72SYuval Mintz pos = pci_find_ext_capability(p_hwfn->cdev->pdev, 32632a47e72SYuval Mintz PCI_EXT_CAP_ID_SRIOV); 32732a47e72SYuval Mintz if (!pos) { 32832a47e72SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, "No PCIe IOV support\n"); 32932a47e72SYuval Mintz return 0; 33032a47e72SYuval Mintz } 33132a47e72SYuval Mintz 33232a47e72SYuval Mintz /* Allocate a new struct for IOV information */ 33332a47e72SYuval Mintz cdev->p_iov_info = kzalloc(sizeof(*cdev->p_iov_info), GFP_KERNEL); 33432a47e72SYuval Mintz if (!cdev->p_iov_info) { 33532a47e72SYuval Mintz DP_NOTICE(p_hwfn, "Can't support IOV due to lack of memory\n"); 33632a47e72SYuval Mintz return -ENOMEM; 33732a47e72SYuval Mintz } 33832a47e72SYuval Mintz cdev->p_iov_info->pos = pos; 33932a47e72SYuval Mintz 34032a47e72SYuval Mintz rc = qed_iov_pci_cfg_info(cdev); 34132a47e72SYuval Mintz if (rc) 34232a47e72SYuval Mintz return rc; 34332a47e72SYuval Mintz 34432a47e72SYuval Mintz /* We want PF IOV to be synonemous with the existance of p_iov_info; 34532a47e72SYuval Mintz * In case the capability is published but there are no VFs, simply 34632a47e72SYuval Mintz * de-allocate the struct. 34732a47e72SYuval Mintz */ 34832a47e72SYuval Mintz if (!cdev->p_iov_info->total_vfs) { 34932a47e72SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 35032a47e72SYuval Mintz "IOV capabilities, but no VFs are published\n"); 35132a47e72SYuval Mintz kfree(cdev->p_iov_info); 35232a47e72SYuval Mintz cdev->p_iov_info = NULL; 35332a47e72SYuval Mintz return 0; 35432a47e72SYuval Mintz } 35532a47e72SYuval Mintz 35632a47e72SYuval Mintz /* Calculate the first VF index - this is a bit tricky; Basically, 35732a47e72SYuval Mintz * VFs start at offset 16 relative to PF0, and 2nd engine VFs begin 35832a47e72SYuval Mintz * after the first engine's VFs. 35932a47e72SYuval Mintz */ 36032a47e72SYuval Mintz cdev->p_iov_info->first_vf_in_pf = p_hwfn->cdev->p_iov_info->offset + 36132a47e72SYuval Mintz p_hwfn->abs_pf_id - 16; 36232a47e72SYuval Mintz if (QED_PATH_ID(p_hwfn)) 36332a47e72SYuval Mintz cdev->p_iov_info->first_vf_in_pf -= MAX_NUM_VFS_BB; 36432a47e72SYuval Mintz 36532a47e72SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 36632a47e72SYuval Mintz "First VF in hwfn 0x%08x\n", 36732a47e72SYuval Mintz cdev->p_iov_info->first_vf_in_pf); 36832a47e72SYuval Mintz 36932a47e72SYuval Mintz return 0; 37032a47e72SYuval Mintz } 37132a47e72SYuval Mintz 37237bff2b9SYuval Mintz static bool qed_iov_pf_sanity_check(struct qed_hwfn *p_hwfn, int vfid) 37337bff2b9SYuval Mintz { 37437bff2b9SYuval Mintz /* Check PF supports sriov */ 37537bff2b9SYuval Mintz if (!IS_QED_SRIOV(p_hwfn->cdev) || !IS_PF_SRIOV_ALLOC(p_hwfn)) 37637bff2b9SYuval Mintz return false; 37737bff2b9SYuval Mintz 37837bff2b9SYuval Mintz /* Check VF validity */ 37937bff2b9SYuval Mintz if (!qed_iov_is_valid_vfid(p_hwfn, vfid, true)) 38037bff2b9SYuval Mintz return false; 38137bff2b9SYuval Mintz 38237bff2b9SYuval Mintz return true; 38337bff2b9SYuval Mintz } 38437bff2b9SYuval Mintz 38537bff2b9SYuval Mintz static bool qed_iov_tlv_supported(u16 tlvtype) 38637bff2b9SYuval Mintz { 38737bff2b9SYuval Mintz return CHANNEL_TLV_NONE < tlvtype && tlvtype < CHANNEL_TLV_MAX; 38837bff2b9SYuval Mintz } 38937bff2b9SYuval Mintz 39037bff2b9SYuval Mintz /* place a given tlv on the tlv buffer, continuing current tlv list */ 39137bff2b9SYuval Mintz void *qed_add_tlv(struct qed_hwfn *p_hwfn, u8 **offset, u16 type, u16 length) 39237bff2b9SYuval Mintz { 39337bff2b9SYuval Mintz struct channel_tlv *tl = (struct channel_tlv *)*offset; 39437bff2b9SYuval Mintz 39537bff2b9SYuval Mintz tl->type = type; 39637bff2b9SYuval Mintz tl->length = length; 39737bff2b9SYuval Mintz 39837bff2b9SYuval Mintz /* Offset should keep pointing to next TLV (the end of the last) */ 39937bff2b9SYuval Mintz *offset += length; 40037bff2b9SYuval Mintz 40137bff2b9SYuval Mintz /* Return a pointer to the start of the added tlv */ 40237bff2b9SYuval Mintz return *offset - length; 40337bff2b9SYuval Mintz } 40437bff2b9SYuval Mintz 40537bff2b9SYuval Mintz /* list the types and lengths of the tlvs on the buffer */ 40637bff2b9SYuval Mintz void qed_dp_tlv_list(struct qed_hwfn *p_hwfn, void *tlvs_list) 40737bff2b9SYuval Mintz { 40837bff2b9SYuval Mintz u16 i = 1, total_length = 0; 40937bff2b9SYuval Mintz struct channel_tlv *tlv; 41037bff2b9SYuval Mintz 41137bff2b9SYuval Mintz do { 41237bff2b9SYuval Mintz tlv = (struct channel_tlv *)((u8 *)tlvs_list + total_length); 41337bff2b9SYuval Mintz 41437bff2b9SYuval Mintz /* output tlv */ 41537bff2b9SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 41637bff2b9SYuval Mintz "TLV number %d: type %d, length %d\n", 41737bff2b9SYuval Mintz i, tlv->type, tlv->length); 41837bff2b9SYuval Mintz 41937bff2b9SYuval Mintz if (tlv->type == CHANNEL_TLV_LIST_END) 42037bff2b9SYuval Mintz return; 42137bff2b9SYuval Mintz 42237bff2b9SYuval Mintz /* Validate entry - protect against malicious VFs */ 42337bff2b9SYuval Mintz if (!tlv->length) { 42437bff2b9SYuval Mintz DP_NOTICE(p_hwfn, "TLV of length 0 found\n"); 42537bff2b9SYuval Mintz return; 42637bff2b9SYuval Mintz } 42737bff2b9SYuval Mintz 42837bff2b9SYuval Mintz total_length += tlv->length; 42937bff2b9SYuval Mintz 43037bff2b9SYuval Mintz if (total_length >= sizeof(struct tlv_buffer_size)) { 43137bff2b9SYuval Mintz DP_NOTICE(p_hwfn, "TLV ==> Buffer overflow\n"); 43237bff2b9SYuval Mintz return; 43337bff2b9SYuval Mintz } 43437bff2b9SYuval Mintz 43537bff2b9SYuval Mintz i++; 43637bff2b9SYuval Mintz } while (1); 43737bff2b9SYuval Mintz } 43837bff2b9SYuval Mintz 43937bff2b9SYuval Mintz static void qed_iov_send_response(struct qed_hwfn *p_hwfn, 44037bff2b9SYuval Mintz struct qed_ptt *p_ptt, 44137bff2b9SYuval Mintz struct qed_vf_info *p_vf, 44237bff2b9SYuval Mintz u16 length, u8 status) 44337bff2b9SYuval Mintz { 44437bff2b9SYuval Mintz struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx; 44537bff2b9SYuval Mintz struct qed_dmae_params params; 44637bff2b9SYuval Mintz u8 eng_vf_id; 44737bff2b9SYuval Mintz 44837bff2b9SYuval Mintz mbx->reply_virt->default_resp.hdr.status = status; 44937bff2b9SYuval Mintz 45037bff2b9SYuval Mintz qed_dp_tlv_list(p_hwfn, mbx->reply_virt); 45137bff2b9SYuval Mintz 45237bff2b9SYuval Mintz eng_vf_id = p_vf->abs_vf_id; 45337bff2b9SYuval Mintz 45437bff2b9SYuval Mintz memset(¶ms, 0, sizeof(struct qed_dmae_params)); 45537bff2b9SYuval Mintz params.flags = QED_DMAE_FLAG_VF_DST; 45637bff2b9SYuval Mintz params.dst_vfid = eng_vf_id; 45737bff2b9SYuval Mintz 45837bff2b9SYuval Mintz qed_dmae_host2host(p_hwfn, p_ptt, mbx->reply_phys + sizeof(u64), 45937bff2b9SYuval Mintz mbx->req_virt->first_tlv.reply_address + 46037bff2b9SYuval Mintz sizeof(u64), 46137bff2b9SYuval Mintz (sizeof(union pfvf_tlvs) - sizeof(u64)) / 4, 46237bff2b9SYuval Mintz ¶ms); 46337bff2b9SYuval Mintz 46437bff2b9SYuval Mintz qed_dmae_host2host(p_hwfn, p_ptt, mbx->reply_phys, 46537bff2b9SYuval Mintz mbx->req_virt->first_tlv.reply_address, 46637bff2b9SYuval Mintz sizeof(u64) / 4, ¶ms); 46737bff2b9SYuval Mintz 46837bff2b9SYuval Mintz REG_WR(p_hwfn, 46937bff2b9SYuval Mintz GTT_BAR0_MAP_REG_USDM_RAM + 47037bff2b9SYuval Mintz USTORM_VF_PF_CHANNEL_READY_OFFSET(eng_vf_id), 1); 47137bff2b9SYuval Mintz } 47237bff2b9SYuval Mintz 47337bff2b9SYuval Mintz static void qed_iov_prepare_resp(struct qed_hwfn *p_hwfn, 47437bff2b9SYuval Mintz struct qed_ptt *p_ptt, 47537bff2b9SYuval Mintz struct qed_vf_info *vf_info, 47637bff2b9SYuval Mintz u16 type, u16 length, u8 status) 47737bff2b9SYuval Mintz { 47837bff2b9SYuval Mintz struct qed_iov_vf_mbx *mbx = &vf_info->vf_mbx; 47937bff2b9SYuval Mintz 48037bff2b9SYuval Mintz mbx->offset = (u8 *)mbx->reply_virt; 48137bff2b9SYuval Mintz 48237bff2b9SYuval Mintz qed_add_tlv(p_hwfn, &mbx->offset, type, length); 48337bff2b9SYuval Mintz qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_LIST_END, 48437bff2b9SYuval Mintz sizeof(struct channel_list_end_tlv)); 48537bff2b9SYuval Mintz 48637bff2b9SYuval Mintz qed_iov_send_response(p_hwfn, p_ptt, vf_info, length, status); 48737bff2b9SYuval Mintz } 48837bff2b9SYuval Mintz 48937bff2b9SYuval Mintz static void qed_iov_process_mbx_dummy_resp(struct qed_hwfn *p_hwfn, 49037bff2b9SYuval Mintz struct qed_ptt *p_ptt, 49137bff2b9SYuval Mintz struct qed_vf_info *p_vf) 49237bff2b9SYuval Mintz { 49337bff2b9SYuval Mintz qed_iov_prepare_resp(p_hwfn, p_ptt, p_vf, CHANNEL_TLV_NONE, 49437bff2b9SYuval Mintz sizeof(struct pfvf_def_resp_tlv), 49537bff2b9SYuval Mintz PFVF_STATUS_SUCCESS); 49637bff2b9SYuval Mintz } 49737bff2b9SYuval Mintz 49837bff2b9SYuval Mintz static void qed_iov_process_mbx_req(struct qed_hwfn *p_hwfn, 49937bff2b9SYuval Mintz struct qed_ptt *p_ptt, int vfid) 50037bff2b9SYuval Mintz { 50137bff2b9SYuval Mintz struct qed_iov_vf_mbx *mbx; 50237bff2b9SYuval Mintz struct qed_vf_info *p_vf; 50337bff2b9SYuval Mintz int i; 50437bff2b9SYuval Mintz 50537bff2b9SYuval Mintz p_vf = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 50637bff2b9SYuval Mintz if (!p_vf) 50737bff2b9SYuval Mintz return; 50837bff2b9SYuval Mintz 50937bff2b9SYuval Mintz mbx = &p_vf->vf_mbx; 51037bff2b9SYuval Mintz 51137bff2b9SYuval Mintz /* qed_iov_process_mbx_request */ 51237bff2b9SYuval Mintz DP_VERBOSE(p_hwfn, 51337bff2b9SYuval Mintz QED_MSG_IOV, 51437bff2b9SYuval Mintz "qed_iov_process_mbx_req vfid %d\n", p_vf->abs_vf_id); 51537bff2b9SYuval Mintz 51637bff2b9SYuval Mintz mbx->first_tlv = mbx->req_virt->first_tlv; 51737bff2b9SYuval Mintz 51837bff2b9SYuval Mintz /* check if tlv type is known */ 51937bff2b9SYuval Mintz if (qed_iov_tlv_supported(mbx->first_tlv.tl.type)) { 52037bff2b9SYuval Mintz qed_iov_process_mbx_dummy_resp(p_hwfn, p_ptt, p_vf); 52137bff2b9SYuval Mintz } else { 52237bff2b9SYuval Mintz /* unknown TLV - this may belong to a VF driver from the future 52337bff2b9SYuval Mintz * - a version written after this PF driver was written, which 52437bff2b9SYuval Mintz * supports features unknown as of yet. Too bad since we don't 52537bff2b9SYuval Mintz * support them. Or this may be because someone wrote a crappy 52637bff2b9SYuval Mintz * VF driver and is sending garbage over the channel. 52737bff2b9SYuval Mintz */ 52837bff2b9SYuval Mintz DP_ERR(p_hwfn, 52937bff2b9SYuval Mintz "unknown TLV. type %d length %d. first 20 bytes of mailbox buffer:\n", 53037bff2b9SYuval Mintz mbx->first_tlv.tl.type, mbx->first_tlv.tl.length); 53137bff2b9SYuval Mintz 53237bff2b9SYuval Mintz for (i = 0; i < 20; i++) { 53337bff2b9SYuval Mintz DP_VERBOSE(p_hwfn, 53437bff2b9SYuval Mintz QED_MSG_IOV, 53537bff2b9SYuval Mintz "%x ", 53637bff2b9SYuval Mintz mbx->req_virt->tlv_buf_size.tlv_buffer[i]); 53737bff2b9SYuval Mintz } 53837bff2b9SYuval Mintz } 53937bff2b9SYuval Mintz } 54037bff2b9SYuval Mintz 54137bff2b9SYuval Mintz void qed_iov_pf_add_pending_events(struct qed_hwfn *p_hwfn, u8 vfid) 54237bff2b9SYuval Mintz { 54337bff2b9SYuval Mintz u64 add_bit = 1ULL << (vfid % 64); 54437bff2b9SYuval Mintz 54537bff2b9SYuval Mintz p_hwfn->pf_iov_info->pending_events[vfid / 64] |= add_bit; 54637bff2b9SYuval Mintz } 54737bff2b9SYuval Mintz 54837bff2b9SYuval Mintz static void qed_iov_pf_get_and_clear_pending_events(struct qed_hwfn *p_hwfn, 54937bff2b9SYuval Mintz u64 *events) 55037bff2b9SYuval Mintz { 55137bff2b9SYuval Mintz u64 *p_pending_events = p_hwfn->pf_iov_info->pending_events; 55237bff2b9SYuval Mintz 55337bff2b9SYuval Mintz memcpy(events, p_pending_events, sizeof(u64) * QED_VF_ARRAY_LENGTH); 55437bff2b9SYuval Mintz memset(p_pending_events, 0, sizeof(u64) * QED_VF_ARRAY_LENGTH); 55537bff2b9SYuval Mintz } 55637bff2b9SYuval Mintz 55737bff2b9SYuval Mintz static int qed_sriov_vfpf_msg(struct qed_hwfn *p_hwfn, 55837bff2b9SYuval Mintz u16 abs_vfid, struct regpair *vf_msg) 55937bff2b9SYuval Mintz { 56037bff2b9SYuval Mintz u8 min = (u8)p_hwfn->cdev->p_iov_info->first_vf_in_pf; 56137bff2b9SYuval Mintz struct qed_vf_info *p_vf; 56237bff2b9SYuval Mintz 56337bff2b9SYuval Mintz if (!qed_iov_pf_sanity_check(p_hwfn, (int)abs_vfid - min)) { 56437bff2b9SYuval Mintz DP_VERBOSE(p_hwfn, 56537bff2b9SYuval Mintz QED_MSG_IOV, 56637bff2b9SYuval Mintz "Got a message from VF [abs 0x%08x] that cannot be handled by PF\n", 56737bff2b9SYuval Mintz abs_vfid); 56837bff2b9SYuval Mintz return 0; 56937bff2b9SYuval Mintz } 57037bff2b9SYuval Mintz p_vf = &p_hwfn->pf_iov_info->vfs_array[(u8)abs_vfid - min]; 57137bff2b9SYuval Mintz 57237bff2b9SYuval Mintz /* List the physical address of the request so that handler 57337bff2b9SYuval Mintz * could later on copy the message from it. 57437bff2b9SYuval Mintz */ 57537bff2b9SYuval Mintz p_vf->vf_mbx.pending_req = (((u64)vf_msg->hi) << 32) | vf_msg->lo; 57637bff2b9SYuval Mintz 57737bff2b9SYuval Mintz /* Mark the event and schedule the workqueue */ 57837bff2b9SYuval Mintz qed_iov_pf_add_pending_events(p_hwfn, p_vf->relative_vf_id); 57937bff2b9SYuval Mintz qed_schedule_iov(p_hwfn, QED_IOV_WQ_MSG_FLAG); 58037bff2b9SYuval Mintz 58137bff2b9SYuval Mintz return 0; 58237bff2b9SYuval Mintz } 58337bff2b9SYuval Mintz 58437bff2b9SYuval Mintz int qed_sriov_eqe_event(struct qed_hwfn *p_hwfn, 58537bff2b9SYuval Mintz u8 opcode, __le16 echo, union event_ring_data *data) 58637bff2b9SYuval Mintz { 58737bff2b9SYuval Mintz switch (opcode) { 58837bff2b9SYuval Mintz case COMMON_EVENT_VF_PF_CHANNEL: 58937bff2b9SYuval Mintz return qed_sriov_vfpf_msg(p_hwfn, le16_to_cpu(echo), 59037bff2b9SYuval Mintz &data->vf_pf_channel.msg_addr); 59137bff2b9SYuval Mintz default: 59237bff2b9SYuval Mintz DP_INFO(p_hwfn->cdev, "Unknown sriov eqe event 0x%02x\n", 59337bff2b9SYuval Mintz opcode); 59437bff2b9SYuval Mintz return -EINVAL; 59537bff2b9SYuval Mintz } 59637bff2b9SYuval Mintz } 59737bff2b9SYuval Mintz 59832a47e72SYuval Mintz u16 qed_iov_get_next_active_vf(struct qed_hwfn *p_hwfn, u16 rel_vf_id) 59932a47e72SYuval Mintz { 60032a47e72SYuval Mintz struct qed_hw_sriov_info *p_iov = p_hwfn->cdev->p_iov_info; 60132a47e72SYuval Mintz u16 i; 60232a47e72SYuval Mintz 60332a47e72SYuval Mintz if (!p_iov) 60432a47e72SYuval Mintz goto out; 60532a47e72SYuval Mintz 60632a47e72SYuval Mintz for (i = rel_vf_id; i < p_iov->total_vfs; i++) 60732a47e72SYuval Mintz if (qed_iov_is_valid_vfid(p_hwfn, rel_vf_id, true)) 60832a47e72SYuval Mintz return i; 60932a47e72SYuval Mintz 61032a47e72SYuval Mintz out: 61132a47e72SYuval Mintz return MAX_NUM_VFS; 61232a47e72SYuval Mintz } 61337bff2b9SYuval Mintz 61437bff2b9SYuval Mintz static int qed_iov_copy_vf_msg(struct qed_hwfn *p_hwfn, struct qed_ptt *ptt, 61537bff2b9SYuval Mintz int vfid) 61637bff2b9SYuval Mintz { 61737bff2b9SYuval Mintz struct qed_dmae_params params; 61837bff2b9SYuval Mintz struct qed_vf_info *vf_info; 61937bff2b9SYuval Mintz 62037bff2b9SYuval Mintz vf_info = qed_iov_get_vf_info(p_hwfn, (u16) vfid, true); 62137bff2b9SYuval Mintz if (!vf_info) 62237bff2b9SYuval Mintz return -EINVAL; 62337bff2b9SYuval Mintz 62437bff2b9SYuval Mintz memset(¶ms, 0, sizeof(struct qed_dmae_params)); 62537bff2b9SYuval Mintz params.flags = QED_DMAE_FLAG_VF_SRC | QED_DMAE_FLAG_COMPLETION_DST; 62637bff2b9SYuval Mintz params.src_vfid = vf_info->abs_vf_id; 62737bff2b9SYuval Mintz 62837bff2b9SYuval Mintz if (qed_dmae_host2host(p_hwfn, ptt, 62937bff2b9SYuval Mintz vf_info->vf_mbx.pending_req, 63037bff2b9SYuval Mintz vf_info->vf_mbx.req_phys, 63137bff2b9SYuval Mintz sizeof(union vfpf_tlvs) / 4, ¶ms)) { 63237bff2b9SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 63337bff2b9SYuval Mintz "Failed to copy message from VF 0x%02x\n", vfid); 63437bff2b9SYuval Mintz 63537bff2b9SYuval Mintz return -EIO; 63637bff2b9SYuval Mintz } 63737bff2b9SYuval Mintz 63837bff2b9SYuval Mintz return 0; 63937bff2b9SYuval Mintz } 64037bff2b9SYuval Mintz 64137bff2b9SYuval Mintz /** 64237bff2b9SYuval Mintz * qed_schedule_iov - schedules IOV task for VF and PF 64337bff2b9SYuval Mintz * @hwfn: hardware function pointer 64437bff2b9SYuval Mintz * @flag: IOV flag for VF/PF 64537bff2b9SYuval Mintz */ 64637bff2b9SYuval Mintz void qed_schedule_iov(struct qed_hwfn *hwfn, enum qed_iov_wq_flag flag) 64737bff2b9SYuval Mintz { 64837bff2b9SYuval Mintz smp_mb__before_atomic(); 64937bff2b9SYuval Mintz set_bit(flag, &hwfn->iov_task_flags); 65037bff2b9SYuval Mintz smp_mb__after_atomic(); 65137bff2b9SYuval Mintz DP_VERBOSE(hwfn, QED_MSG_IOV, "Scheduling iov task [Flag: %d]\n", flag); 65237bff2b9SYuval Mintz queue_delayed_work(hwfn->iov_wq, &hwfn->iov_task, 0); 65337bff2b9SYuval Mintz } 65437bff2b9SYuval Mintz 65537bff2b9SYuval Mintz static void qed_handle_vf_msg(struct qed_hwfn *hwfn) 65637bff2b9SYuval Mintz { 65737bff2b9SYuval Mintz u64 events[QED_VF_ARRAY_LENGTH]; 65837bff2b9SYuval Mintz struct qed_ptt *ptt; 65937bff2b9SYuval Mintz int i; 66037bff2b9SYuval Mintz 66137bff2b9SYuval Mintz ptt = qed_ptt_acquire(hwfn); 66237bff2b9SYuval Mintz if (!ptt) { 66337bff2b9SYuval Mintz DP_VERBOSE(hwfn, QED_MSG_IOV, 66437bff2b9SYuval Mintz "Can't acquire PTT; re-scheduling\n"); 66537bff2b9SYuval Mintz qed_schedule_iov(hwfn, QED_IOV_WQ_MSG_FLAG); 66637bff2b9SYuval Mintz return; 66737bff2b9SYuval Mintz } 66837bff2b9SYuval Mintz 66937bff2b9SYuval Mintz qed_iov_pf_get_and_clear_pending_events(hwfn, events); 67037bff2b9SYuval Mintz 67137bff2b9SYuval Mintz DP_VERBOSE(hwfn, QED_MSG_IOV, 67237bff2b9SYuval Mintz "Event mask of VF events: 0x%llx 0x%llx 0x%llx\n", 67337bff2b9SYuval Mintz events[0], events[1], events[2]); 67437bff2b9SYuval Mintz 67537bff2b9SYuval Mintz qed_for_each_vf(hwfn, i) { 67637bff2b9SYuval Mintz /* Skip VFs with no pending messages */ 67737bff2b9SYuval Mintz if (!(events[i / 64] & (1ULL << (i % 64)))) 67837bff2b9SYuval Mintz continue; 67937bff2b9SYuval Mintz 68037bff2b9SYuval Mintz DP_VERBOSE(hwfn, QED_MSG_IOV, 68137bff2b9SYuval Mintz "Handling VF message from VF 0x%02x [Abs 0x%02x]\n", 68237bff2b9SYuval Mintz i, hwfn->cdev->p_iov_info->first_vf_in_pf + i); 68337bff2b9SYuval Mintz 68437bff2b9SYuval Mintz /* Copy VF's message to PF's request buffer for that VF */ 68537bff2b9SYuval Mintz if (qed_iov_copy_vf_msg(hwfn, ptt, i)) 68637bff2b9SYuval Mintz continue; 68737bff2b9SYuval Mintz 68837bff2b9SYuval Mintz qed_iov_process_mbx_req(hwfn, ptt, i); 68937bff2b9SYuval Mintz } 69037bff2b9SYuval Mintz 69137bff2b9SYuval Mintz qed_ptt_release(hwfn, ptt); 69237bff2b9SYuval Mintz } 69337bff2b9SYuval Mintz 69437bff2b9SYuval Mintz void qed_iov_pf_task(struct work_struct *work) 69537bff2b9SYuval Mintz { 69637bff2b9SYuval Mintz struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn, 69737bff2b9SYuval Mintz iov_task.work); 69837bff2b9SYuval Mintz 69937bff2b9SYuval Mintz if (test_and_clear_bit(QED_IOV_WQ_STOP_WQ_FLAG, &hwfn->iov_task_flags)) 70037bff2b9SYuval Mintz return; 70137bff2b9SYuval Mintz 70237bff2b9SYuval Mintz if (test_and_clear_bit(QED_IOV_WQ_MSG_FLAG, &hwfn->iov_task_flags)) 70337bff2b9SYuval Mintz qed_handle_vf_msg(hwfn); 70437bff2b9SYuval Mintz } 70537bff2b9SYuval Mintz 70637bff2b9SYuval Mintz void qed_iov_wq_stop(struct qed_dev *cdev, bool schedule_first) 70737bff2b9SYuval Mintz { 70837bff2b9SYuval Mintz int i; 70937bff2b9SYuval Mintz 71037bff2b9SYuval Mintz for_each_hwfn(cdev, i) { 71137bff2b9SYuval Mintz if (!cdev->hwfns[i].iov_wq) 71237bff2b9SYuval Mintz continue; 71337bff2b9SYuval Mintz 71437bff2b9SYuval Mintz if (schedule_first) { 71537bff2b9SYuval Mintz qed_schedule_iov(&cdev->hwfns[i], 71637bff2b9SYuval Mintz QED_IOV_WQ_STOP_WQ_FLAG); 71737bff2b9SYuval Mintz cancel_delayed_work_sync(&cdev->hwfns[i].iov_task); 71837bff2b9SYuval Mintz } 71937bff2b9SYuval Mintz 72037bff2b9SYuval Mintz flush_workqueue(cdev->hwfns[i].iov_wq); 72137bff2b9SYuval Mintz destroy_workqueue(cdev->hwfns[i].iov_wq); 72237bff2b9SYuval Mintz } 72337bff2b9SYuval Mintz } 72437bff2b9SYuval Mintz 72537bff2b9SYuval Mintz int qed_iov_wq_start(struct qed_dev *cdev) 72637bff2b9SYuval Mintz { 72737bff2b9SYuval Mintz char name[NAME_SIZE]; 72837bff2b9SYuval Mintz int i; 72937bff2b9SYuval Mintz 73037bff2b9SYuval Mintz for_each_hwfn(cdev, i) { 73137bff2b9SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 73237bff2b9SYuval Mintz 73337bff2b9SYuval Mintz /* PFs needs a dedicated workqueue only if they support IOV. */ 73437bff2b9SYuval Mintz if (!IS_PF_SRIOV(p_hwfn)) 73537bff2b9SYuval Mintz continue; 73637bff2b9SYuval Mintz 73737bff2b9SYuval Mintz snprintf(name, NAME_SIZE, "iov-%02x:%02x.%02x", 73837bff2b9SYuval Mintz cdev->pdev->bus->number, 73937bff2b9SYuval Mintz PCI_SLOT(cdev->pdev->devfn), p_hwfn->abs_pf_id); 74037bff2b9SYuval Mintz 74137bff2b9SYuval Mintz p_hwfn->iov_wq = create_singlethread_workqueue(name); 74237bff2b9SYuval Mintz if (!p_hwfn->iov_wq) { 74337bff2b9SYuval Mintz DP_NOTICE(p_hwfn, "Cannot create iov workqueue\n"); 74437bff2b9SYuval Mintz return -ENOMEM; 74537bff2b9SYuval Mintz } 74637bff2b9SYuval Mintz 74737bff2b9SYuval Mintz INIT_DELAYED_WORK(&p_hwfn->iov_task, qed_iov_pf_task); 74837bff2b9SYuval Mintz } 74937bff2b9SYuval Mintz 75037bff2b9SYuval Mintz return 0; 75137bff2b9SYuval Mintz } 752