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