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