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