aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/qlogic/qlcnic
diff options
context:
space:
mode:
authorRajesh Borundia <rajesh.borundia@qlogic.com>2013-04-19 03:01:09 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-19 16:02:38 -0400
commit97d8105cf3fb1eb84351ff4b69287ef7d25a4422 (patch)
tree8afb96c29213064151a887d1d1a31cd2bc8b7651 /drivers/net/ethernet/qlogic/qlcnic
parentf80bc8fe6d44f1f0ebd90d4e698189c5b9ad25e7 (diff)
qlcnic: VF FLR implementation.
o FLR from Hypervisor - When hypervisor issues a VF FLR request, adapter notifies the parent PF driver of the FLR request for PF driver to perform any cleanup on behalf of that VF. o FLR from VF Driver - VF driver may initiate a VF FLR request, if VF state needs to be cleaned up before a re-initialization. VF re-initialization during kdump is an example. o PF driver cleans up all resources allocated on behalf of a VF, on VF FLR notifications from the adapter or from the VF driver. Signed-off-by: Manish Chopra <manish.chopra@qlogic.com> Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com> Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic')
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h18
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c90
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c229
4 files changed, 320 insertions, 18 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index d132765f92af..33f154e4c75b 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -2112,6 +2112,7 @@ static int __qlcnic_shutdown(struct pci_dev *pdev)
2112 if (netif_running(netdev)) 2112 if (netif_running(netdev))
2113 qlcnic_down(adapter, netdev); 2113 qlcnic_down(adapter, netdev);
2114 2114
2115 qlcnic_sriov_cleanup(adapter);
2115 if (qlcnic_82xx_check(adapter)) 2116 if (qlcnic_82xx_check(adapter))
2116 qlcnic_clr_all_drv_state(adapter, 0); 2117 qlcnic_clr_all_drv_state(adapter, 0);
2117 2118
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
index b476ebac2439..7fda5d4625b0 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
@@ -91,6 +91,8 @@ enum qlcnic_vf_state {
91 QLC_BC_VF_RECV, 91 QLC_BC_VF_RECV,
92 QLC_BC_VF_CHANNEL, 92 QLC_BC_VF_CHANNEL,
93 QLC_BC_VF_STATE, 93 QLC_BC_VF_STATE,
94 QLC_BC_VF_FLR,
95 QLC_BC_VF_SOFT_FLR,
94}; 96};
95 97
96struct qlcnic_resources { 98struct qlcnic_resources {
@@ -124,9 +126,11 @@ struct qlcnic_vf_info {
124 unsigned long state; 126 unsigned long state;
125 struct completion ch_free_cmpl; 127 struct completion ch_free_cmpl;
126 struct work_struct trans_work; 128 struct work_struct trans_work;
129 struct work_struct flr_work;
127 /* It synchronizes commands sent from VF */ 130 /* It synchronizes commands sent from VF */
128 struct mutex send_cmd_lock; 131 struct mutex send_cmd_lock;
129 struct qlcnic_bc_trans *send_cmd; 132 struct qlcnic_bc_trans *send_cmd;
133 struct qlcnic_bc_trans *flr_trans;
130 struct qlcnic_trans_list rcv_act; 134 struct qlcnic_trans_list rcv_act;
131 struct qlcnic_trans_list rcv_pend; 135 struct qlcnic_trans_list rcv_pend;
132 struct qlcnic_adapter *adapter; 136 struct qlcnic_adapter *adapter;
@@ -143,6 +147,7 @@ struct qlcnic_back_channel {
143 u16 trans_counter; 147 u16 trans_counter;
144 struct workqueue_struct *bc_trans_wq; 148 struct workqueue_struct *bc_trans_wq;
145 struct workqueue_struct *bc_async_wq; 149 struct workqueue_struct *bc_async_wq;
150 struct workqueue_struct *bc_flr_wq;
146 struct list_head async_list; 151 struct list_head async_list;
147}; 152};
148 153
@@ -165,6 +170,9 @@ int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *, u8);
165void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *, u32); 170void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *, u32);
166int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *, u8); 171int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *, u8);
167void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *); 172void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *);
173void qlcnic_sriov_cleanup_list(struct qlcnic_trans_list *);
174int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *, struct qlcnic_vf_info *,
175 struct qlcnic_bc_trans *);
168 176
169static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter) 177static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter)
170{ 178{
@@ -185,6 +193,10 @@ void qlcnic_pf_set_interface_id_del_tx_ctx(struct qlcnic_adapter *, u32 *);
185void qlcnic_pf_set_interface_id_promisc(struct qlcnic_adapter *, u32 *); 193void qlcnic_pf_set_interface_id_promisc(struct qlcnic_adapter *, u32 *);
186void qlcnic_pf_set_interface_id_ipaddr(struct qlcnic_adapter *, u32 *); 194void qlcnic_pf_set_interface_id_ipaddr(struct qlcnic_adapter *, u32 *);
187void qlcnic_pf_set_interface_id_macaddr(struct qlcnic_adapter *, u32 *); 195void qlcnic_pf_set_interface_id_macaddr(struct qlcnic_adapter *, u32 *);
196void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *, struct qlcnic_vf_info *);
197bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *,
198 struct qlcnic_bc_trans *,
199 struct qlcnic_vf_info *);
188#else 200#else
189static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {} 201static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {}
190static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {} 202static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {}
@@ -209,6 +221,12 @@ qlcnic_pf_set_interface_id_macaddr(struct qlcnic_adapter *adapter, u32 *int_id)
209static inline void 221static inline void
210qlcnic_pf_set_interface_id_promisc(struct qlcnic_adapter *adapter, u32 *int_id) 222qlcnic_pf_set_interface_id_promisc(struct qlcnic_adapter *adapter, u32 *int_id)
211{} 223{}
224static inline void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
225 struct qlcnic_vf_info *vf) {}
226static inline bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *adapter,
227 struct qlcnic_bc_trans *trans,
228 struct qlcnic_vf_info *vf)
229{ return false; }
212#endif 230#endif
213 231
214#endif 232#endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 14e9ebd3b73a..2346b16b7869 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -18,12 +18,14 @@
18 18
19#define QLC_BC_MSG 0 19#define QLC_BC_MSG 0
20#define QLC_BC_CFREE 1 20#define QLC_BC_CFREE 1
21#define QLC_BC_FLR 2
21#define QLC_BC_HDR_SZ 16 22#define QLC_BC_HDR_SZ 16
22#define QLC_BC_PAYLOAD_SZ (1024 - QLC_BC_HDR_SZ) 23#define QLC_BC_PAYLOAD_SZ (1024 - QLC_BC_HDR_SZ)
23 24
24#define QLC_DEFAULT_RCV_DESCRIPTORS_SRIOV_VF 2048 25#define QLC_DEFAULT_RCV_DESCRIPTORS_SRIOV_VF 2048
25#define QLC_DEFAULT_JUMBO_RCV_DESCRIPTORS_SRIOV_VF 512 26#define QLC_DEFAULT_JUMBO_RCV_DESCRIPTORS_SRIOV_VF 512
26 27
28static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *);
27static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *, 29static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *,
28 struct qlcnic_cmd_args *); 30 struct qlcnic_cmd_args *);
29 31
@@ -84,6 +86,11 @@ static inline bool qlcnic_sriov_channel_free_check(u32 val)
84 return (val & (1 << QLC_BC_CFREE)) ? true : false; 86 return (val & (1 << QLC_BC_CFREE)) ? true : false;
85} 87}
86 88
89static inline bool qlcnic_sriov_flr_check(u32 val)
90{
91 return (val & (1 << QLC_BC_FLR)) ? true : false;
92}
93
87static inline u8 qlcnic_sriov_target_func_id(u32 val) 94static inline u8 qlcnic_sriov_target_func_id(u32 val)
88{ 95{
89 return (val >> 4) & 0xff; 96 return (val >> 4) & 0xff;
@@ -192,10 +199,33 @@ qlcnic_free_sriov:
192 return err; 199 return err;
193} 200}
194 201
202void qlcnic_sriov_cleanup_list(struct qlcnic_trans_list *t_list)
203{
204 struct qlcnic_bc_trans *trans;
205 struct qlcnic_cmd_args cmd;
206 unsigned long flags;
207
208 spin_lock_irqsave(&t_list->lock, flags);
209
210 while (!list_empty(&t_list->wait_list)) {
211 trans = list_first_entry(&t_list->wait_list,
212 struct qlcnic_bc_trans, list);
213 list_del(&trans->list);
214 t_list->count--;
215 cmd.req.arg = (u32 *)trans->req_pay;
216 cmd.rsp.arg = (u32 *)trans->rsp_pay;
217 qlcnic_free_mbx_args(&cmd);
218 qlcnic_sriov_cleanup_transaction(trans);
219 }
220
221 spin_unlock_irqrestore(&t_list->lock, flags);
222}
223
195void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) 224void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
196{ 225{
197 struct qlcnic_sriov *sriov = adapter->ahw->sriov; 226 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
198 struct qlcnic_back_channel *bc = &sriov->bc; 227 struct qlcnic_back_channel *bc = &sriov->bc;
228 struct qlcnic_vf_info *vf;
199 int i; 229 int i;
200 230
201 if (!qlcnic_sriov_enable_check(adapter)) 231 if (!qlcnic_sriov_enable_check(adapter))
@@ -203,6 +233,14 @@ void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
203 233
204 qlcnic_sriov_cleanup_async_list(bc); 234 qlcnic_sriov_cleanup_async_list(bc);
205 destroy_workqueue(bc->bc_async_wq); 235 destroy_workqueue(bc->bc_async_wq);
236
237 for (i = 0; i < sriov->num_vfs; i++) {
238 vf = &sriov->vf_info[i];
239 qlcnic_sriov_cleanup_list(&vf->rcv_pend);
240 cancel_work_sync(&vf->trans_work);
241 qlcnic_sriov_cleanup_list(&vf->rcv_act);
242 }
243
206 destroy_workqueue(bc->bc_trans_wq); 244 destroy_workqueue(bc->bc_trans_wq);
207 245
208 for (i = 0; i < sriov->num_vfs; i++) 246 for (i = 0; i < sriov->num_vfs; i++)
@@ -651,6 +689,9 @@ static void qlcnic_sriov_schedule_bc_cmd(struct qlcnic_sriov *sriov,
651 struct qlcnic_vf_info *vf, 689 struct qlcnic_vf_info *vf,
652 work_func_t func) 690 work_func_t func)
653{ 691{
692 if (test_bit(QLC_BC_VF_FLR, &vf->state))
693 return;
694
654 INIT_WORK(&vf->trans_work, func); 695 INIT_WORK(&vf->trans_work, func);
655 queue_work(sriov->bc.bc_trans_wq, &vf->trans_work); 696 queue_work(sriov->bc.bc_trans_wq, &vf->trans_work);
656} 697}
@@ -768,10 +809,13 @@ static int qlcnic_sriov_issue_bc_post(struct qlcnic_bc_trans *trans, u8 type)
768static int __qlcnic_sriov_send_bc_msg(struct qlcnic_bc_trans *trans, 809static int __qlcnic_sriov_send_bc_msg(struct qlcnic_bc_trans *trans,
769 struct qlcnic_vf_info *vf, u8 type) 810 struct qlcnic_vf_info *vf, u8 type)
770{ 811{
771 int err;
772 bool flag = true; 812 bool flag = true;
813 int err = -EIO;
773 814
774 while (flag) { 815 while (flag) {
816 if (test_bit(QLC_BC_VF_FLR, &vf->state))
817 trans->trans_state = QLC_ABORT;
818
775 switch (trans->trans_state) { 819 switch (trans->trans_state) {
776 case QLC_INIT: 820 case QLC_INIT:
777 trans->trans_state = QLC_WAIT_FOR_CHANNEL_FREE; 821 trans->trans_state = QLC_WAIT_FOR_CHANNEL_FREE;
@@ -853,6 +897,9 @@ static void qlcnic_sriov_process_bc_cmd(struct work_struct *work)
853 struct qlcnic_cmd_args cmd; 897 struct qlcnic_cmd_args cmd;
854 u8 req; 898 u8 req;
855 899
900 if (test_bit(QLC_BC_VF_FLR, &vf->state))
901 return;
902
856 trans = list_first_entry(&vf->rcv_act.wait_list, 903 trans = list_first_entry(&vf->rcv_act.wait_list,
857 struct qlcnic_bc_trans, list); 904 struct qlcnic_bc_trans, list);
858 adapter = vf->adapter; 905 adapter = vf->adapter;
@@ -906,18 +953,30 @@ clear_send:
906 clear_bit(QLC_BC_VF_SEND, &vf->state); 953 clear_bit(QLC_BC_VF_SEND, &vf->state);
907} 954}
908 955
909static int qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov, 956int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov,
910 struct qlcnic_vf_info *vf, 957 struct qlcnic_vf_info *vf,
911 struct qlcnic_bc_trans *trans) 958 struct qlcnic_bc_trans *trans)
912{ 959{
913 struct qlcnic_trans_list *t_list = &vf->rcv_act; 960 struct qlcnic_trans_list *t_list = &vf->rcv_act;
914 961
915 spin_lock(&t_list->lock);
916 t_list->count++; 962 t_list->count++;
917 list_add_tail(&trans->list, &t_list->wait_list); 963 list_add_tail(&trans->list, &t_list->wait_list);
918 if (t_list->count == 1) 964 if (t_list->count == 1)
919 qlcnic_sriov_schedule_bc_cmd(sriov, vf, 965 qlcnic_sriov_schedule_bc_cmd(sriov, vf,
920 qlcnic_sriov_process_bc_cmd); 966 qlcnic_sriov_process_bc_cmd);
967 return 0;
968}
969
970static int qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov,
971 struct qlcnic_vf_info *vf,
972 struct qlcnic_bc_trans *trans)
973{
974 struct qlcnic_trans_list *t_list = &vf->rcv_act;
975
976 spin_lock(&t_list->lock);
977
978 __qlcnic_sriov_add_act_list(sriov, vf, trans);
979
921 spin_unlock(&t_list->lock); 980 spin_unlock(&t_list->lock);
922 return 0; 981 return 0;
923} 982}
@@ -1019,6 +1078,10 @@ static void qlcnic_sriov_handle_bc_cmd(struct qlcnic_sriov *sriov,
1019 trans->vf = vf; 1078 trans->vf = vf;
1020 trans->trans_id = hdr->seq_id; 1079 trans->trans_id = hdr->seq_id;
1021 trans->curr_req_frag++; 1080 trans->curr_req_frag++;
1081
1082 if (qlcnic_sriov_soft_flr_check(adapter, trans, vf))
1083 return;
1084
1022 if (trans->curr_req_frag == trans->req_hdr->num_frags) { 1085 if (trans->curr_req_frag == trans->req_hdr->num_frags) {
1023 if (qlcnic_sriov_add_act_list(sriov, vf, trans)) { 1086 if (qlcnic_sriov_add_act_list(sriov, vf, trans)) {
1024 qlcnic_free_mbx_args(&cmd); 1087 qlcnic_free_mbx_args(&cmd);
@@ -1053,6 +1116,18 @@ static void qlcnic_sriov_handle_msg_event(struct qlcnic_sriov *sriov,
1053 } 1116 }
1054} 1117}
1055 1118
1119static void qlcnic_sriov_handle_flr_event(struct qlcnic_sriov *sriov,
1120 struct qlcnic_vf_info *vf)
1121{
1122 struct qlcnic_adapter *adapter = vf->adapter;
1123
1124 if (qlcnic_sriov_pf_check(adapter))
1125 qlcnic_sriov_pf_handle_flr(sriov, vf);
1126 else
1127 dev_err(&adapter->pdev->dev,
1128 "Invalid event to VF. VF should not get FLR event\n");
1129}
1130
1056void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *adapter, u32 event) 1131void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *adapter, u32 event)
1057{ 1132{
1058 struct qlcnic_vf_info *vf; 1133 struct qlcnic_vf_info *vf;
@@ -1073,6 +1148,11 @@ void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *adapter, u32 event)
1073 if (qlcnic_sriov_channel_free_check(event)) 1148 if (qlcnic_sriov_channel_free_check(event))
1074 complete(&vf->ch_free_cmpl); 1149 complete(&vf->ch_free_cmpl);
1075 1150
1151 if (qlcnic_sriov_flr_check(event)) {
1152 qlcnic_sriov_handle_flr_event(sriov, vf);
1153 return;
1154 }
1155
1076 if (qlcnic_sriov_bc_msg_check(event)) 1156 if (qlcnic_sriov_bc_msg_check(event))
1077 qlcnic_sriov_handle_msg_event(sriov, vf); 1157 qlcnic_sriov_handle_msg_event(sriov, vf);
1078} 1158}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
index 3a86e1682456..50cdd510421a 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -303,6 +303,33 @@ static int qlcnic_sriov_pf_cfg_eswitch(struct qlcnic_adapter *adapter,
303 return err; 303 return err;
304} 304}
305 305
306static void qlcnic_sriov_pf_del_flr_queue(struct qlcnic_adapter *adapter)
307{
308 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
309 struct qlcnic_back_channel *bc = &sriov->bc;
310 int i;
311
312 for (i = 0; i < sriov->num_vfs; i++)
313 cancel_work_sync(&sriov->vf_info[i].flr_work);
314
315 destroy_workqueue(bc->bc_flr_wq);
316}
317
318static int qlcnic_sriov_pf_create_flr_queue(struct qlcnic_adapter *adapter)
319{
320 struct qlcnic_back_channel *bc = &adapter->ahw->sriov->bc;
321 struct workqueue_struct *wq;
322
323 wq = create_singlethread_workqueue("qlcnic-flr");
324 if (wq == NULL) {
325 dev_err(&adapter->pdev->dev, "Cannot create FLR workqueue\n");
326 return -ENOMEM;
327 }
328
329 bc->bc_flr_wq = wq;
330 return 0;
331}
332
306void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) 333void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter)
307{ 334{
308 u8 func = adapter->ahw->pci_func; 335 u8 func = adapter->ahw->pci_func;
@@ -310,6 +337,7 @@ void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter)
310 if (!qlcnic_sriov_enable_check(adapter)) 337 if (!qlcnic_sriov_enable_check(adapter))
311 return; 338 return;
312 339
340 qlcnic_sriov_pf_del_flr_queue(adapter);
313 qlcnic_sriov_cfg_bc_intr(adapter, 0); 341 qlcnic_sriov_cfg_bc_intr(adapter, 0);
314 qlcnic_sriov_pf_config_vport(adapter, 0, func); 342 qlcnic_sriov_pf_config_vport(adapter, 0, func);
315 qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0); 343 qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0);
@@ -367,7 +395,7 @@ static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter)
367 395
368 err = qlcnic_sriov_pf_cfg_eswitch(adapter, func, 1); 396 err = qlcnic_sriov_pf_cfg_eswitch(adapter, func, 1);
369 if (err) 397 if (err)
370 goto clear_sriov_enable; 398 return err;
371 399
372 err = qlcnic_sriov_pf_config_vport(adapter, 1, func); 400 err = qlcnic_sriov_pf_config_vport(adapter, 1, func);
373 if (err) 401 if (err)
@@ -402,10 +430,6 @@ delete_vport:
402disable_eswitch: 430disable_eswitch:
403 qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0); 431 qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0);
404 432
405clear_sriov_enable:
406 __qlcnic_sriov_cleanup(adapter);
407 adapter->ahw->op_mode = QLCNIC_MGMT_FUNC;
408 clear_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state);
409 return err; 433 return err;
410} 434}
411 435
@@ -431,17 +455,31 @@ static int __qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter,
431 set_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state); 455 set_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state);
432 adapter->ahw->op_mode = QLCNIC_SRIOV_PF_FUNC; 456 adapter->ahw->op_mode = QLCNIC_SRIOV_PF_FUNC;
433 457
434 if (qlcnic_sriov_init(adapter, num_vfs)) { 458 err = qlcnic_sriov_init(adapter, num_vfs);
435 clear_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state); 459 if (err)
436 adapter->ahw->op_mode = QLCNIC_MGMT_FUNC; 460 goto clear_op_mode;
437 return -EIO;
438 }
439 461
440 if (qlcnic_sriov_pf_init(adapter)) 462 err = qlcnic_sriov_pf_create_flr_queue(adapter);
441 return -EIO; 463 if (err)
464 goto sriov_cleanup;
465
466 err = qlcnic_sriov_pf_init(adapter);
467 if (err)
468 goto del_flr_queue;
442 469
443 err = qlcnic_sriov_pf_enable(adapter, num_vfs); 470 err = qlcnic_sriov_pf_enable(adapter, num_vfs);
444 return err; 471 return err;
472
473del_flr_queue:
474 qlcnic_sriov_pf_del_flr_queue(adapter);
475
476sriov_cleanup:
477 __qlcnic_sriov_cleanup(adapter);
478
479clear_op_mode:
480 clear_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state);
481 adapter->ahw->op_mode = QLCNIC_MGMT_FUNC;
482 return err;
445} 483}
446 484
447static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs) 485static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs)
@@ -463,12 +501,15 @@ static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs)
463 netdev_info(netdev, "Failed to enable SR-IOV on port %d\n", 501 netdev_info(netdev, "Failed to enable SR-IOV on port %d\n",
464 adapter->portnum); 502 adapter->portnum);
465 503
504 err = -EIO;
466 if (qlcnic_83xx_configure_opmode(adapter)) 505 if (qlcnic_83xx_configure_opmode(adapter))
467 goto error; 506 goto error;
468 } else { 507 } else {
469 netdev_info(adapter->netdev, 508 netdev_info(netdev,
470 "SR-IOV is enabled successfully on port %d\n", 509 "SR-IOV is enabled successfully on port %d\n",
471 adapter->portnum); 510 adapter->portnum);
511 /* Return number of vfs enabled */
512 err = num_vfs;
472 } 513 }
473 if (netif_running(netdev)) 514 if (netif_running(netdev))
474 __qlcnic_up(adapter, netdev); 515 __qlcnic_up(adapter, netdev);
@@ -1173,3 +1214,165 @@ void qlcnic_pf_set_interface_id_macaddr(struct qlcnic_adapter *adapter,
1173 adapter->ahw->pci_func); 1214 adapter->ahw->pci_func);
1174 *int_id |= (vpid << 16) | BIT_31; 1215 *int_id |= (vpid << 16) | BIT_31;
1175} 1216}
1217
1218static void qlcnic_sriov_del_rx_ctx(struct qlcnic_adapter *adapter,
1219 struct qlcnic_vf_info *vf)
1220{
1221 struct qlcnic_cmd_args cmd;
1222 int vpid;
1223
1224 if (!vf->rx_ctx_id)
1225 return;
1226
1227 if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX))
1228 return;
1229
1230 vpid = qlcnic_sriov_pf_get_vport_handle(adapter, vf->pci_func);
1231 if (vpid >= 0) {
1232 cmd.req.arg[1] = vf->rx_ctx_id | (vpid & 0xffff) << 16;
1233 if (qlcnic_issue_cmd(adapter, &cmd))
1234 dev_err(&adapter->pdev->dev,
1235 "Failed to delete Tx ctx in firmware for func 0x%x\n",
1236 vf->pci_func);
1237 else
1238 vf->rx_ctx_id = 0;
1239 }
1240
1241 qlcnic_free_mbx_args(&cmd);
1242}
1243
1244static void qlcnic_sriov_del_tx_ctx(struct qlcnic_adapter *adapter,
1245 struct qlcnic_vf_info *vf)
1246{
1247 struct qlcnic_cmd_args cmd;
1248 int vpid;
1249
1250 if (!vf->tx_ctx_id)
1251 return;
1252
1253 if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX))
1254 return;
1255
1256 vpid = qlcnic_sriov_pf_get_vport_handle(adapter, vf->pci_func);
1257 if (vpid >= 0) {
1258 cmd.req.arg[1] |= vf->tx_ctx_id | (vpid & 0xffff) << 16;
1259 if (qlcnic_issue_cmd(adapter, &cmd))
1260 dev_err(&adapter->pdev->dev,
1261 "Failed to delete Tx ctx in firmware for func 0x%x\n",
1262 vf->pci_func);
1263 else
1264 vf->tx_ctx_id = 0;
1265 }
1266
1267 qlcnic_free_mbx_args(&cmd);
1268}
1269
1270static int qlcnic_sriov_add_act_list_irqsave(struct qlcnic_sriov *sriov,
1271 struct qlcnic_vf_info *vf,
1272 struct qlcnic_bc_trans *trans)
1273{
1274 struct qlcnic_trans_list *t_list = &vf->rcv_act;
1275 unsigned long flag;
1276
1277 spin_lock_irqsave(&t_list->lock, flag);
1278
1279 __qlcnic_sriov_add_act_list(sriov, vf, trans);
1280
1281 spin_unlock_irqrestore(&t_list->lock, flag);
1282 return 0;
1283}
1284
1285static void __qlcnic_sriov_process_flr(struct qlcnic_vf_info *vf)
1286{
1287 struct qlcnic_adapter *adapter = vf->adapter;
1288
1289 qlcnic_sriov_cleanup_list(&vf->rcv_pend);
1290 cancel_work_sync(&vf->trans_work);
1291 qlcnic_sriov_cleanup_list(&vf->rcv_act);
1292
1293 if (test_bit(QLC_BC_VF_SOFT_FLR, &vf->state)) {
1294 qlcnic_sriov_del_tx_ctx(adapter, vf);
1295 qlcnic_sriov_del_rx_ctx(adapter, vf);
1296 }
1297
1298 qlcnic_sriov_pf_config_vport(adapter, 0, vf->pci_func);
1299
1300 clear_bit(QLC_BC_VF_FLR, &vf->state);
1301 if (test_bit(QLC_BC_VF_SOFT_FLR, &vf->state)) {
1302 qlcnic_sriov_add_act_list_irqsave(adapter->ahw->sriov, vf,
1303 vf->flr_trans);
1304 clear_bit(QLC_BC_VF_SOFT_FLR, &vf->state);
1305 vf->flr_trans = NULL;
1306 }
1307}
1308
1309static void qlcnic_sriov_pf_process_flr(struct work_struct *work)
1310{
1311 struct qlcnic_vf_info *vf;
1312
1313 vf = container_of(work, struct qlcnic_vf_info, flr_work);
1314 __qlcnic_sriov_process_flr(vf);
1315 return;
1316}
1317
1318static void qlcnic_sriov_schedule_flr(struct qlcnic_sriov *sriov,
1319 struct qlcnic_vf_info *vf,
1320 work_func_t func)
1321{
1322 if (test_bit(__QLCNIC_RESETTING, &vf->adapter->state))
1323 return;
1324
1325 INIT_WORK(&vf->flr_work, func);
1326 queue_work(sriov->bc.bc_flr_wq, &vf->flr_work);
1327}
1328
1329static void qlcnic_sriov_handle_soft_flr(struct qlcnic_adapter *adapter,
1330 struct qlcnic_bc_trans *trans,
1331 struct qlcnic_vf_info *vf)
1332{
1333 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
1334
1335 set_bit(QLC_BC_VF_FLR, &vf->state);
1336 clear_bit(QLC_BC_VF_STATE, &vf->state);
1337 set_bit(QLC_BC_VF_SOFT_FLR, &vf->state);
1338 vf->flr_trans = trans;
1339 qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr);
1340 netdev_info(adapter->netdev, "Software FLR for PCI func %d\n",
1341 vf->pci_func);
1342}
1343
1344bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *adapter,
1345 struct qlcnic_bc_trans *trans,
1346 struct qlcnic_vf_info *vf)
1347{
1348 struct qlcnic_bc_hdr *hdr = trans->req_hdr;
1349
1350 if ((hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) &&
1351 (hdr->op_type == QLC_BC_CMD) &&
1352 test_bit(QLC_BC_VF_STATE, &vf->state)) {
1353 qlcnic_sriov_handle_soft_flr(adapter, trans, vf);
1354 return true;
1355 }
1356
1357 return false;
1358}
1359
1360void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
1361 struct qlcnic_vf_info *vf)
1362{
1363 struct net_device *dev = vf->adapter->netdev;
1364
1365 if (!test_and_clear_bit(QLC_BC_VF_STATE, &vf->state)) {
1366 clear_bit(QLC_BC_VF_FLR, &vf->state);
1367 return;
1368 }
1369
1370 if (test_and_set_bit(QLC_BC_VF_FLR, &vf->state)) {
1371 netdev_info(dev, "FLR for PCI func %d in progress\n",
1372 vf->pci_func);
1373 return;
1374 }
1375
1376 qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr);
1377 netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func);
1378}