void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) { if (qlcnic_sriov_pf_check(adapter)) qlcnic_sriov_pf_cleanup(adapter); if (qlcnic_sriov_vf_check(adapter)) qlcnic_sriov_vf_cleanup(adapter); }
void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) { if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state)) return; qlcnic_sriov_free_vlans(adapter); if (qlcnic_sriov_pf_check(adapter)) qlcnic_sriov_pf_cleanup(adapter); if (qlcnic_sriov_vf_check(adapter)) qlcnic_sriov_vf_cleanup(adapter); }
static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr, u32 *pay, u8 pci_func, u8 size) { u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, val, wait_time = 0; struct qlcnic_hardware_context *ahw = adapter->ahw; unsigned long flags; u16 opcode; u8 mbx_err_code; int i, j; opcode = ((struct qlcnic_bc_hdr *)hdr)->cmd_op; if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) { dev_info(&adapter->pdev->dev, "Mailbox cmd attempted, 0x%x\n", opcode); dev_info(&adapter->pdev->dev, "Mailbox detached\n"); return 0; } spin_lock_irqsave(&ahw->mbx_lock, flags); mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL); if (mbx_val) { QLCDB(adapter, DRV, "Mailbox cmd attempted, 0x%x\n", opcode); spin_unlock_irqrestore(&ahw->mbx_lock, flags); return QLCNIC_RCODE_TIMEOUT; } /* Fill in mailbox registers */ val = size + (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); mbx_cmd = 0x31 | (val << 16) | (adapter->ahw->fw_hal_version << 29); writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0)); mbx_cmd = 0x1 | (1 << 4); if (qlcnic_sriov_pf_check(adapter)) mbx_cmd |= (pci_func << 5); writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 1)); for (i = 2, j = 0; j < (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); i++, j++) { writel(*(hdr++), QLCNIC_MBX_HOST(ahw, i)); } for (j = 0; j < size; j++, i++) writel(*(pay++), QLCNIC_MBX_HOST(ahw, i)); /* Signal FW about the impending command */ QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER); /* Waiting for the mailbox cmd to complete and while waiting here * some AEN might arrive. If more than 5 seconds expire we can * assume something is wrong. */ poll: rsp = qlcnic_83xx_mbx_poll(adapter, &wait_time); if (rsp != QLCNIC_RCODE_TIMEOUT) { /* Get the FW response data */ fw_data = readl(QLCNIC_MBX_FW(ahw, 0)); if (fw_data & QLCNIC_MBX_ASYNC_EVENT) { __qlcnic_83xx_process_aen(adapter); goto poll; } mbx_err_code = QLCNIC_MBX_STATUS(fw_data); rsp_num = QLCNIC_MBX_NUM_REGS(fw_data); opcode = QLCNIC_MBX_RSP(fw_data); switch (mbx_err_code) { case QLCNIC_MBX_RSP_OK: case QLCNIC_MBX_PORT_RSP_OK: rsp = QLCNIC_RCODE_SUCCESS; break; default: if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) { rsp = qlcnic_83xx_mac_rcode(adapter); if (!rsp) goto out; } dev_err(&adapter->pdev->dev, "MBX command 0x%x failed with err:0x%x\n", opcode, mbx_err_code); rsp = mbx_err_code; break; } goto out; } dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n", QLCNIC_MBX_RSP(mbx_cmd)); rsp = QLCNIC_RCODE_TIMEOUT; out: /* clear fw mbx control register */ QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER); spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags); return rsp; }
int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs) { struct qlcnic_sriov *sriov; struct qlcnic_back_channel *bc; struct workqueue_struct *wq; struct qlcnic_vport *vp; struct qlcnic_vf_info *vf; int err, i; if (!qlcnic_sriov_enable_check(adapter)) return -EIO; sriov = kzalloc(sizeof(struct qlcnic_sriov), GFP_KERNEL); if (!sriov) return -ENOMEM; adapter->ahw->sriov = sriov; sriov->num_vfs = num_vfs; bc = &sriov->bc; sriov->vf_info = kzalloc(sizeof(struct qlcnic_vf_info) * num_vfs, GFP_KERNEL); if (!sriov->vf_info) { err = -ENOMEM; goto qlcnic_free_sriov; } wq = create_singlethread_workqueue("bc-trans"); if (wq == NULL) { err = -ENOMEM; dev_err(&adapter->pdev->dev, "Cannot create bc-trans workqueue\n"); goto qlcnic_free_vf_info; } bc->bc_trans_wq = wq; wq = create_singlethread_workqueue("async"); if (wq == NULL) { err = -ENOMEM; dev_err(&adapter->pdev->dev, "Cannot create async workqueue\n"); goto qlcnic_destroy_trans_wq; } bc->bc_async_wq = wq; INIT_LIST_HEAD(&bc->async_list); for (i = 0; i < num_vfs; i++) { vf = &sriov->vf_info[i]; vf->adapter = adapter; vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i); mutex_init(&vf->send_cmd_lock); INIT_LIST_HEAD(&vf->rcv_act.wait_list); INIT_LIST_HEAD(&vf->rcv_pend.wait_list); spin_lock_init(&vf->rcv_act.lock); spin_lock_init(&vf->rcv_pend.lock); init_completion(&vf->ch_free_cmpl); if (qlcnic_sriov_pf_check(adapter)) { vp = kzalloc(sizeof(struct qlcnic_vport), GFP_KERNEL); if (!vp) { err = -ENOMEM; goto qlcnic_destroy_async_wq; } sriov->vf_info[i].vp = vp; vp->max_tx_bw = MAX_BW; random_ether_addr(vp->mac); dev_info(&adapter->pdev->dev, "MAC Address %pM is configured for VF %d\n", vp->mac, i); } } return 0; qlcnic_destroy_async_wq: destroy_workqueue(bc->bc_async_wq); qlcnic_destroy_trans_wq: destroy_workqueue(bc->bc_trans_wq); qlcnic_free_vf_info: kfree(sriov->vf_info); qlcnic_free_sriov: kfree(adapter->ahw->sriov); return err; }