102feda17SRajesh Borundia /* 202feda17SRajesh Borundia * QLogic qlcnic NIC Driver 302feda17SRajesh Borundia * Copyright (c) 2009-2013 QLogic Corporation 402feda17SRajesh Borundia * 502feda17SRajesh Borundia * See LICENSE.qlcnic for copyright and licensing details. 602feda17SRajesh Borundia */ 702feda17SRajesh Borundia 802feda17SRajesh Borundia #include "qlcnic_sriov.h" 902feda17SRajesh Borundia #include "qlcnic.h" 10f8468331SRajesh Borundia #include "qlcnic_83xx_hw.h" 1102feda17SRajesh Borundia #include <linux/types.h> 1202feda17SRajesh Borundia 13f197a7aaSRajesh Borundia #define QLC_BC_COMMAND 0 14f197a7aaSRajesh Borundia #define QLC_BC_RESPONSE 1 15f197a7aaSRajesh Borundia 16f197a7aaSRajesh Borundia #define QLC_MBOX_RESP_TIMEOUT (10 * HZ) 17f197a7aaSRajesh Borundia #define QLC_MBOX_CH_FREE_TIMEOUT (10 * HZ) 18f197a7aaSRajesh Borundia 19f197a7aaSRajesh Borundia #define QLC_BC_MSG 0 20f197a7aaSRajesh Borundia #define QLC_BC_CFREE 1 2197d8105cSRajesh Borundia #define QLC_BC_FLR 2 22f197a7aaSRajesh Borundia #define QLC_BC_HDR_SZ 16 23f197a7aaSRajesh Borundia #define QLC_BC_PAYLOAD_SZ (1024 - QLC_BC_HDR_SZ) 24f197a7aaSRajesh Borundia 257cb03b23SRajesh Borundia #define QLC_DEFAULT_RCV_DESCRIPTORS_SRIOV_VF 2048 267cb03b23SRajesh Borundia #define QLC_DEFAULT_JUMBO_RCV_DESCRIPTORS_SRIOV_VF 512 277cb03b23SRajesh Borundia 28f036e4f4SRajesh Borundia #define QLC_83XX_VF_RESET_FAIL_THRESH 8 29f036e4f4SRajesh Borundia #define QLC_BC_CMD_MAX_RETRY_CNT 5 30f036e4f4SRajesh Borundia 3191b7282bSRajesh Borundia static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *); 3291b7282bSRajesh Borundia static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *, u32); 33f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *); 34f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *); 3597d8105cSRajesh Borundia static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *); 36f197a7aaSRajesh Borundia static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *, 37f197a7aaSRajesh Borundia struct qlcnic_cmd_args *); 38f197a7aaSRajesh Borundia 39f8468331SRajesh Borundia static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = { 40f8468331SRajesh Borundia .read_crb = qlcnic_83xx_read_crb, 41f8468331SRajesh Borundia .write_crb = qlcnic_83xx_write_crb, 42f8468331SRajesh Borundia .read_reg = qlcnic_83xx_rd_reg_indirect, 43f8468331SRajesh Borundia .write_reg = qlcnic_83xx_wrt_reg_indirect, 44f8468331SRajesh Borundia .get_mac_address = qlcnic_83xx_get_mac_address, 45f8468331SRajesh Borundia .setup_intr = qlcnic_83xx_setup_intr, 46f8468331SRajesh Borundia .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args, 47f197a7aaSRajesh Borundia .mbx_cmd = qlcnic_sriov_vf_mbx_op, 48f8468331SRajesh Borundia .get_func_no = qlcnic_83xx_get_func_no, 49f8468331SRajesh Borundia .api_lock = qlcnic_83xx_cam_lock, 50f8468331SRajesh Borundia .api_unlock = qlcnic_83xx_cam_unlock, 51f8468331SRajesh Borundia .process_lb_rcv_ring_diag = qlcnic_83xx_process_rcv_ring_diag, 52f8468331SRajesh Borundia .create_rx_ctx = qlcnic_83xx_create_rx_ctx, 53f8468331SRajesh Borundia .create_tx_ctx = qlcnic_83xx_create_tx_ctx, 547cb03b23SRajesh Borundia .del_rx_ctx = qlcnic_83xx_del_rx_ctx, 557cb03b23SRajesh Borundia .del_tx_ctx = qlcnic_83xx_del_tx_ctx, 56f8468331SRajesh Borundia .setup_link_event = qlcnic_83xx_setup_link_event, 57f8468331SRajesh Borundia .get_nic_info = qlcnic_83xx_get_nic_info, 58f8468331SRajesh Borundia .get_pci_info = qlcnic_83xx_get_pci_info, 59f8468331SRajesh Borundia .set_nic_info = qlcnic_83xx_set_nic_info, 60f8468331SRajesh Borundia .change_macvlan = qlcnic_83xx_sre_macaddr_change, 61f8468331SRajesh Borundia .napi_enable = qlcnic_83xx_napi_enable, 62f8468331SRajesh Borundia .napi_disable = qlcnic_83xx_napi_disable, 63f8468331SRajesh Borundia .config_intr_coal = qlcnic_83xx_config_intr_coal, 64f8468331SRajesh Borundia .config_rss = qlcnic_83xx_config_rss, 65f8468331SRajesh Borundia .config_hw_lro = qlcnic_83xx_config_hw_lro, 66f8468331SRajesh Borundia .config_promisc_mode = qlcnic_83xx_nic_set_promisc, 67f8468331SRajesh Borundia .change_l2_filter = qlcnic_83xx_change_l2_filter, 68f8468331SRajesh Borundia .get_board_info = qlcnic_83xx_get_port_info, 6991b7282bSRajesh Borundia .free_mac_list = qlcnic_sriov_vf_free_mac_list, 70f8468331SRajesh Borundia }; 71f8468331SRajesh Borundia 72f8468331SRajesh Borundia static struct qlcnic_nic_template qlcnic_sriov_vf_ops = { 73f8468331SRajesh Borundia .config_bridged_mode = qlcnic_config_bridged_mode, 74f8468331SRajesh Borundia .config_led = qlcnic_config_led, 75f036e4f4SRajesh Borundia .cancel_idc_work = qlcnic_sriov_vf_cancel_fw_work, 76f8468331SRajesh Borundia .napi_add = qlcnic_83xx_napi_add, 77f8468331SRajesh Borundia .napi_del = qlcnic_83xx_napi_del, 78f8468331SRajesh Borundia .config_ipaddr = qlcnic_83xx_config_ipaddr, 79f8468331SRajesh Borundia .clear_legacy_intr = qlcnic_83xx_clear_legacy_intr, 80f8468331SRajesh Borundia }; 81f8468331SRajesh Borundia 82f197a7aaSRajesh Borundia static const struct qlcnic_mailbox_metadata qlcnic_sriov_bc_mbx_tbl[] = { 83f197a7aaSRajesh Borundia {QLCNIC_BC_CMD_CHANNEL_INIT, 2, 2}, 84f197a7aaSRajesh Borundia {QLCNIC_BC_CMD_CHANNEL_TERM, 2, 2}, 8591b7282bSRajesh Borundia {QLCNIC_BC_CMD_GET_ACL, 3, 14}, 8691b7282bSRajesh Borundia {QLCNIC_BC_CMD_CFG_GUEST_VLAN, 2, 2}, 87f197a7aaSRajesh Borundia }; 88f197a7aaSRajesh Borundia 89f197a7aaSRajesh Borundia static inline bool qlcnic_sriov_bc_msg_check(u32 val) 90f197a7aaSRajesh Borundia { 91f197a7aaSRajesh Borundia return (val & (1 << QLC_BC_MSG)) ? true : false; 92f197a7aaSRajesh Borundia } 93f197a7aaSRajesh Borundia 94f197a7aaSRajesh Borundia static inline bool qlcnic_sriov_channel_free_check(u32 val) 95f197a7aaSRajesh Borundia { 96f197a7aaSRajesh Borundia return (val & (1 << QLC_BC_CFREE)) ? true : false; 97f197a7aaSRajesh Borundia } 98f197a7aaSRajesh Borundia 9997d8105cSRajesh Borundia static inline bool qlcnic_sriov_flr_check(u32 val) 10097d8105cSRajesh Borundia { 10197d8105cSRajesh Borundia return (val & (1 << QLC_BC_FLR)) ? true : false; 10297d8105cSRajesh Borundia } 10397d8105cSRajesh Borundia 104f197a7aaSRajesh Borundia static inline u8 qlcnic_sriov_target_func_id(u32 val) 105f197a7aaSRajesh Borundia { 106f197a7aaSRajesh Borundia return (val >> 4) & 0xff; 107f197a7aaSRajesh Borundia } 108f197a7aaSRajesh Borundia 109f197a7aaSRajesh Borundia static int qlcnic_sriov_virtid_fn(struct qlcnic_adapter *adapter, int vf_id) 110f197a7aaSRajesh Borundia { 111f197a7aaSRajesh Borundia struct pci_dev *dev = adapter->pdev; 112f197a7aaSRajesh Borundia int pos; 113f197a7aaSRajesh Borundia u16 stride, offset; 114f197a7aaSRajesh Borundia 115f197a7aaSRajesh Borundia if (qlcnic_sriov_vf_check(adapter)) 116f197a7aaSRajesh Borundia return 0; 117f197a7aaSRajesh Borundia 118f197a7aaSRajesh Borundia pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); 119f197a7aaSRajesh Borundia pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset); 120f197a7aaSRajesh Borundia pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride); 121f197a7aaSRajesh Borundia 122f197a7aaSRajesh Borundia return (dev->devfn + offset + stride * vf_id) & 0xff; 123f197a7aaSRajesh Borundia } 124f197a7aaSRajesh Borundia 12502feda17SRajesh Borundia int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs) 12602feda17SRajesh Borundia { 12702feda17SRajesh Borundia struct qlcnic_sriov *sriov; 128f197a7aaSRajesh Borundia struct qlcnic_back_channel *bc; 129f197a7aaSRajesh Borundia struct workqueue_struct *wq; 130f197a7aaSRajesh Borundia struct qlcnic_vport *vp; 131f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf; 132f197a7aaSRajesh Borundia int err, i; 13302feda17SRajesh Borundia 13402feda17SRajesh Borundia if (!qlcnic_sriov_enable_check(adapter)) 13502feda17SRajesh Borundia return -EIO; 13602feda17SRajesh Borundia 13702feda17SRajesh Borundia sriov = kzalloc(sizeof(struct qlcnic_sriov), GFP_KERNEL); 13802feda17SRajesh Borundia if (!sriov) 13902feda17SRajesh Borundia return -ENOMEM; 14002feda17SRajesh Borundia 14102feda17SRajesh Borundia adapter->ahw->sriov = sriov; 14202feda17SRajesh Borundia sriov->num_vfs = num_vfs; 143f197a7aaSRajesh Borundia bc = &sriov->bc; 144f197a7aaSRajesh Borundia sriov->vf_info = kzalloc(sizeof(struct qlcnic_vf_info) * 145f197a7aaSRajesh Borundia num_vfs, GFP_KERNEL); 146f197a7aaSRajesh Borundia if (!sriov->vf_info) { 147f197a7aaSRajesh Borundia err = -ENOMEM; 148f197a7aaSRajesh Borundia goto qlcnic_free_sriov; 149f197a7aaSRajesh Borundia } 150f197a7aaSRajesh Borundia 151f197a7aaSRajesh Borundia wq = create_singlethread_workqueue("bc-trans"); 152f197a7aaSRajesh Borundia if (wq == NULL) { 153f197a7aaSRajesh Borundia err = -ENOMEM; 154f197a7aaSRajesh Borundia dev_err(&adapter->pdev->dev, 155f197a7aaSRajesh Borundia "Cannot create bc-trans workqueue\n"); 156f197a7aaSRajesh Borundia goto qlcnic_free_vf_info; 157f197a7aaSRajesh Borundia } 158f197a7aaSRajesh Borundia 159f197a7aaSRajesh Borundia bc->bc_trans_wq = wq; 160f197a7aaSRajesh Borundia 161e8b508efSRajesh Borundia wq = create_singlethread_workqueue("async"); 162e8b508efSRajesh Borundia if (wq == NULL) { 163e8b508efSRajesh Borundia err = -ENOMEM; 164e8b508efSRajesh Borundia dev_err(&adapter->pdev->dev, "Cannot create async workqueue\n"); 165e8b508efSRajesh Borundia goto qlcnic_destroy_trans_wq; 166e8b508efSRajesh Borundia } 167e8b508efSRajesh Borundia 168e8b508efSRajesh Borundia bc->bc_async_wq = wq; 169e8b508efSRajesh Borundia INIT_LIST_HEAD(&bc->async_list); 170e8b508efSRajesh Borundia 171f197a7aaSRajesh Borundia for (i = 0; i < num_vfs; i++) { 172f197a7aaSRajesh Borundia vf = &sriov->vf_info[i]; 173f197a7aaSRajesh Borundia vf->adapter = adapter; 174f197a7aaSRajesh Borundia vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i); 175f197a7aaSRajesh Borundia mutex_init(&vf->send_cmd_lock); 176f197a7aaSRajesh Borundia INIT_LIST_HEAD(&vf->rcv_act.wait_list); 177f197a7aaSRajesh Borundia INIT_LIST_HEAD(&vf->rcv_pend.wait_list); 178f197a7aaSRajesh Borundia spin_lock_init(&vf->rcv_act.lock); 179f197a7aaSRajesh Borundia spin_lock_init(&vf->rcv_pend.lock); 180f197a7aaSRajesh Borundia init_completion(&vf->ch_free_cmpl); 181f197a7aaSRajesh Borundia 182f197a7aaSRajesh Borundia if (qlcnic_sriov_pf_check(adapter)) { 183f197a7aaSRajesh Borundia vp = kzalloc(sizeof(struct qlcnic_vport), GFP_KERNEL); 184f197a7aaSRajesh Borundia if (!vp) { 185f197a7aaSRajesh Borundia err = -ENOMEM; 186e8b508efSRajesh Borundia goto qlcnic_destroy_async_wq; 187f197a7aaSRajesh Borundia } 188f197a7aaSRajesh Borundia sriov->vf_info[i].vp = vp; 1894000e7a7SRajesh Borundia vp->max_tx_bw = MAX_BW; 190f197a7aaSRajesh Borundia random_ether_addr(vp->mac); 191f197a7aaSRajesh Borundia dev_info(&adapter->pdev->dev, 192f197a7aaSRajesh Borundia "MAC Address %pM is configured for VF %d\n", 193f197a7aaSRajesh Borundia vp->mac, i); 194f197a7aaSRajesh Borundia } 195f197a7aaSRajesh Borundia } 196f197a7aaSRajesh Borundia 19702feda17SRajesh Borundia return 0; 198f197a7aaSRajesh Borundia 199e8b508efSRajesh Borundia qlcnic_destroy_async_wq: 200e8b508efSRajesh Borundia destroy_workqueue(bc->bc_async_wq); 201e8b508efSRajesh Borundia 202f197a7aaSRajesh Borundia qlcnic_destroy_trans_wq: 203f197a7aaSRajesh Borundia destroy_workqueue(bc->bc_trans_wq); 204f197a7aaSRajesh Borundia 205f197a7aaSRajesh Borundia qlcnic_free_vf_info: 206f197a7aaSRajesh Borundia kfree(sriov->vf_info); 207f197a7aaSRajesh Borundia 208f197a7aaSRajesh Borundia qlcnic_free_sriov: 209f197a7aaSRajesh Borundia kfree(adapter->ahw->sriov); 210f197a7aaSRajesh Borundia return err; 21102feda17SRajesh Borundia } 21202feda17SRajesh Borundia 21397d8105cSRajesh Borundia void qlcnic_sriov_cleanup_list(struct qlcnic_trans_list *t_list) 21497d8105cSRajesh Borundia { 21597d8105cSRajesh Borundia struct qlcnic_bc_trans *trans; 21697d8105cSRajesh Borundia struct qlcnic_cmd_args cmd; 21797d8105cSRajesh Borundia unsigned long flags; 21897d8105cSRajesh Borundia 21997d8105cSRajesh Borundia spin_lock_irqsave(&t_list->lock, flags); 22097d8105cSRajesh Borundia 22197d8105cSRajesh Borundia while (!list_empty(&t_list->wait_list)) { 22297d8105cSRajesh Borundia trans = list_first_entry(&t_list->wait_list, 22397d8105cSRajesh Borundia struct qlcnic_bc_trans, list); 22497d8105cSRajesh Borundia list_del(&trans->list); 22597d8105cSRajesh Borundia t_list->count--; 22697d8105cSRajesh Borundia cmd.req.arg = (u32 *)trans->req_pay; 22797d8105cSRajesh Borundia cmd.rsp.arg = (u32 *)trans->rsp_pay; 22897d8105cSRajesh Borundia qlcnic_free_mbx_args(&cmd); 22997d8105cSRajesh Borundia qlcnic_sriov_cleanup_transaction(trans); 23097d8105cSRajesh Borundia } 23197d8105cSRajesh Borundia 23297d8105cSRajesh Borundia spin_unlock_irqrestore(&t_list->lock, flags); 23397d8105cSRajesh Borundia } 23497d8105cSRajesh Borundia 23502feda17SRajesh Borundia void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) 23602feda17SRajesh Borundia { 237f197a7aaSRajesh Borundia struct qlcnic_sriov *sriov = adapter->ahw->sriov; 238f197a7aaSRajesh Borundia struct qlcnic_back_channel *bc = &sriov->bc; 23997d8105cSRajesh Borundia struct qlcnic_vf_info *vf; 240f197a7aaSRajesh Borundia int i; 241f197a7aaSRajesh Borundia 24202feda17SRajesh Borundia if (!qlcnic_sriov_enable_check(adapter)) 24302feda17SRajesh Borundia return; 24402feda17SRajesh Borundia 245e8b508efSRajesh Borundia qlcnic_sriov_cleanup_async_list(bc); 246e8b508efSRajesh Borundia destroy_workqueue(bc->bc_async_wq); 24797d8105cSRajesh Borundia 24897d8105cSRajesh Borundia for (i = 0; i < sriov->num_vfs; i++) { 24997d8105cSRajesh Borundia vf = &sriov->vf_info[i]; 25097d8105cSRajesh Borundia qlcnic_sriov_cleanup_list(&vf->rcv_pend); 25197d8105cSRajesh Borundia cancel_work_sync(&vf->trans_work); 25297d8105cSRajesh Borundia qlcnic_sriov_cleanup_list(&vf->rcv_act); 25397d8105cSRajesh Borundia } 25497d8105cSRajesh Borundia 255f197a7aaSRajesh Borundia destroy_workqueue(bc->bc_trans_wq); 256f197a7aaSRajesh Borundia 257f197a7aaSRajesh Borundia for (i = 0; i < sriov->num_vfs; i++) 258f197a7aaSRajesh Borundia kfree(sriov->vf_info[i].vp); 259f197a7aaSRajesh Borundia 260f197a7aaSRajesh Borundia kfree(sriov->vf_info); 26102feda17SRajesh Borundia kfree(adapter->ahw->sriov); 26202feda17SRajesh Borundia } 26302feda17SRajesh Borundia 264f8468331SRajesh Borundia static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter) 265f8468331SRajesh Borundia { 266f197a7aaSRajesh Borundia qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM); 267f197a7aaSRajesh Borundia qlcnic_sriov_cfg_bc_intr(adapter, 0); 268f8468331SRajesh Borundia __qlcnic_sriov_cleanup(adapter); 269f8468331SRajesh Borundia } 270f8468331SRajesh Borundia 27102feda17SRajesh Borundia void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) 27202feda17SRajesh Borundia { 27302feda17SRajesh Borundia if (qlcnic_sriov_pf_check(adapter)) 27402feda17SRajesh Borundia qlcnic_sriov_pf_cleanup(adapter); 275f8468331SRajesh Borundia 276f8468331SRajesh Borundia if (qlcnic_sriov_vf_check(adapter)) 277f8468331SRajesh Borundia qlcnic_sriov_vf_cleanup(adapter); 278f8468331SRajesh Borundia } 279f8468331SRajesh Borundia 280f197a7aaSRajesh Borundia static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr, 281f197a7aaSRajesh Borundia u32 *pay, u8 pci_func, u8 size) 282f197a7aaSRajesh Borundia { 2839106e5dbSRajesh Borundia u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, val, wait_time = 0; 284f197a7aaSRajesh Borundia struct qlcnic_hardware_context *ahw = adapter->ahw; 285f197a7aaSRajesh Borundia unsigned long flags; 286f197a7aaSRajesh Borundia u16 opcode; 287f197a7aaSRajesh Borundia u8 mbx_err_code; 288f197a7aaSRajesh Borundia int i, j; 289f197a7aaSRajesh Borundia 290f197a7aaSRajesh Borundia opcode = ((struct qlcnic_bc_hdr *)hdr)->cmd_op; 291f197a7aaSRajesh Borundia 292f197a7aaSRajesh Borundia if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) { 293f197a7aaSRajesh Borundia dev_info(&adapter->pdev->dev, 294f197a7aaSRajesh Borundia "Mailbox cmd attempted, 0x%x\n", opcode); 295f197a7aaSRajesh Borundia dev_info(&adapter->pdev->dev, "Mailbox detached\n"); 296f197a7aaSRajesh Borundia return 0; 297f197a7aaSRajesh Borundia } 298f197a7aaSRajesh Borundia 299f197a7aaSRajesh Borundia spin_lock_irqsave(&ahw->mbx_lock, flags); 300f197a7aaSRajesh Borundia 301f197a7aaSRajesh Borundia mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL); 302f197a7aaSRajesh Borundia if (mbx_val) { 303f197a7aaSRajesh Borundia QLCDB(adapter, DRV, "Mailbox cmd attempted, 0x%x\n", opcode); 304f197a7aaSRajesh Borundia spin_unlock_irqrestore(&ahw->mbx_lock, flags); 305f197a7aaSRajesh Borundia return QLCNIC_RCODE_TIMEOUT; 306f197a7aaSRajesh Borundia } 307f197a7aaSRajesh Borundia /* Fill in mailbox registers */ 308f197a7aaSRajesh Borundia val = size + (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); 309f197a7aaSRajesh Borundia mbx_cmd = 0x31 | (val << 16) | (adapter->ahw->fw_hal_version << 29); 310f197a7aaSRajesh Borundia 311f197a7aaSRajesh Borundia writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0)); 312f197a7aaSRajesh Borundia mbx_cmd = 0x1 | (1 << 4); 313f197a7aaSRajesh Borundia 314f197a7aaSRajesh Borundia if (qlcnic_sriov_pf_check(adapter)) 315f197a7aaSRajesh Borundia mbx_cmd |= (pci_func << 5); 316f197a7aaSRajesh Borundia 317f197a7aaSRajesh Borundia writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 1)); 318f197a7aaSRajesh Borundia for (i = 2, j = 0; j < (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); 319f197a7aaSRajesh Borundia i++, j++) { 320f197a7aaSRajesh Borundia writel(*(hdr++), QLCNIC_MBX_HOST(ahw, i)); 321f197a7aaSRajesh Borundia } 322f197a7aaSRajesh Borundia for (j = 0; j < size; j++, i++) 323f197a7aaSRajesh Borundia writel(*(pay++), QLCNIC_MBX_HOST(ahw, i)); 324f197a7aaSRajesh Borundia 325f197a7aaSRajesh Borundia /* Signal FW about the impending command */ 326f197a7aaSRajesh Borundia QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER); 327f197a7aaSRajesh Borundia 328f197a7aaSRajesh Borundia /* Waiting for the mailbox cmd to complete and while waiting here 329f197a7aaSRajesh Borundia * some AEN might arrive. If more than 5 seconds expire we can 330f197a7aaSRajesh Borundia * assume something is wrong. 331f197a7aaSRajesh Borundia */ 332f197a7aaSRajesh Borundia poll: 3339106e5dbSRajesh Borundia rsp = qlcnic_83xx_mbx_poll(adapter, &wait_time); 334f197a7aaSRajesh Borundia if (rsp != QLCNIC_RCODE_TIMEOUT) { 335f197a7aaSRajesh Borundia /* Get the FW response data */ 336f197a7aaSRajesh Borundia fw_data = readl(QLCNIC_MBX_FW(ahw, 0)); 337f197a7aaSRajesh Borundia if (fw_data & QLCNIC_MBX_ASYNC_EVENT) { 338d1a1105eSRajesh Borundia __qlcnic_83xx_process_aen(adapter); 339f197a7aaSRajesh Borundia goto poll; 340f197a7aaSRajesh Borundia } 341f197a7aaSRajesh Borundia mbx_err_code = QLCNIC_MBX_STATUS(fw_data); 342f197a7aaSRajesh Borundia rsp_num = QLCNIC_MBX_NUM_REGS(fw_data); 343f197a7aaSRajesh Borundia opcode = QLCNIC_MBX_RSP(fw_data); 344f197a7aaSRajesh Borundia 345f197a7aaSRajesh Borundia switch (mbx_err_code) { 346f197a7aaSRajesh Borundia case QLCNIC_MBX_RSP_OK: 347f197a7aaSRajesh Borundia case QLCNIC_MBX_PORT_RSP_OK: 348f197a7aaSRajesh Borundia rsp = QLCNIC_RCODE_SUCCESS; 349f197a7aaSRajesh Borundia break; 350f197a7aaSRajesh Borundia default: 351f197a7aaSRajesh Borundia if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) { 352f197a7aaSRajesh Borundia rsp = qlcnic_83xx_mac_rcode(adapter); 353f197a7aaSRajesh Borundia if (!rsp) 354f197a7aaSRajesh Borundia goto out; 355f197a7aaSRajesh Borundia } 356f197a7aaSRajesh Borundia dev_err(&adapter->pdev->dev, 357f197a7aaSRajesh Borundia "MBX command 0x%x failed with err:0x%x\n", 358f197a7aaSRajesh Borundia opcode, mbx_err_code); 359f197a7aaSRajesh Borundia rsp = mbx_err_code; 360f197a7aaSRajesh Borundia break; 361f197a7aaSRajesh Borundia } 362f197a7aaSRajesh Borundia goto out; 363f197a7aaSRajesh Borundia } 364f197a7aaSRajesh Borundia 365f197a7aaSRajesh Borundia dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n", 366f197a7aaSRajesh Borundia QLCNIC_MBX_RSP(mbx_cmd)); 367f197a7aaSRajesh Borundia rsp = QLCNIC_RCODE_TIMEOUT; 368f197a7aaSRajesh Borundia out: 369f197a7aaSRajesh Borundia /* clear fw mbx control register */ 370f197a7aaSRajesh Borundia QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER); 371f197a7aaSRajesh Borundia spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags); 372f197a7aaSRajesh Borundia return rsp; 373f197a7aaSRajesh Borundia } 374f197a7aaSRajesh Borundia 3757cb03b23SRajesh Borundia static void qlcnic_sriov_vf_cfg_buff_desc(struct qlcnic_adapter *adapter) 3767cb03b23SRajesh Borundia { 3777cb03b23SRajesh Borundia adapter->num_rxd = QLC_DEFAULT_RCV_DESCRIPTORS_SRIOV_VF; 3787cb03b23SRajesh Borundia adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G; 3797cb03b23SRajesh Borundia adapter->num_jumbo_rxd = QLC_DEFAULT_JUMBO_RCV_DESCRIPTORS_SRIOV_VF; 3807cb03b23SRajesh Borundia adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; 3817cb03b23SRajesh Borundia adapter->num_txd = MAX_CMD_DESCRIPTORS; 3827cb03b23SRajesh Borundia adapter->max_rds_rings = MAX_RDS_RINGS; 3837cb03b23SRajesh Borundia } 3847cb03b23SRajesh Borundia 3854000e7a7SRajesh Borundia int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *adapter, 3864000e7a7SRajesh Borundia struct qlcnic_info *npar_info, u16 vport_id) 3874000e7a7SRajesh Borundia { 3884000e7a7SRajesh Borundia struct device *dev = &adapter->pdev->dev; 3894000e7a7SRajesh Borundia struct qlcnic_cmd_args cmd; 3904000e7a7SRajesh Borundia int err; 3914000e7a7SRajesh Borundia u32 status; 3924000e7a7SRajesh Borundia 3934000e7a7SRajesh Borundia err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO); 3944000e7a7SRajesh Borundia if (err) 3954000e7a7SRajesh Borundia return err; 3964000e7a7SRajesh Borundia 3974000e7a7SRajesh Borundia cmd.req.arg[1] = vport_id << 16 | 0x1; 3984000e7a7SRajesh Borundia err = qlcnic_issue_cmd(adapter, &cmd); 3994000e7a7SRajesh Borundia if (err) { 4004000e7a7SRajesh Borundia dev_err(&adapter->pdev->dev, 4014000e7a7SRajesh Borundia "Failed to get vport info, err=%d\n", err); 4024000e7a7SRajesh Borundia qlcnic_free_mbx_args(&cmd); 4034000e7a7SRajesh Borundia return err; 4044000e7a7SRajesh Borundia } 4054000e7a7SRajesh Borundia 4064000e7a7SRajesh Borundia status = cmd.rsp.arg[2] & 0xffff; 4074000e7a7SRajesh Borundia if (status & BIT_0) 4084000e7a7SRajesh Borundia npar_info->min_tx_bw = MSW(cmd.rsp.arg[2]); 4094000e7a7SRajesh Borundia if (status & BIT_1) 4104000e7a7SRajesh Borundia npar_info->max_tx_bw = LSW(cmd.rsp.arg[3]); 4114000e7a7SRajesh Borundia if (status & BIT_2) 4124000e7a7SRajesh Borundia npar_info->max_tx_ques = MSW(cmd.rsp.arg[3]); 4134000e7a7SRajesh Borundia if (status & BIT_3) 4144000e7a7SRajesh Borundia npar_info->max_tx_mac_filters = LSW(cmd.rsp.arg[4]); 4154000e7a7SRajesh Borundia if (status & BIT_4) 4164000e7a7SRajesh Borundia npar_info->max_rx_mcast_mac_filters = MSW(cmd.rsp.arg[4]); 4174000e7a7SRajesh Borundia if (status & BIT_5) 4184000e7a7SRajesh Borundia npar_info->max_rx_ucast_mac_filters = LSW(cmd.rsp.arg[5]); 4194000e7a7SRajesh Borundia if (status & BIT_6) 4204000e7a7SRajesh Borundia npar_info->max_rx_ip_addr = MSW(cmd.rsp.arg[5]); 4214000e7a7SRajesh Borundia if (status & BIT_7) 4224000e7a7SRajesh Borundia npar_info->max_rx_lro_flow = LSW(cmd.rsp.arg[6]); 4234000e7a7SRajesh Borundia if (status & BIT_8) 4244000e7a7SRajesh Borundia npar_info->max_rx_status_rings = MSW(cmd.rsp.arg[6]); 4254000e7a7SRajesh Borundia if (status & BIT_9) 4264000e7a7SRajesh Borundia npar_info->max_rx_buf_rings = LSW(cmd.rsp.arg[7]); 4274000e7a7SRajesh Borundia 4284000e7a7SRajesh Borundia npar_info->max_rx_ques = MSW(cmd.rsp.arg[7]); 4294000e7a7SRajesh Borundia npar_info->max_tx_vlan_keys = LSW(cmd.rsp.arg[8]); 4304000e7a7SRajesh Borundia npar_info->max_local_ipv6_addrs = MSW(cmd.rsp.arg[8]); 4314000e7a7SRajesh Borundia npar_info->max_remote_ipv6_addrs = LSW(cmd.rsp.arg[9]); 4324000e7a7SRajesh Borundia 4334000e7a7SRajesh Borundia dev_info(dev, "\n\tmin_tx_bw: %d, max_tx_bw: %d max_tx_ques: %d,\n" 4344000e7a7SRajesh Borundia "\tmax_tx_mac_filters: %d max_rx_mcast_mac_filters: %d,\n" 4354000e7a7SRajesh Borundia "\tmax_rx_ucast_mac_filters: 0x%x, max_rx_ip_addr: %d,\n" 4364000e7a7SRajesh Borundia "\tmax_rx_lro_flow: %d max_rx_status_rings: %d,\n" 4374000e7a7SRajesh Borundia "\tmax_rx_buf_rings: %d, max_rx_ques: %d, max_tx_vlan_keys %d\n" 4384000e7a7SRajesh Borundia "\tlocal_ipv6_addr: %d, remote_ipv6_addr: %d\n", 4394000e7a7SRajesh Borundia npar_info->min_tx_bw, npar_info->max_tx_bw, 4404000e7a7SRajesh Borundia npar_info->max_tx_ques, npar_info->max_tx_mac_filters, 4414000e7a7SRajesh Borundia npar_info->max_rx_mcast_mac_filters, 4424000e7a7SRajesh Borundia npar_info->max_rx_ucast_mac_filters, npar_info->max_rx_ip_addr, 4434000e7a7SRajesh Borundia npar_info->max_rx_lro_flow, npar_info->max_rx_status_rings, 4444000e7a7SRajesh Borundia npar_info->max_rx_buf_rings, npar_info->max_rx_ques, 4454000e7a7SRajesh Borundia npar_info->max_tx_vlan_keys, npar_info->max_local_ipv6_addrs, 4464000e7a7SRajesh Borundia npar_info->max_remote_ipv6_addrs); 4474000e7a7SRajesh Borundia 4484000e7a7SRajesh Borundia qlcnic_free_mbx_args(&cmd); 4494000e7a7SRajesh Borundia return err; 4504000e7a7SRajesh Borundia } 4514000e7a7SRajesh Borundia 45291b7282bSRajesh Borundia static int qlcnic_sriov_set_pvid_mode(struct qlcnic_adapter *adapter, 45391b7282bSRajesh Borundia struct qlcnic_cmd_args *cmd) 45491b7282bSRajesh Borundia { 45591b7282bSRajesh Borundia adapter->rx_pvid = (cmd->rsp.arg[1] >> 16) & 0xffff; 45691b7282bSRajesh Borundia adapter->flags &= ~QLCNIC_TAGGING_ENABLED; 45791b7282bSRajesh Borundia return 0; 45891b7282bSRajesh Borundia } 45991b7282bSRajesh Borundia 46091b7282bSRajesh Borundia static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter, 46191b7282bSRajesh Borundia struct qlcnic_cmd_args *cmd) 46291b7282bSRajesh Borundia { 46391b7282bSRajesh Borundia struct qlcnic_sriov *sriov = adapter->ahw->sriov; 46491b7282bSRajesh Borundia int i, num_vlans; 46591b7282bSRajesh Borundia u16 *vlans; 46691b7282bSRajesh Borundia 46791b7282bSRajesh Borundia if (sriov->allowed_vlans) 46891b7282bSRajesh Borundia return 0; 46991b7282bSRajesh Borundia 47091b7282bSRajesh Borundia sriov->any_vlan = cmd->rsp.arg[2] & 0xf; 47191b7282bSRajesh Borundia if (!sriov->any_vlan) 47291b7282bSRajesh Borundia return 0; 47391b7282bSRajesh Borundia 47491b7282bSRajesh Borundia sriov->num_allowed_vlans = cmd->rsp.arg[2] >> 16; 47591b7282bSRajesh Borundia num_vlans = sriov->num_allowed_vlans; 47691b7282bSRajesh Borundia sriov->allowed_vlans = kzalloc(sizeof(u16) * num_vlans, GFP_KERNEL); 47791b7282bSRajesh Borundia if (!sriov->allowed_vlans) 47891b7282bSRajesh Borundia return -ENOMEM; 47991b7282bSRajesh Borundia 48091b7282bSRajesh Borundia vlans = (u16 *)&cmd->rsp.arg[3]; 48191b7282bSRajesh Borundia for (i = 0; i < num_vlans; i++) 48291b7282bSRajesh Borundia sriov->allowed_vlans[i] = vlans[i]; 48391b7282bSRajesh Borundia 48491b7282bSRajesh Borundia return 0; 48591b7282bSRajesh Borundia } 48691b7282bSRajesh Borundia 48791b7282bSRajesh Borundia static int qlcnic_sriov_get_vf_acl(struct qlcnic_adapter *adapter) 48891b7282bSRajesh Borundia { 48991b7282bSRajesh Borundia struct qlcnic_sriov *sriov = adapter->ahw->sriov; 49091b7282bSRajesh Borundia struct qlcnic_cmd_args cmd; 49191b7282bSRajesh Borundia int ret; 49291b7282bSRajesh Borundia 49391b7282bSRajesh Borundia ret = qlcnic_sriov_alloc_bc_mbx_args(&cmd, QLCNIC_BC_CMD_GET_ACL); 49491b7282bSRajesh Borundia if (ret) 49591b7282bSRajesh Borundia return ret; 49691b7282bSRajesh Borundia 49791b7282bSRajesh Borundia ret = qlcnic_issue_cmd(adapter, &cmd); 49891b7282bSRajesh Borundia if (ret) { 49991b7282bSRajesh Borundia dev_err(&adapter->pdev->dev, "Failed to get ACL, err=%d\n", 50091b7282bSRajesh Borundia ret); 50191b7282bSRajesh Borundia } else { 50291b7282bSRajesh Borundia sriov->vlan_mode = cmd.rsp.arg[1] & 0x3; 50391b7282bSRajesh Borundia switch (sriov->vlan_mode) { 50491b7282bSRajesh Borundia case QLC_GUEST_VLAN_MODE: 50591b7282bSRajesh Borundia ret = qlcnic_sriov_set_guest_vlan_mode(adapter, &cmd); 50691b7282bSRajesh Borundia break; 50791b7282bSRajesh Borundia case QLC_PVID_MODE: 50891b7282bSRajesh Borundia ret = qlcnic_sriov_set_pvid_mode(adapter, &cmd); 50991b7282bSRajesh Borundia break; 51091b7282bSRajesh Borundia } 51191b7282bSRajesh Borundia } 51291b7282bSRajesh Borundia 51391b7282bSRajesh Borundia qlcnic_free_mbx_args(&cmd); 51491b7282bSRajesh Borundia return ret; 51591b7282bSRajesh Borundia } 51691b7282bSRajesh Borundia 5177cb03b23SRajesh Borundia static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter) 5187cb03b23SRajesh Borundia { 5197cb03b23SRajesh Borundia struct qlcnic_info nic_info; 5207cb03b23SRajesh Borundia struct qlcnic_hardware_context *ahw = adapter->ahw; 5217cb03b23SRajesh Borundia int err; 5227cb03b23SRajesh Borundia 5234000e7a7SRajesh Borundia err = qlcnic_sriov_get_vf_vport_info(adapter, &nic_info, 0); 5244000e7a7SRajesh Borundia if (err) 5254000e7a7SRajesh Borundia return err; 5264000e7a7SRajesh Borundia 5277cb03b23SRajesh Borundia err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func); 5287cb03b23SRajesh Borundia if (err) 5297cb03b23SRajesh Borundia return -EIO; 5307cb03b23SRajesh Borundia 53191b7282bSRajesh Borundia err = qlcnic_sriov_get_vf_acl(adapter); 53291b7282bSRajesh Borundia if (err) 53391b7282bSRajesh Borundia return err; 53491b7282bSRajesh Borundia 5357cb03b23SRajesh Borundia if (qlcnic_83xx_get_port_info(adapter)) 5367cb03b23SRajesh Borundia return -EIO; 5377cb03b23SRajesh Borundia 5387cb03b23SRajesh Borundia qlcnic_sriov_vf_cfg_buff_desc(adapter); 5397cb03b23SRajesh Borundia adapter->flags |= QLCNIC_ADAPTER_INITIALIZED; 5407cb03b23SRajesh Borundia dev_info(&adapter->pdev->dev, "HAL Version: %d\n", 5417cb03b23SRajesh Borundia adapter->ahw->fw_hal_version); 5427cb03b23SRajesh Borundia 5437cb03b23SRajesh Borundia ahw->physical_port = (u8) nic_info.phys_port; 5447cb03b23SRajesh Borundia ahw->switch_mode = nic_info.switch_mode; 5457cb03b23SRajesh Borundia ahw->max_mtu = nic_info.max_mtu; 5467cb03b23SRajesh Borundia ahw->op_mode = nic_info.op_mode; 5477cb03b23SRajesh Borundia ahw->capabilities = nic_info.capabilities; 5487cb03b23SRajesh Borundia return 0; 5497cb03b23SRajesh Borundia } 5507cb03b23SRajesh Borundia 551f8468331SRajesh Borundia static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, 552f8468331SRajesh Borundia int pci_using_dac) 553f8468331SRajesh Borundia { 554f8468331SRajesh Borundia int err; 555f8468331SRajesh Borundia 556e8b508efSRajesh Borundia INIT_LIST_HEAD(&adapter->vf_mc_list); 557f8468331SRajesh Borundia if (!qlcnic_use_msi_x && !!qlcnic_use_msi) 558f8468331SRajesh Borundia dev_warn(&adapter->pdev->dev, 559f8468331SRajesh Borundia "83xx adapter do not support MSI interrupts\n"); 560f8468331SRajesh Borundia 561f8468331SRajesh Borundia err = qlcnic_setup_intr(adapter, 1); 562f8468331SRajesh Borundia if (err) { 563f8468331SRajesh Borundia dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n"); 564f8468331SRajesh Borundia goto err_out_disable_msi; 565f8468331SRajesh Borundia } 566f8468331SRajesh Borundia 567f8468331SRajesh Borundia err = qlcnic_83xx_setup_mbx_intr(adapter); 568f8468331SRajesh Borundia if (err) 569f8468331SRajesh Borundia goto err_out_disable_msi; 570f8468331SRajesh Borundia 571f8468331SRajesh Borundia err = qlcnic_sriov_init(adapter, 1); 572f8468331SRajesh Borundia if (err) 573f8468331SRajesh Borundia goto err_out_disable_mbx_intr; 574f8468331SRajesh Borundia 575f197a7aaSRajesh Borundia err = qlcnic_sriov_cfg_bc_intr(adapter, 1); 576f8468331SRajesh Borundia if (err) 577f8468331SRajesh Borundia goto err_out_cleanup_sriov; 578f8468331SRajesh Borundia 579f197a7aaSRajesh Borundia err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT); 580f197a7aaSRajesh Borundia if (err) 581f197a7aaSRajesh Borundia goto err_out_disable_bc_intr; 582f197a7aaSRajesh Borundia 5837cb03b23SRajesh Borundia err = qlcnic_sriov_vf_init_driver(adapter); 5847cb03b23SRajesh Borundia if (err) 5857cb03b23SRajesh Borundia goto err_out_send_channel_term; 5867cb03b23SRajesh Borundia 587f197a7aaSRajesh Borundia err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac); 588f197a7aaSRajesh Borundia if (err) 589f197a7aaSRajesh Borundia goto err_out_send_channel_term; 590f197a7aaSRajesh Borundia 591f8468331SRajesh Borundia pci_set_drvdata(adapter->pdev, adapter); 592f8468331SRajesh Borundia dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n", 593f8468331SRajesh Borundia adapter->netdev->name); 594f036e4f4SRajesh Borundia qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state, 595f036e4f4SRajesh Borundia adapter->ahw->idc.delay); 596f8468331SRajesh Borundia return 0; 597f8468331SRajesh Borundia 598f197a7aaSRajesh Borundia err_out_send_channel_term: 599f197a7aaSRajesh Borundia qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM); 600f197a7aaSRajesh Borundia 601f197a7aaSRajesh Borundia err_out_disable_bc_intr: 602f197a7aaSRajesh Borundia qlcnic_sriov_cfg_bc_intr(adapter, 0); 603f197a7aaSRajesh Borundia 604f8468331SRajesh Borundia err_out_cleanup_sriov: 605f8468331SRajesh Borundia __qlcnic_sriov_cleanup(adapter); 606f8468331SRajesh Borundia 607f8468331SRajesh Borundia err_out_disable_mbx_intr: 608f8468331SRajesh Borundia qlcnic_83xx_free_mbx_intr(adapter); 609f8468331SRajesh Borundia 610f8468331SRajesh Borundia err_out_disable_msi: 611f8468331SRajesh Borundia qlcnic_teardown_intr(adapter); 612f8468331SRajesh Borundia return err; 613f8468331SRajesh Borundia } 614f8468331SRajesh Borundia 615f036e4f4SRajesh Borundia static int qlcnic_sriov_check_dev_ready(struct qlcnic_adapter *adapter) 616f036e4f4SRajesh Borundia { 617f036e4f4SRajesh Borundia u32 state; 618f036e4f4SRajesh Borundia 619f036e4f4SRajesh Borundia do { 620f036e4f4SRajesh Borundia msleep(20); 621f036e4f4SRajesh Borundia if (++adapter->fw_fail_cnt > QLC_BC_CMD_MAX_RETRY_CNT) 622f036e4f4SRajesh Borundia return -EIO; 623f036e4f4SRajesh Borundia state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE); 624f036e4f4SRajesh Borundia } while (state != QLC_83XX_IDC_DEV_READY); 625f036e4f4SRajesh Borundia 626f036e4f4SRajesh Borundia return 0; 627f036e4f4SRajesh Borundia } 628f036e4f4SRajesh Borundia 629f8468331SRajesh Borundia int qlcnic_sriov_vf_init(struct qlcnic_adapter *adapter, int pci_using_dac) 630f8468331SRajesh Borundia { 631f8468331SRajesh Borundia struct qlcnic_hardware_context *ahw = adapter->ahw; 632f036e4f4SRajesh Borundia int err; 633f8468331SRajesh Borundia 634f8468331SRajesh Borundia spin_lock_init(&ahw->mbx_lock); 635f036e4f4SRajesh Borundia set_bit(QLC_83XX_MBX_READY, &ahw->idc.status); 636f036e4f4SRajesh Borundia set_bit(QLC_83XX_MODULE_LOADED, &ahw->idc.status); 637f036e4f4SRajesh Borundia ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY; 638f036e4f4SRajesh Borundia ahw->reset_context = 0; 639f036e4f4SRajesh Borundia adapter->fw_fail_cnt = 0; 640f8468331SRajesh Borundia ahw->msix_supported = 1; 641f036e4f4SRajesh Borundia adapter->need_fw_reset = 0; 642da6c8063SRajesh Borundia adapter->flags |= QLCNIC_TX_INTR_SHARED; 643f8468331SRajesh Borundia 644f036e4f4SRajesh Borundia err = qlcnic_sriov_check_dev_ready(adapter); 645f036e4f4SRajesh Borundia if (err) 646f036e4f4SRajesh Borundia return err; 647f036e4f4SRajesh Borundia 648f036e4f4SRajesh Borundia err = qlcnic_sriov_setup_vf(adapter, pci_using_dac); 649f036e4f4SRajesh Borundia if (err) 650f036e4f4SRajesh Borundia return err; 651f8468331SRajesh Borundia 652f8468331SRajesh Borundia if (qlcnic_read_mac_addr(adapter)) 653f8468331SRajesh Borundia dev_warn(&adapter->pdev->dev, "failed to read mac addr\n"); 654f8468331SRajesh Borundia 655f8468331SRajesh Borundia clear_bit(__QLCNIC_RESETTING, &adapter->state); 656f8468331SRajesh Borundia return 0; 657f8468331SRajesh Borundia } 658f8468331SRajesh Borundia 659f8468331SRajesh Borundia void qlcnic_sriov_vf_set_ops(struct qlcnic_adapter *adapter) 660f8468331SRajesh Borundia { 661f8468331SRajesh Borundia struct qlcnic_hardware_context *ahw = adapter->ahw; 662f8468331SRajesh Borundia 663f8468331SRajesh Borundia ahw->op_mode = QLCNIC_SRIOV_VF_FUNC; 664f8468331SRajesh Borundia dev_info(&adapter->pdev->dev, 665f8468331SRajesh Borundia "HAL Version: %d Non Privileged SRIOV function\n", 666f8468331SRajesh Borundia ahw->fw_hal_version); 667f8468331SRajesh Borundia adapter->nic_ops = &qlcnic_sriov_vf_ops; 668f8468331SRajesh Borundia set_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state); 669f8468331SRajesh Borundia return; 670f8468331SRajesh Borundia } 671f8468331SRajesh Borundia 672f8468331SRajesh Borundia void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *ahw) 673f8468331SRajesh Borundia { 674f8468331SRajesh Borundia ahw->hw_ops = &qlcnic_sriov_vf_hw_ops; 675f8468331SRajesh Borundia ahw->reg_tbl = (u32 *)qlcnic_83xx_reg_tbl; 676f8468331SRajesh Borundia ahw->ext_reg_tbl = (u32 *)qlcnic_83xx_ext_reg_tbl; 67702feda17SRajesh Borundia } 678f197a7aaSRajesh Borundia 679f197a7aaSRajesh Borundia static u32 qlcnic_sriov_get_bc_paysize(u32 real_pay_size, u8 curr_frag) 680f197a7aaSRajesh Borundia { 681f197a7aaSRajesh Borundia u32 pay_size; 682f197a7aaSRajesh Borundia 683f197a7aaSRajesh Borundia pay_size = real_pay_size / ((curr_frag + 1) * QLC_BC_PAYLOAD_SZ); 684f197a7aaSRajesh Borundia 685f197a7aaSRajesh Borundia if (pay_size) 686f197a7aaSRajesh Borundia pay_size = QLC_BC_PAYLOAD_SZ; 687f197a7aaSRajesh Borundia else 688f197a7aaSRajesh Borundia pay_size = real_pay_size % QLC_BC_PAYLOAD_SZ; 689f197a7aaSRajesh Borundia 690f197a7aaSRajesh Borundia return pay_size; 691f197a7aaSRajesh Borundia } 692f197a7aaSRajesh Borundia 693f197a7aaSRajesh Borundia int qlcnic_sriov_func_to_index(struct qlcnic_adapter *adapter, u8 pci_func) 694f197a7aaSRajesh Borundia { 695f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf_info = adapter->ahw->sriov->vf_info; 696f197a7aaSRajesh Borundia u8 i; 697f197a7aaSRajesh Borundia 698f197a7aaSRajesh Borundia if (qlcnic_sriov_vf_check(adapter)) 699f197a7aaSRajesh Borundia return 0; 700f197a7aaSRajesh Borundia 701f197a7aaSRajesh Borundia for (i = 0; i < adapter->ahw->sriov->num_vfs; i++) { 702f197a7aaSRajesh Borundia if (vf_info[i].pci_func == pci_func) 703f197a7aaSRajesh Borundia return i; 704f197a7aaSRajesh Borundia } 705f197a7aaSRajesh Borundia 706f197a7aaSRajesh Borundia return -EINVAL; 707f197a7aaSRajesh Borundia } 708f197a7aaSRajesh Borundia 709f197a7aaSRajesh Borundia static inline int qlcnic_sriov_alloc_bc_trans(struct qlcnic_bc_trans **trans) 710f197a7aaSRajesh Borundia { 711f197a7aaSRajesh Borundia *trans = kzalloc(sizeof(struct qlcnic_bc_trans), GFP_ATOMIC); 712f197a7aaSRajesh Borundia if (!*trans) 713f197a7aaSRajesh Borundia return -ENOMEM; 714f197a7aaSRajesh Borundia 715f197a7aaSRajesh Borundia init_completion(&(*trans)->resp_cmpl); 716f197a7aaSRajesh Borundia return 0; 717f197a7aaSRajesh Borundia } 718f197a7aaSRajesh Borundia 719f197a7aaSRajesh Borundia static inline int qlcnic_sriov_alloc_bc_msg(struct qlcnic_bc_hdr **hdr, 720f197a7aaSRajesh Borundia u32 size) 721f197a7aaSRajesh Borundia { 722f197a7aaSRajesh Borundia *hdr = kzalloc(sizeof(struct qlcnic_bc_hdr) * size, GFP_ATOMIC); 723f197a7aaSRajesh Borundia if (!*hdr) 724f197a7aaSRajesh Borundia return -ENOMEM; 725f197a7aaSRajesh Borundia 726f197a7aaSRajesh Borundia return 0; 727f197a7aaSRajesh Borundia } 728f197a7aaSRajesh Borundia 729f197a7aaSRajesh Borundia static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type) 730f197a7aaSRajesh Borundia { 731f197a7aaSRajesh Borundia const struct qlcnic_mailbox_metadata *mbx_tbl; 732f197a7aaSRajesh Borundia int i, size; 733f197a7aaSRajesh Borundia 734f197a7aaSRajesh Borundia mbx_tbl = qlcnic_sriov_bc_mbx_tbl; 735f197a7aaSRajesh Borundia size = ARRAY_SIZE(qlcnic_sriov_bc_mbx_tbl); 736f197a7aaSRajesh Borundia 737f197a7aaSRajesh Borundia for (i = 0; i < size; i++) { 738f197a7aaSRajesh Borundia if (type == mbx_tbl[i].cmd) { 739f197a7aaSRajesh Borundia mbx->op_type = QLC_BC_CMD; 740f197a7aaSRajesh Borundia mbx->req.num = mbx_tbl[i].in_args; 741f197a7aaSRajesh Borundia mbx->rsp.num = mbx_tbl[i].out_args; 742f197a7aaSRajesh Borundia mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32), 743f197a7aaSRajesh Borundia GFP_ATOMIC); 744f197a7aaSRajesh Borundia if (!mbx->req.arg) 745f197a7aaSRajesh Borundia return -ENOMEM; 746f197a7aaSRajesh Borundia mbx->rsp.arg = kcalloc(mbx->rsp.num, sizeof(u32), 747f197a7aaSRajesh Borundia GFP_ATOMIC); 748f197a7aaSRajesh Borundia if (!mbx->rsp.arg) { 749f197a7aaSRajesh Borundia kfree(mbx->req.arg); 750f197a7aaSRajesh Borundia mbx->req.arg = NULL; 751f197a7aaSRajesh Borundia return -ENOMEM; 752f197a7aaSRajesh Borundia } 753f197a7aaSRajesh Borundia memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num); 754f197a7aaSRajesh Borundia memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num); 755f197a7aaSRajesh Borundia mbx->req.arg[0] = (type | (mbx->req.num << 16) | 756f197a7aaSRajesh Borundia (3 << 29)); 757f197a7aaSRajesh Borundia return 0; 758f197a7aaSRajesh Borundia } 759f197a7aaSRajesh Borundia } 760f197a7aaSRajesh Borundia return -EINVAL; 761f197a7aaSRajesh Borundia } 762f197a7aaSRajesh Borundia 763f197a7aaSRajesh Borundia static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans, 764f197a7aaSRajesh Borundia struct qlcnic_cmd_args *cmd, 765f197a7aaSRajesh Borundia u16 seq, u8 msg_type) 766f197a7aaSRajesh Borundia { 767f197a7aaSRajesh Borundia struct qlcnic_bc_hdr *hdr; 768f197a7aaSRajesh Borundia int i; 769f197a7aaSRajesh Borundia u32 num_regs, bc_pay_sz; 770f197a7aaSRajesh Borundia u16 remainder; 771f197a7aaSRajesh Borundia u8 cmd_op, num_frags, t_num_frags; 772f197a7aaSRajesh Borundia 773f197a7aaSRajesh Borundia bc_pay_sz = QLC_BC_PAYLOAD_SZ; 774f197a7aaSRajesh Borundia if (msg_type == QLC_BC_COMMAND) { 775f197a7aaSRajesh Borundia trans->req_pay = (struct qlcnic_bc_payload *)cmd->req.arg; 776f197a7aaSRajesh Borundia trans->rsp_pay = (struct qlcnic_bc_payload *)cmd->rsp.arg; 777f197a7aaSRajesh Borundia num_regs = cmd->req.num; 778f197a7aaSRajesh Borundia trans->req_pay_size = (num_regs * 4); 779f197a7aaSRajesh Borundia num_regs = cmd->rsp.num; 780f197a7aaSRajesh Borundia trans->rsp_pay_size = (num_regs * 4); 781f197a7aaSRajesh Borundia cmd_op = cmd->req.arg[0] & 0xff; 782f197a7aaSRajesh Borundia remainder = (trans->req_pay_size) % (bc_pay_sz); 783f197a7aaSRajesh Borundia num_frags = (trans->req_pay_size) / (bc_pay_sz); 784f197a7aaSRajesh Borundia if (remainder) 785f197a7aaSRajesh Borundia num_frags++; 786f197a7aaSRajesh Borundia t_num_frags = num_frags; 787f197a7aaSRajesh Borundia if (qlcnic_sriov_alloc_bc_msg(&trans->req_hdr, num_frags)) 788f197a7aaSRajesh Borundia return -ENOMEM; 789f197a7aaSRajesh Borundia remainder = (trans->rsp_pay_size) % (bc_pay_sz); 790f197a7aaSRajesh Borundia num_frags = (trans->rsp_pay_size) / (bc_pay_sz); 791f197a7aaSRajesh Borundia if (remainder) 792f197a7aaSRajesh Borundia num_frags++; 793f197a7aaSRajesh Borundia if (qlcnic_sriov_alloc_bc_msg(&trans->rsp_hdr, num_frags)) 794f197a7aaSRajesh Borundia return -ENOMEM; 795f197a7aaSRajesh Borundia num_frags = t_num_frags; 796f197a7aaSRajesh Borundia hdr = trans->req_hdr; 797f197a7aaSRajesh Borundia } else { 798f197a7aaSRajesh Borundia cmd->req.arg = (u32 *)trans->req_pay; 799f197a7aaSRajesh Borundia cmd->rsp.arg = (u32 *)trans->rsp_pay; 800f197a7aaSRajesh Borundia cmd_op = cmd->req.arg[0] & 0xff; 801f197a7aaSRajesh Borundia remainder = (trans->rsp_pay_size) % (bc_pay_sz); 802f197a7aaSRajesh Borundia num_frags = (trans->rsp_pay_size) / (bc_pay_sz); 803f197a7aaSRajesh Borundia if (remainder) 804f197a7aaSRajesh Borundia num_frags++; 805f197a7aaSRajesh Borundia cmd->req.num = trans->req_pay_size / 4; 806f197a7aaSRajesh Borundia cmd->rsp.num = trans->rsp_pay_size / 4; 807f197a7aaSRajesh Borundia hdr = trans->rsp_hdr; 808f197a7aaSRajesh Borundia } 809f197a7aaSRajesh Borundia 810f197a7aaSRajesh Borundia trans->trans_id = seq; 811f197a7aaSRajesh Borundia trans->cmd_id = cmd_op; 812f197a7aaSRajesh Borundia for (i = 0; i < num_frags; i++) { 813f197a7aaSRajesh Borundia hdr[i].version = 2; 814f197a7aaSRajesh Borundia hdr[i].msg_type = msg_type; 815f197a7aaSRajesh Borundia hdr[i].op_type = cmd->op_type; 816f197a7aaSRajesh Borundia hdr[i].num_cmds = 1; 817f197a7aaSRajesh Borundia hdr[i].num_frags = num_frags; 818f197a7aaSRajesh Borundia hdr[i].frag_num = i + 1; 819f197a7aaSRajesh Borundia hdr[i].cmd_op = cmd_op; 820f197a7aaSRajesh Borundia hdr[i].seq_id = seq; 821f197a7aaSRajesh Borundia } 822f197a7aaSRajesh Borundia return 0; 823f197a7aaSRajesh Borundia } 824f197a7aaSRajesh Borundia 825f197a7aaSRajesh Borundia static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *trans) 826f197a7aaSRajesh Borundia { 827f197a7aaSRajesh Borundia if (!trans) 828f197a7aaSRajesh Borundia return; 829f197a7aaSRajesh Borundia kfree(trans->req_hdr); 830f197a7aaSRajesh Borundia kfree(trans->rsp_hdr); 831f197a7aaSRajesh Borundia kfree(trans); 832f197a7aaSRajesh Borundia } 833f197a7aaSRajesh Borundia 834f197a7aaSRajesh Borundia static int qlcnic_sriov_clear_trans(struct qlcnic_vf_info *vf, 835f197a7aaSRajesh Borundia struct qlcnic_bc_trans *trans, u8 type) 836f197a7aaSRajesh Borundia { 837f197a7aaSRajesh Borundia struct qlcnic_trans_list *t_list; 838f197a7aaSRajesh Borundia unsigned long flags; 839f197a7aaSRajesh Borundia int ret = 0; 840f197a7aaSRajesh Borundia 841f197a7aaSRajesh Borundia if (type == QLC_BC_RESPONSE) { 842f197a7aaSRajesh Borundia t_list = &vf->rcv_act; 843f197a7aaSRajesh Borundia spin_lock_irqsave(&t_list->lock, flags); 844f197a7aaSRajesh Borundia t_list->count--; 845f197a7aaSRajesh Borundia list_del(&trans->list); 846f197a7aaSRajesh Borundia if (t_list->count > 0) 847f197a7aaSRajesh Borundia ret = 1; 848f197a7aaSRajesh Borundia spin_unlock_irqrestore(&t_list->lock, flags); 849f197a7aaSRajesh Borundia } 850f197a7aaSRajesh Borundia if (type == QLC_BC_COMMAND) { 851f197a7aaSRajesh Borundia while (test_and_set_bit(QLC_BC_VF_SEND, &vf->state)) 852f197a7aaSRajesh Borundia msleep(100); 853f197a7aaSRajesh Borundia vf->send_cmd = NULL; 854f197a7aaSRajesh Borundia clear_bit(QLC_BC_VF_SEND, &vf->state); 855f197a7aaSRajesh Borundia } 856f197a7aaSRajesh Borundia return ret; 857f197a7aaSRajesh Borundia } 858f197a7aaSRajesh Borundia 859f197a7aaSRajesh Borundia static void qlcnic_sriov_schedule_bc_cmd(struct qlcnic_sriov *sriov, 860f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf, 861f197a7aaSRajesh Borundia work_func_t func) 862f197a7aaSRajesh Borundia { 863f036e4f4SRajesh Borundia if (test_bit(QLC_BC_VF_FLR, &vf->state) || 864f036e4f4SRajesh Borundia vf->adapter->need_fw_reset) 86597d8105cSRajesh Borundia return; 86697d8105cSRajesh Borundia 867f197a7aaSRajesh Borundia INIT_WORK(&vf->trans_work, func); 868f197a7aaSRajesh Borundia queue_work(sriov->bc.bc_trans_wq, &vf->trans_work); 869f197a7aaSRajesh Borundia } 870f197a7aaSRajesh Borundia 871f197a7aaSRajesh Borundia static inline void qlcnic_sriov_wait_for_resp(struct qlcnic_bc_trans *trans) 872f197a7aaSRajesh Borundia { 873f197a7aaSRajesh Borundia struct completion *cmpl = &trans->resp_cmpl; 874f197a7aaSRajesh Borundia 875f197a7aaSRajesh Borundia if (wait_for_completion_timeout(cmpl, QLC_MBOX_RESP_TIMEOUT)) 876f197a7aaSRajesh Borundia trans->trans_state = QLC_END; 877f197a7aaSRajesh Borundia else 878f197a7aaSRajesh Borundia trans->trans_state = QLC_ABORT; 879f197a7aaSRajesh Borundia 880f197a7aaSRajesh Borundia return; 881f197a7aaSRajesh Borundia } 882f197a7aaSRajesh Borundia 883f197a7aaSRajesh Borundia static void qlcnic_sriov_handle_multi_frags(struct qlcnic_bc_trans *trans, 884f197a7aaSRajesh Borundia u8 type) 885f197a7aaSRajesh Borundia { 886f197a7aaSRajesh Borundia if (type == QLC_BC_RESPONSE) { 887f197a7aaSRajesh Borundia trans->curr_rsp_frag++; 888f197a7aaSRajesh Borundia if (trans->curr_rsp_frag < trans->rsp_hdr->num_frags) 889f197a7aaSRajesh Borundia trans->trans_state = QLC_INIT; 890f197a7aaSRajesh Borundia else 891f197a7aaSRajesh Borundia trans->trans_state = QLC_END; 892f197a7aaSRajesh Borundia } else { 893f197a7aaSRajesh Borundia trans->curr_req_frag++; 894f197a7aaSRajesh Borundia if (trans->curr_req_frag < trans->req_hdr->num_frags) 895f197a7aaSRajesh Borundia trans->trans_state = QLC_INIT; 896f197a7aaSRajesh Borundia else 897f197a7aaSRajesh Borundia trans->trans_state = QLC_WAIT_FOR_RESP; 898f197a7aaSRajesh Borundia } 899f197a7aaSRajesh Borundia } 900f197a7aaSRajesh Borundia 901f197a7aaSRajesh Borundia static void qlcnic_sriov_wait_for_channel_free(struct qlcnic_bc_trans *trans, 902f197a7aaSRajesh Borundia u8 type) 903f197a7aaSRajesh Borundia { 904f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf = trans->vf; 905f197a7aaSRajesh Borundia struct completion *cmpl = &vf->ch_free_cmpl; 906f197a7aaSRajesh Borundia 907f197a7aaSRajesh Borundia if (!wait_for_completion_timeout(cmpl, QLC_MBOX_CH_FREE_TIMEOUT)) { 908f197a7aaSRajesh Borundia trans->trans_state = QLC_ABORT; 909f197a7aaSRajesh Borundia return; 910f197a7aaSRajesh Borundia } 911f197a7aaSRajesh Borundia 912f197a7aaSRajesh Borundia clear_bit(QLC_BC_VF_CHANNEL, &vf->state); 913f197a7aaSRajesh Borundia qlcnic_sriov_handle_multi_frags(trans, type); 914f197a7aaSRajesh Borundia } 915f197a7aaSRajesh Borundia 916f197a7aaSRajesh Borundia static void qlcnic_sriov_pull_bc_msg(struct qlcnic_adapter *adapter, 917f197a7aaSRajesh Borundia u32 *hdr, u32 *pay, u32 size) 918f197a7aaSRajesh Borundia { 919f197a7aaSRajesh Borundia struct qlcnic_hardware_context *ahw = adapter->ahw; 920f197a7aaSRajesh Borundia u32 fw_mbx; 921f197a7aaSRajesh Borundia u8 i, max = 2, hdr_size, j; 922f197a7aaSRajesh Borundia 923f197a7aaSRajesh Borundia hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); 924f197a7aaSRajesh Borundia max = (size / sizeof(u32)) + hdr_size; 925f197a7aaSRajesh Borundia 926f197a7aaSRajesh Borundia fw_mbx = readl(QLCNIC_MBX_FW(ahw, 0)); 927f197a7aaSRajesh Borundia for (i = 2, j = 0; j < hdr_size; i++, j++) 928f197a7aaSRajesh Borundia *(hdr++) = readl(QLCNIC_MBX_FW(ahw, i)); 929f197a7aaSRajesh Borundia for (; j < max; i++, j++) 930f197a7aaSRajesh Borundia *(pay++) = readl(QLCNIC_MBX_FW(ahw, i)); 931f197a7aaSRajesh Borundia } 932f197a7aaSRajesh Borundia 933f197a7aaSRajesh Borundia static int __qlcnic_sriov_issue_bc_post(struct qlcnic_vf_info *vf) 934f197a7aaSRajesh Borundia { 935f197a7aaSRajesh Borundia int ret = -EBUSY; 936f197a7aaSRajesh Borundia u32 timeout = 10000; 937f197a7aaSRajesh Borundia 938f197a7aaSRajesh Borundia do { 939f197a7aaSRajesh Borundia if (!test_and_set_bit(QLC_BC_VF_CHANNEL, &vf->state)) { 940f197a7aaSRajesh Borundia ret = 0; 941f197a7aaSRajesh Borundia break; 942f197a7aaSRajesh Borundia } 943f197a7aaSRajesh Borundia mdelay(1); 944f197a7aaSRajesh Borundia } while (--timeout); 945f197a7aaSRajesh Borundia 946f197a7aaSRajesh Borundia return ret; 947f197a7aaSRajesh Borundia } 948f197a7aaSRajesh Borundia 949f197a7aaSRajesh Borundia static int qlcnic_sriov_issue_bc_post(struct qlcnic_bc_trans *trans, u8 type) 950f197a7aaSRajesh Borundia { 951f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf = trans->vf; 952f197a7aaSRajesh Borundia u32 pay_size, hdr_size; 953f197a7aaSRajesh Borundia u32 *hdr, *pay; 954f197a7aaSRajesh Borundia int ret; 955f197a7aaSRajesh Borundia u8 pci_func = trans->func_id; 956f197a7aaSRajesh Borundia 957f197a7aaSRajesh Borundia if (__qlcnic_sriov_issue_bc_post(vf)) 958f197a7aaSRajesh Borundia return -EBUSY; 959f197a7aaSRajesh Borundia 960f197a7aaSRajesh Borundia if (type == QLC_BC_COMMAND) { 961f197a7aaSRajesh Borundia hdr = (u32 *)(trans->req_hdr + trans->curr_req_frag); 962f197a7aaSRajesh Borundia pay = (u32 *)(trans->req_pay + trans->curr_req_frag); 963f197a7aaSRajesh Borundia hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); 964f197a7aaSRajesh Borundia pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size, 965f197a7aaSRajesh Borundia trans->curr_req_frag); 966f197a7aaSRajesh Borundia pay_size = (pay_size / sizeof(u32)); 967f197a7aaSRajesh Borundia } else { 968f197a7aaSRajesh Borundia hdr = (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag); 969f197a7aaSRajesh Borundia pay = (u32 *)(trans->rsp_pay + trans->curr_rsp_frag); 970f197a7aaSRajesh Borundia hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); 971f197a7aaSRajesh Borundia pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size, 972f197a7aaSRajesh Borundia trans->curr_rsp_frag); 973f197a7aaSRajesh Borundia pay_size = (pay_size / sizeof(u32)); 974f197a7aaSRajesh Borundia } 975f197a7aaSRajesh Borundia 976f197a7aaSRajesh Borundia ret = qlcnic_sriov_post_bc_msg(vf->adapter, hdr, pay, 977f197a7aaSRajesh Borundia pci_func, pay_size); 978f197a7aaSRajesh Borundia return ret; 979f197a7aaSRajesh Borundia } 980f197a7aaSRajesh Borundia 981f197a7aaSRajesh Borundia static int __qlcnic_sriov_send_bc_msg(struct qlcnic_bc_trans *trans, 982f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf, u8 type) 983f197a7aaSRajesh Borundia { 984f197a7aaSRajesh Borundia bool flag = true; 98597d8105cSRajesh Borundia int err = -EIO; 986f197a7aaSRajesh Borundia 987f197a7aaSRajesh Borundia while (flag) { 988f036e4f4SRajesh Borundia if (test_bit(QLC_BC_VF_FLR, &vf->state) || 989f036e4f4SRajesh Borundia vf->adapter->need_fw_reset) 99097d8105cSRajesh Borundia trans->trans_state = QLC_ABORT; 99197d8105cSRajesh Borundia 992f197a7aaSRajesh Borundia switch (trans->trans_state) { 993f197a7aaSRajesh Borundia case QLC_INIT: 994f197a7aaSRajesh Borundia trans->trans_state = QLC_WAIT_FOR_CHANNEL_FREE; 995f197a7aaSRajesh Borundia if (qlcnic_sriov_issue_bc_post(trans, type)) 996f197a7aaSRajesh Borundia trans->trans_state = QLC_ABORT; 997f197a7aaSRajesh Borundia break; 998f197a7aaSRajesh Borundia case QLC_WAIT_FOR_CHANNEL_FREE: 999f197a7aaSRajesh Borundia qlcnic_sriov_wait_for_channel_free(trans, type); 1000f197a7aaSRajesh Borundia break; 1001f197a7aaSRajesh Borundia case QLC_WAIT_FOR_RESP: 1002f197a7aaSRajesh Borundia qlcnic_sriov_wait_for_resp(trans); 1003f197a7aaSRajesh Borundia break; 1004f197a7aaSRajesh Borundia case QLC_END: 1005f197a7aaSRajesh Borundia err = 0; 1006f197a7aaSRajesh Borundia flag = false; 1007f197a7aaSRajesh Borundia break; 1008f197a7aaSRajesh Borundia case QLC_ABORT: 1009f197a7aaSRajesh Borundia err = -EIO; 1010f197a7aaSRajesh Borundia flag = false; 1011f197a7aaSRajesh Borundia clear_bit(QLC_BC_VF_CHANNEL, &vf->state); 1012f197a7aaSRajesh Borundia break; 1013f197a7aaSRajesh Borundia default: 1014f197a7aaSRajesh Borundia err = -EIO; 1015f197a7aaSRajesh Borundia flag = false; 1016f197a7aaSRajesh Borundia } 1017f197a7aaSRajesh Borundia } 1018f197a7aaSRajesh Borundia return err; 1019f197a7aaSRajesh Borundia } 1020f197a7aaSRajesh Borundia 1021f197a7aaSRajesh Borundia static int qlcnic_sriov_send_bc_cmd(struct qlcnic_adapter *adapter, 1022f197a7aaSRajesh Borundia struct qlcnic_bc_trans *trans, int pci_func) 1023f197a7aaSRajesh Borundia { 1024f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf; 1025f197a7aaSRajesh Borundia int err, index = qlcnic_sriov_func_to_index(adapter, pci_func); 1026f197a7aaSRajesh Borundia 1027f197a7aaSRajesh Borundia if (index < 0) 1028f197a7aaSRajesh Borundia return -EIO; 1029f197a7aaSRajesh Borundia 1030f197a7aaSRajesh Borundia vf = &adapter->ahw->sriov->vf_info[index]; 1031f197a7aaSRajesh Borundia trans->vf = vf; 1032f197a7aaSRajesh Borundia trans->func_id = pci_func; 1033f197a7aaSRajesh Borundia 1034f197a7aaSRajesh Borundia if (!test_bit(QLC_BC_VF_STATE, &vf->state)) { 1035f197a7aaSRajesh Borundia if (qlcnic_sriov_pf_check(adapter)) 1036f197a7aaSRajesh Borundia return -EIO; 1037f197a7aaSRajesh Borundia if (qlcnic_sriov_vf_check(adapter) && 1038f197a7aaSRajesh Borundia trans->cmd_id != QLCNIC_BC_CMD_CHANNEL_INIT) 1039f197a7aaSRajesh Borundia return -EIO; 1040f197a7aaSRajesh Borundia } 1041f197a7aaSRajesh Borundia 1042f197a7aaSRajesh Borundia mutex_lock(&vf->send_cmd_lock); 1043f197a7aaSRajesh Borundia vf->send_cmd = trans; 1044f197a7aaSRajesh Borundia err = __qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_COMMAND); 1045f197a7aaSRajesh Borundia qlcnic_sriov_clear_trans(vf, trans, QLC_BC_COMMAND); 1046f197a7aaSRajesh Borundia mutex_unlock(&vf->send_cmd_lock); 1047f197a7aaSRajesh Borundia return err; 1048f197a7aaSRajesh Borundia } 1049f197a7aaSRajesh Borundia 1050f197a7aaSRajesh Borundia static void __qlcnic_sriov_process_bc_cmd(struct qlcnic_adapter *adapter, 1051f197a7aaSRajesh Borundia struct qlcnic_bc_trans *trans, 1052f197a7aaSRajesh Borundia struct qlcnic_cmd_args *cmd) 1053f197a7aaSRajesh Borundia { 1054f197a7aaSRajesh Borundia #ifdef CONFIG_QLCNIC_SRIOV 1055f197a7aaSRajesh Borundia if (qlcnic_sriov_pf_check(adapter)) { 1056f197a7aaSRajesh Borundia qlcnic_sriov_pf_process_bc_cmd(adapter, trans, cmd); 1057f197a7aaSRajesh Borundia return; 1058f197a7aaSRajesh Borundia } 1059f197a7aaSRajesh Borundia #endif 1060f197a7aaSRajesh Borundia cmd->rsp.arg[0] |= (0x9 << 25); 1061f197a7aaSRajesh Borundia return; 1062f197a7aaSRajesh Borundia } 1063f197a7aaSRajesh Borundia 1064f197a7aaSRajesh Borundia static void qlcnic_sriov_process_bc_cmd(struct work_struct *work) 1065f197a7aaSRajesh Borundia { 1066f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf = container_of(work, struct qlcnic_vf_info, 1067f197a7aaSRajesh Borundia trans_work); 1068f197a7aaSRajesh Borundia struct qlcnic_bc_trans *trans = NULL; 1069f197a7aaSRajesh Borundia struct qlcnic_adapter *adapter = vf->adapter; 1070f197a7aaSRajesh Borundia struct qlcnic_cmd_args cmd; 1071f197a7aaSRajesh Borundia u8 req; 1072f197a7aaSRajesh Borundia 1073f036e4f4SRajesh Borundia if (adapter->need_fw_reset) 1074f036e4f4SRajesh Borundia return; 1075f036e4f4SRajesh Borundia 107697d8105cSRajesh Borundia if (test_bit(QLC_BC_VF_FLR, &vf->state)) 107797d8105cSRajesh Borundia return; 107897d8105cSRajesh Borundia 1079f197a7aaSRajesh Borundia trans = list_first_entry(&vf->rcv_act.wait_list, 1080f197a7aaSRajesh Borundia struct qlcnic_bc_trans, list); 1081f197a7aaSRajesh Borundia adapter = vf->adapter; 1082f197a7aaSRajesh Borundia 1083f197a7aaSRajesh Borundia if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, trans->req_hdr->seq_id, 1084f197a7aaSRajesh Borundia QLC_BC_RESPONSE)) 1085f197a7aaSRajesh Borundia goto cleanup_trans; 1086f197a7aaSRajesh Borundia 1087f197a7aaSRajesh Borundia __qlcnic_sriov_process_bc_cmd(adapter, trans, &cmd); 1088f197a7aaSRajesh Borundia trans->trans_state = QLC_INIT; 1089f197a7aaSRajesh Borundia __qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_RESPONSE); 1090f197a7aaSRajesh Borundia 1091f197a7aaSRajesh Borundia cleanup_trans: 1092f197a7aaSRajesh Borundia qlcnic_free_mbx_args(&cmd); 1093f197a7aaSRajesh Borundia req = qlcnic_sriov_clear_trans(vf, trans, QLC_BC_RESPONSE); 1094f197a7aaSRajesh Borundia qlcnic_sriov_cleanup_transaction(trans); 1095f197a7aaSRajesh Borundia if (req) 1096f197a7aaSRajesh Borundia qlcnic_sriov_schedule_bc_cmd(adapter->ahw->sriov, vf, 1097f197a7aaSRajesh Borundia qlcnic_sriov_process_bc_cmd); 1098f197a7aaSRajesh Borundia } 1099f197a7aaSRajesh Borundia 1100f197a7aaSRajesh Borundia static void qlcnic_sriov_handle_bc_resp(struct qlcnic_bc_hdr *hdr, 1101f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf) 1102f197a7aaSRajesh Borundia { 1103f197a7aaSRajesh Borundia struct qlcnic_bc_trans *trans; 1104f197a7aaSRajesh Borundia u32 pay_size; 1105f197a7aaSRajesh Borundia 1106f197a7aaSRajesh Borundia if (test_and_set_bit(QLC_BC_VF_SEND, &vf->state)) 1107f197a7aaSRajesh Borundia return; 1108f197a7aaSRajesh Borundia 1109f197a7aaSRajesh Borundia trans = vf->send_cmd; 1110f197a7aaSRajesh Borundia 1111f197a7aaSRajesh Borundia if (trans == NULL) 1112f197a7aaSRajesh Borundia goto clear_send; 1113f197a7aaSRajesh Borundia 1114f197a7aaSRajesh Borundia if (trans->trans_id != hdr->seq_id) 1115f197a7aaSRajesh Borundia goto clear_send; 1116f197a7aaSRajesh Borundia 1117f197a7aaSRajesh Borundia pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size, 1118f197a7aaSRajesh Borundia trans->curr_rsp_frag); 1119f197a7aaSRajesh Borundia qlcnic_sriov_pull_bc_msg(vf->adapter, 1120f197a7aaSRajesh Borundia (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag), 1121f197a7aaSRajesh Borundia (u32 *)(trans->rsp_pay + trans->curr_rsp_frag), 1122f197a7aaSRajesh Borundia pay_size); 1123f197a7aaSRajesh Borundia if (++trans->curr_rsp_frag < trans->rsp_hdr->num_frags) 1124f197a7aaSRajesh Borundia goto clear_send; 1125f197a7aaSRajesh Borundia 1126f197a7aaSRajesh Borundia complete(&trans->resp_cmpl); 1127f197a7aaSRajesh Borundia 1128f197a7aaSRajesh Borundia clear_send: 1129f197a7aaSRajesh Borundia clear_bit(QLC_BC_VF_SEND, &vf->state); 1130f197a7aaSRajesh Borundia } 1131f197a7aaSRajesh Borundia 113297d8105cSRajesh Borundia int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov, 113397d8105cSRajesh Borundia struct qlcnic_vf_info *vf, 113497d8105cSRajesh Borundia struct qlcnic_bc_trans *trans) 113597d8105cSRajesh Borundia { 113697d8105cSRajesh Borundia struct qlcnic_trans_list *t_list = &vf->rcv_act; 113797d8105cSRajesh Borundia 113897d8105cSRajesh Borundia t_list->count++; 113997d8105cSRajesh Borundia list_add_tail(&trans->list, &t_list->wait_list); 114097d8105cSRajesh Borundia if (t_list->count == 1) 114197d8105cSRajesh Borundia qlcnic_sriov_schedule_bc_cmd(sriov, vf, 114297d8105cSRajesh Borundia qlcnic_sriov_process_bc_cmd); 114397d8105cSRajesh Borundia return 0; 114497d8105cSRajesh Borundia } 114597d8105cSRajesh Borundia 1146f197a7aaSRajesh Borundia static int qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov, 1147f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf, 1148f197a7aaSRajesh Borundia struct qlcnic_bc_trans *trans) 1149f197a7aaSRajesh Borundia { 1150f197a7aaSRajesh Borundia struct qlcnic_trans_list *t_list = &vf->rcv_act; 1151f197a7aaSRajesh Borundia 1152f197a7aaSRajesh Borundia spin_lock(&t_list->lock); 115397d8105cSRajesh Borundia 115497d8105cSRajesh Borundia __qlcnic_sriov_add_act_list(sriov, vf, trans); 115597d8105cSRajesh Borundia 1156f197a7aaSRajesh Borundia spin_unlock(&t_list->lock); 1157f197a7aaSRajesh Borundia return 0; 1158f197a7aaSRajesh Borundia } 1159f197a7aaSRajesh Borundia 1160f197a7aaSRajesh Borundia static void qlcnic_sriov_handle_pending_trans(struct qlcnic_sriov *sriov, 1161f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf, 1162f197a7aaSRajesh Borundia struct qlcnic_bc_hdr *hdr) 1163f197a7aaSRajesh Borundia { 1164f197a7aaSRajesh Borundia struct qlcnic_bc_trans *trans = NULL; 1165f197a7aaSRajesh Borundia struct list_head *node; 1166f197a7aaSRajesh Borundia u32 pay_size, curr_frag; 1167f197a7aaSRajesh Borundia u8 found = 0, active = 0; 1168f197a7aaSRajesh Borundia 1169f197a7aaSRajesh Borundia spin_lock(&vf->rcv_pend.lock); 1170f197a7aaSRajesh Borundia if (vf->rcv_pend.count > 0) { 1171f197a7aaSRajesh Borundia list_for_each(node, &vf->rcv_pend.wait_list) { 1172f197a7aaSRajesh Borundia trans = list_entry(node, struct qlcnic_bc_trans, list); 1173f197a7aaSRajesh Borundia if (trans->trans_id == hdr->seq_id) { 1174f197a7aaSRajesh Borundia found = 1; 1175f197a7aaSRajesh Borundia break; 1176f197a7aaSRajesh Borundia } 1177f197a7aaSRajesh Borundia } 1178f197a7aaSRajesh Borundia } 1179f197a7aaSRajesh Borundia 1180f197a7aaSRajesh Borundia if (found) { 1181f197a7aaSRajesh Borundia curr_frag = trans->curr_req_frag; 1182f197a7aaSRajesh Borundia pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size, 1183f197a7aaSRajesh Borundia curr_frag); 1184f197a7aaSRajesh Borundia qlcnic_sriov_pull_bc_msg(vf->adapter, 1185f197a7aaSRajesh Borundia (u32 *)(trans->req_hdr + curr_frag), 1186f197a7aaSRajesh Borundia (u32 *)(trans->req_pay + curr_frag), 1187f197a7aaSRajesh Borundia pay_size); 1188f197a7aaSRajesh Borundia trans->curr_req_frag++; 1189f197a7aaSRajesh Borundia if (trans->curr_req_frag >= hdr->num_frags) { 1190f197a7aaSRajesh Borundia vf->rcv_pend.count--; 1191f197a7aaSRajesh Borundia list_del(&trans->list); 1192f197a7aaSRajesh Borundia active = 1; 1193f197a7aaSRajesh Borundia } 1194f197a7aaSRajesh Borundia } 1195f197a7aaSRajesh Borundia spin_unlock(&vf->rcv_pend.lock); 1196f197a7aaSRajesh Borundia 1197f197a7aaSRajesh Borundia if (active) 1198f197a7aaSRajesh Borundia if (qlcnic_sriov_add_act_list(sriov, vf, trans)) 1199f197a7aaSRajesh Borundia qlcnic_sriov_cleanup_transaction(trans); 1200f197a7aaSRajesh Borundia 1201f197a7aaSRajesh Borundia return; 1202f197a7aaSRajesh Borundia } 1203f197a7aaSRajesh Borundia 1204f197a7aaSRajesh Borundia static void qlcnic_sriov_handle_bc_cmd(struct qlcnic_sriov *sriov, 1205f197a7aaSRajesh Borundia struct qlcnic_bc_hdr *hdr, 1206f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf) 1207f197a7aaSRajesh Borundia { 1208f197a7aaSRajesh Borundia struct qlcnic_bc_trans *trans; 1209f197a7aaSRajesh Borundia struct qlcnic_adapter *adapter = vf->adapter; 1210f197a7aaSRajesh Borundia struct qlcnic_cmd_args cmd; 1211f197a7aaSRajesh Borundia u32 pay_size; 1212f197a7aaSRajesh Borundia int err; 1213f197a7aaSRajesh Borundia u8 cmd_op; 1214f197a7aaSRajesh Borundia 1215f036e4f4SRajesh Borundia if (adapter->need_fw_reset) 1216f036e4f4SRajesh Borundia return; 1217f036e4f4SRajesh Borundia 1218f197a7aaSRajesh Borundia if (!test_bit(QLC_BC_VF_STATE, &vf->state) && 1219f197a7aaSRajesh Borundia hdr->op_type != QLC_BC_CMD && 1220f197a7aaSRajesh Borundia hdr->cmd_op != QLCNIC_BC_CMD_CHANNEL_INIT) 1221f197a7aaSRajesh Borundia return; 1222f197a7aaSRajesh Borundia 1223f197a7aaSRajesh Borundia if (hdr->frag_num > 1) { 1224f197a7aaSRajesh Borundia qlcnic_sriov_handle_pending_trans(sriov, vf, hdr); 1225f197a7aaSRajesh Borundia return; 1226f197a7aaSRajesh Borundia } 1227f197a7aaSRajesh Borundia 1228f197a7aaSRajesh Borundia cmd_op = hdr->cmd_op; 1229f197a7aaSRajesh Borundia if (qlcnic_sriov_alloc_bc_trans(&trans)) 1230f197a7aaSRajesh Borundia return; 1231f197a7aaSRajesh Borundia 1232f197a7aaSRajesh Borundia if (hdr->op_type == QLC_BC_CMD) 1233f197a7aaSRajesh Borundia err = qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op); 1234f197a7aaSRajesh Borundia else 1235f197a7aaSRajesh Borundia err = qlcnic_alloc_mbx_args(&cmd, adapter, cmd_op); 1236f197a7aaSRajesh Borundia 1237f197a7aaSRajesh Borundia if (err) { 1238f197a7aaSRajesh Borundia qlcnic_sriov_cleanup_transaction(trans); 1239f197a7aaSRajesh Borundia return; 1240f197a7aaSRajesh Borundia } 1241f197a7aaSRajesh Borundia 1242f197a7aaSRajesh Borundia cmd.op_type = hdr->op_type; 1243f197a7aaSRajesh Borundia if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, hdr->seq_id, 1244f197a7aaSRajesh Borundia QLC_BC_COMMAND)) { 1245f197a7aaSRajesh Borundia qlcnic_free_mbx_args(&cmd); 1246f197a7aaSRajesh Borundia qlcnic_sriov_cleanup_transaction(trans); 1247f197a7aaSRajesh Borundia return; 1248f197a7aaSRajesh Borundia } 1249f197a7aaSRajesh Borundia 1250f197a7aaSRajesh Borundia pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size, 1251f197a7aaSRajesh Borundia trans->curr_req_frag); 1252f197a7aaSRajesh Borundia qlcnic_sriov_pull_bc_msg(vf->adapter, 1253f197a7aaSRajesh Borundia (u32 *)(trans->req_hdr + trans->curr_req_frag), 1254f197a7aaSRajesh Borundia (u32 *)(trans->req_pay + trans->curr_req_frag), 1255f197a7aaSRajesh Borundia pay_size); 1256f197a7aaSRajesh Borundia trans->func_id = vf->pci_func; 1257f197a7aaSRajesh Borundia trans->vf = vf; 1258f197a7aaSRajesh Borundia trans->trans_id = hdr->seq_id; 1259f197a7aaSRajesh Borundia trans->curr_req_frag++; 126097d8105cSRajesh Borundia 126197d8105cSRajesh Borundia if (qlcnic_sriov_soft_flr_check(adapter, trans, vf)) 126297d8105cSRajesh Borundia return; 126397d8105cSRajesh Borundia 1264f197a7aaSRajesh Borundia if (trans->curr_req_frag == trans->req_hdr->num_frags) { 1265f197a7aaSRajesh Borundia if (qlcnic_sriov_add_act_list(sriov, vf, trans)) { 1266f197a7aaSRajesh Borundia qlcnic_free_mbx_args(&cmd); 1267f197a7aaSRajesh Borundia qlcnic_sriov_cleanup_transaction(trans); 1268f197a7aaSRajesh Borundia } 1269f197a7aaSRajesh Borundia } else { 1270f197a7aaSRajesh Borundia spin_lock(&vf->rcv_pend.lock); 1271f197a7aaSRajesh Borundia list_add_tail(&trans->list, &vf->rcv_pend.wait_list); 1272f197a7aaSRajesh Borundia vf->rcv_pend.count++; 1273f197a7aaSRajesh Borundia spin_unlock(&vf->rcv_pend.lock); 1274f197a7aaSRajesh Borundia } 1275f197a7aaSRajesh Borundia } 1276f197a7aaSRajesh Borundia 1277f197a7aaSRajesh Borundia static void qlcnic_sriov_handle_msg_event(struct qlcnic_sriov *sriov, 1278f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf) 1279f197a7aaSRajesh Borundia { 1280f197a7aaSRajesh Borundia struct qlcnic_bc_hdr hdr; 1281f197a7aaSRajesh Borundia u32 *ptr = (u32 *)&hdr; 1282f197a7aaSRajesh Borundia u8 msg_type, i; 1283f197a7aaSRajesh Borundia 1284f197a7aaSRajesh Borundia for (i = 2; i < 6; i++) 1285f197a7aaSRajesh Borundia ptr[i - 2] = readl(QLCNIC_MBX_FW(vf->adapter->ahw, i)); 1286f197a7aaSRajesh Borundia msg_type = hdr.msg_type; 1287f197a7aaSRajesh Borundia 1288f197a7aaSRajesh Borundia switch (msg_type) { 1289f197a7aaSRajesh Borundia case QLC_BC_COMMAND: 1290f197a7aaSRajesh Borundia qlcnic_sriov_handle_bc_cmd(sriov, &hdr, vf); 1291f197a7aaSRajesh Borundia break; 1292f197a7aaSRajesh Borundia case QLC_BC_RESPONSE: 1293f197a7aaSRajesh Borundia qlcnic_sriov_handle_bc_resp(&hdr, vf); 1294f197a7aaSRajesh Borundia break; 1295f197a7aaSRajesh Borundia } 1296f197a7aaSRajesh Borundia } 1297f197a7aaSRajesh Borundia 129897d8105cSRajesh Borundia static void qlcnic_sriov_handle_flr_event(struct qlcnic_sriov *sriov, 129997d8105cSRajesh Borundia struct qlcnic_vf_info *vf) 130097d8105cSRajesh Borundia { 130197d8105cSRajesh Borundia struct qlcnic_adapter *adapter = vf->adapter; 130297d8105cSRajesh Borundia 130397d8105cSRajesh Borundia if (qlcnic_sriov_pf_check(adapter)) 130497d8105cSRajesh Borundia qlcnic_sriov_pf_handle_flr(sriov, vf); 130597d8105cSRajesh Borundia else 130697d8105cSRajesh Borundia dev_err(&adapter->pdev->dev, 130797d8105cSRajesh Borundia "Invalid event to VF. VF should not get FLR event\n"); 130897d8105cSRajesh Borundia } 130997d8105cSRajesh Borundia 1310f197a7aaSRajesh Borundia void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *adapter, u32 event) 1311f197a7aaSRajesh Borundia { 1312f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf; 1313f197a7aaSRajesh Borundia struct qlcnic_sriov *sriov; 1314f197a7aaSRajesh Borundia int index; 1315f197a7aaSRajesh Borundia u8 pci_func; 1316f197a7aaSRajesh Borundia 1317f197a7aaSRajesh Borundia sriov = adapter->ahw->sriov; 1318f197a7aaSRajesh Borundia pci_func = qlcnic_sriov_target_func_id(event); 1319f197a7aaSRajesh Borundia index = qlcnic_sriov_func_to_index(adapter, pci_func); 1320f197a7aaSRajesh Borundia 1321f197a7aaSRajesh Borundia if (index < 0) 1322f197a7aaSRajesh Borundia return; 1323f197a7aaSRajesh Borundia 1324f197a7aaSRajesh Borundia vf = &sriov->vf_info[index]; 1325f197a7aaSRajesh Borundia vf->pci_func = pci_func; 1326f197a7aaSRajesh Borundia 1327f197a7aaSRajesh Borundia if (qlcnic_sriov_channel_free_check(event)) 1328f197a7aaSRajesh Borundia complete(&vf->ch_free_cmpl); 1329f197a7aaSRajesh Borundia 133097d8105cSRajesh Borundia if (qlcnic_sriov_flr_check(event)) { 133197d8105cSRajesh Borundia qlcnic_sriov_handle_flr_event(sriov, vf); 133297d8105cSRajesh Borundia return; 133397d8105cSRajesh Borundia } 133497d8105cSRajesh Borundia 1335f197a7aaSRajesh Borundia if (qlcnic_sriov_bc_msg_check(event)) 1336f197a7aaSRajesh Borundia qlcnic_sriov_handle_msg_event(sriov, vf); 1337f197a7aaSRajesh Borundia } 1338f197a7aaSRajesh Borundia 1339f197a7aaSRajesh Borundia int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *adapter, u8 enable) 1340f197a7aaSRajesh Borundia { 1341f197a7aaSRajesh Borundia struct qlcnic_cmd_args cmd; 1342f197a7aaSRajesh Borundia int err; 1343f197a7aaSRajesh Borundia 1344f197a7aaSRajesh Borundia if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state)) 1345f197a7aaSRajesh Borundia return 0; 1346f197a7aaSRajesh Borundia 1347f197a7aaSRajesh Borundia if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_BC_EVENT_SETUP)) 1348f197a7aaSRajesh Borundia return -ENOMEM; 1349f197a7aaSRajesh Borundia 1350f197a7aaSRajesh Borundia if (enable) 1351f197a7aaSRajesh Borundia cmd.req.arg[1] = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7); 1352f197a7aaSRajesh Borundia 1353f197a7aaSRajesh Borundia err = qlcnic_83xx_mbx_op(adapter, &cmd); 1354f197a7aaSRajesh Borundia 1355f197a7aaSRajesh Borundia if (err != QLCNIC_RCODE_SUCCESS) { 1356f197a7aaSRajesh Borundia dev_err(&adapter->pdev->dev, 1357f197a7aaSRajesh Borundia "Failed to %s bc events, err=%d\n", 1358f197a7aaSRajesh Borundia (enable ? "enable" : "disable"), err); 1359f197a7aaSRajesh Borundia } 1360f197a7aaSRajesh Borundia 1361f197a7aaSRajesh Borundia qlcnic_free_mbx_args(&cmd); 1362f197a7aaSRajesh Borundia return err; 1363f197a7aaSRajesh Borundia } 1364f197a7aaSRajesh Borundia 1365f036e4f4SRajesh Borundia static int qlcnic_sriov_retry_bc_cmd(struct qlcnic_adapter *adapter, 1366f036e4f4SRajesh Borundia struct qlcnic_bc_trans *trans) 1367f036e4f4SRajesh Borundia { 1368f036e4f4SRajesh Borundia u8 max = QLC_BC_CMD_MAX_RETRY_CNT; 1369f036e4f4SRajesh Borundia u32 state; 1370f036e4f4SRajesh Borundia 1371f036e4f4SRajesh Borundia state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE); 1372f036e4f4SRajesh Borundia if (state == QLC_83XX_IDC_DEV_READY) { 1373f036e4f4SRajesh Borundia msleep(20); 1374f036e4f4SRajesh Borundia clear_bit(QLC_BC_VF_CHANNEL, &trans->vf->state); 1375f036e4f4SRajesh Borundia trans->trans_state = QLC_INIT; 1376f036e4f4SRajesh Borundia if (++adapter->fw_fail_cnt > max) 1377f036e4f4SRajesh Borundia return -EIO; 1378f036e4f4SRajesh Borundia else 1379f036e4f4SRajesh Borundia return 0; 1380f036e4f4SRajesh Borundia } 1381f036e4f4SRajesh Borundia 1382f036e4f4SRajesh Borundia return -EIO; 1383f036e4f4SRajesh Borundia } 1384f036e4f4SRajesh Borundia 1385f197a7aaSRajesh Borundia static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter, 1386f197a7aaSRajesh Borundia struct qlcnic_cmd_args *cmd) 1387f197a7aaSRajesh Borundia { 1388f036e4f4SRajesh Borundia struct qlcnic_hardware_context *ahw = adapter->ahw; 1389f036e4f4SRajesh Borundia struct device *dev = &adapter->pdev->dev; 1390f197a7aaSRajesh Borundia struct qlcnic_bc_trans *trans; 1391f197a7aaSRajesh Borundia int err; 1392f197a7aaSRajesh Borundia u32 rsp_data, opcode, mbx_err_code, rsp; 1393f197a7aaSRajesh Borundia u16 seq = ++adapter->ahw->sriov->bc.trans_counter; 1394f036e4f4SRajesh Borundia u8 func = ahw->pci_func; 1395f197a7aaSRajesh Borundia 1396f036e4f4SRajesh Borundia rsp = qlcnic_sriov_alloc_bc_trans(&trans); 1397f036e4f4SRajesh Borundia if (rsp) 1398f036e4f4SRajesh Borundia return rsp; 1399f197a7aaSRajesh Borundia 1400f036e4f4SRajesh Borundia rsp = qlcnic_sriov_prepare_bc_hdr(trans, cmd, seq, QLC_BC_COMMAND); 1401f036e4f4SRajesh Borundia if (rsp) 1402f036e4f4SRajesh Borundia goto cleanup_transaction; 1403f197a7aaSRajesh Borundia 1404f036e4f4SRajesh Borundia retry: 1405f197a7aaSRajesh Borundia if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) { 1406f197a7aaSRajesh Borundia rsp = -EIO; 1407f197a7aaSRajesh Borundia QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n", 1408f036e4f4SRajesh Borundia QLCNIC_MBX_RSP(cmd->req.arg[0]), func); 1409f197a7aaSRajesh Borundia goto err_out; 1410f197a7aaSRajesh Borundia } 1411f197a7aaSRajesh Borundia 1412f036e4f4SRajesh Borundia err = qlcnic_sriov_send_bc_cmd(adapter, trans, func); 1413f197a7aaSRajesh Borundia if (err) { 1414f036e4f4SRajesh Borundia dev_err(dev, "MBX command 0x%x timed out for VF %d\n", 1415f036e4f4SRajesh Borundia (cmd->req.arg[0] & 0xffff), func); 1416f197a7aaSRajesh Borundia rsp = QLCNIC_RCODE_TIMEOUT; 1417f036e4f4SRajesh Borundia 1418f036e4f4SRajesh Borundia /* After adapter reset PF driver may take some time to 1419f036e4f4SRajesh Borundia * respond to VF's request. Retry request till maximum retries. 1420f036e4f4SRajesh Borundia */ 1421f036e4f4SRajesh Borundia if ((trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) && 1422f036e4f4SRajesh Borundia !qlcnic_sriov_retry_bc_cmd(adapter, trans)) 1423f036e4f4SRajesh Borundia goto retry; 1424f036e4f4SRajesh Borundia 1425f197a7aaSRajesh Borundia goto err_out; 1426f197a7aaSRajesh Borundia } 1427f197a7aaSRajesh Borundia 1428f197a7aaSRajesh Borundia rsp_data = cmd->rsp.arg[0]; 1429f197a7aaSRajesh Borundia mbx_err_code = QLCNIC_MBX_STATUS(rsp_data); 1430f197a7aaSRajesh Borundia opcode = QLCNIC_MBX_RSP(cmd->req.arg[0]); 1431f197a7aaSRajesh Borundia 1432f197a7aaSRajesh Borundia if ((mbx_err_code == QLCNIC_MBX_RSP_OK) || 1433f197a7aaSRajesh Borundia (mbx_err_code == QLCNIC_MBX_PORT_RSP_OK)) { 1434f197a7aaSRajesh Borundia rsp = QLCNIC_RCODE_SUCCESS; 1435f197a7aaSRajesh Borundia } else { 1436f197a7aaSRajesh Borundia rsp = mbx_err_code; 1437f197a7aaSRajesh Borundia if (!rsp) 1438f197a7aaSRajesh Borundia rsp = 1; 1439f036e4f4SRajesh Borundia dev_err(dev, 1440f197a7aaSRajesh Borundia "MBX command 0x%x failed with err:0x%x for VF %d\n", 1441f036e4f4SRajesh Borundia opcode, mbx_err_code, func); 1442f197a7aaSRajesh Borundia } 1443f197a7aaSRajesh Borundia 1444f197a7aaSRajesh Borundia err_out: 1445f036e4f4SRajesh Borundia if (rsp == QLCNIC_RCODE_TIMEOUT) { 1446f036e4f4SRajesh Borundia ahw->reset_context = 1; 1447f036e4f4SRajesh Borundia adapter->need_fw_reset = 1; 1448f036e4f4SRajesh Borundia clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status); 1449f036e4f4SRajesh Borundia } 1450f036e4f4SRajesh Borundia 1451f036e4f4SRajesh Borundia cleanup_transaction: 1452f197a7aaSRajesh Borundia qlcnic_sriov_cleanup_transaction(trans); 1453f197a7aaSRajesh Borundia return rsp; 1454f197a7aaSRajesh Borundia } 1455f197a7aaSRajesh Borundia 1456f197a7aaSRajesh Borundia int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op) 1457f197a7aaSRajesh Borundia { 1458f197a7aaSRajesh Borundia struct qlcnic_cmd_args cmd; 1459f197a7aaSRajesh Borundia struct qlcnic_vf_info *vf = &adapter->ahw->sriov->vf_info[0]; 1460f197a7aaSRajesh Borundia int ret; 1461f197a7aaSRajesh Borundia 1462f197a7aaSRajesh Borundia if (qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op)) 1463f197a7aaSRajesh Borundia return -ENOMEM; 1464f197a7aaSRajesh Borundia 1465f197a7aaSRajesh Borundia ret = qlcnic_issue_cmd(adapter, &cmd); 1466f197a7aaSRajesh Borundia if (ret) { 1467f197a7aaSRajesh Borundia dev_err(&adapter->pdev->dev, 1468f197a7aaSRajesh Borundia "Failed bc channel %s %d\n", cmd_op ? "term" : "init", 1469f197a7aaSRajesh Borundia ret); 1470f197a7aaSRajesh Borundia goto out; 1471f197a7aaSRajesh Borundia } 1472f197a7aaSRajesh Borundia 1473f197a7aaSRajesh Borundia cmd_op = (cmd.rsp.arg[0] & 0xff); 1474f197a7aaSRajesh Borundia if (cmd.rsp.arg[0] >> 25 == 2) 1475f197a7aaSRajesh Borundia return 2; 1476f197a7aaSRajesh Borundia if (cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) 1477f197a7aaSRajesh Borundia set_bit(QLC_BC_VF_STATE, &vf->state); 1478f197a7aaSRajesh Borundia else 1479f197a7aaSRajesh Borundia clear_bit(QLC_BC_VF_STATE, &vf->state); 1480f197a7aaSRajesh Borundia 1481f197a7aaSRajesh Borundia out: 1482f197a7aaSRajesh Borundia qlcnic_free_mbx_args(&cmd); 1483f197a7aaSRajesh Borundia return ret; 1484f197a7aaSRajesh Borundia } 1485e8b508efSRajesh Borundia 148691b7282bSRajesh Borundia void qlcnic_vf_add_mc_list(struct net_device *netdev, u16 vlan) 1487e8b508efSRajesh Borundia { 1488e8b508efSRajesh Borundia struct qlcnic_adapter *adapter = netdev_priv(netdev); 1489e8b508efSRajesh Borundia struct qlcnic_mac_list_s *cur; 1490e8b508efSRajesh Borundia struct list_head *head, tmp_list; 1491e8b508efSRajesh Borundia 1492e8b508efSRajesh Borundia INIT_LIST_HEAD(&tmp_list); 1493e8b508efSRajesh Borundia head = &adapter->vf_mc_list; 1494e8b508efSRajesh Borundia netif_addr_lock_bh(netdev); 1495e8b508efSRajesh Borundia 1496e8b508efSRajesh Borundia while (!list_empty(head)) { 1497e8b508efSRajesh Borundia cur = list_entry(head->next, struct qlcnic_mac_list_s, list); 1498e8b508efSRajesh Borundia list_move(&cur->list, &tmp_list); 1499e8b508efSRajesh Borundia } 1500e8b508efSRajesh Borundia 1501e8b508efSRajesh Borundia netif_addr_unlock_bh(netdev); 1502e8b508efSRajesh Borundia 1503e8b508efSRajesh Borundia while (!list_empty(&tmp_list)) { 1504e8b508efSRajesh Borundia cur = list_entry((&tmp_list)->next, 1505e8b508efSRajesh Borundia struct qlcnic_mac_list_s, list); 150691b7282bSRajesh Borundia qlcnic_nic_add_mac(adapter, cur->mac_addr, vlan); 1507e8b508efSRajesh Borundia list_del(&cur->list); 1508e8b508efSRajesh Borundia kfree(cur); 1509e8b508efSRajesh Borundia } 1510e8b508efSRajesh Borundia } 1511e8b508efSRajesh Borundia 1512e8b508efSRajesh Borundia void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *bc) 1513e8b508efSRajesh Borundia { 1514e8b508efSRajesh Borundia struct list_head *head = &bc->async_list; 1515e8b508efSRajesh Borundia struct qlcnic_async_work_list *entry; 1516e8b508efSRajesh Borundia 1517e8b508efSRajesh Borundia while (!list_empty(head)) { 1518e8b508efSRajesh Borundia entry = list_entry(head->next, struct qlcnic_async_work_list, 1519e8b508efSRajesh Borundia list); 1520e8b508efSRajesh Borundia cancel_work_sync(&entry->work); 1521e8b508efSRajesh Borundia list_del(&entry->list); 1522e8b508efSRajesh Borundia kfree(entry); 1523e8b508efSRajesh Borundia } 1524e8b508efSRajesh Borundia } 1525e8b508efSRajesh Borundia 1526e8b508efSRajesh Borundia static void qlcnic_sriov_vf_set_multi(struct net_device *netdev) 1527e8b508efSRajesh Borundia { 1528e8b508efSRajesh Borundia struct qlcnic_adapter *adapter = netdev_priv(netdev); 152991b7282bSRajesh Borundia u16 vlan; 1530e8b508efSRajesh Borundia 1531e8b508efSRajesh Borundia if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) 1532e8b508efSRajesh Borundia return; 1533e8b508efSRajesh Borundia 153491b7282bSRajesh Borundia vlan = adapter->ahw->sriov->vlan; 153591b7282bSRajesh Borundia __qlcnic_set_multi(netdev, vlan); 1536e8b508efSRajesh Borundia } 1537e8b508efSRajesh Borundia 1538e8b508efSRajesh Borundia static void qlcnic_sriov_handle_async_multi(struct work_struct *work) 1539e8b508efSRajesh Borundia { 1540e8b508efSRajesh Borundia struct qlcnic_async_work_list *entry; 1541e8b508efSRajesh Borundia struct net_device *netdev; 1542e8b508efSRajesh Borundia 1543e8b508efSRajesh Borundia entry = container_of(work, struct qlcnic_async_work_list, work); 1544e8b508efSRajesh Borundia netdev = (struct net_device *)entry->ptr; 1545e8b508efSRajesh Borundia 1546e8b508efSRajesh Borundia qlcnic_sriov_vf_set_multi(netdev); 1547e8b508efSRajesh Borundia return; 1548e8b508efSRajesh Borundia } 1549e8b508efSRajesh Borundia 1550e8b508efSRajesh Borundia static struct qlcnic_async_work_list * 1551e8b508efSRajesh Borundia qlcnic_sriov_get_free_node_async_work(struct qlcnic_back_channel *bc) 1552e8b508efSRajesh Borundia { 1553e8b508efSRajesh Borundia struct list_head *node; 1554e8b508efSRajesh Borundia struct qlcnic_async_work_list *entry = NULL; 1555e8b508efSRajesh Borundia u8 empty = 0; 1556e8b508efSRajesh Borundia 1557e8b508efSRajesh Borundia list_for_each(node, &bc->async_list) { 1558e8b508efSRajesh Borundia entry = list_entry(node, struct qlcnic_async_work_list, list); 1559e8b508efSRajesh Borundia if (!work_pending(&entry->work)) { 1560e8b508efSRajesh Borundia empty = 1; 1561e8b508efSRajesh Borundia break; 1562e8b508efSRajesh Borundia } 1563e8b508efSRajesh Borundia } 1564e8b508efSRajesh Borundia 1565e8b508efSRajesh Borundia if (!empty) { 1566e8b508efSRajesh Borundia entry = kzalloc(sizeof(struct qlcnic_async_work_list), 1567e8b508efSRajesh Borundia GFP_ATOMIC); 1568e8b508efSRajesh Borundia if (entry == NULL) 1569e8b508efSRajesh Borundia return NULL; 1570e8b508efSRajesh Borundia list_add_tail(&entry->list, &bc->async_list); 1571e8b508efSRajesh Borundia } 1572e8b508efSRajesh Borundia 1573e8b508efSRajesh Borundia return entry; 1574e8b508efSRajesh Borundia } 1575e8b508efSRajesh Borundia 1576e8b508efSRajesh Borundia static void qlcnic_sriov_schedule_bc_async_work(struct qlcnic_back_channel *bc, 1577e8b508efSRajesh Borundia work_func_t func, void *data) 1578e8b508efSRajesh Borundia { 1579e8b508efSRajesh Borundia struct qlcnic_async_work_list *entry = NULL; 1580e8b508efSRajesh Borundia 1581e8b508efSRajesh Borundia entry = qlcnic_sriov_get_free_node_async_work(bc); 1582e8b508efSRajesh Borundia if (!entry) 1583e8b508efSRajesh Borundia return; 1584e8b508efSRajesh Borundia 1585e8b508efSRajesh Borundia entry->ptr = data; 1586e8b508efSRajesh Borundia INIT_WORK(&entry->work, func); 1587e8b508efSRajesh Borundia queue_work(bc->bc_async_wq, &entry->work); 1588e8b508efSRajesh Borundia } 1589e8b508efSRajesh Borundia 1590e8b508efSRajesh Borundia void qlcnic_sriov_vf_schedule_multi(struct net_device *netdev) 1591e8b508efSRajesh Borundia { 1592e8b508efSRajesh Borundia 1593e8b508efSRajesh Borundia struct qlcnic_adapter *adapter = netdev_priv(netdev); 1594e8b508efSRajesh Borundia struct qlcnic_back_channel *bc = &adapter->ahw->sriov->bc; 1595e8b508efSRajesh Borundia 1596f036e4f4SRajesh Borundia if (adapter->need_fw_reset) 1597f036e4f4SRajesh Borundia return; 1598f036e4f4SRajesh Borundia 1599e8b508efSRajesh Borundia qlcnic_sriov_schedule_bc_async_work(bc, qlcnic_sriov_handle_async_multi, 1600e8b508efSRajesh Borundia netdev); 1601e8b508efSRajesh Borundia } 1602f036e4f4SRajesh Borundia 1603f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter) 1604f036e4f4SRajesh Borundia { 1605f036e4f4SRajesh Borundia int err; 1606f036e4f4SRajesh Borundia 1607f036e4f4SRajesh Borundia set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status); 1608f036e4f4SRajesh Borundia qlcnic_83xx_enable_mbx_intrpt(adapter); 1609f036e4f4SRajesh Borundia 1610f036e4f4SRajesh Borundia err = qlcnic_sriov_cfg_bc_intr(adapter, 1); 1611f036e4f4SRajesh Borundia if (err) 1612f036e4f4SRajesh Borundia return err; 1613f036e4f4SRajesh Borundia 1614f036e4f4SRajesh Borundia err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT); 1615f036e4f4SRajesh Borundia if (err) 1616f036e4f4SRajesh Borundia goto err_out_cleanup_bc_intr; 1617f036e4f4SRajesh Borundia 1618f036e4f4SRajesh Borundia err = qlcnic_sriov_vf_init_driver(adapter); 1619f036e4f4SRajesh Borundia if (err) 1620f036e4f4SRajesh Borundia goto err_out_term_channel; 1621f036e4f4SRajesh Borundia 1622f036e4f4SRajesh Borundia return 0; 1623f036e4f4SRajesh Borundia 1624f036e4f4SRajesh Borundia err_out_term_channel: 1625f036e4f4SRajesh Borundia qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM); 1626f036e4f4SRajesh Borundia 1627f036e4f4SRajesh Borundia err_out_cleanup_bc_intr: 1628f036e4f4SRajesh Borundia qlcnic_sriov_cfg_bc_intr(adapter, 0); 1629f036e4f4SRajesh Borundia return err; 1630f036e4f4SRajesh Borundia } 1631f036e4f4SRajesh Borundia 1632f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_attach(struct qlcnic_adapter *adapter) 1633f036e4f4SRajesh Borundia { 1634f036e4f4SRajesh Borundia struct net_device *netdev = adapter->netdev; 1635f036e4f4SRajesh Borundia 1636f036e4f4SRajesh Borundia if (netif_running(netdev)) { 1637f036e4f4SRajesh Borundia if (!qlcnic_up(adapter, netdev)) 1638f036e4f4SRajesh Borundia qlcnic_restore_indev_addr(netdev, NETDEV_UP); 1639f036e4f4SRajesh Borundia } 1640f036e4f4SRajesh Borundia 1641f036e4f4SRajesh Borundia netif_device_attach(netdev); 1642f036e4f4SRajesh Borundia } 1643f036e4f4SRajesh Borundia 1644f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_detach(struct qlcnic_adapter *adapter) 1645f036e4f4SRajesh Borundia { 1646f036e4f4SRajesh Borundia struct qlcnic_hardware_context *ahw = adapter->ahw; 1647f036e4f4SRajesh Borundia struct qlcnic_intrpt_config *intr_tbl = ahw->intr_tbl; 1648f036e4f4SRajesh Borundia struct net_device *netdev = adapter->netdev; 1649f036e4f4SRajesh Borundia u8 i, max_ints = ahw->num_msix - 1; 1650f036e4f4SRajesh Borundia 1651f036e4f4SRajesh Borundia qlcnic_83xx_disable_mbx_intr(adapter); 1652f036e4f4SRajesh Borundia netif_device_detach(netdev); 1653f036e4f4SRajesh Borundia if (netif_running(netdev)) 1654f036e4f4SRajesh Borundia qlcnic_down(adapter, netdev); 1655f036e4f4SRajesh Borundia 1656f036e4f4SRajesh Borundia for (i = 0; i < max_ints; i++) { 1657f036e4f4SRajesh Borundia intr_tbl[i].id = i; 1658f036e4f4SRajesh Borundia intr_tbl[i].enabled = 0; 1659f036e4f4SRajesh Borundia intr_tbl[i].src = 0; 1660f036e4f4SRajesh Borundia } 1661f036e4f4SRajesh Borundia ahw->reset_context = 0; 1662f036e4f4SRajesh Borundia } 1663f036e4f4SRajesh Borundia 1664f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_handle_dev_ready(struct qlcnic_adapter *adapter) 1665f036e4f4SRajesh Borundia { 1666f036e4f4SRajesh Borundia struct qlcnic_hardware_context *ahw = adapter->ahw; 1667f036e4f4SRajesh Borundia struct device *dev = &adapter->pdev->dev; 1668f036e4f4SRajesh Borundia struct qlc_83xx_idc *idc = &ahw->idc; 1669f036e4f4SRajesh Borundia u8 func = ahw->pci_func; 1670f036e4f4SRajesh Borundia u32 state; 1671f036e4f4SRajesh Borundia 1672f036e4f4SRajesh Borundia if ((idc->prev_state == QLC_83XX_IDC_DEV_NEED_RESET) || 1673f036e4f4SRajesh Borundia (idc->prev_state == QLC_83XX_IDC_DEV_INIT)) { 1674f036e4f4SRajesh Borundia if (!qlcnic_sriov_vf_reinit_driver(adapter)) { 1675f036e4f4SRajesh Borundia qlcnic_sriov_vf_attach(adapter); 1676f036e4f4SRajesh Borundia adapter->fw_fail_cnt = 0; 1677f036e4f4SRajesh Borundia dev_info(dev, 1678f036e4f4SRajesh Borundia "%s: Reinitalization of VF 0x%x done after FW reset\n", 1679f036e4f4SRajesh Borundia __func__, func); 1680f036e4f4SRajesh Borundia } else { 1681f036e4f4SRajesh Borundia dev_err(dev, 1682f036e4f4SRajesh Borundia "%s: Reinitialization of VF 0x%x failed after FW reset\n", 1683f036e4f4SRajesh Borundia __func__, func); 1684f036e4f4SRajesh Borundia state = QLCRDX(ahw, QLC_83XX_IDC_DEV_STATE); 1685f036e4f4SRajesh Borundia dev_info(dev, "Current state 0x%x after FW reset\n", 1686f036e4f4SRajesh Borundia state); 1687f036e4f4SRajesh Borundia } 1688f036e4f4SRajesh Borundia } 1689f036e4f4SRajesh Borundia 1690f036e4f4SRajesh Borundia return 0; 1691f036e4f4SRajesh Borundia } 1692f036e4f4SRajesh Borundia 1693f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_handle_context_reset(struct qlcnic_adapter *adapter) 1694f036e4f4SRajesh Borundia { 1695f036e4f4SRajesh Borundia struct qlcnic_hardware_context *ahw = adapter->ahw; 1696f036e4f4SRajesh Borundia struct device *dev = &adapter->pdev->dev; 1697f036e4f4SRajesh Borundia struct qlc_83xx_idc *idc = &ahw->idc; 1698f036e4f4SRajesh Borundia u8 func = ahw->pci_func; 1699f036e4f4SRajesh Borundia u32 state; 1700f036e4f4SRajesh Borundia 1701f036e4f4SRajesh Borundia adapter->reset_ctx_cnt++; 1702f036e4f4SRajesh Borundia 1703f036e4f4SRajesh Borundia /* Skip the context reset and check if FW is hung */ 1704f036e4f4SRajesh Borundia if (adapter->reset_ctx_cnt < 3) { 1705f036e4f4SRajesh Borundia adapter->need_fw_reset = 1; 1706f036e4f4SRajesh Borundia clear_bit(QLC_83XX_MBX_READY, &idc->status); 1707f036e4f4SRajesh Borundia dev_info(dev, 1708f036e4f4SRajesh Borundia "Resetting context, wait here to check if FW is in failed state\n"); 1709f036e4f4SRajesh Borundia return 0; 1710f036e4f4SRajesh Borundia } 1711f036e4f4SRajesh Borundia 1712f036e4f4SRajesh Borundia /* Check if number of resets exceed the threshold. 1713f036e4f4SRajesh Borundia * If it exceeds the threshold just fail the VF. 1714f036e4f4SRajesh Borundia */ 1715f036e4f4SRajesh Borundia if (adapter->reset_ctx_cnt > QLC_83XX_VF_RESET_FAIL_THRESH) { 1716f036e4f4SRajesh Borundia clear_bit(QLC_83XX_MODULE_LOADED, &idc->status); 1717f036e4f4SRajesh Borundia adapter->tx_timeo_cnt = 0; 1718f036e4f4SRajesh Borundia adapter->fw_fail_cnt = 0; 1719f036e4f4SRajesh Borundia adapter->reset_ctx_cnt = 0; 1720f036e4f4SRajesh Borundia qlcnic_sriov_vf_detach(adapter); 1721f036e4f4SRajesh Borundia dev_err(dev, 1722f036e4f4SRajesh Borundia "Device context resets have exceeded the threshold, device interface will be shutdown\n"); 1723f036e4f4SRajesh Borundia return -EIO; 1724f036e4f4SRajesh Borundia } 1725f036e4f4SRajesh Borundia 1726f036e4f4SRajesh Borundia dev_info(dev, "Resetting context of VF 0x%x\n", func); 1727f036e4f4SRajesh Borundia dev_info(dev, "%s: Context reset count %d for VF 0x%x\n", 1728f036e4f4SRajesh Borundia __func__, adapter->reset_ctx_cnt, func); 1729f036e4f4SRajesh Borundia set_bit(__QLCNIC_RESETTING, &adapter->state); 1730f036e4f4SRajesh Borundia adapter->need_fw_reset = 1; 1731f036e4f4SRajesh Borundia clear_bit(QLC_83XX_MBX_READY, &idc->status); 1732f036e4f4SRajesh Borundia qlcnic_sriov_vf_detach(adapter); 1733f036e4f4SRajesh Borundia adapter->need_fw_reset = 0; 1734f036e4f4SRajesh Borundia 1735f036e4f4SRajesh Borundia if (!qlcnic_sriov_vf_reinit_driver(adapter)) { 1736f036e4f4SRajesh Borundia qlcnic_sriov_vf_attach(adapter); 1737f036e4f4SRajesh Borundia adapter->netdev->trans_start = jiffies; 1738f036e4f4SRajesh Borundia adapter->tx_timeo_cnt = 0; 1739f036e4f4SRajesh Borundia adapter->reset_ctx_cnt = 0; 1740f036e4f4SRajesh Borundia adapter->fw_fail_cnt = 0; 1741f036e4f4SRajesh Borundia dev_info(dev, "Done resetting context for VF 0x%x\n", func); 1742f036e4f4SRajesh Borundia } else { 1743f036e4f4SRajesh Borundia dev_err(dev, "%s: Reinitialization of VF 0x%x failed\n", 1744f036e4f4SRajesh Borundia __func__, func); 1745f036e4f4SRajesh Borundia state = QLCRDX(ahw, QLC_83XX_IDC_DEV_STATE); 1746f036e4f4SRajesh Borundia dev_info(dev, "%s: Current state 0x%x\n", __func__, state); 1747f036e4f4SRajesh Borundia } 1748f036e4f4SRajesh Borundia 1749f036e4f4SRajesh Borundia return 0; 1750f036e4f4SRajesh Borundia } 1751f036e4f4SRajesh Borundia 1752f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_idc_ready_state(struct qlcnic_adapter *adapter) 1753f036e4f4SRajesh Borundia { 1754f036e4f4SRajesh Borundia struct qlcnic_hardware_context *ahw = adapter->ahw; 1755f036e4f4SRajesh Borundia int ret = 0; 1756f036e4f4SRajesh Borundia 1757f036e4f4SRajesh Borundia if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_READY) 1758f036e4f4SRajesh Borundia ret = qlcnic_sriov_vf_handle_dev_ready(adapter); 1759f036e4f4SRajesh Borundia else if (ahw->reset_context) 1760f036e4f4SRajesh Borundia ret = qlcnic_sriov_vf_handle_context_reset(adapter); 1761f036e4f4SRajesh Borundia 1762f036e4f4SRajesh Borundia clear_bit(__QLCNIC_RESETTING, &adapter->state); 1763f036e4f4SRajesh Borundia return ret; 1764f036e4f4SRajesh Borundia } 1765f036e4f4SRajesh Borundia 1766f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_idc_failed_state(struct qlcnic_adapter *adapter) 1767f036e4f4SRajesh Borundia { 1768f036e4f4SRajesh Borundia struct qlc_83xx_idc *idc = &adapter->ahw->idc; 1769f036e4f4SRajesh Borundia 1770f036e4f4SRajesh Borundia dev_err(&adapter->pdev->dev, "Device is in failed state\n"); 1771f036e4f4SRajesh Borundia if (idc->prev_state == QLC_83XX_IDC_DEV_READY) 1772f036e4f4SRajesh Borundia qlcnic_sriov_vf_detach(adapter); 1773f036e4f4SRajesh Borundia 1774f036e4f4SRajesh Borundia clear_bit(QLC_83XX_MODULE_LOADED, &idc->status); 1775f036e4f4SRajesh Borundia clear_bit(__QLCNIC_RESETTING, &adapter->state); 1776f036e4f4SRajesh Borundia return -EIO; 1777f036e4f4SRajesh Borundia } 1778f036e4f4SRajesh Borundia 1779f036e4f4SRajesh Borundia static int 1780f036e4f4SRajesh Borundia qlcnic_sriov_vf_idc_need_quiescent_state(struct qlcnic_adapter *adapter) 1781f036e4f4SRajesh Borundia { 1782f036e4f4SRajesh Borundia struct qlc_83xx_idc *idc = &adapter->ahw->idc; 1783f036e4f4SRajesh Borundia 1784f036e4f4SRajesh Borundia dev_info(&adapter->pdev->dev, "Device is in quiescent state\n"); 1785f036e4f4SRajesh Borundia if (idc->prev_state == QLC_83XX_IDC_DEV_READY) { 1786f036e4f4SRajesh Borundia set_bit(__QLCNIC_RESETTING, &adapter->state); 1787f036e4f4SRajesh Borundia adapter->tx_timeo_cnt = 0; 1788f036e4f4SRajesh Borundia adapter->reset_ctx_cnt = 0; 1789f036e4f4SRajesh Borundia clear_bit(QLC_83XX_MBX_READY, &idc->status); 1790f036e4f4SRajesh Borundia qlcnic_sriov_vf_detach(adapter); 1791f036e4f4SRajesh Borundia } 1792f036e4f4SRajesh Borundia 1793f036e4f4SRajesh Borundia return 0; 1794f036e4f4SRajesh Borundia } 1795f036e4f4SRajesh Borundia 1796f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_idc_init_reset_state(struct qlcnic_adapter *adapter) 1797f036e4f4SRajesh Borundia { 1798f036e4f4SRajesh Borundia struct qlc_83xx_idc *idc = &adapter->ahw->idc; 1799f036e4f4SRajesh Borundia u8 func = adapter->ahw->pci_func; 1800f036e4f4SRajesh Borundia 1801f036e4f4SRajesh Borundia if (idc->prev_state == QLC_83XX_IDC_DEV_READY) { 1802f036e4f4SRajesh Borundia dev_err(&adapter->pdev->dev, 1803f036e4f4SRajesh Borundia "Firmware hang detected by VF 0x%x\n", func); 1804f036e4f4SRajesh Borundia set_bit(__QLCNIC_RESETTING, &adapter->state); 1805f036e4f4SRajesh Borundia adapter->tx_timeo_cnt = 0; 1806f036e4f4SRajesh Borundia adapter->reset_ctx_cnt = 0; 1807f036e4f4SRajesh Borundia clear_bit(QLC_83XX_MBX_READY, &idc->status); 1808f036e4f4SRajesh Borundia qlcnic_sriov_vf_detach(adapter); 1809f036e4f4SRajesh Borundia } 1810f036e4f4SRajesh Borundia return 0; 1811f036e4f4SRajesh Borundia } 1812f036e4f4SRajesh Borundia 1813f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_idc_unknown_state(struct qlcnic_adapter *adapter) 1814f036e4f4SRajesh Borundia { 1815f036e4f4SRajesh Borundia dev_err(&adapter->pdev->dev, "%s: Device in unknown state\n", __func__); 1816f036e4f4SRajesh Borundia return 0; 1817f036e4f4SRajesh Borundia } 1818f036e4f4SRajesh Borundia 1819f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *work) 1820f036e4f4SRajesh Borundia { 1821f036e4f4SRajesh Borundia struct qlcnic_adapter *adapter; 1822f036e4f4SRajesh Borundia struct qlc_83xx_idc *idc; 1823f036e4f4SRajesh Borundia int ret = 0; 1824f036e4f4SRajesh Borundia 1825f036e4f4SRajesh Borundia adapter = container_of(work, struct qlcnic_adapter, fw_work.work); 1826f036e4f4SRajesh Borundia idc = &adapter->ahw->idc; 1827f036e4f4SRajesh Borundia idc->curr_state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE); 1828f036e4f4SRajesh Borundia 1829f036e4f4SRajesh Borundia switch (idc->curr_state) { 1830f036e4f4SRajesh Borundia case QLC_83XX_IDC_DEV_READY: 1831f036e4f4SRajesh Borundia ret = qlcnic_sriov_vf_idc_ready_state(adapter); 1832f036e4f4SRajesh Borundia break; 1833f036e4f4SRajesh Borundia case QLC_83XX_IDC_DEV_NEED_RESET: 1834f036e4f4SRajesh Borundia case QLC_83XX_IDC_DEV_INIT: 1835f036e4f4SRajesh Borundia ret = qlcnic_sriov_vf_idc_init_reset_state(adapter); 1836f036e4f4SRajesh Borundia break; 1837f036e4f4SRajesh Borundia case QLC_83XX_IDC_DEV_NEED_QUISCENT: 1838f036e4f4SRajesh Borundia ret = qlcnic_sriov_vf_idc_need_quiescent_state(adapter); 1839f036e4f4SRajesh Borundia break; 1840f036e4f4SRajesh Borundia case QLC_83XX_IDC_DEV_FAILED: 1841f036e4f4SRajesh Borundia ret = qlcnic_sriov_vf_idc_failed_state(adapter); 1842f036e4f4SRajesh Borundia break; 1843f036e4f4SRajesh Borundia case QLC_83XX_IDC_DEV_QUISCENT: 1844f036e4f4SRajesh Borundia break; 1845f036e4f4SRajesh Borundia default: 1846f036e4f4SRajesh Borundia ret = qlcnic_sriov_vf_idc_unknown_state(adapter); 1847f036e4f4SRajesh Borundia } 1848f036e4f4SRajesh Borundia 1849f036e4f4SRajesh Borundia idc->prev_state = idc->curr_state; 1850f036e4f4SRajesh Borundia if (!ret && test_bit(QLC_83XX_MODULE_LOADED, &idc->status)) 1851f036e4f4SRajesh Borundia qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state, 1852f036e4f4SRajesh Borundia idc->delay); 1853f036e4f4SRajesh Borundia } 1854f036e4f4SRajesh Borundia 1855f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *adapter) 1856f036e4f4SRajesh Borundia { 1857f036e4f4SRajesh Borundia while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) 1858f036e4f4SRajesh Borundia msleep(20); 1859f036e4f4SRajesh Borundia 1860f036e4f4SRajesh Borundia clear_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status); 1861f036e4f4SRajesh Borundia clear_bit(__QLCNIC_RESETTING, &adapter->state); 1862f036e4f4SRajesh Borundia cancel_delayed_work_sync(&adapter->fw_work); 1863f036e4f4SRajesh Borundia } 186491b7282bSRajesh Borundia 186591b7282bSRajesh Borundia static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_sriov *sriov, 186691b7282bSRajesh Borundia u16 vid, u8 enable) 186791b7282bSRajesh Borundia { 186891b7282bSRajesh Borundia u16 vlan = sriov->vlan; 186991b7282bSRajesh Borundia u8 allowed = 0; 187091b7282bSRajesh Borundia int i; 187191b7282bSRajesh Borundia 187291b7282bSRajesh Borundia if (sriov->vlan_mode != QLC_GUEST_VLAN_MODE) 187391b7282bSRajesh Borundia return -EINVAL; 187491b7282bSRajesh Borundia 187591b7282bSRajesh Borundia if (enable) { 187691b7282bSRajesh Borundia if (vlan) 187791b7282bSRajesh Borundia return -EINVAL; 187891b7282bSRajesh Borundia 187991b7282bSRajesh Borundia if (sriov->any_vlan) { 188091b7282bSRajesh Borundia for (i = 0; i < sriov->num_allowed_vlans; i++) { 188191b7282bSRajesh Borundia if (sriov->allowed_vlans[i] == vid) 188291b7282bSRajesh Borundia allowed = 1; 188391b7282bSRajesh Borundia } 188491b7282bSRajesh Borundia 188591b7282bSRajesh Borundia if (!allowed) 188691b7282bSRajesh Borundia return -EINVAL; 188791b7282bSRajesh Borundia } 188891b7282bSRajesh Borundia } else { 188991b7282bSRajesh Borundia if (!vlan || vlan != vid) 189091b7282bSRajesh Borundia return -EINVAL; 189191b7282bSRajesh Borundia } 189291b7282bSRajesh Borundia 189391b7282bSRajesh Borundia return 0; 189491b7282bSRajesh Borundia } 189591b7282bSRajesh Borundia 189691b7282bSRajesh Borundia int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter, 189791b7282bSRajesh Borundia u16 vid, u8 enable) 189891b7282bSRajesh Borundia { 189991b7282bSRajesh Borundia struct qlcnic_sriov *sriov = adapter->ahw->sriov; 190091b7282bSRajesh Borundia struct qlcnic_cmd_args cmd; 190191b7282bSRajesh Borundia int ret; 190291b7282bSRajesh Borundia 190391b7282bSRajesh Borundia if (vid == 0) 190491b7282bSRajesh Borundia return 0; 190591b7282bSRajesh Borundia 190691b7282bSRajesh Borundia ret = qlcnic_sriov_validate_vlan_cfg(sriov, vid, enable); 190791b7282bSRajesh Borundia if (ret) 190891b7282bSRajesh Borundia return ret; 190991b7282bSRajesh Borundia 191091b7282bSRajesh Borundia ret = qlcnic_sriov_alloc_bc_mbx_args(&cmd, 191191b7282bSRajesh Borundia QLCNIC_BC_CMD_CFG_GUEST_VLAN); 191291b7282bSRajesh Borundia if (ret) 191391b7282bSRajesh Borundia return ret; 191491b7282bSRajesh Borundia 191591b7282bSRajesh Borundia cmd.req.arg[1] = (enable & 1) | vid << 16; 191691b7282bSRajesh Borundia 191791b7282bSRajesh Borundia qlcnic_sriov_cleanup_async_list(&sriov->bc); 191891b7282bSRajesh Borundia ret = qlcnic_issue_cmd(adapter, &cmd); 191991b7282bSRajesh Borundia if (ret) { 192091b7282bSRajesh Borundia dev_err(&adapter->pdev->dev, 192191b7282bSRajesh Borundia "Failed to configure guest VLAN, err=%d\n", ret); 192291b7282bSRajesh Borundia } else { 192391b7282bSRajesh Borundia qlcnic_free_mac_list(adapter); 192491b7282bSRajesh Borundia 192591b7282bSRajesh Borundia if (enable) 192691b7282bSRajesh Borundia sriov->vlan = vid; 192791b7282bSRajesh Borundia else 192891b7282bSRajesh Borundia sriov->vlan = 0; 192991b7282bSRajesh Borundia 193091b7282bSRajesh Borundia qlcnic_sriov_vf_set_multi(adapter->netdev); 193191b7282bSRajesh Borundia } 193291b7282bSRajesh Borundia 193391b7282bSRajesh Borundia qlcnic_free_mbx_args(&cmd); 193491b7282bSRajesh Borundia return ret; 193591b7282bSRajesh Borundia } 193691b7282bSRajesh Borundia 193791b7282bSRajesh Borundia static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *adapter) 193891b7282bSRajesh Borundia { 193991b7282bSRajesh Borundia struct list_head *head = &adapter->mac_list; 194091b7282bSRajesh Borundia struct qlcnic_mac_list_s *cur; 194191b7282bSRajesh Borundia u16 vlan; 194291b7282bSRajesh Borundia 194391b7282bSRajesh Borundia vlan = adapter->ahw->sriov->vlan; 194491b7282bSRajesh Borundia 194591b7282bSRajesh Borundia while (!list_empty(head)) { 194691b7282bSRajesh Borundia cur = list_entry(head->next, struct qlcnic_mac_list_s, list); 194791b7282bSRajesh Borundia qlcnic_sre_macaddr_change(adapter, cur->mac_addr, 194891b7282bSRajesh Borundia vlan, QLCNIC_MAC_DEL); 194991b7282bSRajesh Borundia list_del(&cur->list); 195091b7282bSRajesh Borundia kfree(cur); 195191b7282bSRajesh Borundia } 195291b7282bSRajesh Borundia } 1953