int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *adapter) { struct qlcnic_hardware_context *ahw = adapter->ahw; struct qlc_83xx_idc *idc = &ahw->idc; u32 state; state = QLCRDX(ahw, QLC_83XX_VNIC_STATE); while (state != QLCNIC_DEV_NPAR_OPER && idc->vnic_wait_limit--) { msleep(1000); state = QLCRDX(ahw, QLC_83XX_VNIC_STATE); } if (!idc->vnic_wait_limit) { dev_err(&adapter->pdev->dev, "vNIC mode not operational, state check timed out.\n"); return -EIO; } return 0; }
static int qlcnic_sriov_check_dev_ready(struct qlcnic_adapter *adapter) { u32 state; do { msleep(20); if (++adapter->fw_fail_cnt > QLC_BC_CMD_MAX_RETRY_CNT) return -EIO; state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE); } while (state != QLC_83XX_IDC_DEV_READY); return 0; }
/** * qlcnic_83xx_vnic_opmode * * @adapter: adapter structure * Identify virtual NIC operational modes. * * Returns: Success(0) or error code. * **/ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter) { u32 op_mode, priv_level; struct qlcnic_hardware_context *ahw = adapter->ahw; struct qlcnic_nic_template *nic_ops = adapter->nic_ops; qlcnic_get_func_no(adapter); op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE); if (op_mode == QLC_83XX_DEFAULT_OPMODE) priv_level = QLCNIC_MGMT_FUNC; else priv_level = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode, ahw->pci_func); switch (priv_level) { case QLCNIC_NON_PRIV_FUNC: ahw->op_mode = QLCNIC_NON_PRIV_FUNC; ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; nic_ops->init_driver = qlcnic_83xx_init_non_privileged_vnic; break; case QLCNIC_PRIV_FUNC: ahw->op_mode = QLCNIC_PRIV_FUNC; ahw->idc.state_entry = qlcnic_83xx_idc_vnic_pf_entry; nic_ops->init_driver = qlcnic_83xx_init_privileged_vnic; break; case QLCNIC_MGMT_FUNC: ahw->op_mode = QLCNIC_MGMT_FUNC; ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; nic_ops->init_driver = qlcnic_83xx_init_mgmt_vnic; break; default: dev_err(&adapter->pdev->dev, "Invalid Virtual NIC opmode\n"); return -EIO; } if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) adapter->flags |= QLCNIC_ESWITCH_ENABLED; else adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER; ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO; return 0; }
int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *adapter) { u8 id; int ret = -EBUSY; u32 data = QLCNIC_MGMT_FUNC; struct qlcnic_hardware_context *ahw = adapter->ahw; if (qlcnic_83xx_lock_driver(adapter)) return ret; id = ahw->pci_func; data = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE); data = (data & ~QLC_83XX_SET_FUNC_OPMODE(0x3, id)) | QLC_83XX_SET_FUNC_OPMODE(QLCNIC_MGMT_FUNC, id); QLCWRX(adapter->ahw, QLC_83XX_DRV_OP_MODE, data); qlcnic_83xx_unlock_driver(adapter); return 0; }
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; }