1004b26b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
202feda17SRajesh Borundia /*
302feda17SRajesh Borundia  * QLogic qlcnic NIC Driver
402feda17SRajesh Borundia  * Copyright (c) 2009-2013 QLogic Corporation
502feda17SRajesh Borundia  */
602feda17SRajesh Borundia 
7a930a463SHarish Patil #include <linux/types.h>
8a930a463SHarish Patil 
902feda17SRajesh Borundia #include "qlcnic_sriov.h"
1002feda17SRajesh Borundia #include "qlcnic.h"
11f8468331SRajesh Borundia #include "qlcnic_83xx_hw.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 
312b10d3ecSManish Chopra static void qlcnic_sriov_handle_async_issue_cmd(struct work_struct *work);
3291b7282bSRajesh Borundia static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *);
3391b7282bSRajesh Borundia static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *, u32);
34f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *);
35f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *);
3697d8105cSRajesh Borundia static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *);
37e5c4e6c6SManish Chopra static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *,
38f197a7aaSRajesh Borundia 				  struct qlcnic_cmd_args *);
3921041400Sstephen hemminger static int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *, u8);
401267ff96SSucheta Chakraborty static void qlcnic_sriov_process_bc_cmd(struct work_struct *);
4121041400Sstephen hemminger static int qlcnic_sriov_vf_shutdown(struct pci_dev *);
4221041400Sstephen hemminger static int qlcnic_sriov_vf_resume(struct qlcnic_adapter *);
4374b7ba1aSRajesh Borundia static int qlcnic_sriov_async_issue_cmd(struct qlcnic_adapter *,
4474b7ba1aSRajesh Borundia 					struct qlcnic_cmd_args *);
45f197a7aaSRajesh Borundia 
46f8468331SRajesh Borundia static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {
47f8468331SRajesh Borundia 	.read_crb			= qlcnic_83xx_read_crb,
48f8468331SRajesh Borundia 	.write_crb			= qlcnic_83xx_write_crb,
49f8468331SRajesh Borundia 	.read_reg			= qlcnic_83xx_rd_reg_indirect,
50f8468331SRajesh Borundia 	.write_reg			= qlcnic_83xx_wrt_reg_indirect,
51f8468331SRajesh Borundia 	.get_mac_address		= qlcnic_83xx_get_mac_address,
52f8468331SRajesh Borundia 	.setup_intr			= qlcnic_83xx_setup_intr,
53f8468331SRajesh Borundia 	.alloc_mbx_args			= qlcnic_83xx_alloc_mbx_args,
54e5c4e6c6SManish Chopra 	.mbx_cmd			= qlcnic_sriov_issue_cmd,
55f8468331SRajesh Borundia 	.get_func_no			= qlcnic_83xx_get_func_no,
56f8468331SRajesh Borundia 	.api_lock			= qlcnic_83xx_cam_lock,
57f8468331SRajesh Borundia 	.api_unlock			= qlcnic_83xx_cam_unlock,
58f8468331SRajesh Borundia 	.process_lb_rcv_ring_diag	= qlcnic_83xx_process_rcv_ring_diag,
59f8468331SRajesh Borundia 	.create_rx_ctx			= qlcnic_83xx_create_rx_ctx,
60f8468331SRajesh Borundia 	.create_tx_ctx			= qlcnic_83xx_create_tx_ctx,
617cb03b23SRajesh Borundia 	.del_rx_ctx			= qlcnic_83xx_del_rx_ctx,
627cb03b23SRajesh Borundia 	.del_tx_ctx			= qlcnic_83xx_del_tx_ctx,
63f8468331SRajesh Borundia 	.setup_link_event		= qlcnic_83xx_setup_link_event,
64f8468331SRajesh Borundia 	.get_nic_info			= qlcnic_83xx_get_nic_info,
65f8468331SRajesh Borundia 	.get_pci_info			= qlcnic_83xx_get_pci_info,
66f8468331SRajesh Borundia 	.set_nic_info			= qlcnic_83xx_set_nic_info,
67f8468331SRajesh Borundia 	.change_macvlan			= qlcnic_83xx_sre_macaddr_change,
68f8468331SRajesh Borundia 	.napi_enable			= qlcnic_83xx_napi_enable,
69f8468331SRajesh Borundia 	.napi_disable			= qlcnic_83xx_napi_disable,
70f8468331SRajesh Borundia 	.config_intr_coal		= qlcnic_83xx_config_intr_coal,
71f8468331SRajesh Borundia 	.config_rss			= qlcnic_83xx_config_rss,
72f8468331SRajesh Borundia 	.config_hw_lro			= qlcnic_83xx_config_hw_lro,
73f8468331SRajesh Borundia 	.config_promisc_mode		= qlcnic_83xx_nic_set_promisc,
74f8468331SRajesh Borundia 	.change_l2_filter		= qlcnic_83xx_change_l2_filter,
75f8468331SRajesh Borundia 	.get_board_info			= qlcnic_83xx_get_port_info,
7691b7282bSRajesh Borundia 	.free_mac_list			= qlcnic_sriov_vf_free_mac_list,
772cc5752eSManish chopra 	.enable_sds_intr		= qlcnic_83xx_enable_sds_intr,
782cc5752eSManish chopra 	.disable_sds_intr		= qlcnic_83xx_disable_sds_intr,
794bd7ef0bSChopra, Manish 	.encap_rx_offload               = qlcnic_83xx_encap_rx_offload,
804bd7ef0bSChopra, Manish 	.encap_tx_offload               = qlcnic_83xx_encap_tx_offload,
81f8468331SRajesh Borundia };
82f8468331SRajesh Borundia 
83f8468331SRajesh Borundia static struct qlcnic_nic_template qlcnic_sriov_vf_ops = {
84f8468331SRajesh Borundia 	.config_bridged_mode	= qlcnic_config_bridged_mode,
85f8468331SRajesh Borundia 	.config_led		= qlcnic_config_led,
86f036e4f4SRajesh Borundia 	.cancel_idc_work        = qlcnic_sriov_vf_cancel_fw_work,
87f8468331SRajesh Borundia 	.napi_add		= qlcnic_83xx_napi_add,
88f8468331SRajesh Borundia 	.napi_del		= qlcnic_83xx_napi_del,
89486a5bc7SRajesh Borundia 	.shutdown		= qlcnic_sriov_vf_shutdown,
90486a5bc7SRajesh Borundia 	.resume			= qlcnic_sriov_vf_resume,
91f8468331SRajesh Borundia 	.config_ipaddr		= qlcnic_83xx_config_ipaddr,
92f8468331SRajesh Borundia 	.clear_legacy_intr	= qlcnic_83xx_clear_legacy_intr,
93f8468331SRajesh Borundia };
94f8468331SRajesh Borundia 
95f197a7aaSRajesh Borundia static const struct qlcnic_mailbox_metadata qlcnic_sriov_bc_mbx_tbl[] = {
96f197a7aaSRajesh Borundia 	{QLCNIC_BC_CMD_CHANNEL_INIT, 2, 2},
97f197a7aaSRajesh Borundia 	{QLCNIC_BC_CMD_CHANNEL_TERM, 2, 2},
9891b7282bSRajesh Borundia 	{QLCNIC_BC_CMD_GET_ACL, 3, 14},
9991b7282bSRajesh Borundia 	{QLCNIC_BC_CMD_CFG_GUEST_VLAN, 2, 2},
100f197a7aaSRajesh Borundia };
101f197a7aaSRajesh Borundia 
qlcnic_sriov_bc_msg_check(u32 val)102f197a7aaSRajesh Borundia static inline bool qlcnic_sriov_bc_msg_check(u32 val)
103f197a7aaSRajesh Borundia {
104f197a7aaSRajesh Borundia 	return (val & (1 << QLC_BC_MSG)) ? true : false;
105f197a7aaSRajesh Borundia }
106f197a7aaSRajesh Borundia 
qlcnic_sriov_channel_free_check(u32 val)107f197a7aaSRajesh Borundia static inline bool qlcnic_sriov_channel_free_check(u32 val)
108f197a7aaSRajesh Borundia {
109f197a7aaSRajesh Borundia 	return (val & (1 << QLC_BC_CFREE)) ? true : false;
110f197a7aaSRajesh Borundia }
111f197a7aaSRajesh Borundia 
qlcnic_sriov_flr_check(u32 val)11297d8105cSRajesh Borundia static inline bool qlcnic_sriov_flr_check(u32 val)
11397d8105cSRajesh Borundia {
11497d8105cSRajesh Borundia 	return (val & (1 << QLC_BC_FLR)) ? true : false;
11597d8105cSRajesh Borundia }
11697d8105cSRajesh Borundia 
qlcnic_sriov_target_func_id(u32 val)117f197a7aaSRajesh Borundia static inline u8 qlcnic_sriov_target_func_id(u32 val)
118f197a7aaSRajesh Borundia {
119f197a7aaSRajesh Borundia 	return (val >> 4) & 0xff;
120f197a7aaSRajesh Borundia }
121f197a7aaSRajesh Borundia 
qlcnic_sriov_virtid_fn(struct qlcnic_adapter * adapter,int vf_id)122f197a7aaSRajesh Borundia static int qlcnic_sriov_virtid_fn(struct qlcnic_adapter *adapter, int vf_id)
123f197a7aaSRajesh Borundia {
124f197a7aaSRajesh Borundia 	struct pci_dev *dev = adapter->pdev;
125f197a7aaSRajesh Borundia 	int pos;
126f197a7aaSRajesh Borundia 	u16 stride, offset;
127f197a7aaSRajesh Borundia 
128f197a7aaSRajesh Borundia 	if (qlcnic_sriov_vf_check(adapter))
129f197a7aaSRajesh Borundia 		return 0;
130f197a7aaSRajesh Borundia 
131f197a7aaSRajesh Borundia 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
13291ec701aSPan Bian 	if (!pos)
13391ec701aSPan Bian 		return 0;
134f197a7aaSRajesh Borundia 	pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
135f197a7aaSRajesh Borundia 	pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
136f197a7aaSRajesh Borundia 
137f197a7aaSRajesh Borundia 	return (dev->devfn + offset + stride * vf_id) & 0xff;
138f197a7aaSRajesh Borundia }
139f197a7aaSRajesh Borundia 
qlcnic_sriov_init(struct qlcnic_adapter * adapter,int num_vfs)14002feda17SRajesh Borundia int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
14102feda17SRajesh Borundia {
14202feda17SRajesh Borundia 	struct qlcnic_sriov *sriov;
143f197a7aaSRajesh Borundia 	struct qlcnic_back_channel *bc;
144f197a7aaSRajesh Borundia 	struct workqueue_struct *wq;
145f197a7aaSRajesh Borundia 	struct qlcnic_vport *vp;
146f197a7aaSRajesh Borundia 	struct qlcnic_vf_info *vf;
147f197a7aaSRajesh Borundia 	int err, i;
14802feda17SRajesh Borundia 
14902feda17SRajesh Borundia 	if (!qlcnic_sriov_enable_check(adapter))
15002feda17SRajesh Borundia 		return -EIO;
15102feda17SRajesh Borundia 
15202feda17SRajesh Borundia 	sriov  = kzalloc(sizeof(struct qlcnic_sriov), GFP_KERNEL);
15302feda17SRajesh Borundia 	if (!sriov)
15402feda17SRajesh Borundia 		return -ENOMEM;
15502feda17SRajesh Borundia 
15602feda17SRajesh Borundia 	adapter->ahw->sriov = sriov;
15702feda17SRajesh Borundia 	sriov->num_vfs = num_vfs;
158f197a7aaSRajesh Borundia 	bc = &sriov->bc;
1596396bb22SKees Cook 	sriov->vf_info = kcalloc(num_vfs, sizeof(struct qlcnic_vf_info),
1606396bb22SKees Cook 				 GFP_KERNEL);
161f197a7aaSRajesh Borundia 	if (!sriov->vf_info) {
162f197a7aaSRajesh Borundia 		err = -ENOMEM;
163f197a7aaSRajesh Borundia 		goto qlcnic_free_sriov;
164f197a7aaSRajesh Borundia 	}
165f197a7aaSRajesh Borundia 
166f197a7aaSRajesh Borundia 	wq = create_singlethread_workqueue("bc-trans");
167f197a7aaSRajesh Borundia 	if (wq == NULL) {
168f197a7aaSRajesh Borundia 		err = -ENOMEM;
169f197a7aaSRajesh Borundia 		dev_err(&adapter->pdev->dev,
170f197a7aaSRajesh Borundia 			"Cannot create bc-trans workqueue\n");
171f197a7aaSRajesh Borundia 		goto qlcnic_free_vf_info;
172f197a7aaSRajesh Borundia 	}
173f197a7aaSRajesh Borundia 
174f197a7aaSRajesh Borundia 	bc->bc_trans_wq = wq;
175f197a7aaSRajesh Borundia 
176e8b508efSRajesh Borundia 	wq = create_singlethread_workqueue("async");
177e8b508efSRajesh Borundia 	if (wq == NULL) {
178e8b508efSRajesh Borundia 		err = -ENOMEM;
179e8b508efSRajesh Borundia 		dev_err(&adapter->pdev->dev, "Cannot create async workqueue\n");
180e8b508efSRajesh Borundia 		goto qlcnic_destroy_trans_wq;
181e8b508efSRajesh Borundia 	}
182e8b508efSRajesh Borundia 
183e8b508efSRajesh Borundia 	bc->bc_async_wq =  wq;
1842b10d3ecSManish Chopra 	INIT_LIST_HEAD(&bc->async_cmd_list);
1852b10d3ecSManish Chopra 	INIT_WORK(&bc->vf_async_work, qlcnic_sriov_handle_async_issue_cmd);
1862b10d3ecSManish Chopra 	spin_lock_init(&bc->queue_lock);
1872b10d3ecSManish Chopra 	bc->adapter = adapter;
188e8b508efSRajesh Borundia 
189f197a7aaSRajesh Borundia 	for (i = 0; i < num_vfs; i++) {
190f197a7aaSRajesh Borundia 		vf = &sriov->vf_info[i];
191f197a7aaSRajesh Borundia 		vf->adapter = adapter;
192f197a7aaSRajesh Borundia 		vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i);
193f197a7aaSRajesh Borundia 		mutex_init(&vf->send_cmd_lock);
19474b7ba1aSRajesh Borundia 		spin_lock_init(&vf->vlan_list_lock);
195f197a7aaSRajesh Borundia 		INIT_LIST_HEAD(&vf->rcv_act.wait_list);
196f197a7aaSRajesh Borundia 		INIT_LIST_HEAD(&vf->rcv_pend.wait_list);
197f197a7aaSRajesh Borundia 		spin_lock_init(&vf->rcv_act.lock);
198f197a7aaSRajesh Borundia 		spin_lock_init(&vf->rcv_pend.lock);
199f197a7aaSRajesh Borundia 		init_completion(&vf->ch_free_cmpl);
200f197a7aaSRajesh Borundia 
2011267ff96SSucheta Chakraborty 		INIT_WORK(&vf->trans_work, qlcnic_sriov_process_bc_cmd);
2021267ff96SSucheta Chakraborty 
203f197a7aaSRajesh Borundia 		if (qlcnic_sriov_pf_check(adapter)) {
204f197a7aaSRajesh Borundia 			vp = kzalloc(sizeof(struct qlcnic_vport), GFP_KERNEL);
205f197a7aaSRajesh Borundia 			if (!vp) {
206f197a7aaSRajesh Borundia 				err = -ENOMEM;
207e8b508efSRajesh Borundia 				goto qlcnic_destroy_async_wq;
208f197a7aaSRajesh Borundia 			}
209f197a7aaSRajesh Borundia 			sriov->vf_info[i].vp = vp;
210d747c333SRajesh Borundia 			vp->vlan_mode = QLC_GUEST_VLAN_MODE;
2114000e7a7SRajesh Borundia 			vp->max_tx_bw = MAX_BW;
212ed616689SSucheta Chakraborty 			vp->min_tx_bw = MIN_BW;
213132a3f2bSRajesh Borundia 			vp->spoofchk = false;
2146c1f0a1fSJoe Perches 			eth_random_addr(vp->mac);
215f197a7aaSRajesh Borundia 			dev_info(&adapter->pdev->dev,
216f197a7aaSRajesh Borundia 				 "MAC Address %pM is configured for VF %d\n",
217f197a7aaSRajesh Borundia 				 vp->mac, i);
218f197a7aaSRajesh Borundia 		}
219f197a7aaSRajesh Borundia 	}
220f197a7aaSRajesh Borundia 
22102feda17SRajesh Borundia 	return 0;
222f197a7aaSRajesh Borundia 
223e8b508efSRajesh Borundia qlcnic_destroy_async_wq:
224*01de1123SYuan Can 	while (i--)
225*01de1123SYuan Can 		kfree(sriov->vf_info[i].vp);
226e8b508efSRajesh Borundia 	destroy_workqueue(bc->bc_async_wq);
227e8b508efSRajesh Borundia 
228f197a7aaSRajesh Borundia qlcnic_destroy_trans_wq:
229f197a7aaSRajesh Borundia 	destroy_workqueue(bc->bc_trans_wq);
230f197a7aaSRajesh Borundia 
231f197a7aaSRajesh Borundia qlcnic_free_vf_info:
232f197a7aaSRajesh Borundia 	kfree(sriov->vf_info);
233f197a7aaSRajesh Borundia 
234f197a7aaSRajesh Borundia qlcnic_free_sriov:
235f197a7aaSRajesh Borundia 	kfree(adapter->ahw->sriov);
236f197a7aaSRajesh Borundia 	return err;
23702feda17SRajesh Borundia }
23802feda17SRajesh Borundia 
qlcnic_sriov_cleanup_list(struct qlcnic_trans_list * t_list)23997d8105cSRajesh Borundia void qlcnic_sriov_cleanup_list(struct qlcnic_trans_list *t_list)
24097d8105cSRajesh Borundia {
24197d8105cSRajesh Borundia 	struct qlcnic_bc_trans *trans;
24297d8105cSRajesh Borundia 	struct qlcnic_cmd_args cmd;
24397d8105cSRajesh Borundia 	unsigned long flags;
24497d8105cSRajesh Borundia 
24597d8105cSRajesh Borundia 	spin_lock_irqsave(&t_list->lock, flags);
24697d8105cSRajesh Borundia 
24797d8105cSRajesh Borundia 	while (!list_empty(&t_list->wait_list)) {
24897d8105cSRajesh Borundia 		trans = list_first_entry(&t_list->wait_list,
24997d8105cSRajesh Borundia 					 struct qlcnic_bc_trans, list);
25097d8105cSRajesh Borundia 		list_del(&trans->list);
25197d8105cSRajesh Borundia 		t_list->count--;
25297d8105cSRajesh Borundia 		cmd.req.arg = (u32 *)trans->req_pay;
25397d8105cSRajesh Borundia 		cmd.rsp.arg = (u32 *)trans->rsp_pay;
25497d8105cSRajesh Borundia 		qlcnic_free_mbx_args(&cmd);
25597d8105cSRajesh Borundia 		qlcnic_sriov_cleanup_transaction(trans);
25697d8105cSRajesh Borundia 	}
25797d8105cSRajesh Borundia 
25897d8105cSRajesh Borundia 	spin_unlock_irqrestore(&t_list->lock, flags);
25997d8105cSRajesh Borundia }
26097d8105cSRajesh Borundia 
__qlcnic_sriov_cleanup(struct qlcnic_adapter * adapter)26102feda17SRajesh Borundia void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
26202feda17SRajesh Borundia {
263f197a7aaSRajesh Borundia 	struct qlcnic_sriov *sriov = adapter->ahw->sriov;
264f197a7aaSRajesh Borundia 	struct qlcnic_back_channel *bc = &sriov->bc;
26597d8105cSRajesh Borundia 	struct qlcnic_vf_info *vf;
266f197a7aaSRajesh Borundia 	int i;
267f197a7aaSRajesh Borundia 
26802feda17SRajesh Borundia 	if (!qlcnic_sriov_enable_check(adapter))
26902feda17SRajesh Borundia 		return;
27002feda17SRajesh Borundia 
271e8b508efSRajesh Borundia 	qlcnic_sriov_cleanup_async_list(bc);
272e8b508efSRajesh Borundia 	destroy_workqueue(bc->bc_async_wq);
27397d8105cSRajesh Borundia 
27497d8105cSRajesh Borundia 	for (i = 0; i < sriov->num_vfs; i++) {
27597d8105cSRajesh Borundia 		vf = &sriov->vf_info[i];
27697d8105cSRajesh Borundia 		qlcnic_sriov_cleanup_list(&vf->rcv_pend);
27797d8105cSRajesh Borundia 		cancel_work_sync(&vf->trans_work);
27897d8105cSRajesh Borundia 		qlcnic_sriov_cleanup_list(&vf->rcv_act);
27997d8105cSRajesh Borundia 	}
28097d8105cSRajesh Borundia 
281f197a7aaSRajesh Borundia 	destroy_workqueue(bc->bc_trans_wq);
282f197a7aaSRajesh Borundia 
283f197a7aaSRajesh Borundia 	for (i = 0; i < sriov->num_vfs; i++)
284f197a7aaSRajesh Borundia 		kfree(sriov->vf_info[i].vp);
285f197a7aaSRajesh Borundia 
286f197a7aaSRajesh Borundia 	kfree(sriov->vf_info);
28702feda17SRajesh Borundia 	kfree(adapter->ahw->sriov);
28802feda17SRajesh Borundia }
28902feda17SRajesh Borundia 
qlcnic_sriov_vf_cleanup(struct qlcnic_adapter * adapter)290f8468331SRajesh Borundia static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter)
291f8468331SRajesh Borundia {
292f197a7aaSRajesh Borundia 	qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
293f197a7aaSRajesh Borundia 	qlcnic_sriov_cfg_bc_intr(adapter, 0);
294f8468331SRajesh Borundia 	__qlcnic_sriov_cleanup(adapter);
295f8468331SRajesh Borundia }
296f8468331SRajesh Borundia 
qlcnic_sriov_cleanup(struct qlcnic_adapter * adapter)29702feda17SRajesh Borundia void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
29802feda17SRajesh Borundia {
2996e1f586dSManish Chopra 	if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state))
300154d0c81SManish Chopra 		return;
301154d0c81SManish Chopra 
302154d0c81SManish Chopra 	qlcnic_sriov_free_vlans(adapter);
303154d0c81SManish Chopra 
30402feda17SRajesh Borundia 	if (qlcnic_sriov_pf_check(adapter))
30502feda17SRajesh Borundia 		qlcnic_sriov_pf_cleanup(adapter);
306f8468331SRajesh Borundia 
307f8468331SRajesh Borundia 	if (qlcnic_sriov_vf_check(adapter))
308f8468331SRajesh Borundia 		qlcnic_sriov_vf_cleanup(adapter);
309f8468331SRajesh Borundia }
310f8468331SRajesh Borundia 
qlcnic_sriov_post_bc_msg(struct qlcnic_adapter * adapter,u32 * hdr,u32 * pay,u8 pci_func,u8 size)311f197a7aaSRajesh Borundia static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr,
312f197a7aaSRajesh Borundia 				    u32 *pay, u8 pci_func, u8 size)
313f197a7aaSRajesh Borundia {
314f197a7aaSRajesh Borundia 	struct qlcnic_hardware_context *ahw = adapter->ahw;
315068a8d19SManish Chopra 	struct qlcnic_mailbox *mbx = ahw->mailbox;
316068a8d19SManish Chopra 	struct qlcnic_cmd_args cmd;
317068a8d19SManish Chopra 	unsigned long timeout;
318068a8d19SManish Chopra 	int err;
319f197a7aaSRajesh Borundia 
320068a8d19SManish Chopra 	memset(&cmd, 0, sizeof(struct qlcnic_cmd_args));
321068a8d19SManish Chopra 	cmd.hdr = hdr;
322068a8d19SManish Chopra 	cmd.pay = pay;
323068a8d19SManish Chopra 	cmd.pay_size = size;
324068a8d19SManish Chopra 	cmd.func_num = pci_func;
325068a8d19SManish Chopra 	cmd.op_type = QLC_83XX_MBX_POST_BC_OP;
326068a8d19SManish Chopra 	cmd.cmd_op = ((struct qlcnic_bc_hdr *)hdr)->cmd_op;
327f197a7aaSRajesh Borundia 
328068a8d19SManish Chopra 	err = mbx->ops->enqueue_cmd(adapter, &cmd, &timeout);
329068a8d19SManish Chopra 	if (err) {
330f197a7aaSRajesh Borundia 		dev_err(&adapter->pdev->dev,
331068a8d19SManish Chopra 			"%s: Mailbox not available, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",
332068a8d19SManish Chopra 			__func__, cmd.cmd_op, cmd.type, ahw->pci_func,
333068a8d19SManish Chopra 			ahw->op_mode);
334068a8d19SManish Chopra 		return err;
335f197a7aaSRajesh Borundia 	}
336f197a7aaSRajesh Borundia 
337068a8d19SManish Chopra 	if (!wait_for_completion_timeout(&cmd.completion, timeout)) {
338068a8d19SManish Chopra 		dev_err(&adapter->pdev->dev,
339068a8d19SManish Chopra 			"%s: Mailbox command timed out, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",
340068a8d19SManish Chopra 			__func__, cmd.cmd_op, cmd.type, ahw->pci_func,
341068a8d19SManish Chopra 			ahw->op_mode);
342068a8d19SManish Chopra 		flush_workqueue(mbx->work_q);
343068a8d19SManish Chopra 	}
344068a8d19SManish Chopra 
345068a8d19SManish Chopra 	return cmd.rsp_opcode;
346f197a7aaSRajesh Borundia }
347f197a7aaSRajesh Borundia 
qlcnic_sriov_vf_cfg_buff_desc(struct qlcnic_adapter * adapter)3487cb03b23SRajesh Borundia static void qlcnic_sriov_vf_cfg_buff_desc(struct qlcnic_adapter *adapter)
3497cb03b23SRajesh Borundia {
3507cb03b23SRajesh Borundia 	adapter->num_rxd = QLC_DEFAULT_RCV_DESCRIPTORS_SRIOV_VF;
3517cb03b23SRajesh Borundia 	adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G;
3527cb03b23SRajesh Borundia 	adapter->num_jumbo_rxd = QLC_DEFAULT_JUMBO_RCV_DESCRIPTORS_SRIOV_VF;
3537cb03b23SRajesh Borundia 	adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
3547cb03b23SRajesh Borundia 	adapter->num_txd = MAX_CMD_DESCRIPTORS;
3557cb03b23SRajesh Borundia 	adapter->max_rds_rings = MAX_RDS_RINGS;
3567cb03b23SRajesh Borundia }
3577cb03b23SRajesh Borundia 
qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter * adapter,struct qlcnic_info * npar_info,u16 vport_id)3584000e7a7SRajesh Borundia int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *adapter,
3594000e7a7SRajesh Borundia 				   struct qlcnic_info *npar_info, u16 vport_id)
3604000e7a7SRajesh Borundia {
3614000e7a7SRajesh Borundia 	struct device *dev = &adapter->pdev->dev;
3624000e7a7SRajesh Borundia 	struct qlcnic_cmd_args cmd;
3634000e7a7SRajesh Borundia 	int err;
3644000e7a7SRajesh Borundia 	u32 status;
3654000e7a7SRajesh Borundia 
3664000e7a7SRajesh Borundia 	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
3674000e7a7SRajesh Borundia 	if (err)
3684000e7a7SRajesh Borundia 		return err;
3694000e7a7SRajesh Borundia 
3704000e7a7SRajesh Borundia 	cmd.req.arg[1] = vport_id << 16 | 0x1;
3714000e7a7SRajesh Borundia 	err = qlcnic_issue_cmd(adapter, &cmd);
3724000e7a7SRajesh Borundia 	if (err) {
3734000e7a7SRajesh Borundia 		dev_err(&adapter->pdev->dev,
3744000e7a7SRajesh Borundia 			"Failed to get vport info, err=%d\n", err);
3754000e7a7SRajesh Borundia 		qlcnic_free_mbx_args(&cmd);
3764000e7a7SRajesh Borundia 		return err;
3774000e7a7SRajesh Borundia 	}
3784000e7a7SRajesh Borundia 
3794000e7a7SRajesh Borundia 	status = cmd.rsp.arg[2] & 0xffff;
3804000e7a7SRajesh Borundia 	if (status & BIT_0)
3814000e7a7SRajesh Borundia 		npar_info->min_tx_bw = MSW(cmd.rsp.arg[2]);
3824000e7a7SRajesh Borundia 	if (status & BIT_1)
3834000e7a7SRajesh Borundia 		npar_info->max_tx_bw = LSW(cmd.rsp.arg[3]);
3844000e7a7SRajesh Borundia 	if (status & BIT_2)
3854000e7a7SRajesh Borundia 		npar_info->max_tx_ques = MSW(cmd.rsp.arg[3]);
3864000e7a7SRajesh Borundia 	if (status & BIT_3)
3874000e7a7SRajesh Borundia 		npar_info->max_tx_mac_filters = LSW(cmd.rsp.arg[4]);
3884000e7a7SRajesh Borundia 	if (status & BIT_4)
3894000e7a7SRajesh Borundia 		npar_info->max_rx_mcast_mac_filters = MSW(cmd.rsp.arg[4]);
3904000e7a7SRajesh Borundia 	if (status & BIT_5)
3914000e7a7SRajesh Borundia 		npar_info->max_rx_ucast_mac_filters = LSW(cmd.rsp.arg[5]);
3924000e7a7SRajesh Borundia 	if (status & BIT_6)
3934000e7a7SRajesh Borundia 		npar_info->max_rx_ip_addr = MSW(cmd.rsp.arg[5]);
3944000e7a7SRajesh Borundia 	if (status & BIT_7)
3954000e7a7SRajesh Borundia 		npar_info->max_rx_lro_flow = LSW(cmd.rsp.arg[6]);
3964000e7a7SRajesh Borundia 	if (status & BIT_8)
3974000e7a7SRajesh Borundia 		npar_info->max_rx_status_rings = MSW(cmd.rsp.arg[6]);
3984000e7a7SRajesh Borundia 	if (status & BIT_9)
3994000e7a7SRajesh Borundia 		npar_info->max_rx_buf_rings = LSW(cmd.rsp.arg[7]);
4004000e7a7SRajesh Borundia 
4014000e7a7SRajesh Borundia 	npar_info->max_rx_ques = MSW(cmd.rsp.arg[7]);
4024000e7a7SRajesh Borundia 	npar_info->max_tx_vlan_keys = LSW(cmd.rsp.arg[8]);
4034000e7a7SRajesh Borundia 	npar_info->max_local_ipv6_addrs = MSW(cmd.rsp.arg[8]);
4044000e7a7SRajesh Borundia 	npar_info->max_remote_ipv6_addrs = LSW(cmd.rsp.arg[9]);
4054000e7a7SRajesh Borundia 
4064000e7a7SRajesh Borundia 	dev_info(dev, "\n\tmin_tx_bw: %d, max_tx_bw: %d max_tx_ques: %d,\n"
4074000e7a7SRajesh Borundia 		 "\tmax_tx_mac_filters: %d max_rx_mcast_mac_filters: %d,\n"
4084000e7a7SRajesh Borundia 		 "\tmax_rx_ucast_mac_filters: 0x%x, max_rx_ip_addr: %d,\n"
4094000e7a7SRajesh Borundia 		 "\tmax_rx_lro_flow: %d max_rx_status_rings: %d,\n"
4104000e7a7SRajesh Borundia 		 "\tmax_rx_buf_rings: %d, max_rx_ques: %d, max_tx_vlan_keys %d\n"
4114000e7a7SRajesh Borundia 		 "\tlocal_ipv6_addr: %d, remote_ipv6_addr: %d\n",
4124000e7a7SRajesh Borundia 		 npar_info->min_tx_bw, npar_info->max_tx_bw,
4134000e7a7SRajesh Borundia 		 npar_info->max_tx_ques, npar_info->max_tx_mac_filters,
4144000e7a7SRajesh Borundia 		 npar_info->max_rx_mcast_mac_filters,
4154000e7a7SRajesh Borundia 		 npar_info->max_rx_ucast_mac_filters, npar_info->max_rx_ip_addr,
4164000e7a7SRajesh Borundia 		 npar_info->max_rx_lro_flow, npar_info->max_rx_status_rings,
4174000e7a7SRajesh Borundia 		 npar_info->max_rx_buf_rings, npar_info->max_rx_ques,
4184000e7a7SRajesh Borundia 		 npar_info->max_tx_vlan_keys, npar_info->max_local_ipv6_addrs,
4194000e7a7SRajesh Borundia 		 npar_info->max_remote_ipv6_addrs);
4204000e7a7SRajesh Borundia 
4214000e7a7SRajesh Borundia 	qlcnic_free_mbx_args(&cmd);
4224000e7a7SRajesh Borundia 	return err;
4234000e7a7SRajesh Borundia }
4244000e7a7SRajesh Borundia 
qlcnic_sriov_set_pvid_mode(struct qlcnic_adapter * adapter,struct qlcnic_cmd_args * cmd)42591b7282bSRajesh Borundia static int qlcnic_sriov_set_pvid_mode(struct qlcnic_adapter *adapter,
426991ca269SManish Chopra 				      struct qlcnic_cmd_args *cmd)
42791b7282bSRajesh Borundia {
428991ca269SManish Chopra 	adapter->rx_pvid = MSW(cmd->rsp.arg[1]) & 0xffff;
42991b7282bSRajesh Borundia 	adapter->flags &= ~QLCNIC_TAGGING_ENABLED;
43091b7282bSRajesh Borundia 	return 0;
43191b7282bSRajesh Borundia }
43291b7282bSRajesh Borundia 
qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter * adapter,struct qlcnic_cmd_args * cmd)43391b7282bSRajesh Borundia static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter,
43491b7282bSRajesh Borundia 					    struct qlcnic_cmd_args *cmd)
43591b7282bSRajesh Borundia {
43691b7282bSRajesh Borundia 	struct qlcnic_sriov *sriov = adapter->ahw->sriov;
43760ec7fcfSJiasheng Jiang 	int i, num_vlans, ret;
43891b7282bSRajesh Borundia 	u16 *vlans;
43991b7282bSRajesh Borundia 
44091b7282bSRajesh Borundia 	if (sriov->allowed_vlans)
44191b7282bSRajesh Borundia 		return 0;
44291b7282bSRajesh Borundia 
44391b7282bSRajesh Borundia 	sriov->any_vlan = cmd->rsp.arg[2] & 0xf;
444154d0c81SManish Chopra 	sriov->num_allowed_vlans = cmd->rsp.arg[2] >> 16;
445154d0c81SManish Chopra 	dev_info(&adapter->pdev->dev, "Number of allowed Guest VLANs = %d\n",
446154d0c81SManish Chopra 		 sriov->num_allowed_vlans);
447154d0c81SManish Chopra 
44860ec7fcfSJiasheng Jiang 	ret = qlcnic_sriov_alloc_vlans(adapter);
44960ec7fcfSJiasheng Jiang 	if (ret)
45060ec7fcfSJiasheng Jiang 		return ret;
451154d0c81SManish Chopra 
45291b7282bSRajesh Borundia 	if (!sriov->any_vlan)
45391b7282bSRajesh Borundia 		return 0;
45491b7282bSRajesh Borundia 
45591b7282bSRajesh Borundia 	num_vlans = sriov->num_allowed_vlans;
4566396bb22SKees Cook 	sriov->allowed_vlans = kcalloc(num_vlans, sizeof(u16), GFP_KERNEL);
45791b7282bSRajesh Borundia 	if (!sriov->allowed_vlans)
45891b7282bSRajesh Borundia 		return -ENOMEM;
45991b7282bSRajesh Borundia 
46091b7282bSRajesh Borundia 	vlans = (u16 *)&cmd->rsp.arg[3];
46191b7282bSRajesh Borundia 	for (i = 0; i < num_vlans; i++)
46291b7282bSRajesh Borundia 		sriov->allowed_vlans[i] = vlans[i];
46391b7282bSRajesh Borundia 
46491b7282bSRajesh Borundia 	return 0;
46591b7282bSRajesh Borundia }
46691b7282bSRajesh Borundia 
qlcnic_sriov_get_vf_acl(struct qlcnic_adapter * adapter)467bcf6cb1aSRajesh Borundia static int qlcnic_sriov_get_vf_acl(struct qlcnic_adapter *adapter)
46891b7282bSRajesh Borundia {
46991b7282bSRajesh Borundia 	struct qlcnic_sriov *sriov = adapter->ahw->sriov;
47091b7282bSRajesh Borundia 	struct qlcnic_cmd_args cmd;
471991ca269SManish Chopra 	int ret = 0;
47291b7282bSRajesh Borundia 
473c5316920SRajesh Borundia 	memset(&cmd, 0, sizeof(cmd));
47491b7282bSRajesh Borundia 	ret = qlcnic_sriov_alloc_bc_mbx_args(&cmd, QLCNIC_BC_CMD_GET_ACL);
47591b7282bSRajesh Borundia 	if (ret)
47691b7282bSRajesh Borundia 		return ret;
47791b7282bSRajesh Borundia 
47891b7282bSRajesh Borundia 	ret = qlcnic_issue_cmd(adapter, &cmd);
47991b7282bSRajesh Borundia 	if (ret) {
48091b7282bSRajesh Borundia 		dev_err(&adapter->pdev->dev, "Failed to get ACL, err=%d\n",
48191b7282bSRajesh Borundia 			ret);
48291b7282bSRajesh Borundia 	} else {
48391b7282bSRajesh Borundia 		sriov->vlan_mode = cmd.rsp.arg[1] & 0x3;
48491b7282bSRajesh Borundia 		switch (sriov->vlan_mode) {
48591b7282bSRajesh Borundia 		case QLC_GUEST_VLAN_MODE:
48691b7282bSRajesh Borundia 			ret = qlcnic_sriov_set_guest_vlan_mode(adapter, &cmd);
48791b7282bSRajesh Borundia 			break;
48891b7282bSRajesh Borundia 		case QLC_PVID_MODE:
489991ca269SManish Chopra 			ret = qlcnic_sriov_set_pvid_mode(adapter, &cmd);
49091b7282bSRajesh Borundia 			break;
49191b7282bSRajesh Borundia 		}
49291b7282bSRajesh Borundia 	}
49391b7282bSRajesh Borundia 
49491b7282bSRajesh Borundia 	qlcnic_free_mbx_args(&cmd);
49591b7282bSRajesh Borundia 	return ret;
49691b7282bSRajesh Borundia }
49791b7282bSRajesh Borundia 
qlcnic_sriov_vf_init_driver(struct qlcnic_adapter * adapter)4987cb03b23SRajesh Borundia static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter)
4997cb03b23SRajesh Borundia {
5007cb03b23SRajesh Borundia 	struct qlcnic_hardware_context *ahw = adapter->ahw;
501068a8d19SManish Chopra 	struct qlcnic_info nic_info;
5027cb03b23SRajesh Borundia 	int err;
5037cb03b23SRajesh Borundia 
5044000e7a7SRajesh Borundia 	err = qlcnic_sriov_get_vf_vport_info(adapter, &nic_info, 0);
5054000e7a7SRajesh Borundia 	if (err)
5064000e7a7SRajesh Borundia 		return err;
5074000e7a7SRajesh Borundia 
508154d0c81SManish Chopra 	ahw->max_mc_count = nic_info.max_rx_mcast_mac_filters;
509154d0c81SManish Chopra 
5107cb03b23SRajesh Borundia 	err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func);
5117cb03b23SRajesh Borundia 	if (err)
5127cb03b23SRajesh Borundia 		return -EIO;
5137cb03b23SRajesh Borundia 
5147cb03b23SRajesh Borundia 	if (qlcnic_83xx_get_port_info(adapter))
5157cb03b23SRajesh Borundia 		return -EIO;
5167cb03b23SRajesh Borundia 
5177cb03b23SRajesh Borundia 	qlcnic_sriov_vf_cfg_buff_desc(adapter);
5187cb03b23SRajesh Borundia 	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
5197cb03b23SRajesh Borundia 	dev_info(&adapter->pdev->dev, "HAL Version: %d\n",
5207cb03b23SRajesh Borundia 		 adapter->ahw->fw_hal_version);
5217cb03b23SRajesh Borundia 
5227cb03b23SRajesh Borundia 	ahw->physical_port = (u8) nic_info.phys_port;
5237cb03b23SRajesh Borundia 	ahw->switch_mode = nic_info.switch_mode;
5247cb03b23SRajesh Borundia 	ahw->max_mtu = nic_info.max_mtu;
5257cb03b23SRajesh Borundia 	ahw->op_mode = nic_info.op_mode;
5267cb03b23SRajesh Borundia 	ahw->capabilities = nic_info.capabilities;
5277cb03b23SRajesh Borundia 	return 0;
5287cb03b23SRajesh Borundia }
5297cb03b23SRajesh Borundia 
qlcnic_sriov_setup_vf(struct qlcnic_adapter * adapter)530a72dc199SChristophe JAILLET static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter)
531f8468331SRajesh Borundia {
532f8468331SRajesh Borundia 	int err;
533f8468331SRajesh Borundia 
534d747c333SRajesh Borundia 	adapter->flags |= QLCNIC_VLAN_FILTERING;
535d747c333SRajesh Borundia 	adapter->ahw->total_nic_func = 1;
536e8b508efSRajesh Borundia 	INIT_LIST_HEAD(&adapter->vf_mc_list);
537f8468331SRajesh Borundia 	if (!qlcnic_use_msi_x && !!qlcnic_use_msi)
538f8468331SRajesh Borundia 		dev_warn(&adapter->pdev->dev,
53901b91f4cSPratik Pujar 			 "Device does not support MSI interrupts\n");
540f8468331SRajesh Borundia 
54134e8c406SHimanshu Madhani 	/* compute and set default and max tx/sds rings */
54234e8c406SHimanshu Madhani 	qlcnic_set_tx_ring_count(adapter, QLCNIC_SINGLE_RING);
54334e8c406SHimanshu Madhani 	qlcnic_set_sds_ring_count(adapter, QLCNIC_SINGLE_RING);
54434e8c406SHimanshu Madhani 
54534e8c406SHimanshu Madhani 	err = qlcnic_setup_intr(adapter);
546f8468331SRajesh Borundia 	if (err) {
547f8468331SRajesh Borundia 		dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n");
548f8468331SRajesh Borundia 		goto err_out_disable_msi;
549f8468331SRajesh Borundia 	}
550f8468331SRajesh Borundia 
551f8468331SRajesh Borundia 	err = qlcnic_83xx_setup_mbx_intr(adapter);
552f8468331SRajesh Borundia 	if (err)
553f8468331SRajesh Borundia 		goto err_out_disable_msi;
554f8468331SRajesh Borundia 
555f8468331SRajesh Borundia 	err = qlcnic_sriov_init(adapter, 1);
556f8468331SRajesh Borundia 	if (err)
557f8468331SRajesh Borundia 		goto err_out_disable_mbx_intr;
558f8468331SRajesh Borundia 
559f197a7aaSRajesh Borundia 	err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
560f8468331SRajesh Borundia 	if (err)
561f8468331SRajesh Borundia 		goto err_out_cleanup_sriov;
562f8468331SRajesh Borundia 
563f197a7aaSRajesh Borundia 	err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT);
564f197a7aaSRajesh Borundia 	if (err)
565f197a7aaSRajesh Borundia 		goto err_out_disable_bc_intr;
566f197a7aaSRajesh Borundia 
5677cb03b23SRajesh Borundia 	err = qlcnic_sriov_vf_init_driver(adapter);
5687cb03b23SRajesh Borundia 	if (err)
5697cb03b23SRajesh Borundia 		goto err_out_send_channel_term;
5707cb03b23SRajesh Borundia 
571bcf6cb1aSRajesh Borundia 	err = qlcnic_sriov_get_vf_acl(adapter);
572bcf6cb1aSRajesh Borundia 	if (err)
573bcf6cb1aSRajesh Borundia 		goto err_out_send_channel_term;
574bcf6cb1aSRajesh Borundia 
575a72dc199SChristophe JAILLET 	err = qlcnic_setup_netdev(adapter, adapter->netdev);
576f197a7aaSRajesh Borundia 	if (err)
577f197a7aaSRajesh Borundia 		goto err_out_send_channel_term;
578f197a7aaSRajesh Borundia 
579f8468331SRajesh Borundia 	pci_set_drvdata(adapter->pdev, adapter);
580f8468331SRajesh Borundia 	dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
581f8468331SRajesh Borundia 		 adapter->netdev->name);
58214d385b9SSucheta Chakraborty 
583f036e4f4SRajesh Borundia 	qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state,
584f036e4f4SRajesh Borundia 			     adapter->ahw->idc.delay);
585f8468331SRajesh Borundia 	return 0;
586f8468331SRajesh Borundia 
587f197a7aaSRajesh Borundia err_out_send_channel_term:
588f197a7aaSRajesh Borundia 	qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
589f197a7aaSRajesh Borundia 
590f197a7aaSRajesh Borundia err_out_disable_bc_intr:
591f197a7aaSRajesh Borundia 	qlcnic_sriov_cfg_bc_intr(adapter, 0);
592f197a7aaSRajesh Borundia 
593f8468331SRajesh Borundia err_out_cleanup_sriov:
594f8468331SRajesh Borundia 	__qlcnic_sriov_cleanup(adapter);
595f8468331SRajesh Borundia 
596f8468331SRajesh Borundia err_out_disable_mbx_intr:
597f8468331SRajesh Borundia 	qlcnic_83xx_free_mbx_intr(adapter);
598f8468331SRajesh Borundia 
599f8468331SRajesh Borundia err_out_disable_msi:
600f8468331SRajesh Borundia 	qlcnic_teardown_intr(adapter);
601f8468331SRajesh Borundia 	return err;
602f8468331SRajesh Borundia }
603f8468331SRajesh Borundia 
qlcnic_sriov_check_dev_ready(struct qlcnic_adapter * adapter)604f036e4f4SRajesh Borundia static int qlcnic_sriov_check_dev_ready(struct qlcnic_adapter *adapter)
605f036e4f4SRajesh Borundia {
606f036e4f4SRajesh Borundia 	u32 state;
607f036e4f4SRajesh Borundia 
608f036e4f4SRajesh Borundia 	do {
609f036e4f4SRajesh Borundia 		msleep(20);
610f036e4f4SRajesh Borundia 		if (++adapter->fw_fail_cnt > QLC_BC_CMD_MAX_RETRY_CNT)
611f036e4f4SRajesh Borundia 			return -EIO;
612f036e4f4SRajesh Borundia 		state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
613f036e4f4SRajesh Borundia 	} while (state != QLC_83XX_IDC_DEV_READY);
614f036e4f4SRajesh Borundia 
615f036e4f4SRajesh Borundia 	return 0;
616f036e4f4SRajesh Borundia }
617f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_init(struct qlcnic_adapter * adapter)618a72dc199SChristophe JAILLET int qlcnic_sriov_vf_init(struct qlcnic_adapter *adapter)
619f8468331SRajesh Borundia {
620f8468331SRajesh Borundia 	struct qlcnic_hardware_context *ahw = adapter->ahw;
621f036e4f4SRajesh Borundia 	int err;
622f8468331SRajesh Borundia 
623f036e4f4SRajesh Borundia 	set_bit(QLC_83XX_MODULE_LOADED, &ahw->idc.status);
624f036e4f4SRajesh Borundia 	ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
625f036e4f4SRajesh Borundia 	ahw->reset_context = 0;
626f036e4f4SRajesh Borundia 	adapter->fw_fail_cnt = 0;
627f8468331SRajesh Borundia 	ahw->msix_supported = 1;
628f036e4f4SRajesh Borundia 	adapter->need_fw_reset = 0;
629da6c8063SRajesh Borundia 	adapter->flags |= QLCNIC_TX_INTR_SHARED;
630f8468331SRajesh Borundia 
631f036e4f4SRajesh Borundia 	err = qlcnic_sriov_check_dev_ready(adapter);
632f036e4f4SRajesh Borundia 	if (err)
633f036e4f4SRajesh Borundia 		return err;
634f036e4f4SRajesh Borundia 
635a72dc199SChristophe JAILLET 	err = qlcnic_sriov_setup_vf(adapter);
636f036e4f4SRajesh Borundia 	if (err)
637f036e4f4SRajesh Borundia 		return err;
638f8468331SRajesh Borundia 
639f8468331SRajesh Borundia 	if (qlcnic_read_mac_addr(adapter))
640f8468331SRajesh Borundia 		dev_warn(&adapter->pdev->dev, "failed to read mac addr\n");
641f8468331SRajesh Borundia 
6421267ff96SSucheta Chakraborty 	INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
6431267ff96SSucheta Chakraborty 
644f8468331SRajesh Borundia 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
645f8468331SRajesh Borundia 	return 0;
646f8468331SRajesh Borundia }
647f8468331SRajesh Borundia 
qlcnic_sriov_vf_set_ops(struct qlcnic_adapter * adapter)648f8468331SRajesh Borundia void qlcnic_sriov_vf_set_ops(struct qlcnic_adapter *adapter)
649f8468331SRajesh Borundia {
650f8468331SRajesh Borundia 	struct qlcnic_hardware_context *ahw = adapter->ahw;
651f8468331SRajesh Borundia 
652f8468331SRajesh Borundia 	ahw->op_mode = QLCNIC_SRIOV_VF_FUNC;
653f8468331SRajesh Borundia 	dev_info(&adapter->pdev->dev,
654f8468331SRajesh Borundia 		 "HAL Version: %d Non Privileged SRIOV function\n",
655f8468331SRajesh Borundia 		 ahw->fw_hal_version);
656f8468331SRajesh Borundia 	adapter->nic_ops = &qlcnic_sriov_vf_ops;
657f8468331SRajesh Borundia 	set_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state);
658f8468331SRajesh Borundia 	return;
659f8468331SRajesh Borundia }
660f8468331SRajesh Borundia 
qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context * ahw)661f8468331SRajesh Borundia void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *ahw)
662f8468331SRajesh Borundia {
663f8468331SRajesh Borundia 	ahw->hw_ops		= &qlcnic_sriov_vf_hw_ops;
664f8468331SRajesh Borundia 	ahw->reg_tbl		= (u32 *)qlcnic_83xx_reg_tbl;
665f8468331SRajesh Borundia 	ahw->ext_reg_tbl	= (u32 *)qlcnic_83xx_ext_reg_tbl;
66602feda17SRajesh Borundia }
667f197a7aaSRajesh Borundia 
qlcnic_sriov_get_bc_paysize(u32 real_pay_size,u8 curr_frag)668f197a7aaSRajesh Borundia static u32 qlcnic_sriov_get_bc_paysize(u32 real_pay_size, u8 curr_frag)
669f197a7aaSRajesh Borundia {
670f197a7aaSRajesh Borundia 	u32 pay_size;
671f197a7aaSRajesh Borundia 
672f197a7aaSRajesh Borundia 	pay_size = real_pay_size / ((curr_frag + 1) * QLC_BC_PAYLOAD_SZ);
673f197a7aaSRajesh Borundia 
674f197a7aaSRajesh Borundia 	if (pay_size)
675f197a7aaSRajesh Borundia 		pay_size = QLC_BC_PAYLOAD_SZ;
676f197a7aaSRajesh Borundia 	else
677f197a7aaSRajesh Borundia 		pay_size = real_pay_size % QLC_BC_PAYLOAD_SZ;
678f197a7aaSRajesh Borundia 
679f197a7aaSRajesh Borundia 	return pay_size;
680f197a7aaSRajesh Borundia }
681f197a7aaSRajesh Borundia 
qlcnic_sriov_func_to_index(struct qlcnic_adapter * adapter,u8 pci_func)682f197a7aaSRajesh Borundia int qlcnic_sriov_func_to_index(struct qlcnic_adapter *adapter, u8 pci_func)
683f197a7aaSRajesh Borundia {
684f197a7aaSRajesh Borundia 	struct qlcnic_vf_info *vf_info = adapter->ahw->sriov->vf_info;
685f197a7aaSRajesh Borundia 	u8 i;
686f197a7aaSRajesh Borundia 
687f197a7aaSRajesh Borundia 	if (qlcnic_sriov_vf_check(adapter))
688f197a7aaSRajesh Borundia 		return 0;
689f197a7aaSRajesh Borundia 
690f197a7aaSRajesh Borundia 	for (i = 0; i < adapter->ahw->sriov->num_vfs; i++) {
691f197a7aaSRajesh Borundia 		if (vf_info[i].pci_func == pci_func)
692f197a7aaSRajesh Borundia 			return i;
693f197a7aaSRajesh Borundia 	}
694f197a7aaSRajesh Borundia 
695f197a7aaSRajesh Borundia 	return -EINVAL;
696f197a7aaSRajesh Borundia }
697f197a7aaSRajesh Borundia 
qlcnic_sriov_alloc_bc_trans(struct qlcnic_bc_trans ** trans)698f197a7aaSRajesh Borundia static inline int qlcnic_sriov_alloc_bc_trans(struct qlcnic_bc_trans **trans)
699f197a7aaSRajesh Borundia {
700f197a7aaSRajesh Borundia 	*trans = kzalloc(sizeof(struct qlcnic_bc_trans), GFP_ATOMIC);
701f197a7aaSRajesh Borundia 	if (!*trans)
702f197a7aaSRajesh Borundia 		return -ENOMEM;
703f197a7aaSRajesh Borundia 
704f197a7aaSRajesh Borundia 	init_completion(&(*trans)->resp_cmpl);
705f197a7aaSRajesh Borundia 	return 0;
706f197a7aaSRajesh Borundia }
707f197a7aaSRajesh Borundia 
qlcnic_sriov_alloc_bc_msg(struct qlcnic_bc_hdr ** hdr,u32 size)708f197a7aaSRajesh Borundia static inline int qlcnic_sriov_alloc_bc_msg(struct qlcnic_bc_hdr **hdr,
709f197a7aaSRajesh Borundia 					    u32 size)
710f197a7aaSRajesh Borundia {
7116396bb22SKees Cook 	*hdr = kcalloc(size, sizeof(struct qlcnic_bc_hdr), GFP_ATOMIC);
712f197a7aaSRajesh Borundia 	if (!*hdr)
713f197a7aaSRajesh Borundia 		return -ENOMEM;
714f197a7aaSRajesh Borundia 
715f197a7aaSRajesh Borundia 	return 0;
716f197a7aaSRajesh Borundia }
717f197a7aaSRajesh Borundia 
qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args * mbx,u32 type)718f197a7aaSRajesh Borundia static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type)
719f197a7aaSRajesh Borundia {
720f197a7aaSRajesh Borundia 	const struct qlcnic_mailbox_metadata *mbx_tbl;
721f197a7aaSRajesh Borundia 	int i, size;
722f197a7aaSRajesh Borundia 
723f197a7aaSRajesh Borundia 	mbx_tbl = qlcnic_sriov_bc_mbx_tbl;
724f197a7aaSRajesh Borundia 	size = ARRAY_SIZE(qlcnic_sriov_bc_mbx_tbl);
725f197a7aaSRajesh Borundia 
726f197a7aaSRajesh Borundia 	for (i = 0; i < size; i++) {
727f197a7aaSRajesh Borundia 		if (type == mbx_tbl[i].cmd) {
728f197a7aaSRajesh Borundia 			mbx->op_type = QLC_BC_CMD;
729f197a7aaSRajesh Borundia 			mbx->req.num = mbx_tbl[i].in_args;
730f197a7aaSRajesh Borundia 			mbx->rsp.num = mbx_tbl[i].out_args;
731f197a7aaSRajesh Borundia 			mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32),
732f197a7aaSRajesh Borundia 					       GFP_ATOMIC);
733f197a7aaSRajesh Borundia 			if (!mbx->req.arg)
734f197a7aaSRajesh Borundia 				return -ENOMEM;
735f197a7aaSRajesh Borundia 			mbx->rsp.arg = kcalloc(mbx->rsp.num, sizeof(u32),
736f197a7aaSRajesh Borundia 					       GFP_ATOMIC);
737f197a7aaSRajesh Borundia 			if (!mbx->rsp.arg) {
738f197a7aaSRajesh Borundia 				kfree(mbx->req.arg);
739f197a7aaSRajesh Borundia 				mbx->req.arg = NULL;
740f197a7aaSRajesh Borundia 				return -ENOMEM;
741f197a7aaSRajesh Borundia 			}
742f197a7aaSRajesh Borundia 			mbx->req.arg[0] = (type | (mbx->req.num << 16) |
743f197a7aaSRajesh Borundia 					   (3 << 29));
7446226204bSPratik Pujar 			mbx->rsp.arg[0] = (type & 0xffff) | mbx->rsp.num << 16;
745f197a7aaSRajesh Borundia 			return 0;
746f197a7aaSRajesh Borundia 		}
747f197a7aaSRajesh Borundia 	}
748f197a7aaSRajesh Borundia 	return -EINVAL;
749f197a7aaSRajesh Borundia }
750f197a7aaSRajesh Borundia 
qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans * trans,struct qlcnic_cmd_args * cmd,u16 seq,u8 msg_type)751f197a7aaSRajesh Borundia static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans,
752f197a7aaSRajesh Borundia 				       struct qlcnic_cmd_args *cmd,
753f197a7aaSRajesh Borundia 				       u16 seq, u8 msg_type)
754f197a7aaSRajesh Borundia {
755f197a7aaSRajesh Borundia 	struct qlcnic_bc_hdr *hdr;
756f197a7aaSRajesh Borundia 	int i;
757f197a7aaSRajesh Borundia 	u32 num_regs, bc_pay_sz;
758f197a7aaSRajesh Borundia 	u16 remainder;
759f197a7aaSRajesh Borundia 	u8 cmd_op, num_frags, t_num_frags;
760f197a7aaSRajesh Borundia 
761f197a7aaSRajesh Borundia 	bc_pay_sz = QLC_BC_PAYLOAD_SZ;
762f197a7aaSRajesh Borundia 	if (msg_type == QLC_BC_COMMAND) {
763f197a7aaSRajesh Borundia 		trans->req_pay = (struct qlcnic_bc_payload *)cmd->req.arg;
764f197a7aaSRajesh Borundia 		trans->rsp_pay = (struct qlcnic_bc_payload *)cmd->rsp.arg;
765f197a7aaSRajesh Borundia 		num_regs = cmd->req.num;
766f197a7aaSRajesh Borundia 		trans->req_pay_size = (num_regs * 4);
767f197a7aaSRajesh Borundia 		num_regs = cmd->rsp.num;
768f197a7aaSRajesh Borundia 		trans->rsp_pay_size = (num_regs * 4);
769f197a7aaSRajesh Borundia 		cmd_op = cmd->req.arg[0] & 0xff;
770f197a7aaSRajesh Borundia 		remainder = (trans->req_pay_size) % (bc_pay_sz);
771f197a7aaSRajesh Borundia 		num_frags = (trans->req_pay_size) / (bc_pay_sz);
772f197a7aaSRajesh Borundia 		if (remainder)
773f197a7aaSRajesh Borundia 			num_frags++;
774f197a7aaSRajesh Borundia 		t_num_frags = num_frags;
775f197a7aaSRajesh Borundia 		if (qlcnic_sriov_alloc_bc_msg(&trans->req_hdr, num_frags))
776f197a7aaSRajesh Borundia 			return -ENOMEM;
777f197a7aaSRajesh Borundia 		remainder = (trans->rsp_pay_size) % (bc_pay_sz);
778f197a7aaSRajesh Borundia 		num_frags = (trans->rsp_pay_size) / (bc_pay_sz);
779f197a7aaSRajesh Borundia 		if (remainder)
780f197a7aaSRajesh Borundia 			num_frags++;
781f197a7aaSRajesh Borundia 		if (qlcnic_sriov_alloc_bc_msg(&trans->rsp_hdr, num_frags))
782f197a7aaSRajesh Borundia 			return -ENOMEM;
783f197a7aaSRajesh Borundia 		num_frags  = t_num_frags;
784f197a7aaSRajesh Borundia 		hdr = trans->req_hdr;
785f197a7aaSRajesh Borundia 	}  else {
786f197a7aaSRajesh Borundia 		cmd->req.arg = (u32 *)trans->req_pay;
787f197a7aaSRajesh Borundia 		cmd->rsp.arg = (u32 *)trans->rsp_pay;
788f197a7aaSRajesh Borundia 		cmd_op = cmd->req.arg[0] & 0xff;
789d747c333SRajesh Borundia 		cmd->cmd_op = cmd_op;
790f197a7aaSRajesh Borundia 		remainder = (trans->rsp_pay_size) % (bc_pay_sz);
791f197a7aaSRajesh Borundia 		num_frags = (trans->rsp_pay_size) / (bc_pay_sz);
792f197a7aaSRajesh Borundia 		if (remainder)
793f197a7aaSRajesh Borundia 			num_frags++;
794f197a7aaSRajesh Borundia 		cmd->req.num = trans->req_pay_size / 4;
795f197a7aaSRajesh Borundia 		cmd->rsp.num = trans->rsp_pay_size / 4;
796f197a7aaSRajesh Borundia 		hdr = trans->rsp_hdr;
7976226204bSPratik Pujar 		cmd->op_type = trans->req_hdr->op_type;
798f197a7aaSRajesh Borundia 	}
799f197a7aaSRajesh Borundia 
800f197a7aaSRajesh Borundia 	trans->trans_id = seq;
801f197a7aaSRajesh Borundia 	trans->cmd_id = cmd_op;
802f197a7aaSRajesh Borundia 	for (i = 0; i < num_frags; i++) {
803f197a7aaSRajesh Borundia 		hdr[i].version = 2;
804f197a7aaSRajesh Borundia 		hdr[i].msg_type = msg_type;
805f197a7aaSRajesh Borundia 		hdr[i].op_type = cmd->op_type;
806f197a7aaSRajesh Borundia 		hdr[i].num_cmds = 1;
807f197a7aaSRajesh Borundia 		hdr[i].num_frags = num_frags;
808f197a7aaSRajesh Borundia 		hdr[i].frag_num = i + 1;
809f197a7aaSRajesh Borundia 		hdr[i].cmd_op = cmd_op;
810f197a7aaSRajesh Borundia 		hdr[i].seq_id = seq;
811f197a7aaSRajesh Borundia 	}
812f197a7aaSRajesh Borundia 	return 0;
813f197a7aaSRajesh Borundia }
814f197a7aaSRajesh Borundia 
qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans * trans)815f197a7aaSRajesh Borundia static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *trans)
816f197a7aaSRajesh Borundia {
817f197a7aaSRajesh Borundia 	if (!trans)
818f197a7aaSRajesh Borundia 		return;
819f197a7aaSRajesh Borundia 	kfree(trans->req_hdr);
820f197a7aaSRajesh Borundia 	kfree(trans->rsp_hdr);
821f197a7aaSRajesh Borundia 	kfree(trans);
822f197a7aaSRajesh Borundia }
823f197a7aaSRajesh Borundia 
qlcnic_sriov_clear_trans(struct qlcnic_vf_info * vf,struct qlcnic_bc_trans * trans,u8 type)824f197a7aaSRajesh Borundia static int qlcnic_sriov_clear_trans(struct qlcnic_vf_info *vf,
825f197a7aaSRajesh Borundia 				    struct qlcnic_bc_trans *trans, u8 type)
826f197a7aaSRajesh Borundia {
827f197a7aaSRajesh Borundia 	struct qlcnic_trans_list *t_list;
828f197a7aaSRajesh Borundia 	unsigned long flags;
829f197a7aaSRajesh Borundia 	int ret = 0;
830f197a7aaSRajesh Borundia 
831f197a7aaSRajesh Borundia 	if (type == QLC_BC_RESPONSE) {
832f197a7aaSRajesh Borundia 		t_list = &vf->rcv_act;
833f197a7aaSRajesh Borundia 		spin_lock_irqsave(&t_list->lock, flags);
834f197a7aaSRajesh Borundia 		t_list->count--;
835f197a7aaSRajesh Borundia 		list_del(&trans->list);
836f197a7aaSRajesh Borundia 		if (t_list->count > 0)
837f197a7aaSRajesh Borundia 			ret = 1;
838f197a7aaSRajesh Borundia 		spin_unlock_irqrestore(&t_list->lock, flags);
839f197a7aaSRajesh Borundia 	}
840f197a7aaSRajesh Borundia 	if (type == QLC_BC_COMMAND) {
841f197a7aaSRajesh Borundia 		while (test_and_set_bit(QLC_BC_VF_SEND, &vf->state))
842f197a7aaSRajesh Borundia 			msleep(100);
843f197a7aaSRajesh Borundia 		vf->send_cmd = NULL;
844f197a7aaSRajesh Borundia 		clear_bit(QLC_BC_VF_SEND, &vf->state);
845f197a7aaSRajesh Borundia 	}
846f197a7aaSRajesh Borundia 	return ret;
847f197a7aaSRajesh Borundia }
848f197a7aaSRajesh Borundia 
qlcnic_sriov_schedule_bc_cmd(struct qlcnic_sriov * sriov,struct qlcnic_vf_info * vf,work_func_t func)849f197a7aaSRajesh Borundia static void qlcnic_sriov_schedule_bc_cmd(struct qlcnic_sriov *sriov,
850f197a7aaSRajesh Borundia 					 struct qlcnic_vf_info *vf,
851f197a7aaSRajesh Borundia 					 work_func_t func)
852f197a7aaSRajesh Borundia {
853f036e4f4SRajesh Borundia 	if (test_bit(QLC_BC_VF_FLR, &vf->state) ||
854f036e4f4SRajesh Borundia 	    vf->adapter->need_fw_reset)
85597d8105cSRajesh Borundia 		return;
85697d8105cSRajesh Borundia 
857f197a7aaSRajesh Borundia 	queue_work(sriov->bc.bc_trans_wq, &vf->trans_work);
858f197a7aaSRajesh Borundia }
859f197a7aaSRajesh Borundia 
qlcnic_sriov_wait_for_resp(struct qlcnic_bc_trans * trans)860f197a7aaSRajesh Borundia static inline void qlcnic_sriov_wait_for_resp(struct qlcnic_bc_trans *trans)
861f197a7aaSRajesh Borundia {
862f197a7aaSRajesh Borundia 	struct completion *cmpl = &trans->resp_cmpl;
863f197a7aaSRajesh Borundia 
864f197a7aaSRajesh Borundia 	if (wait_for_completion_timeout(cmpl, QLC_MBOX_RESP_TIMEOUT))
865f197a7aaSRajesh Borundia 		trans->trans_state = QLC_END;
866f197a7aaSRajesh Borundia 	else
867f197a7aaSRajesh Borundia 		trans->trans_state = QLC_ABORT;
868f197a7aaSRajesh Borundia 
869f197a7aaSRajesh Borundia 	return;
870f197a7aaSRajesh Borundia }
871f197a7aaSRajesh Borundia 
qlcnic_sriov_handle_multi_frags(struct qlcnic_bc_trans * trans,u8 type)872f197a7aaSRajesh Borundia static void qlcnic_sriov_handle_multi_frags(struct qlcnic_bc_trans *trans,
873f197a7aaSRajesh Borundia 					    u8 type)
874f197a7aaSRajesh Borundia {
875f197a7aaSRajesh Borundia 	if (type == QLC_BC_RESPONSE) {
876f197a7aaSRajesh Borundia 		trans->curr_rsp_frag++;
877f197a7aaSRajesh Borundia 		if (trans->curr_rsp_frag < trans->rsp_hdr->num_frags)
878f197a7aaSRajesh Borundia 			trans->trans_state = QLC_INIT;
879f197a7aaSRajesh Borundia 		else
880f197a7aaSRajesh Borundia 			trans->trans_state = QLC_END;
881f197a7aaSRajesh Borundia 	} else {
882f197a7aaSRajesh Borundia 		trans->curr_req_frag++;
883f197a7aaSRajesh Borundia 		if (trans->curr_req_frag < trans->req_hdr->num_frags)
884f197a7aaSRajesh Borundia 			trans->trans_state = QLC_INIT;
885f197a7aaSRajesh Borundia 		else
886f197a7aaSRajesh Borundia 			trans->trans_state = QLC_WAIT_FOR_RESP;
887f197a7aaSRajesh Borundia 	}
888f197a7aaSRajesh Borundia }
889f197a7aaSRajesh Borundia 
qlcnic_sriov_wait_for_channel_free(struct qlcnic_bc_trans * trans,u8 type)890f197a7aaSRajesh Borundia static void qlcnic_sriov_wait_for_channel_free(struct qlcnic_bc_trans *trans,
891f197a7aaSRajesh Borundia 					       u8 type)
892f197a7aaSRajesh Borundia {
893f197a7aaSRajesh Borundia 	struct qlcnic_vf_info *vf = trans->vf;
894f197a7aaSRajesh Borundia 	struct completion *cmpl = &vf->ch_free_cmpl;
895f197a7aaSRajesh Borundia 
896f197a7aaSRajesh Borundia 	if (!wait_for_completion_timeout(cmpl, QLC_MBOX_CH_FREE_TIMEOUT)) {
897f197a7aaSRajesh Borundia 		trans->trans_state = QLC_ABORT;
898f197a7aaSRajesh Borundia 		return;
899f197a7aaSRajesh Borundia 	}
900f197a7aaSRajesh Borundia 
901f197a7aaSRajesh Borundia 	clear_bit(QLC_BC_VF_CHANNEL, &vf->state);
902f197a7aaSRajesh Borundia 	qlcnic_sriov_handle_multi_frags(trans, type);
903f197a7aaSRajesh Borundia }
904f197a7aaSRajesh Borundia 
qlcnic_sriov_pull_bc_msg(struct qlcnic_adapter * adapter,u32 * hdr,u32 * pay,u32 size)905f197a7aaSRajesh Borundia static void qlcnic_sriov_pull_bc_msg(struct qlcnic_adapter *adapter,
906f197a7aaSRajesh Borundia 				     u32 *hdr, u32 *pay, u32 size)
907f197a7aaSRajesh Borundia {
908f197a7aaSRajesh Borundia 	struct qlcnic_hardware_context *ahw = adapter->ahw;
909f197a7aaSRajesh Borundia 	u8 i, max = 2, hdr_size, j;
910f197a7aaSRajesh Borundia 
911f197a7aaSRajesh Borundia 	hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
912f197a7aaSRajesh Borundia 	max = (size / sizeof(u32)) + hdr_size;
913f197a7aaSRajesh Borundia 
914f197a7aaSRajesh Borundia 	for (i = 2, j = 0; j < hdr_size; i++, j++)
915f197a7aaSRajesh Borundia 		*(hdr++) = readl(QLCNIC_MBX_FW(ahw, i));
916f197a7aaSRajesh Borundia 	for (; j < max; i++, j++)
917f197a7aaSRajesh Borundia 		*(pay++) = readl(QLCNIC_MBX_FW(ahw, i));
918f197a7aaSRajesh Borundia }
919f197a7aaSRajesh Borundia 
__qlcnic_sriov_issue_bc_post(struct qlcnic_vf_info * vf)920f197a7aaSRajesh Borundia static int __qlcnic_sriov_issue_bc_post(struct qlcnic_vf_info *vf)
921f197a7aaSRajesh Borundia {
922f197a7aaSRajesh Borundia 	int ret = -EBUSY;
923f197a7aaSRajesh Borundia 	u32 timeout = 10000;
924f197a7aaSRajesh Borundia 
925f197a7aaSRajesh Borundia 	do {
926f197a7aaSRajesh Borundia 		if (!test_and_set_bit(QLC_BC_VF_CHANNEL, &vf->state)) {
927f197a7aaSRajesh Borundia 			ret = 0;
928f197a7aaSRajesh Borundia 			break;
929f197a7aaSRajesh Borundia 		}
930f197a7aaSRajesh Borundia 		mdelay(1);
931f197a7aaSRajesh Borundia 	} while (--timeout);
932f197a7aaSRajesh Borundia 
933f197a7aaSRajesh Borundia 	return ret;
934f197a7aaSRajesh Borundia }
935f197a7aaSRajesh Borundia 
qlcnic_sriov_issue_bc_post(struct qlcnic_bc_trans * trans,u8 type)936f197a7aaSRajesh Borundia static int qlcnic_sriov_issue_bc_post(struct qlcnic_bc_trans *trans, u8 type)
937f197a7aaSRajesh Borundia {
938f197a7aaSRajesh Borundia 	struct qlcnic_vf_info *vf = trans->vf;
939db3df242SYue Haibing 	u32 pay_size;
940f197a7aaSRajesh Borundia 	u32 *hdr, *pay;
941f197a7aaSRajesh Borundia 	int ret;
942f197a7aaSRajesh Borundia 	u8 pci_func = trans->func_id;
943f197a7aaSRajesh Borundia 
944f197a7aaSRajesh Borundia 	if (__qlcnic_sriov_issue_bc_post(vf))
945f197a7aaSRajesh Borundia 		return -EBUSY;
946f197a7aaSRajesh Borundia 
947f197a7aaSRajesh Borundia 	if (type == QLC_BC_COMMAND) {
948f197a7aaSRajesh Borundia 		hdr = (u32 *)(trans->req_hdr + trans->curr_req_frag);
949f197a7aaSRajesh Borundia 		pay = (u32 *)(trans->req_pay + trans->curr_req_frag);
950f197a7aaSRajesh Borundia 		pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
951f197a7aaSRajesh Borundia 						       trans->curr_req_frag);
952f197a7aaSRajesh Borundia 		pay_size = (pay_size / sizeof(u32));
953f197a7aaSRajesh Borundia 	} else {
954f197a7aaSRajesh Borundia 		hdr = (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag);
955f197a7aaSRajesh Borundia 		pay = (u32 *)(trans->rsp_pay + trans->curr_rsp_frag);
956f197a7aaSRajesh Borundia 		pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size,
957f197a7aaSRajesh Borundia 						       trans->curr_rsp_frag);
958f197a7aaSRajesh Borundia 		pay_size = (pay_size / sizeof(u32));
959f197a7aaSRajesh Borundia 	}
960f197a7aaSRajesh Borundia 
961f197a7aaSRajesh Borundia 	ret = qlcnic_sriov_post_bc_msg(vf->adapter, hdr, pay,
962f197a7aaSRajesh Borundia 				       pci_func, pay_size);
963f197a7aaSRajesh Borundia 	return ret;
964f197a7aaSRajesh Borundia }
965f197a7aaSRajesh Borundia 
__qlcnic_sriov_send_bc_msg(struct qlcnic_bc_trans * trans,struct qlcnic_vf_info * vf,u8 type)966f197a7aaSRajesh Borundia static int __qlcnic_sriov_send_bc_msg(struct qlcnic_bc_trans *trans,
967f197a7aaSRajesh Borundia 				      struct qlcnic_vf_info *vf, u8 type)
968f197a7aaSRajesh Borundia {
969f197a7aaSRajesh Borundia 	bool flag = true;
97097d8105cSRajesh Borundia 	int err = -EIO;
971f197a7aaSRajesh Borundia 
972f197a7aaSRajesh Borundia 	while (flag) {
973f036e4f4SRajesh Borundia 		if (test_bit(QLC_BC_VF_FLR, &vf->state) ||
974f036e4f4SRajesh Borundia 		    vf->adapter->need_fw_reset)
97597d8105cSRajesh Borundia 			trans->trans_state = QLC_ABORT;
97697d8105cSRajesh Borundia 
977f197a7aaSRajesh Borundia 		switch (trans->trans_state) {
978f197a7aaSRajesh Borundia 		case QLC_INIT:
979f197a7aaSRajesh Borundia 			trans->trans_state = QLC_WAIT_FOR_CHANNEL_FREE;
980f197a7aaSRajesh Borundia 			if (qlcnic_sriov_issue_bc_post(trans, type))
981f197a7aaSRajesh Borundia 				trans->trans_state = QLC_ABORT;
982f197a7aaSRajesh Borundia 			break;
983f197a7aaSRajesh Borundia 		case QLC_WAIT_FOR_CHANNEL_FREE:
984f197a7aaSRajesh Borundia 			qlcnic_sriov_wait_for_channel_free(trans, type);
985f197a7aaSRajesh Borundia 			break;
986f197a7aaSRajesh Borundia 		case QLC_WAIT_FOR_RESP:
987f197a7aaSRajesh Borundia 			qlcnic_sriov_wait_for_resp(trans);
988f197a7aaSRajesh Borundia 			break;
989f197a7aaSRajesh Borundia 		case QLC_END:
990f197a7aaSRajesh Borundia 			err = 0;
991f197a7aaSRajesh Borundia 			flag = false;
992f197a7aaSRajesh Borundia 			break;
993f197a7aaSRajesh Borundia 		case QLC_ABORT:
994f197a7aaSRajesh Borundia 			err = -EIO;
995f197a7aaSRajesh Borundia 			flag = false;
996f197a7aaSRajesh Borundia 			clear_bit(QLC_BC_VF_CHANNEL, &vf->state);
997f197a7aaSRajesh Borundia 			break;
998f197a7aaSRajesh Borundia 		default:
999f197a7aaSRajesh Borundia 			err = -EIO;
1000f197a7aaSRajesh Borundia 			flag = false;
1001f197a7aaSRajesh Borundia 		}
1002f197a7aaSRajesh Borundia 	}
1003f197a7aaSRajesh Borundia 	return err;
1004f197a7aaSRajesh Borundia }
1005f197a7aaSRajesh Borundia 
qlcnic_sriov_send_bc_cmd(struct qlcnic_adapter * adapter,struct qlcnic_bc_trans * trans,int pci_func)1006f197a7aaSRajesh Borundia static int qlcnic_sriov_send_bc_cmd(struct qlcnic_adapter *adapter,
1007f197a7aaSRajesh Borundia 				    struct qlcnic_bc_trans *trans, int pci_func)
1008f197a7aaSRajesh Borundia {
1009f197a7aaSRajesh Borundia 	struct qlcnic_vf_info *vf;
1010f197a7aaSRajesh Borundia 	int err, index = qlcnic_sriov_func_to_index(adapter, pci_func);
1011f197a7aaSRajesh Borundia 
1012f197a7aaSRajesh Borundia 	if (index < 0)
1013f197a7aaSRajesh Borundia 		return -EIO;
1014f197a7aaSRajesh Borundia 
1015f197a7aaSRajesh Borundia 	vf = &adapter->ahw->sriov->vf_info[index];
1016f197a7aaSRajesh Borundia 	trans->vf = vf;
1017f197a7aaSRajesh Borundia 	trans->func_id = pci_func;
1018f197a7aaSRajesh Borundia 
1019f197a7aaSRajesh Borundia 	if (!test_bit(QLC_BC_VF_STATE, &vf->state)) {
1020f197a7aaSRajesh Borundia 		if (qlcnic_sriov_pf_check(adapter))
1021f197a7aaSRajesh Borundia 			return -EIO;
1022f197a7aaSRajesh Borundia 		if (qlcnic_sriov_vf_check(adapter) &&
1023f197a7aaSRajesh Borundia 		    trans->cmd_id != QLCNIC_BC_CMD_CHANNEL_INIT)
1024f197a7aaSRajesh Borundia 			return -EIO;
1025f197a7aaSRajesh Borundia 	}
1026f197a7aaSRajesh Borundia 
1027f197a7aaSRajesh Borundia 	mutex_lock(&vf->send_cmd_lock);
1028f197a7aaSRajesh Borundia 	vf->send_cmd = trans;
1029f197a7aaSRajesh Borundia 	err = __qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_COMMAND);
1030f197a7aaSRajesh Borundia 	qlcnic_sriov_clear_trans(vf, trans, QLC_BC_COMMAND);
1031f197a7aaSRajesh Borundia 	mutex_unlock(&vf->send_cmd_lock);
1032f197a7aaSRajesh Borundia 	return err;
1033f197a7aaSRajesh Borundia }
1034f197a7aaSRajesh Borundia 
__qlcnic_sriov_process_bc_cmd(struct qlcnic_adapter * adapter,struct qlcnic_bc_trans * trans,struct qlcnic_cmd_args * cmd)1035f197a7aaSRajesh Borundia static void __qlcnic_sriov_process_bc_cmd(struct qlcnic_adapter *adapter,
1036f197a7aaSRajesh Borundia 					  struct qlcnic_bc_trans *trans,
1037f197a7aaSRajesh Borundia 					  struct qlcnic_cmd_args *cmd)
1038f197a7aaSRajesh Borundia {
1039f197a7aaSRajesh Borundia #ifdef CONFIG_QLCNIC_SRIOV
1040f197a7aaSRajesh Borundia 	if (qlcnic_sriov_pf_check(adapter)) {
1041f197a7aaSRajesh Borundia 		qlcnic_sriov_pf_process_bc_cmd(adapter, trans, cmd);
1042f197a7aaSRajesh Borundia 		return;
1043f197a7aaSRajesh Borundia 	}
1044f197a7aaSRajesh Borundia #endif
1045f197a7aaSRajesh Borundia 	cmd->rsp.arg[0] |= (0x9 << 25);
1046f197a7aaSRajesh Borundia 	return;
1047f197a7aaSRajesh Borundia }
1048f197a7aaSRajesh Borundia 
qlcnic_sriov_process_bc_cmd(struct work_struct * work)1049f197a7aaSRajesh Borundia static void qlcnic_sriov_process_bc_cmd(struct work_struct *work)
1050f197a7aaSRajesh Borundia {
1051f197a7aaSRajesh Borundia 	struct qlcnic_vf_info *vf = container_of(work, struct qlcnic_vf_info,
1052f197a7aaSRajesh Borundia 						 trans_work);
1053f197a7aaSRajesh Borundia 	struct qlcnic_bc_trans *trans = NULL;
1054f197a7aaSRajesh Borundia 	struct qlcnic_adapter *adapter  = vf->adapter;
1055f197a7aaSRajesh Borundia 	struct qlcnic_cmd_args cmd;
1056f197a7aaSRajesh Borundia 	u8 req;
1057f197a7aaSRajesh Borundia 
1058f036e4f4SRajesh Borundia 	if (adapter->need_fw_reset)
1059f036e4f4SRajesh Borundia 		return;
1060f036e4f4SRajesh Borundia 
106197d8105cSRajesh Borundia 	if (test_bit(QLC_BC_VF_FLR, &vf->state))
106297d8105cSRajesh Borundia 		return;
106397d8105cSRajesh Borundia 
1064e5c4e6c6SManish Chopra 	memset(&cmd, 0, sizeof(struct qlcnic_cmd_args));
1065f197a7aaSRajesh Borundia 	trans = list_first_entry(&vf->rcv_act.wait_list,
1066f197a7aaSRajesh Borundia 				 struct qlcnic_bc_trans, list);
1067f197a7aaSRajesh Borundia 	adapter = vf->adapter;
1068f197a7aaSRajesh Borundia 
1069f197a7aaSRajesh Borundia 	if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, trans->req_hdr->seq_id,
1070f197a7aaSRajesh Borundia 					QLC_BC_RESPONSE))
1071f197a7aaSRajesh Borundia 		goto cleanup_trans;
1072f197a7aaSRajesh Borundia 
1073f197a7aaSRajesh Borundia 	__qlcnic_sriov_process_bc_cmd(adapter, trans, &cmd);
1074f197a7aaSRajesh Borundia 	trans->trans_state = QLC_INIT;
1075f197a7aaSRajesh Borundia 	__qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_RESPONSE);
1076f197a7aaSRajesh Borundia 
1077f197a7aaSRajesh Borundia cleanup_trans:
1078f197a7aaSRajesh Borundia 	qlcnic_free_mbx_args(&cmd);
1079f197a7aaSRajesh Borundia 	req = qlcnic_sriov_clear_trans(vf, trans, QLC_BC_RESPONSE);
1080f197a7aaSRajesh Borundia 	qlcnic_sriov_cleanup_transaction(trans);
1081f197a7aaSRajesh Borundia 	if (req)
1082f197a7aaSRajesh Borundia 		qlcnic_sriov_schedule_bc_cmd(adapter->ahw->sriov, vf,
1083f197a7aaSRajesh Borundia 					     qlcnic_sriov_process_bc_cmd);
1084f197a7aaSRajesh Borundia }
1085f197a7aaSRajesh Borundia 
qlcnic_sriov_handle_bc_resp(struct qlcnic_bc_hdr * hdr,struct qlcnic_vf_info * vf)1086f197a7aaSRajesh Borundia static void qlcnic_sriov_handle_bc_resp(struct qlcnic_bc_hdr *hdr,
1087f197a7aaSRajesh Borundia 					struct qlcnic_vf_info *vf)
1088f197a7aaSRajesh Borundia {
1089f197a7aaSRajesh Borundia 	struct qlcnic_bc_trans *trans;
1090f197a7aaSRajesh Borundia 	u32 pay_size;
1091f197a7aaSRajesh Borundia 
1092f197a7aaSRajesh Borundia 	if (test_and_set_bit(QLC_BC_VF_SEND, &vf->state))
1093f197a7aaSRajesh Borundia 		return;
1094f197a7aaSRajesh Borundia 
1095f197a7aaSRajesh Borundia 	trans = vf->send_cmd;
1096f197a7aaSRajesh Borundia 
1097f197a7aaSRajesh Borundia 	if (trans == NULL)
1098f197a7aaSRajesh Borundia 		goto clear_send;
1099f197a7aaSRajesh Borundia 
1100f197a7aaSRajesh Borundia 	if (trans->trans_id != hdr->seq_id)
1101f197a7aaSRajesh Borundia 		goto clear_send;
1102f197a7aaSRajesh Borundia 
1103f197a7aaSRajesh Borundia 	pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size,
1104f197a7aaSRajesh Borundia 					       trans->curr_rsp_frag);
1105f197a7aaSRajesh Borundia 	qlcnic_sriov_pull_bc_msg(vf->adapter,
1106f197a7aaSRajesh Borundia 				 (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag),
1107f197a7aaSRajesh Borundia 				 (u32 *)(trans->rsp_pay + trans->curr_rsp_frag),
1108f197a7aaSRajesh Borundia 				 pay_size);
1109f197a7aaSRajesh Borundia 	if (++trans->curr_rsp_frag < trans->rsp_hdr->num_frags)
1110f197a7aaSRajesh Borundia 		goto clear_send;
1111f197a7aaSRajesh Borundia 
1112f197a7aaSRajesh Borundia 	complete(&trans->resp_cmpl);
1113f197a7aaSRajesh Borundia 
1114f197a7aaSRajesh Borundia clear_send:
1115f197a7aaSRajesh Borundia 	clear_bit(QLC_BC_VF_SEND, &vf->state);
1116f197a7aaSRajesh Borundia }
1117f197a7aaSRajesh Borundia 
__qlcnic_sriov_add_act_list(struct qlcnic_sriov * sriov,struct qlcnic_vf_info * vf,struct qlcnic_bc_trans * trans)111897d8105cSRajesh Borundia int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov,
111997d8105cSRajesh Borundia 				struct qlcnic_vf_info *vf,
112097d8105cSRajesh Borundia 				struct qlcnic_bc_trans *trans)
112197d8105cSRajesh Borundia {
112297d8105cSRajesh Borundia 	struct qlcnic_trans_list *t_list = &vf->rcv_act;
112397d8105cSRajesh Borundia 
112497d8105cSRajesh Borundia 	t_list->count++;
112597d8105cSRajesh Borundia 	list_add_tail(&trans->list, &t_list->wait_list);
112697d8105cSRajesh Borundia 	if (t_list->count == 1)
112797d8105cSRajesh Borundia 		qlcnic_sriov_schedule_bc_cmd(sriov, vf,
112897d8105cSRajesh Borundia 					     qlcnic_sriov_process_bc_cmd);
112997d8105cSRajesh Borundia 	return 0;
113097d8105cSRajesh Borundia }
113197d8105cSRajesh Borundia 
qlcnic_sriov_add_act_list(struct qlcnic_sriov * sriov,struct qlcnic_vf_info * vf,struct qlcnic_bc_trans * trans)1132f197a7aaSRajesh Borundia static int qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov,
1133f197a7aaSRajesh Borundia 				     struct qlcnic_vf_info *vf,
1134f197a7aaSRajesh Borundia 				     struct qlcnic_bc_trans *trans)
1135f197a7aaSRajesh Borundia {
1136f197a7aaSRajesh Borundia 	struct qlcnic_trans_list *t_list = &vf->rcv_act;
1137f197a7aaSRajesh Borundia 
1138f197a7aaSRajesh Borundia 	spin_lock(&t_list->lock);
113997d8105cSRajesh Borundia 
114097d8105cSRajesh Borundia 	__qlcnic_sriov_add_act_list(sriov, vf, trans);
114197d8105cSRajesh Borundia 
1142f197a7aaSRajesh Borundia 	spin_unlock(&t_list->lock);
1143f197a7aaSRajesh Borundia 	return 0;
1144f197a7aaSRajesh Borundia }
1145f197a7aaSRajesh Borundia 
qlcnic_sriov_handle_pending_trans(struct qlcnic_sriov * sriov,struct qlcnic_vf_info * vf,struct qlcnic_bc_hdr * hdr)1146f197a7aaSRajesh Borundia static void qlcnic_sriov_handle_pending_trans(struct qlcnic_sriov *sriov,
1147f197a7aaSRajesh Borundia 					      struct qlcnic_vf_info *vf,
1148f197a7aaSRajesh Borundia 					      struct qlcnic_bc_hdr *hdr)
1149f197a7aaSRajesh Borundia {
1150f197a7aaSRajesh Borundia 	struct qlcnic_bc_trans *trans = NULL;
1151f197a7aaSRajesh Borundia 	struct list_head *node;
1152f197a7aaSRajesh Borundia 	u32 pay_size, curr_frag;
1153f197a7aaSRajesh Borundia 	u8 found = 0, active = 0;
1154f197a7aaSRajesh Borundia 
1155f197a7aaSRajesh Borundia 	spin_lock(&vf->rcv_pend.lock);
1156f197a7aaSRajesh Borundia 	if (vf->rcv_pend.count > 0) {
1157f197a7aaSRajesh Borundia 		list_for_each(node, &vf->rcv_pend.wait_list) {
1158f197a7aaSRajesh Borundia 			trans = list_entry(node, struct qlcnic_bc_trans, list);
1159f197a7aaSRajesh Borundia 			if (trans->trans_id == hdr->seq_id) {
1160f197a7aaSRajesh Borundia 				found = 1;
1161f197a7aaSRajesh Borundia 				break;
1162f197a7aaSRajesh Borundia 			}
1163f197a7aaSRajesh Borundia 		}
1164f197a7aaSRajesh Borundia 	}
1165f197a7aaSRajesh Borundia 
1166f197a7aaSRajesh Borundia 	if (found) {
1167f197a7aaSRajesh Borundia 		curr_frag = trans->curr_req_frag;
1168f197a7aaSRajesh Borundia 		pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
1169f197a7aaSRajesh Borundia 						       curr_frag);
1170f197a7aaSRajesh Borundia 		qlcnic_sriov_pull_bc_msg(vf->adapter,
1171f197a7aaSRajesh Borundia 					 (u32 *)(trans->req_hdr + curr_frag),
1172f197a7aaSRajesh Borundia 					 (u32 *)(trans->req_pay + curr_frag),
1173f197a7aaSRajesh Borundia 					 pay_size);
1174f197a7aaSRajesh Borundia 		trans->curr_req_frag++;
1175f197a7aaSRajesh Borundia 		if (trans->curr_req_frag >= hdr->num_frags) {
1176f197a7aaSRajesh Borundia 			vf->rcv_pend.count--;
1177f197a7aaSRajesh Borundia 			list_del(&trans->list);
1178f197a7aaSRajesh Borundia 			active = 1;
1179f197a7aaSRajesh Borundia 		}
1180f197a7aaSRajesh Borundia 	}
1181f197a7aaSRajesh Borundia 	spin_unlock(&vf->rcv_pend.lock);
1182f197a7aaSRajesh Borundia 
1183f197a7aaSRajesh Borundia 	if (active)
1184f197a7aaSRajesh Borundia 		if (qlcnic_sriov_add_act_list(sriov, vf, trans))
1185f197a7aaSRajesh Borundia 			qlcnic_sriov_cleanup_transaction(trans);
1186f197a7aaSRajesh Borundia 
1187f197a7aaSRajesh Borundia 	return;
1188f197a7aaSRajesh Borundia }
1189f197a7aaSRajesh Borundia 
qlcnic_sriov_handle_bc_cmd(struct qlcnic_sriov * sriov,struct qlcnic_bc_hdr * hdr,struct qlcnic_vf_info * vf)1190f197a7aaSRajesh Borundia static void qlcnic_sriov_handle_bc_cmd(struct qlcnic_sriov *sriov,
1191f197a7aaSRajesh Borundia 				       struct qlcnic_bc_hdr *hdr,
1192f197a7aaSRajesh Borundia 				       struct qlcnic_vf_info *vf)
1193f197a7aaSRajesh Borundia {
1194f197a7aaSRajesh Borundia 	struct qlcnic_bc_trans *trans;
1195f197a7aaSRajesh Borundia 	struct qlcnic_adapter *adapter = vf->adapter;
1196f197a7aaSRajesh Borundia 	struct qlcnic_cmd_args cmd;
1197f197a7aaSRajesh Borundia 	u32 pay_size;
1198f197a7aaSRajesh Borundia 	int err;
1199f197a7aaSRajesh Borundia 	u8 cmd_op;
1200f197a7aaSRajesh Borundia 
1201f036e4f4SRajesh Borundia 	if (adapter->need_fw_reset)
1202f036e4f4SRajesh Borundia 		return;
1203f036e4f4SRajesh Borundia 
1204f197a7aaSRajesh Borundia 	if (!test_bit(QLC_BC_VF_STATE, &vf->state) &&
1205f197a7aaSRajesh Borundia 	    hdr->op_type != QLC_BC_CMD &&
1206f197a7aaSRajesh Borundia 	    hdr->cmd_op != QLCNIC_BC_CMD_CHANNEL_INIT)
1207f197a7aaSRajesh Borundia 		return;
1208f197a7aaSRajesh Borundia 
1209f197a7aaSRajesh Borundia 	if (hdr->frag_num > 1) {
1210f197a7aaSRajesh Borundia 		qlcnic_sriov_handle_pending_trans(sriov, vf, hdr);
1211f197a7aaSRajesh Borundia 		return;
1212f197a7aaSRajesh Borundia 	}
1213f197a7aaSRajesh Borundia 
1214e5c4e6c6SManish Chopra 	memset(&cmd, 0, sizeof(struct qlcnic_cmd_args));
1215f197a7aaSRajesh Borundia 	cmd_op = hdr->cmd_op;
1216f197a7aaSRajesh Borundia 	if (qlcnic_sriov_alloc_bc_trans(&trans))
1217f197a7aaSRajesh Borundia 		return;
1218f197a7aaSRajesh Borundia 
1219f197a7aaSRajesh Borundia 	if (hdr->op_type == QLC_BC_CMD)
1220f197a7aaSRajesh Borundia 		err = qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op);
1221f197a7aaSRajesh Borundia 	else
1222f197a7aaSRajesh Borundia 		err = qlcnic_alloc_mbx_args(&cmd, adapter, cmd_op);
1223f197a7aaSRajesh Borundia 
1224f197a7aaSRajesh Borundia 	if (err) {
1225f197a7aaSRajesh Borundia 		qlcnic_sriov_cleanup_transaction(trans);
1226f197a7aaSRajesh Borundia 		return;
1227f197a7aaSRajesh Borundia 	}
1228f197a7aaSRajesh Borundia 
1229f197a7aaSRajesh Borundia 	cmd.op_type = hdr->op_type;
1230f197a7aaSRajesh Borundia 	if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, hdr->seq_id,
1231f197a7aaSRajesh Borundia 					QLC_BC_COMMAND)) {
1232f197a7aaSRajesh Borundia 		qlcnic_free_mbx_args(&cmd);
1233f197a7aaSRajesh Borundia 		qlcnic_sriov_cleanup_transaction(trans);
1234f197a7aaSRajesh Borundia 		return;
1235f197a7aaSRajesh Borundia 	}
1236f197a7aaSRajesh Borundia 
1237f197a7aaSRajesh Borundia 	pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
1238f197a7aaSRajesh Borundia 					 trans->curr_req_frag);
1239f197a7aaSRajesh Borundia 	qlcnic_sriov_pull_bc_msg(vf->adapter,
1240f197a7aaSRajesh Borundia 				 (u32 *)(trans->req_hdr + trans->curr_req_frag),
1241f197a7aaSRajesh Borundia 				 (u32 *)(trans->req_pay + trans->curr_req_frag),
1242f197a7aaSRajesh Borundia 				 pay_size);
1243f197a7aaSRajesh Borundia 	trans->func_id = vf->pci_func;
1244f197a7aaSRajesh Borundia 	trans->vf = vf;
1245f197a7aaSRajesh Borundia 	trans->trans_id = hdr->seq_id;
1246f197a7aaSRajesh Borundia 	trans->curr_req_frag++;
124797d8105cSRajesh Borundia 
124897d8105cSRajesh Borundia 	if (qlcnic_sriov_soft_flr_check(adapter, trans, vf))
124997d8105cSRajesh Borundia 		return;
125097d8105cSRajesh Borundia 
1251f197a7aaSRajesh Borundia 	if (trans->curr_req_frag == trans->req_hdr->num_frags) {
1252f197a7aaSRajesh Borundia 		if (qlcnic_sriov_add_act_list(sriov, vf, trans)) {
1253f197a7aaSRajesh Borundia 			qlcnic_free_mbx_args(&cmd);
1254f197a7aaSRajesh Borundia 			qlcnic_sriov_cleanup_transaction(trans);
1255f197a7aaSRajesh Borundia 		}
1256f197a7aaSRajesh Borundia 	} else {
1257f197a7aaSRajesh Borundia 		spin_lock(&vf->rcv_pend.lock);
1258f197a7aaSRajesh Borundia 		list_add_tail(&trans->list, &vf->rcv_pend.wait_list);
1259f197a7aaSRajesh Borundia 		vf->rcv_pend.count++;
1260f197a7aaSRajesh Borundia 		spin_unlock(&vf->rcv_pend.lock);
1261f197a7aaSRajesh Borundia 	}
1262f197a7aaSRajesh Borundia }
1263f197a7aaSRajesh Borundia 
qlcnic_sriov_handle_msg_event(struct qlcnic_sriov * sriov,struct qlcnic_vf_info * vf)1264f197a7aaSRajesh Borundia static void qlcnic_sriov_handle_msg_event(struct qlcnic_sriov *sriov,
1265f197a7aaSRajesh Borundia 					  struct qlcnic_vf_info *vf)
1266f197a7aaSRajesh Borundia {
1267f197a7aaSRajesh Borundia 	struct qlcnic_bc_hdr hdr;
1268f197a7aaSRajesh Borundia 	u32 *ptr = (u32 *)&hdr;
1269f197a7aaSRajesh Borundia 	u8 msg_type, i;
1270f197a7aaSRajesh Borundia 
1271f197a7aaSRajesh Borundia 	for (i = 2; i < 6; i++)
1272f197a7aaSRajesh Borundia 		ptr[i - 2] = readl(QLCNIC_MBX_FW(vf->adapter->ahw, i));
1273f197a7aaSRajesh Borundia 	msg_type = hdr.msg_type;
1274f197a7aaSRajesh Borundia 
1275f197a7aaSRajesh Borundia 	switch (msg_type) {
1276f197a7aaSRajesh Borundia 	case QLC_BC_COMMAND:
1277f197a7aaSRajesh Borundia 		qlcnic_sriov_handle_bc_cmd(sriov, &hdr, vf);
1278f197a7aaSRajesh Borundia 		break;
1279f197a7aaSRajesh Borundia 	case QLC_BC_RESPONSE:
1280f197a7aaSRajesh Borundia 		qlcnic_sriov_handle_bc_resp(&hdr, vf);
1281f197a7aaSRajesh Borundia 		break;
1282f197a7aaSRajesh Borundia 	}
1283f197a7aaSRajesh Borundia }
1284f197a7aaSRajesh Borundia 
qlcnic_sriov_handle_flr_event(struct qlcnic_sriov * sriov,struct qlcnic_vf_info * vf)128597d8105cSRajesh Borundia static void qlcnic_sriov_handle_flr_event(struct qlcnic_sriov *sriov,
128697d8105cSRajesh Borundia 					  struct qlcnic_vf_info *vf)
128797d8105cSRajesh Borundia {
128897d8105cSRajesh Borundia 	struct qlcnic_adapter *adapter = vf->adapter;
128997d8105cSRajesh Borundia 
129097d8105cSRajesh Borundia 	if (qlcnic_sriov_pf_check(adapter))
129197d8105cSRajesh Borundia 		qlcnic_sriov_pf_handle_flr(sriov, vf);
129297d8105cSRajesh Borundia 	else
129397d8105cSRajesh Borundia 		dev_err(&adapter->pdev->dev,
129497d8105cSRajesh Borundia 			"Invalid event to VF. VF should not get FLR event\n");
129597d8105cSRajesh Borundia }
129697d8105cSRajesh Borundia 
qlcnic_sriov_handle_bc_event(struct qlcnic_adapter * adapter,u32 event)1297f197a7aaSRajesh Borundia void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *adapter, u32 event)
1298f197a7aaSRajesh Borundia {
1299f197a7aaSRajesh Borundia 	struct qlcnic_vf_info *vf;
1300f197a7aaSRajesh Borundia 	struct qlcnic_sriov *sriov;
1301f197a7aaSRajesh Borundia 	int index;
1302f197a7aaSRajesh Borundia 	u8 pci_func;
1303f197a7aaSRajesh Borundia 
1304f197a7aaSRajesh Borundia 	sriov = adapter->ahw->sriov;
1305f197a7aaSRajesh Borundia 	pci_func = qlcnic_sriov_target_func_id(event);
1306f197a7aaSRajesh Borundia 	index = qlcnic_sriov_func_to_index(adapter, pci_func);
1307f197a7aaSRajesh Borundia 
1308f197a7aaSRajesh Borundia 	if (index < 0)
1309f197a7aaSRajesh Borundia 		return;
1310f197a7aaSRajesh Borundia 
1311f197a7aaSRajesh Borundia 	vf = &sriov->vf_info[index];
1312f197a7aaSRajesh Borundia 	vf->pci_func = pci_func;
1313f197a7aaSRajesh Borundia 
1314f197a7aaSRajesh Borundia 	if (qlcnic_sriov_channel_free_check(event))
1315f197a7aaSRajesh Borundia 		complete(&vf->ch_free_cmpl);
1316f197a7aaSRajesh Borundia 
131797d8105cSRajesh Borundia 	if (qlcnic_sriov_flr_check(event)) {
131897d8105cSRajesh Borundia 		qlcnic_sriov_handle_flr_event(sriov, vf);
131997d8105cSRajesh Borundia 		return;
132097d8105cSRajesh Borundia 	}
132197d8105cSRajesh Borundia 
1322f197a7aaSRajesh Borundia 	if (qlcnic_sriov_bc_msg_check(event))
1323f197a7aaSRajesh Borundia 		qlcnic_sriov_handle_msg_event(sriov, vf);
1324f197a7aaSRajesh Borundia }
1325f197a7aaSRajesh Borundia 
qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter * adapter,u8 enable)1326f197a7aaSRajesh Borundia int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *adapter, u8 enable)
1327f197a7aaSRajesh Borundia {
1328f197a7aaSRajesh Borundia 	struct qlcnic_cmd_args cmd;
1329f197a7aaSRajesh Borundia 	int err;
1330f197a7aaSRajesh Borundia 
1331f197a7aaSRajesh Borundia 	if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state))
1332f197a7aaSRajesh Borundia 		return 0;
1333f197a7aaSRajesh Borundia 
1334f197a7aaSRajesh Borundia 	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_BC_EVENT_SETUP))
1335f197a7aaSRajesh Borundia 		return -ENOMEM;
1336f197a7aaSRajesh Borundia 
1337f197a7aaSRajesh Borundia 	if (enable)
1338f197a7aaSRajesh Borundia 		cmd.req.arg[1] = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7);
1339f197a7aaSRajesh Borundia 
1340e5c4e6c6SManish Chopra 	err = qlcnic_83xx_issue_cmd(adapter, &cmd);
1341f197a7aaSRajesh Borundia 
1342f197a7aaSRajesh Borundia 	if (err != QLCNIC_RCODE_SUCCESS) {
1343f197a7aaSRajesh Borundia 		dev_err(&adapter->pdev->dev,
1344f197a7aaSRajesh Borundia 			"Failed to %s bc events, err=%d\n",
1345f197a7aaSRajesh Borundia 			(enable ? "enable" : "disable"), err);
1346f197a7aaSRajesh Borundia 	}
1347f197a7aaSRajesh Borundia 
1348f197a7aaSRajesh Borundia 	qlcnic_free_mbx_args(&cmd);
1349f197a7aaSRajesh Borundia 	return err;
1350f197a7aaSRajesh Borundia }
1351f197a7aaSRajesh Borundia 
qlcnic_sriov_retry_bc_cmd(struct qlcnic_adapter * adapter,struct qlcnic_bc_trans * trans)1352f036e4f4SRajesh Borundia static int qlcnic_sriov_retry_bc_cmd(struct qlcnic_adapter *adapter,
1353f036e4f4SRajesh Borundia 				     struct qlcnic_bc_trans *trans)
1354f036e4f4SRajesh Borundia {
1355f036e4f4SRajesh Borundia 	u8 max = QLC_BC_CMD_MAX_RETRY_CNT;
1356f036e4f4SRajesh Borundia 	u32 state;
1357f036e4f4SRajesh Borundia 
1358f036e4f4SRajesh Borundia 	state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
1359f036e4f4SRajesh Borundia 	if (state == QLC_83XX_IDC_DEV_READY) {
1360f036e4f4SRajesh Borundia 		msleep(20);
1361f036e4f4SRajesh Borundia 		clear_bit(QLC_BC_VF_CHANNEL, &trans->vf->state);
1362f036e4f4SRajesh Borundia 		trans->trans_state = QLC_INIT;
1363f036e4f4SRajesh Borundia 		if (++adapter->fw_fail_cnt > max)
1364f036e4f4SRajesh Borundia 			return -EIO;
1365f036e4f4SRajesh Borundia 		else
1366f036e4f4SRajesh Borundia 			return 0;
1367f036e4f4SRajesh Borundia 	}
1368f036e4f4SRajesh Borundia 
1369f036e4f4SRajesh Borundia 	return -EIO;
1370f036e4f4SRajesh Borundia }
1371f036e4f4SRajesh Borundia 
__qlcnic_sriov_issue_cmd(struct qlcnic_adapter * adapter,struct qlcnic_cmd_args * cmd)137274b7ba1aSRajesh Borundia static int __qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,
1373f197a7aaSRajesh Borundia 				  struct qlcnic_cmd_args *cmd)
1374f197a7aaSRajesh Borundia {
1375f036e4f4SRajesh Borundia 	struct qlcnic_hardware_context *ahw = adapter->ahw;
1376068a8d19SManish Chopra 	struct qlcnic_mailbox *mbx = ahw->mailbox;
1377f036e4f4SRajesh Borundia 	struct device *dev = &adapter->pdev->dev;
1378f197a7aaSRajesh Borundia 	struct qlcnic_bc_trans *trans;
1379f197a7aaSRajesh Borundia 	int err;
1380f197a7aaSRajesh Borundia 	u32 rsp_data, opcode, mbx_err_code, rsp;
1381f197a7aaSRajesh Borundia 	u16 seq = ++adapter->ahw->sriov->bc.trans_counter;
1382f036e4f4SRajesh Borundia 	u8 func = ahw->pci_func;
1383f197a7aaSRajesh Borundia 
1384f036e4f4SRajesh Borundia 	rsp = qlcnic_sriov_alloc_bc_trans(&trans);
1385f036e4f4SRajesh Borundia 	if (rsp)
1386ab0648e8SRajesh Borundia 		goto free_cmd;
1387f197a7aaSRajesh Borundia 
1388f036e4f4SRajesh Borundia 	rsp = qlcnic_sriov_prepare_bc_hdr(trans, cmd, seq, QLC_BC_COMMAND);
1389f036e4f4SRajesh Borundia 	if (rsp)
1390f036e4f4SRajesh Borundia 		goto cleanup_transaction;
1391f197a7aaSRajesh Borundia 
1392f036e4f4SRajesh Borundia retry:
1393068a8d19SManish Chopra 	if (!test_bit(QLC_83XX_MBX_READY, &mbx->status)) {
1394f197a7aaSRajesh Borundia 		rsp = -EIO;
1395f197a7aaSRajesh Borundia 		QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n",
1396f036e4f4SRajesh Borundia 		      QLCNIC_MBX_RSP(cmd->req.arg[0]), func);
1397f197a7aaSRajesh Borundia 		goto err_out;
1398f197a7aaSRajesh Borundia 	}
1399f197a7aaSRajesh Borundia 
1400f036e4f4SRajesh Borundia 	err = qlcnic_sriov_send_bc_cmd(adapter, trans, func);
1401f197a7aaSRajesh Borundia 	if (err) {
1402f036e4f4SRajesh Borundia 		dev_err(dev, "MBX command 0x%x timed out for VF %d\n",
1403f036e4f4SRajesh Borundia 			(cmd->req.arg[0] & 0xffff), func);
1404f197a7aaSRajesh Borundia 		rsp = QLCNIC_RCODE_TIMEOUT;
1405f036e4f4SRajesh Borundia 
1406f036e4f4SRajesh Borundia 		/* After adapter reset PF driver may take some time to
1407f036e4f4SRajesh Borundia 		 * respond to VF's request. Retry request till maximum retries.
1408f036e4f4SRajesh Borundia 		 */
1409f036e4f4SRajesh Borundia 		if ((trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) &&
1410f036e4f4SRajesh Borundia 		    !qlcnic_sriov_retry_bc_cmd(adapter, trans))
1411f036e4f4SRajesh Borundia 			goto retry;
1412f036e4f4SRajesh Borundia 
1413f197a7aaSRajesh Borundia 		goto err_out;
1414f197a7aaSRajesh Borundia 	}
1415f197a7aaSRajesh Borundia 
1416f197a7aaSRajesh Borundia 	rsp_data = cmd->rsp.arg[0];
1417f197a7aaSRajesh Borundia 	mbx_err_code = QLCNIC_MBX_STATUS(rsp_data);
1418f197a7aaSRajesh Borundia 	opcode = QLCNIC_MBX_RSP(cmd->req.arg[0]);
1419f197a7aaSRajesh Borundia 
1420f197a7aaSRajesh Borundia 	if ((mbx_err_code == QLCNIC_MBX_RSP_OK) ||
1421f197a7aaSRajesh Borundia 	    (mbx_err_code == QLCNIC_MBX_PORT_RSP_OK)) {
1422f197a7aaSRajesh Borundia 		rsp = QLCNIC_RCODE_SUCCESS;
1423f197a7aaSRajesh Borundia 	} else {
1424d747c333SRajesh Borundia 		if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT) {
1425d747c333SRajesh Borundia 			rsp = QLCNIC_RCODE_SUCCESS;
1426d747c333SRajesh Borundia 		} else {
1427f197a7aaSRajesh Borundia 			rsp = mbx_err_code;
1428f197a7aaSRajesh Borundia 			if (!rsp)
1429f197a7aaSRajesh Borundia 				rsp = 1;
1430d747c333SRajesh Borundia 
1431f036e4f4SRajesh Borundia 			dev_err(dev,
1432f197a7aaSRajesh Borundia 				"MBX command 0x%x failed with err:0x%x for VF %d\n",
1433f036e4f4SRajesh Borundia 				opcode, mbx_err_code, func);
1434f197a7aaSRajesh Borundia 		}
1435d747c333SRajesh Borundia 	}
1436f197a7aaSRajesh Borundia 
1437f197a7aaSRajesh Borundia err_out:
1438f036e4f4SRajesh Borundia 	if (rsp == QLCNIC_RCODE_TIMEOUT) {
1439f036e4f4SRajesh Borundia 		ahw->reset_context = 1;
1440f036e4f4SRajesh Borundia 		adapter->need_fw_reset = 1;
1441068a8d19SManish Chopra 		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
1442f036e4f4SRajesh Borundia 	}
1443f036e4f4SRajesh Borundia 
1444f036e4f4SRajesh Borundia cleanup_transaction:
1445f197a7aaSRajesh Borundia 	qlcnic_sriov_cleanup_transaction(trans);
1446ab0648e8SRajesh Borundia 
1447ab0648e8SRajesh Borundia free_cmd:
1448ab0648e8SRajesh Borundia 	if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT) {
1449ab0648e8SRajesh Borundia 		qlcnic_free_mbx_args(cmd);
1450ab0648e8SRajesh Borundia 		kfree(cmd);
1451ab0648e8SRajesh Borundia 	}
1452ab0648e8SRajesh Borundia 
1453f197a7aaSRajesh Borundia 	return rsp;
1454f197a7aaSRajesh Borundia }
1455f197a7aaSRajesh Borundia 
145674b7ba1aSRajesh Borundia 
qlcnic_sriov_issue_cmd(struct qlcnic_adapter * adapter,struct qlcnic_cmd_args * cmd)145774b7ba1aSRajesh Borundia static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,
145874b7ba1aSRajesh Borundia 				  struct qlcnic_cmd_args *cmd)
145974b7ba1aSRajesh Borundia {
146074b7ba1aSRajesh Borundia 	if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT)
146174b7ba1aSRajesh Borundia 		return qlcnic_sriov_async_issue_cmd(adapter, cmd);
146274b7ba1aSRajesh Borundia 	else
146374b7ba1aSRajesh Borundia 		return __qlcnic_sriov_issue_cmd(adapter, cmd);
146474b7ba1aSRajesh Borundia }
146574b7ba1aSRajesh Borundia 
qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter * adapter,u8 cmd_op)146621041400Sstephen hemminger static int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op)
1467f197a7aaSRajesh Borundia {
1468f197a7aaSRajesh Borundia 	struct qlcnic_cmd_args cmd;
1469f197a7aaSRajesh Borundia 	struct qlcnic_vf_info *vf = &adapter->ahw->sriov->vf_info[0];
1470f197a7aaSRajesh Borundia 	int ret;
1471f197a7aaSRajesh Borundia 
1472c5316920SRajesh Borundia 	memset(&cmd, 0, sizeof(cmd));
1473f197a7aaSRajesh Borundia 	if (qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op))
1474f197a7aaSRajesh Borundia 		return -ENOMEM;
1475f197a7aaSRajesh Borundia 
1476f197a7aaSRajesh Borundia 	ret = qlcnic_issue_cmd(adapter, &cmd);
1477f197a7aaSRajesh Borundia 	if (ret) {
1478f197a7aaSRajesh Borundia 		dev_err(&adapter->pdev->dev,
1479f197a7aaSRajesh Borundia 			"Failed bc channel %s %d\n", cmd_op ? "term" : "init",
1480f197a7aaSRajesh Borundia 			ret);
1481f197a7aaSRajesh Borundia 		goto out;
1482f197a7aaSRajesh Borundia 	}
1483f197a7aaSRajesh Borundia 
1484f197a7aaSRajesh Borundia 	cmd_op = (cmd.rsp.arg[0] & 0xff);
1485f197a7aaSRajesh Borundia 	if (cmd.rsp.arg[0] >> 25 == 2)
1486f197a7aaSRajesh Borundia 		return 2;
1487f197a7aaSRajesh Borundia 	if (cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT)
1488f197a7aaSRajesh Borundia 		set_bit(QLC_BC_VF_STATE, &vf->state);
1489f197a7aaSRajesh Borundia 	else
1490f197a7aaSRajesh Borundia 		clear_bit(QLC_BC_VF_STATE, &vf->state);
1491f197a7aaSRajesh Borundia 
1492f197a7aaSRajesh Borundia out:
1493f197a7aaSRajesh Borundia 	qlcnic_free_mbx_args(&cmd);
1494f197a7aaSRajesh Borundia 	return ret;
1495f197a7aaSRajesh Borundia }
1496e8b508efSRajesh Borundia 
qlcnic_vf_add_mc_list(struct net_device * netdev,const u8 * mac,enum qlcnic_mac_type mac_type)1497fe79fabbSShahed Shaikh static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac,
1498fe79fabbSShahed Shaikh 				  enum qlcnic_mac_type mac_type)
1499e8b508efSRajesh Borundia {
1500e8b508efSRajesh Borundia 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
1501154d0c81SManish Chopra 	struct qlcnic_sriov *sriov = adapter->ahw->sriov;
1502154d0c81SManish Chopra 	struct qlcnic_vf_info *vf;
1503154d0c81SManish Chopra 	u16 vlan_id;
1504154d0c81SManish Chopra 	int i;
1505e8b508efSRajesh Borundia 
1506154d0c81SManish Chopra 	vf = &adapter->ahw->sriov->vf_info[0];
1507e8b508efSRajesh Borundia 
1508154d0c81SManish Chopra 	if (!qlcnic_sriov_check_any_vlan(vf)) {
1509fe79fabbSShahed Shaikh 		qlcnic_nic_add_mac(adapter, mac, 0, mac_type);
1510154d0c81SManish Chopra 	} else {
151174b7ba1aSRajesh Borundia 		spin_lock(&vf->vlan_list_lock);
1512154d0c81SManish Chopra 		for (i = 0; i < sriov->num_allowed_vlans; i++) {
1513154d0c81SManish Chopra 			vlan_id = vf->sriov_vlans[i];
151474b7ba1aSRajesh Borundia 			if (vlan_id)
1515fe79fabbSShahed Shaikh 				qlcnic_nic_add_mac(adapter, mac, vlan_id,
1516fe79fabbSShahed Shaikh 						   mac_type);
1517154d0c81SManish Chopra 		}
151874b7ba1aSRajesh Borundia 		spin_unlock(&vf->vlan_list_lock);
151974b7ba1aSRajesh Borundia 		if (qlcnic_84xx_check(adapter))
1520fe79fabbSShahed Shaikh 			qlcnic_nic_add_mac(adapter, mac, 0, mac_type);
1521e8b508efSRajesh Borundia 	}
1522e8b508efSRajesh Borundia }
1523e8b508efSRajesh Borundia 
qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel * bc)1524e8b508efSRajesh Borundia void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *bc)
1525e8b508efSRajesh Borundia {
15262b10d3ecSManish Chopra 	struct list_head *head = &bc->async_cmd_list;
15272b10d3ecSManish Chopra 	struct qlcnic_async_cmd *entry;
1528e8b508efSRajesh Borundia 
152974b7ba1aSRajesh Borundia 	flush_workqueue(bc->bc_async_wq);
15302b10d3ecSManish Chopra 	cancel_work_sync(&bc->vf_async_work);
15312b10d3ecSManish Chopra 
15322b10d3ecSManish Chopra 	spin_lock(&bc->queue_lock);
1533e8b508efSRajesh Borundia 	while (!list_empty(head)) {
15342b10d3ecSManish Chopra 		entry = list_entry(head->next, struct qlcnic_async_cmd,
1535e8b508efSRajesh Borundia 				   list);
1536e8b508efSRajesh Borundia 		list_del(&entry->list);
15372b10d3ecSManish Chopra 		kfree(entry->cmd);
1538e8b508efSRajesh Borundia 		kfree(entry);
1539e8b508efSRajesh Borundia 	}
15402b10d3ecSManish Chopra 	spin_unlock(&bc->queue_lock);
1541e8b508efSRajesh Borundia }
1542e8b508efSRajesh Borundia 
qlcnic_sriov_vf_set_multi(struct net_device * netdev)154374b7ba1aSRajesh Borundia void qlcnic_sriov_vf_set_multi(struct net_device *netdev)
1544e8b508efSRajesh Borundia {
1545e8b508efSRajesh Borundia 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
1546154d0c81SManish Chopra 	struct qlcnic_hardware_context *ahw = adapter->ahw;
154774b7ba1aSRajesh Borundia 	static const u8 bcast_addr[ETH_ALEN] = {
154874b7ba1aSRajesh Borundia 		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
154974b7ba1aSRajesh Borundia 	};
155074b7ba1aSRajesh Borundia 	struct netdev_hw_addr *ha;
1551154d0c81SManish Chopra 	u32 mode = VPORT_MISS_MODE_DROP;
1552e8b508efSRajesh Borundia 
1553e8b508efSRajesh Borundia 	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
1554e8b508efSRajesh Borundia 		return;
1555e8b508efSRajesh Borundia 
1556154d0c81SManish Chopra 	if (netdev->flags & IFF_PROMISC) {
1557154d0c81SManish Chopra 		if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
1558154d0c81SManish Chopra 			mode = VPORT_MISS_MODE_ACCEPT_ALL;
1559154d0c81SManish Chopra 	} else if ((netdev->flags & IFF_ALLMULTI) ||
1560154d0c81SManish Chopra 		   (netdev_mc_count(netdev) > ahw->max_mc_count)) {
1561154d0c81SManish Chopra 		mode = VPORT_MISS_MODE_ACCEPT_MULTI;
156274b7ba1aSRajesh Borundia 	} else {
1563fe79fabbSShahed Shaikh 		qlcnic_vf_add_mc_list(netdev, bcast_addr, QLCNIC_BROADCAST_MAC);
156474b7ba1aSRajesh Borundia 		if (!netdev_mc_empty(netdev)) {
1565fe79fabbSShahed Shaikh 			qlcnic_flush_mcast_mac(adapter);
156674b7ba1aSRajesh Borundia 			netdev_for_each_mc_addr(ha, netdev)
1567fe79fabbSShahed Shaikh 				qlcnic_vf_add_mc_list(netdev, ha->addr,
1568fe79fabbSShahed Shaikh 						      QLCNIC_MULTICAST_MAC);
1569154d0c81SManish Chopra 		}
157074b7ba1aSRajesh Borundia 	}
1571154d0c81SManish Chopra 
1572d747c333SRajesh Borundia 	/* configure unicast MAC address, if there is not sufficient space
1573d747c333SRajesh Borundia 	 * to store all the unicast addresses then enable promiscuous mode
1574d747c333SRajesh Borundia 	 */
1575d747c333SRajesh Borundia 	if (netdev_uc_count(netdev) > ahw->max_uc_count) {
1576d747c333SRajesh Borundia 		mode = VPORT_MISS_MODE_ACCEPT_ALL;
1577d747c333SRajesh Borundia 	} else if (!netdev_uc_empty(netdev)) {
1578d747c333SRajesh Borundia 		netdev_for_each_uc_addr(ha, netdev)
1579fe79fabbSShahed Shaikh 			qlcnic_vf_add_mc_list(netdev, ha->addr,
1580fe79fabbSShahed Shaikh 					      QLCNIC_UNICAST_MAC);
1581d747c333SRajesh Borundia 	}
1582d747c333SRajesh Borundia 
1583d747c333SRajesh Borundia 	if (adapter->pdev->is_virtfn) {
1584d747c333SRajesh Borundia 		if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
1585d747c333SRajesh Borundia 		    !adapter->fdb_mac_learn) {
1586d747c333SRajesh Borundia 			qlcnic_alloc_lb_filters_mem(adapter);
1587d9a1c584SJason Yan 			adapter->drv_mac_learn = true;
1588d747c333SRajesh Borundia 			adapter->rx_mac_learn = true;
1589d747c333SRajesh Borundia 		} else {
1590d9a1c584SJason Yan 			adapter->drv_mac_learn = false;
1591d747c333SRajesh Borundia 			adapter->rx_mac_learn = false;
1592d747c333SRajesh Borundia 		}
1593d747c333SRajesh Borundia 	}
1594d747c333SRajesh Borundia 
1595154d0c81SManish Chopra 	qlcnic_nic_set_promisc(adapter, mode);
1596e8b508efSRajesh Borundia }
1597e8b508efSRajesh Borundia 
qlcnic_sriov_handle_async_issue_cmd(struct work_struct * work)159874b7ba1aSRajesh Borundia static void qlcnic_sriov_handle_async_issue_cmd(struct work_struct *work)
1599e8b508efSRajesh Borundia {
16002b10d3ecSManish Chopra 	struct qlcnic_async_cmd *entry, *tmp;
16012b10d3ecSManish Chopra 	struct qlcnic_back_channel *bc;
160274b7ba1aSRajesh Borundia 	struct qlcnic_cmd_args *cmd;
16032b10d3ecSManish Chopra 	struct list_head *head;
16042b10d3ecSManish Chopra 	LIST_HEAD(del_list);
1605e8b508efSRajesh Borundia 
16062b10d3ecSManish Chopra 	bc = container_of(work, struct qlcnic_back_channel, vf_async_work);
16072b10d3ecSManish Chopra 	head = &bc->async_cmd_list;
16082b10d3ecSManish Chopra 
16092b10d3ecSManish Chopra 	spin_lock(&bc->queue_lock);
16102b10d3ecSManish Chopra 	list_splice_init(head, &del_list);
16112b10d3ecSManish Chopra 	spin_unlock(&bc->queue_lock);
16122b10d3ecSManish Chopra 
16132b10d3ecSManish Chopra 	list_for_each_entry_safe(entry, tmp, &del_list, list) {
16142b10d3ecSManish Chopra 		list_del(&entry->list);
161574b7ba1aSRajesh Borundia 		cmd = entry->cmd;
16162b10d3ecSManish Chopra 		__qlcnic_sriov_issue_cmd(bc->adapter, cmd);
16172b10d3ecSManish Chopra 		kfree(entry);
16182b10d3ecSManish Chopra 	}
16192b10d3ecSManish Chopra 
16202b10d3ecSManish Chopra 	if (!list_empty(head))
16212b10d3ecSManish Chopra 		queue_work(bc->bc_async_wq, &bc->vf_async_work);
16222b10d3ecSManish Chopra 
1623e8b508efSRajesh Borundia 	return;
1624e8b508efSRajesh Borundia }
1625e8b508efSRajesh Borundia 
16262b10d3ecSManish Chopra static struct qlcnic_async_cmd *
qlcnic_sriov_alloc_async_cmd(struct qlcnic_back_channel * bc,struct qlcnic_cmd_args * cmd)16272b10d3ecSManish Chopra qlcnic_sriov_alloc_async_cmd(struct qlcnic_back_channel *bc,
16282b10d3ecSManish Chopra 			     struct qlcnic_cmd_args *cmd)
1629e8b508efSRajesh Borundia {
16302b10d3ecSManish Chopra 	struct qlcnic_async_cmd *entry = NULL;
1631e8b508efSRajesh Borundia 
16322b10d3ecSManish Chopra 	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
16332b10d3ecSManish Chopra 	if (!entry)
1634e8b508efSRajesh Borundia 		return NULL;
16352b10d3ecSManish Chopra 
16362b10d3ecSManish Chopra 	entry->cmd = cmd;
16372b10d3ecSManish Chopra 
16382b10d3ecSManish Chopra 	spin_lock(&bc->queue_lock);
16392b10d3ecSManish Chopra 	list_add_tail(&entry->list, &bc->async_cmd_list);
16402b10d3ecSManish Chopra 	spin_unlock(&bc->queue_lock);
1641e8b508efSRajesh Borundia 
1642e8b508efSRajesh Borundia 	return entry;
1643e8b508efSRajesh Borundia }
1644e8b508efSRajesh Borundia 
qlcnic_sriov_schedule_async_cmd(struct qlcnic_back_channel * bc,struct qlcnic_cmd_args * cmd)164574b7ba1aSRajesh Borundia static void qlcnic_sriov_schedule_async_cmd(struct qlcnic_back_channel *bc,
164674b7ba1aSRajesh Borundia 					    struct qlcnic_cmd_args *cmd)
1647e8b508efSRajesh Borundia {
16482b10d3ecSManish Chopra 	struct qlcnic_async_cmd *entry = NULL;
1649e8b508efSRajesh Borundia 
16502b10d3ecSManish Chopra 	entry = qlcnic_sriov_alloc_async_cmd(bc, cmd);
16512b10d3ecSManish Chopra 	if (!entry) {
16522b10d3ecSManish Chopra 		qlcnic_free_mbx_args(cmd);
16532b10d3ecSManish Chopra 		kfree(cmd);
1654e8b508efSRajesh Borundia 		return;
16552b10d3ecSManish Chopra 	}
1656e8b508efSRajesh Borundia 
16572b10d3ecSManish Chopra 	queue_work(bc->bc_async_wq, &bc->vf_async_work);
1658e8b508efSRajesh Borundia }
1659e8b508efSRajesh Borundia 
qlcnic_sriov_async_issue_cmd(struct qlcnic_adapter * adapter,struct qlcnic_cmd_args * cmd)166074b7ba1aSRajesh Borundia static int qlcnic_sriov_async_issue_cmd(struct qlcnic_adapter *adapter,
166174b7ba1aSRajesh Borundia 					struct qlcnic_cmd_args *cmd)
1662e8b508efSRajesh Borundia {
1663e8b508efSRajesh Borundia 
1664e8b508efSRajesh Borundia 	struct qlcnic_back_channel *bc = &adapter->ahw->sriov->bc;
1665e8b508efSRajesh Borundia 
1666f036e4f4SRajesh Borundia 	if (adapter->need_fw_reset)
166774b7ba1aSRajesh Borundia 		return -EIO;
1668f036e4f4SRajesh Borundia 
16692b10d3ecSManish Chopra 	qlcnic_sriov_schedule_async_cmd(bc, cmd);
16702b10d3ecSManish Chopra 
167174b7ba1aSRajesh Borundia 	return 0;
1672e8b508efSRajesh Borundia }
1673f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter * adapter)1674f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter)
1675f036e4f4SRajesh Borundia {
1676f036e4f4SRajesh Borundia 	int err;
1677f036e4f4SRajesh Borundia 
16785c44bbdaSManish Chopra 	adapter->need_fw_reset = 0;
167991b86e3dSManish Chopra 	qlcnic_83xx_reinit_mbx_work(adapter->ahw->mailbox);
1680e5c4e6c6SManish Chopra 	qlcnic_83xx_enable_mbx_interrupt(adapter);
1681f036e4f4SRajesh Borundia 
1682f036e4f4SRajesh Borundia 	err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
1683f036e4f4SRajesh Borundia 	if (err)
1684f036e4f4SRajesh Borundia 		return err;
1685f036e4f4SRajesh Borundia 
1686f036e4f4SRajesh Borundia 	err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT);
1687f036e4f4SRajesh Borundia 	if (err)
1688f036e4f4SRajesh Borundia 		goto err_out_cleanup_bc_intr;
1689f036e4f4SRajesh Borundia 
1690f036e4f4SRajesh Borundia 	err = qlcnic_sriov_vf_init_driver(adapter);
1691f036e4f4SRajesh Borundia 	if (err)
1692f036e4f4SRajesh Borundia 		goto err_out_term_channel;
1693f036e4f4SRajesh Borundia 
1694f036e4f4SRajesh Borundia 	return 0;
1695f036e4f4SRajesh Borundia 
1696f036e4f4SRajesh Borundia err_out_term_channel:
1697f036e4f4SRajesh Borundia 	qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
1698f036e4f4SRajesh Borundia 
1699f036e4f4SRajesh Borundia err_out_cleanup_bc_intr:
1700f036e4f4SRajesh Borundia 	qlcnic_sriov_cfg_bc_intr(adapter, 0);
1701f036e4f4SRajesh Borundia 	return err;
1702f036e4f4SRajesh Borundia }
1703f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_attach(struct qlcnic_adapter * adapter)1704f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_attach(struct qlcnic_adapter *adapter)
1705f036e4f4SRajesh Borundia {
1706f036e4f4SRajesh Borundia 	struct net_device *netdev = adapter->netdev;
1707f036e4f4SRajesh Borundia 
1708f036e4f4SRajesh Borundia 	if (netif_running(netdev)) {
1709f036e4f4SRajesh Borundia 		if (!qlcnic_up(adapter, netdev))
1710f036e4f4SRajesh Borundia 			qlcnic_restore_indev_addr(netdev, NETDEV_UP);
1711f036e4f4SRajesh Borundia 	}
1712f036e4f4SRajesh Borundia 
1713f036e4f4SRajesh Borundia 	netif_device_attach(netdev);
1714f036e4f4SRajesh Borundia }
1715f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_detach(struct qlcnic_adapter * adapter)1716f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_detach(struct qlcnic_adapter *adapter)
1717f036e4f4SRajesh Borundia {
1718f036e4f4SRajesh Borundia 	struct qlcnic_hardware_context *ahw = adapter->ahw;
1719f036e4f4SRajesh Borundia 	struct qlcnic_intrpt_config *intr_tbl = ahw->intr_tbl;
1720f036e4f4SRajesh Borundia 	struct net_device *netdev = adapter->netdev;
1721f036e4f4SRajesh Borundia 	u8 i, max_ints = ahw->num_msix - 1;
1722f036e4f4SRajesh Borundia 
1723f036e4f4SRajesh Borundia 	netif_device_detach(netdev);
1724068a8d19SManish Chopra 	qlcnic_83xx_detach_mailbox_work(adapter);
1725068a8d19SManish Chopra 	qlcnic_83xx_disable_mbx_intr(adapter);
1726068a8d19SManish Chopra 
1727f036e4f4SRajesh Borundia 	if (netif_running(netdev))
1728f036e4f4SRajesh Borundia 		qlcnic_down(adapter, netdev);
1729f036e4f4SRajesh Borundia 
1730f036e4f4SRajesh Borundia 	for (i = 0; i < max_ints; i++) {
1731f036e4f4SRajesh Borundia 		intr_tbl[i].id = i;
1732f036e4f4SRajesh Borundia 		intr_tbl[i].enabled = 0;
1733f036e4f4SRajesh Borundia 		intr_tbl[i].src = 0;
1734f036e4f4SRajesh Borundia 	}
1735f036e4f4SRajesh Borundia 	ahw->reset_context = 0;
1736f036e4f4SRajesh Borundia }
1737f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_handle_dev_ready(struct qlcnic_adapter * adapter)1738f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_handle_dev_ready(struct qlcnic_adapter *adapter)
1739f036e4f4SRajesh Borundia {
1740f036e4f4SRajesh Borundia 	struct qlcnic_hardware_context *ahw = adapter->ahw;
1741f036e4f4SRajesh Borundia 	struct device *dev = &adapter->pdev->dev;
1742f036e4f4SRajesh Borundia 	struct qlc_83xx_idc *idc = &ahw->idc;
1743f036e4f4SRajesh Borundia 	u8 func = ahw->pci_func;
1744f036e4f4SRajesh Borundia 	u32 state;
1745f036e4f4SRajesh Borundia 
1746f036e4f4SRajesh Borundia 	if ((idc->prev_state == QLC_83XX_IDC_DEV_NEED_RESET) ||
1747f036e4f4SRajesh Borundia 	    (idc->prev_state == QLC_83XX_IDC_DEV_INIT)) {
1748f036e4f4SRajesh Borundia 		if (!qlcnic_sriov_vf_reinit_driver(adapter)) {
1749f036e4f4SRajesh Borundia 			qlcnic_sriov_vf_attach(adapter);
1750f036e4f4SRajesh Borundia 			adapter->fw_fail_cnt = 0;
1751f036e4f4SRajesh Borundia 			dev_info(dev,
17528b513d0cSMasanari Iida 				 "%s: Reinitialization of VF 0x%x done after FW reset\n",
1753f036e4f4SRajesh Borundia 				 __func__, func);
1754f036e4f4SRajesh Borundia 		} else {
1755f036e4f4SRajesh Borundia 			dev_err(dev,
1756f036e4f4SRajesh Borundia 				"%s: Reinitialization of VF 0x%x failed after FW reset\n",
1757f036e4f4SRajesh Borundia 				__func__, func);
1758f036e4f4SRajesh Borundia 			state = QLCRDX(ahw, QLC_83XX_IDC_DEV_STATE);
1759f036e4f4SRajesh Borundia 			dev_info(dev, "Current state 0x%x after FW reset\n",
1760f036e4f4SRajesh Borundia 				 state);
1761f036e4f4SRajesh Borundia 		}
1762f036e4f4SRajesh Borundia 	}
1763f036e4f4SRajesh Borundia 
1764f036e4f4SRajesh Borundia 	return 0;
1765f036e4f4SRajesh Borundia }
1766f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_handle_context_reset(struct qlcnic_adapter * adapter)1767f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_handle_context_reset(struct qlcnic_adapter *adapter)
1768f036e4f4SRajesh Borundia {
1769f036e4f4SRajesh Borundia 	struct qlcnic_hardware_context *ahw = adapter->ahw;
1770068a8d19SManish Chopra 	struct qlcnic_mailbox *mbx = ahw->mailbox;
1771f036e4f4SRajesh Borundia 	struct device *dev = &adapter->pdev->dev;
1772f036e4f4SRajesh Borundia 	struct qlc_83xx_idc *idc = &ahw->idc;
1773f036e4f4SRajesh Borundia 	u8 func = ahw->pci_func;
1774f036e4f4SRajesh Borundia 	u32 state;
1775f036e4f4SRajesh Borundia 
1776f036e4f4SRajesh Borundia 	adapter->reset_ctx_cnt++;
1777f036e4f4SRajesh Borundia 
1778f036e4f4SRajesh Borundia 	/* Skip the context reset and check if FW is hung */
1779f036e4f4SRajesh Borundia 	if (adapter->reset_ctx_cnt < 3) {
1780f036e4f4SRajesh Borundia 		adapter->need_fw_reset = 1;
1781068a8d19SManish Chopra 		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
1782f036e4f4SRajesh Borundia 		dev_info(dev,
1783f036e4f4SRajesh Borundia 			 "Resetting context, wait here to check if FW is in failed state\n");
1784f036e4f4SRajesh Borundia 		return 0;
1785f036e4f4SRajesh Borundia 	}
1786f036e4f4SRajesh Borundia 
1787f036e4f4SRajesh Borundia 	/* Check if number of resets exceed the threshold.
1788f036e4f4SRajesh Borundia 	 * If it exceeds the threshold just fail the VF.
1789f036e4f4SRajesh Borundia 	 */
1790f036e4f4SRajesh Borundia 	if (adapter->reset_ctx_cnt > QLC_83XX_VF_RESET_FAIL_THRESH) {
1791f036e4f4SRajesh Borundia 		clear_bit(QLC_83XX_MODULE_LOADED, &idc->status);
1792f036e4f4SRajesh Borundia 		adapter->tx_timeo_cnt = 0;
1793f036e4f4SRajesh Borundia 		adapter->fw_fail_cnt = 0;
1794f036e4f4SRajesh Borundia 		adapter->reset_ctx_cnt = 0;
1795f036e4f4SRajesh Borundia 		qlcnic_sriov_vf_detach(adapter);
1796f036e4f4SRajesh Borundia 		dev_err(dev,
1797f036e4f4SRajesh Borundia 			"Device context resets have exceeded the threshold, device interface will be shutdown\n");
1798f036e4f4SRajesh Borundia 		return -EIO;
1799f036e4f4SRajesh Borundia 	}
1800f036e4f4SRajesh Borundia 
1801f036e4f4SRajesh Borundia 	dev_info(dev, "Resetting context of VF 0x%x\n", func);
1802f036e4f4SRajesh Borundia 	dev_info(dev, "%s: Context reset count %d for VF 0x%x\n",
1803f036e4f4SRajesh Borundia 		 __func__, adapter->reset_ctx_cnt, func);
1804f036e4f4SRajesh Borundia 	set_bit(__QLCNIC_RESETTING, &adapter->state);
1805f036e4f4SRajesh Borundia 	adapter->need_fw_reset = 1;
1806068a8d19SManish Chopra 	clear_bit(QLC_83XX_MBX_READY, &mbx->status);
1807f036e4f4SRajesh Borundia 	qlcnic_sriov_vf_detach(adapter);
1808f036e4f4SRajesh Borundia 	adapter->need_fw_reset = 0;
1809f036e4f4SRajesh Borundia 
1810f036e4f4SRajesh Borundia 	if (!qlcnic_sriov_vf_reinit_driver(adapter)) {
1811f036e4f4SRajesh Borundia 		qlcnic_sriov_vf_attach(adapter);
1812f036e4f4SRajesh Borundia 		adapter->tx_timeo_cnt = 0;
1813f036e4f4SRajesh Borundia 		adapter->reset_ctx_cnt = 0;
1814f036e4f4SRajesh Borundia 		adapter->fw_fail_cnt = 0;
1815f036e4f4SRajesh Borundia 		dev_info(dev, "Done resetting context for VF 0x%x\n", func);
1816f036e4f4SRajesh Borundia 	} else {
1817f036e4f4SRajesh Borundia 		dev_err(dev, "%s: Reinitialization of VF 0x%x failed\n",
1818f036e4f4SRajesh Borundia 			__func__, func);
1819f036e4f4SRajesh Borundia 		state = QLCRDX(ahw, QLC_83XX_IDC_DEV_STATE);
1820f036e4f4SRajesh Borundia 		dev_info(dev, "%s: Current state 0x%x\n", __func__, state);
1821f036e4f4SRajesh Borundia 	}
1822f036e4f4SRajesh Borundia 
1823f036e4f4SRajesh Borundia 	return 0;
1824f036e4f4SRajesh Borundia }
1825f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_idc_ready_state(struct qlcnic_adapter * adapter)1826f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_idc_ready_state(struct qlcnic_adapter *adapter)
1827f036e4f4SRajesh Borundia {
1828f036e4f4SRajesh Borundia 	struct qlcnic_hardware_context *ahw = adapter->ahw;
1829f036e4f4SRajesh Borundia 	int ret = 0;
1830f036e4f4SRajesh Borundia 
1831f036e4f4SRajesh Borundia 	if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_READY)
1832f036e4f4SRajesh Borundia 		ret = qlcnic_sriov_vf_handle_dev_ready(adapter);
1833f036e4f4SRajesh Borundia 	else if (ahw->reset_context)
1834f036e4f4SRajesh Borundia 		ret = qlcnic_sriov_vf_handle_context_reset(adapter);
1835f036e4f4SRajesh Borundia 
1836f036e4f4SRajesh Borundia 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
1837f036e4f4SRajesh Borundia 	return ret;
1838f036e4f4SRajesh Borundia }
1839f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_idc_failed_state(struct qlcnic_adapter * adapter)1840f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_idc_failed_state(struct qlcnic_adapter *adapter)
1841f036e4f4SRajesh Borundia {
1842f036e4f4SRajesh Borundia 	struct qlc_83xx_idc *idc = &adapter->ahw->idc;
1843f036e4f4SRajesh Borundia 
1844f036e4f4SRajesh Borundia 	dev_err(&adapter->pdev->dev, "Device is in failed state\n");
1845f036e4f4SRajesh Borundia 	if (idc->prev_state == QLC_83XX_IDC_DEV_READY)
1846f036e4f4SRajesh Borundia 		qlcnic_sriov_vf_detach(adapter);
1847f036e4f4SRajesh Borundia 
1848f036e4f4SRajesh Borundia 	clear_bit(QLC_83XX_MODULE_LOADED, &idc->status);
1849f036e4f4SRajesh Borundia 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
1850f036e4f4SRajesh Borundia 	return -EIO;
1851f036e4f4SRajesh Borundia }
1852f036e4f4SRajesh Borundia 
1853f036e4f4SRajesh Borundia static int
qlcnic_sriov_vf_idc_need_quiescent_state(struct qlcnic_adapter * adapter)1854f036e4f4SRajesh Borundia qlcnic_sriov_vf_idc_need_quiescent_state(struct qlcnic_adapter *adapter)
1855f036e4f4SRajesh Borundia {
1856068a8d19SManish Chopra 	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
1857f036e4f4SRajesh Borundia 	struct qlc_83xx_idc *idc = &adapter->ahw->idc;
1858f036e4f4SRajesh Borundia 
1859f036e4f4SRajesh Borundia 	dev_info(&adapter->pdev->dev, "Device is in quiescent state\n");
1860f036e4f4SRajesh Borundia 	if (idc->prev_state == QLC_83XX_IDC_DEV_READY) {
1861f036e4f4SRajesh Borundia 		set_bit(__QLCNIC_RESETTING, &adapter->state);
1862f036e4f4SRajesh Borundia 		adapter->tx_timeo_cnt = 0;
1863f036e4f4SRajesh Borundia 		adapter->reset_ctx_cnt = 0;
1864068a8d19SManish Chopra 		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
1865f036e4f4SRajesh Borundia 		qlcnic_sriov_vf_detach(adapter);
1866f036e4f4SRajesh Borundia 	}
1867f036e4f4SRajesh Borundia 
1868f036e4f4SRajesh Borundia 	return 0;
1869f036e4f4SRajesh Borundia }
1870f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_idc_init_reset_state(struct qlcnic_adapter * adapter)1871f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_idc_init_reset_state(struct qlcnic_adapter *adapter)
1872f036e4f4SRajesh Borundia {
1873068a8d19SManish Chopra 	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
1874f036e4f4SRajesh Borundia 	struct qlc_83xx_idc *idc = &adapter->ahw->idc;
1875f036e4f4SRajesh Borundia 	u8 func = adapter->ahw->pci_func;
1876f036e4f4SRajesh Borundia 
1877f036e4f4SRajesh Borundia 	if (idc->prev_state == QLC_83XX_IDC_DEV_READY) {
1878f036e4f4SRajesh Borundia 		dev_err(&adapter->pdev->dev,
1879f036e4f4SRajesh Borundia 			"Firmware hang detected by VF 0x%x\n", func);
1880f036e4f4SRajesh Borundia 		set_bit(__QLCNIC_RESETTING, &adapter->state);
1881f036e4f4SRajesh Borundia 		adapter->tx_timeo_cnt = 0;
1882f036e4f4SRajesh Borundia 		adapter->reset_ctx_cnt = 0;
1883068a8d19SManish Chopra 		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
1884f036e4f4SRajesh Borundia 		qlcnic_sriov_vf_detach(adapter);
1885f036e4f4SRajesh Borundia 	}
1886f036e4f4SRajesh Borundia 	return 0;
1887f036e4f4SRajesh Borundia }
1888f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_idc_unknown_state(struct qlcnic_adapter * adapter)1889f036e4f4SRajesh Borundia static int qlcnic_sriov_vf_idc_unknown_state(struct qlcnic_adapter *adapter)
1890f036e4f4SRajesh Borundia {
1891f036e4f4SRajesh Borundia 	dev_err(&adapter->pdev->dev, "%s: Device in unknown state\n", __func__);
1892f036e4f4SRajesh Borundia 	return 0;
1893f036e4f4SRajesh Borundia }
1894f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_periodic_tasks(struct qlcnic_adapter * adapter)1895d747c333SRajesh Borundia static void qlcnic_sriov_vf_periodic_tasks(struct qlcnic_adapter *adapter)
1896d747c333SRajesh Borundia {
1897d747c333SRajesh Borundia 	if (adapter->fhash.fnum)
1898d747c333SRajesh Borundia 		qlcnic_prune_lb_filters(adapter);
1899d747c333SRajesh Borundia }
1900d747c333SRajesh Borundia 
qlcnic_sriov_vf_poll_dev_state(struct work_struct * work)1901f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *work)
1902f036e4f4SRajesh Borundia {
1903f036e4f4SRajesh Borundia 	struct qlcnic_adapter *adapter;
1904f036e4f4SRajesh Borundia 	struct qlc_83xx_idc *idc;
1905f036e4f4SRajesh Borundia 	int ret = 0;
1906f036e4f4SRajesh Borundia 
1907f036e4f4SRajesh Borundia 	adapter = container_of(work, struct qlcnic_adapter, fw_work.work);
1908f036e4f4SRajesh Borundia 	idc = &adapter->ahw->idc;
1909f036e4f4SRajesh Borundia 	idc->curr_state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
1910f036e4f4SRajesh Borundia 
1911f036e4f4SRajesh Borundia 	switch (idc->curr_state) {
1912f036e4f4SRajesh Borundia 	case QLC_83XX_IDC_DEV_READY:
1913f036e4f4SRajesh Borundia 		ret = qlcnic_sriov_vf_idc_ready_state(adapter);
1914f036e4f4SRajesh Borundia 		break;
1915f036e4f4SRajesh Borundia 	case QLC_83XX_IDC_DEV_NEED_RESET:
1916f036e4f4SRajesh Borundia 	case QLC_83XX_IDC_DEV_INIT:
1917f036e4f4SRajesh Borundia 		ret = qlcnic_sriov_vf_idc_init_reset_state(adapter);
1918f036e4f4SRajesh Borundia 		break;
1919f036e4f4SRajesh Borundia 	case QLC_83XX_IDC_DEV_NEED_QUISCENT:
1920f036e4f4SRajesh Borundia 		ret = qlcnic_sriov_vf_idc_need_quiescent_state(adapter);
1921f036e4f4SRajesh Borundia 		break;
1922f036e4f4SRajesh Borundia 	case QLC_83XX_IDC_DEV_FAILED:
1923f036e4f4SRajesh Borundia 		ret = qlcnic_sriov_vf_idc_failed_state(adapter);
1924f036e4f4SRajesh Borundia 		break;
1925f036e4f4SRajesh Borundia 	case QLC_83XX_IDC_DEV_QUISCENT:
1926f036e4f4SRajesh Borundia 		break;
1927f036e4f4SRajesh Borundia 	default:
1928f036e4f4SRajesh Borundia 		ret = qlcnic_sriov_vf_idc_unknown_state(adapter);
1929f036e4f4SRajesh Borundia 	}
1930f036e4f4SRajesh Borundia 
1931f036e4f4SRajesh Borundia 	idc->prev_state = idc->curr_state;
1932d747c333SRajesh Borundia 	qlcnic_sriov_vf_periodic_tasks(adapter);
1933d747c333SRajesh Borundia 
1934f036e4f4SRajesh Borundia 	if (!ret && test_bit(QLC_83XX_MODULE_LOADED, &idc->status))
1935f036e4f4SRajesh Borundia 		qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state,
1936f036e4f4SRajesh Borundia 				     idc->delay);
1937f036e4f4SRajesh Borundia }
1938f036e4f4SRajesh Borundia 
qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter * adapter)1939f036e4f4SRajesh Borundia static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *adapter)
1940f036e4f4SRajesh Borundia {
1941f036e4f4SRajesh Borundia 	while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
1942f036e4f4SRajesh Borundia 		msleep(20);
1943f036e4f4SRajesh Borundia 
1944f036e4f4SRajesh Borundia 	clear_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
1945f036e4f4SRajesh Borundia 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
1946f036e4f4SRajesh Borundia 	cancel_delayed_work_sync(&adapter->fw_work);
1947f036e4f4SRajesh Borundia }
194891b7282bSRajesh Borundia 
qlcnic_sriov_check_vlan_id(struct qlcnic_sriov * sriov,struct qlcnic_vf_info * vf,u16 vlan_id)1949154d0c81SManish Chopra static int qlcnic_sriov_check_vlan_id(struct qlcnic_sriov *sriov,
1950154d0c81SManish Chopra 				      struct qlcnic_vf_info *vf, u16 vlan_id)
1951154d0c81SManish Chopra {
1952154d0c81SManish Chopra 	int i, err = -EINVAL;
1953154d0c81SManish Chopra 
1954154d0c81SManish Chopra 	if (!vf->sriov_vlans)
1955154d0c81SManish Chopra 		return err;
1956154d0c81SManish Chopra 
195774b7ba1aSRajesh Borundia 	spin_lock_bh(&vf->vlan_list_lock);
1958154d0c81SManish Chopra 
1959154d0c81SManish Chopra 	for (i = 0; i < sriov->num_allowed_vlans; i++) {
1960154d0c81SManish Chopra 		if (vf->sriov_vlans[i] == vlan_id) {
1961154d0c81SManish Chopra 			err = 0;
1962154d0c81SManish Chopra 			break;
1963154d0c81SManish Chopra 		}
1964154d0c81SManish Chopra 	}
1965154d0c81SManish Chopra 
196674b7ba1aSRajesh Borundia 	spin_unlock_bh(&vf->vlan_list_lock);
1967154d0c81SManish Chopra 	return err;
1968154d0c81SManish Chopra }
1969154d0c81SManish Chopra 
qlcnic_sriov_validate_num_vlans(struct qlcnic_sriov * sriov,struct qlcnic_vf_info * vf)1970154d0c81SManish Chopra static int qlcnic_sriov_validate_num_vlans(struct qlcnic_sriov *sriov,
1971154d0c81SManish Chopra 					   struct qlcnic_vf_info *vf)
1972154d0c81SManish Chopra {
1973154d0c81SManish Chopra 	int err = 0;
1974154d0c81SManish Chopra 
197574b7ba1aSRajesh Borundia 	spin_lock_bh(&vf->vlan_list_lock);
1976154d0c81SManish Chopra 
1977154d0c81SManish Chopra 	if (vf->num_vlan >= sriov->num_allowed_vlans)
1978154d0c81SManish Chopra 		err = -EINVAL;
1979154d0c81SManish Chopra 
198074b7ba1aSRajesh Borundia 	spin_unlock_bh(&vf->vlan_list_lock);
1981154d0c81SManish Chopra 	return err;
1982154d0c81SManish Chopra }
1983154d0c81SManish Chopra 
qlcnic_sriov_validate_vlan_cfg(struct qlcnic_adapter * adapter,u16 vid,u8 enable)1984154d0c81SManish Chopra static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_adapter *adapter,
198591b7282bSRajesh Borundia 					  u16 vid, u8 enable)
198691b7282bSRajesh Borundia {
1987154d0c81SManish Chopra 	struct qlcnic_sriov *sriov = adapter->ahw->sriov;
1988154d0c81SManish Chopra 	struct qlcnic_vf_info *vf;
1989154d0c81SManish Chopra 	bool vlan_exist;
199091b7282bSRajesh Borundia 	u8 allowed = 0;
199191b7282bSRajesh Borundia 	int i;
199291b7282bSRajesh Borundia 
1993154d0c81SManish Chopra 	vf = &adapter->ahw->sriov->vf_info[0];
1994154d0c81SManish Chopra 	vlan_exist = qlcnic_sriov_check_any_vlan(vf);
199591b7282bSRajesh Borundia 	if (sriov->vlan_mode != QLC_GUEST_VLAN_MODE)
199691b7282bSRajesh Borundia 		return -EINVAL;
199791b7282bSRajesh Borundia 
199891b7282bSRajesh Borundia 	if (enable) {
1999154d0c81SManish Chopra 		if (qlcnic_83xx_vf_check(adapter) && vlan_exist)
2000154d0c81SManish Chopra 			return -EINVAL;
2001154d0c81SManish Chopra 
2002154d0c81SManish Chopra 		if (qlcnic_sriov_validate_num_vlans(sriov, vf))
200391b7282bSRajesh Borundia 			return -EINVAL;
200491b7282bSRajesh Borundia 
200591b7282bSRajesh Borundia 		if (sriov->any_vlan) {
200691b7282bSRajesh Borundia 			for (i = 0; i < sriov->num_allowed_vlans; i++) {
200791b7282bSRajesh Borundia 				if (sriov->allowed_vlans[i] == vid)
200891b7282bSRajesh Borundia 					allowed = 1;
200991b7282bSRajesh Borundia 			}
201091b7282bSRajesh Borundia 
201191b7282bSRajesh Borundia 			if (!allowed)
201291b7282bSRajesh Borundia 				return -EINVAL;
201391b7282bSRajesh Borundia 		}
201491b7282bSRajesh Borundia 	} else {
2015154d0c81SManish Chopra 		if (!vlan_exist || qlcnic_sriov_check_vlan_id(sriov, vf, vid))
201691b7282bSRajesh Borundia 			return -EINVAL;
201791b7282bSRajesh Borundia 	}
201891b7282bSRajesh Borundia 
201991b7282bSRajesh Borundia 	return 0;
202091b7282bSRajesh Borundia }
202191b7282bSRajesh Borundia 
qlcnic_sriov_vlan_operation(struct qlcnic_vf_info * vf,u16 vlan_id,enum qlcnic_vlan_operations opcode)2022154d0c81SManish Chopra static void qlcnic_sriov_vlan_operation(struct qlcnic_vf_info *vf, u16 vlan_id,
2023154d0c81SManish Chopra 					enum qlcnic_vlan_operations opcode)
2024154d0c81SManish Chopra {
2025154d0c81SManish Chopra 	struct qlcnic_adapter *adapter = vf->adapter;
2026154d0c81SManish Chopra 	struct qlcnic_sriov *sriov;
2027154d0c81SManish Chopra 
2028154d0c81SManish Chopra 	sriov = adapter->ahw->sriov;
2029154d0c81SManish Chopra 
2030154d0c81SManish Chopra 	if (!vf->sriov_vlans)
2031154d0c81SManish Chopra 		return;
2032154d0c81SManish Chopra 
203374b7ba1aSRajesh Borundia 	spin_lock_bh(&vf->vlan_list_lock);
2034154d0c81SManish Chopra 
2035154d0c81SManish Chopra 	switch (opcode) {
2036154d0c81SManish Chopra 	case QLC_VLAN_ADD:
2037154d0c81SManish Chopra 		qlcnic_sriov_add_vlan_id(sriov, vf, vlan_id);
2038154d0c81SManish Chopra 		break;
2039154d0c81SManish Chopra 	case QLC_VLAN_DELETE:
2040154d0c81SManish Chopra 		qlcnic_sriov_del_vlan_id(sriov, vf, vlan_id);
2041154d0c81SManish Chopra 		break;
2042154d0c81SManish Chopra 	default:
2043154d0c81SManish Chopra 		netdev_err(adapter->netdev, "Invalid VLAN operation\n");
2044154d0c81SManish Chopra 	}
2045154d0c81SManish Chopra 
204674b7ba1aSRajesh Borundia 	spin_unlock_bh(&vf->vlan_list_lock);
2047154d0c81SManish Chopra 	return;
2048154d0c81SManish Chopra }
2049154d0c81SManish Chopra 
qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter * adapter,u16 vid,u8 enable)205091b7282bSRajesh Borundia int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,
205191b7282bSRajesh Borundia 				   u16 vid, u8 enable)
205291b7282bSRajesh Borundia {
205391b7282bSRajesh Borundia 	struct qlcnic_sriov *sriov = adapter->ahw->sriov;
205474b7ba1aSRajesh Borundia 	struct net_device *netdev = adapter->netdev;
2055154d0c81SManish Chopra 	struct qlcnic_vf_info *vf;
205691b7282bSRajesh Borundia 	struct qlcnic_cmd_args cmd;
205791b7282bSRajesh Borundia 	int ret;
205891b7282bSRajesh Borundia 
2059c5316920SRajesh Borundia 	memset(&cmd, 0, sizeof(cmd));
206091b7282bSRajesh Borundia 	if (vid == 0)
206191b7282bSRajesh Borundia 		return 0;
206291b7282bSRajesh Borundia 
2063154d0c81SManish Chopra 	vf = &adapter->ahw->sriov->vf_info[0];
2064154d0c81SManish Chopra 	ret = qlcnic_sriov_validate_vlan_cfg(adapter, vid, enable);
206591b7282bSRajesh Borundia 	if (ret)
206691b7282bSRajesh Borundia 		return ret;
206791b7282bSRajesh Borundia 
206891b7282bSRajesh Borundia 	ret = qlcnic_sriov_alloc_bc_mbx_args(&cmd,
206991b7282bSRajesh Borundia 					     QLCNIC_BC_CMD_CFG_GUEST_VLAN);
207091b7282bSRajesh Borundia 	if (ret)
207191b7282bSRajesh Borundia 		return ret;
207291b7282bSRajesh Borundia 
207391b7282bSRajesh Borundia 	cmd.req.arg[1] = (enable & 1) | vid << 16;
207491b7282bSRajesh Borundia 
207591b7282bSRajesh Borundia 	qlcnic_sriov_cleanup_async_list(&sriov->bc);
207691b7282bSRajesh Borundia 	ret = qlcnic_issue_cmd(adapter, &cmd);
207791b7282bSRajesh Borundia 	if (ret) {
207891b7282bSRajesh Borundia 		dev_err(&adapter->pdev->dev,
207991b7282bSRajesh Borundia 			"Failed to configure guest VLAN, err=%d\n", ret);
208091b7282bSRajesh Borundia 	} else {
208174b7ba1aSRajesh Borundia 		netif_addr_lock_bh(netdev);
208291b7282bSRajesh Borundia 		qlcnic_free_mac_list(adapter);
208374b7ba1aSRajesh Borundia 		netif_addr_unlock_bh(netdev);
208491b7282bSRajesh Borundia 
208591b7282bSRajesh Borundia 		if (enable)
2086154d0c81SManish Chopra 			qlcnic_sriov_vlan_operation(vf, vid, QLC_VLAN_ADD);
208791b7282bSRajesh Borundia 		else
2088154d0c81SManish Chopra 			qlcnic_sriov_vlan_operation(vf, vid, QLC_VLAN_DELETE);
208991b7282bSRajesh Borundia 
209074b7ba1aSRajesh Borundia 		netif_addr_lock_bh(netdev);
209174b7ba1aSRajesh Borundia 		qlcnic_set_multi(netdev);
209274b7ba1aSRajesh Borundia 		netif_addr_unlock_bh(netdev);
209391b7282bSRajesh Borundia 	}
209491b7282bSRajesh Borundia 
209591b7282bSRajesh Borundia 	qlcnic_free_mbx_args(&cmd);
209691b7282bSRajesh Borundia 	return ret;
209791b7282bSRajesh Borundia }
209891b7282bSRajesh Borundia 
qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter * adapter)209991b7282bSRajesh Borundia static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *adapter)
210091b7282bSRajesh Borundia {
210191b7282bSRajesh Borundia 	struct list_head *head = &adapter->mac_list;
2102154d0c81SManish Chopra 	struct qlcnic_mac_vlan_list *cur;
210391b7282bSRajesh Borundia 
210491b7282bSRajesh Borundia 	while (!list_empty(head)) {
2105154d0c81SManish Chopra 		cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list);
2106154d0c81SManish Chopra 		qlcnic_sre_macaddr_change(adapter, cur->mac_addr, cur->vlan_id,
2107154d0c81SManish Chopra 					  QLCNIC_MAC_DEL);
210891b7282bSRajesh Borundia 		list_del(&cur->list);
210991b7282bSRajesh Borundia 		kfree(cur);
211091b7282bSRajesh Borundia 	}
211191b7282bSRajesh Borundia }
2112486a5bc7SRajesh Borundia 
2113154d0c81SManish Chopra 
qlcnic_sriov_vf_shutdown(struct pci_dev * pdev)211421041400Sstephen hemminger static int qlcnic_sriov_vf_shutdown(struct pci_dev *pdev)
2115486a5bc7SRajesh Borundia {
2116486a5bc7SRajesh Borundia 	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
2117486a5bc7SRajesh Borundia 	struct net_device *netdev = adapter->netdev;
2118486a5bc7SRajesh Borundia 
2119486a5bc7SRajesh Borundia 	netif_device_detach(netdev);
2120486a5bc7SRajesh Borundia 	qlcnic_cancel_idc_work(adapter);
2121486a5bc7SRajesh Borundia 
2122486a5bc7SRajesh Borundia 	if (netif_running(netdev))
2123486a5bc7SRajesh Borundia 		qlcnic_down(adapter, netdev);
2124486a5bc7SRajesh Borundia 
2125486a5bc7SRajesh Borundia 	qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
2126486a5bc7SRajesh Borundia 	qlcnic_sriov_cfg_bc_intr(adapter, 0);
2127486a5bc7SRajesh Borundia 	qlcnic_83xx_disable_mbx_intr(adapter);
2128486a5bc7SRajesh Borundia 	cancel_delayed_work_sync(&adapter->idc_aen_work);
2129486a5bc7SRajesh Borundia 
21306eea3926SZheng Yongjun 	return pci_save_state(pdev);
2131486a5bc7SRajesh Borundia }
2132486a5bc7SRajesh Borundia 
qlcnic_sriov_vf_resume(struct qlcnic_adapter * adapter)213321041400Sstephen hemminger static int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter)
2134486a5bc7SRajesh Borundia {
2135486a5bc7SRajesh Borundia 	struct qlc_83xx_idc *idc = &adapter->ahw->idc;
2136486a5bc7SRajesh Borundia 	struct net_device *netdev = adapter->netdev;
2137486a5bc7SRajesh Borundia 	int err;
2138486a5bc7SRajesh Borundia 
2139486a5bc7SRajesh Borundia 	set_bit(QLC_83XX_MODULE_LOADED, &idc->status);
2140e5c4e6c6SManish Chopra 	qlcnic_83xx_enable_mbx_interrupt(adapter);
2141486a5bc7SRajesh Borundia 	err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
2142486a5bc7SRajesh Borundia 	if (err)
2143486a5bc7SRajesh Borundia 		return err;
2144486a5bc7SRajesh Borundia 
2145486a5bc7SRajesh Borundia 	err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT);
2146486a5bc7SRajesh Borundia 	if (!err) {
2147486a5bc7SRajesh Borundia 		if (netif_running(netdev)) {
2148486a5bc7SRajesh Borundia 			err = qlcnic_up(adapter, netdev);
2149486a5bc7SRajesh Borundia 			if (!err)
2150486a5bc7SRajesh Borundia 				qlcnic_restore_indev_addr(netdev, NETDEV_UP);
2151486a5bc7SRajesh Borundia 		}
2152486a5bc7SRajesh Borundia 	}
2153486a5bc7SRajesh Borundia 
2154486a5bc7SRajesh Borundia 	netif_device_attach(netdev);
2155486a5bc7SRajesh Borundia 	qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state,
2156486a5bc7SRajesh Borundia 			     idc->delay);
2157486a5bc7SRajesh Borundia 	return err;
2158486a5bc7SRajesh Borundia }
2159154d0c81SManish Chopra 
qlcnic_sriov_alloc_vlans(struct qlcnic_adapter * adapter)216060ec7fcfSJiasheng Jiang int qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *adapter)
2161154d0c81SManish Chopra {
2162154d0c81SManish Chopra 	struct qlcnic_sriov *sriov = adapter->ahw->sriov;
2163154d0c81SManish Chopra 	struct qlcnic_vf_info *vf;
2164154d0c81SManish Chopra 	int i;
2165154d0c81SManish Chopra 
2166154d0c81SManish Chopra 	for (i = 0; i < sriov->num_vfs; i++) {
2167154d0c81SManish Chopra 		vf = &sriov->vf_info[i];
2168154d0c81SManish Chopra 		vf->sriov_vlans = kcalloc(sriov->num_allowed_vlans,
2169154d0c81SManish Chopra 					  sizeof(*vf->sriov_vlans), GFP_KERNEL);
217060ec7fcfSJiasheng Jiang 		if (!vf->sriov_vlans)
217160ec7fcfSJiasheng Jiang 			return -ENOMEM;
2172154d0c81SManish Chopra 	}
217360ec7fcfSJiasheng Jiang 
217460ec7fcfSJiasheng Jiang 	return 0;
2175154d0c81SManish Chopra }
2176154d0c81SManish Chopra 
qlcnic_sriov_free_vlans(struct qlcnic_adapter * adapter)2177154d0c81SManish Chopra void qlcnic_sriov_free_vlans(struct qlcnic_adapter *adapter)
2178154d0c81SManish Chopra {
2179154d0c81SManish Chopra 	struct qlcnic_sriov *sriov = adapter->ahw->sriov;
2180154d0c81SManish Chopra 	struct qlcnic_vf_info *vf;
2181154d0c81SManish Chopra 	int i;
2182154d0c81SManish Chopra 
2183154d0c81SManish Chopra 	for (i = 0; i < sriov->num_vfs; i++) {
2184154d0c81SManish Chopra 		vf = &sriov->vf_info[i];
2185154d0c81SManish Chopra 		kfree(vf->sriov_vlans);
2186154d0c81SManish Chopra 		vf->sriov_vlans = NULL;
2187154d0c81SManish Chopra 	}
2188154d0c81SManish Chopra }
2189154d0c81SManish Chopra 
qlcnic_sriov_add_vlan_id(struct qlcnic_sriov * sriov,struct qlcnic_vf_info * vf,u16 vlan_id)2190154d0c81SManish Chopra void qlcnic_sriov_add_vlan_id(struct qlcnic_sriov *sriov,
2191154d0c81SManish Chopra 			      struct qlcnic_vf_info *vf, u16 vlan_id)
2192154d0c81SManish Chopra {
2193154d0c81SManish Chopra 	int i;
2194154d0c81SManish Chopra 
2195154d0c81SManish Chopra 	for (i = 0; i < sriov->num_allowed_vlans; i++) {
2196154d0c81SManish Chopra 		if (!vf->sriov_vlans[i]) {
2197154d0c81SManish Chopra 			vf->sriov_vlans[i] = vlan_id;
2198154d0c81SManish Chopra 			vf->num_vlan++;
2199154d0c81SManish Chopra 			return;
2200154d0c81SManish Chopra 		}
2201154d0c81SManish Chopra 	}
2202154d0c81SManish Chopra }
2203154d0c81SManish Chopra 
qlcnic_sriov_del_vlan_id(struct qlcnic_sriov * sriov,struct qlcnic_vf_info * vf,u16 vlan_id)2204154d0c81SManish Chopra void qlcnic_sriov_del_vlan_id(struct qlcnic_sriov *sriov,
2205154d0c81SManish Chopra 			      struct qlcnic_vf_info *vf, u16 vlan_id)
2206154d0c81SManish Chopra {
2207154d0c81SManish Chopra 	int i;
2208154d0c81SManish Chopra 
2209154d0c81SManish Chopra 	for (i = 0; i < sriov->num_allowed_vlans; i++) {
2210154d0c81SManish Chopra 		if (vf->sriov_vlans[i] == vlan_id) {
2211154d0c81SManish Chopra 			vf->sriov_vlans[i] = 0;
2212154d0c81SManish Chopra 			vf->num_vlan--;
2213154d0c81SManish Chopra 			return;
2214154d0c81SManish Chopra 		}
2215154d0c81SManish Chopra 	}
2216154d0c81SManish Chopra }
2217154d0c81SManish Chopra 
qlcnic_sriov_check_any_vlan(struct qlcnic_vf_info * vf)2218154d0c81SManish Chopra bool qlcnic_sriov_check_any_vlan(struct qlcnic_vf_info *vf)
2219154d0c81SManish Chopra {
2220154d0c81SManish Chopra 	bool err = false;
2221154d0c81SManish Chopra 
222274b7ba1aSRajesh Borundia 	spin_lock_bh(&vf->vlan_list_lock);
2223154d0c81SManish Chopra 
2224154d0c81SManish Chopra 	if (vf->num_vlan)
2225154d0c81SManish Chopra 		err = true;
2226154d0c81SManish Chopra 
222774b7ba1aSRajesh Borundia 	spin_unlock_bh(&vf->vlan_list_lock);
2228154d0c81SManish Chopra 	return err;
2229154d0c81SManish Chopra }
2230