aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
diff options
context:
space:
mode:
authorRajesh Borundia <rajesh.borundia@qlogic.com>2013-03-29 01:46:36 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-29 15:51:05 -0400
commitf197a7aa62888f27c9a7976b18eb4f040f6606ce (patch)
tree7d61aefe5ea028bb2602cafa099449a7b783cb7a /drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
parentda6c806311b9fd2b1aa79f9d5d151bc40060a1fc (diff)
qlcnic: VF-PF communication channel implementation
o Adapter provides communication channel between VF and PF. Any control commands from the VF driver are sent to the PF driver through this communication channel. PF driver validates the commands before sending them to the adapter. Similarly PF driver forwards any control command responses to the VF driver through this communication channel. Adapter sends message pending event to VF or PF when there is an outstanding response or a command for VF or PF respectively. When a command or a response is sent over a channel VF or PF cannot send another command or a response until adapter sends a channel free event. Adapter allocates 1K area to VF and PF each for this communication. o Commands and responses are encapsulated in a header. Header determines sequence id, number of fragments, fragment number etc. 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/qlcnic_sriov_common.c')
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c951
1 files changed, 950 insertions, 1 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 0e097f79a14a..0615086f4526 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -10,6 +10,20 @@
10#include "qlcnic_83xx_hw.h" 10#include "qlcnic_83xx_hw.h"
11#include <linux/types.h> 11#include <linux/types.h>
12 12
13#define QLC_BC_COMMAND 0
14#define QLC_BC_RESPONSE 1
15
16#define QLC_MBOX_RESP_TIMEOUT (10 * HZ)
17#define QLC_MBOX_CH_FREE_TIMEOUT (10 * HZ)
18
19#define QLC_BC_MSG 0
20#define QLC_BC_CFREE 1
21#define QLC_BC_HDR_SZ 16
22#define QLC_BC_PAYLOAD_SZ (1024 - QLC_BC_HDR_SZ)
23
24static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *,
25 struct qlcnic_cmd_args *);
26
13static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = { 27static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {
14 .read_crb = qlcnic_83xx_read_crb, 28 .read_crb = qlcnic_83xx_read_crb,
15 .write_crb = qlcnic_83xx_write_crb, 29 .write_crb = qlcnic_83xx_write_crb,
@@ -18,6 +32,7 @@ static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {
18 .get_mac_address = qlcnic_83xx_get_mac_address, 32 .get_mac_address = qlcnic_83xx_get_mac_address,
19 .setup_intr = qlcnic_83xx_setup_intr, 33 .setup_intr = qlcnic_83xx_setup_intr,
20 .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args, 34 .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args,
35 .mbx_cmd = qlcnic_sriov_vf_mbx_op,
21 .get_func_no = qlcnic_83xx_get_func_no, 36 .get_func_no = qlcnic_83xx_get_func_no,
22 .api_lock = qlcnic_83xx_cam_lock, 37 .api_lock = qlcnic_83xx_cam_lock,
23 .api_unlock = qlcnic_83xx_cam_unlock, 38 .api_unlock = qlcnic_83xx_cam_unlock,
@@ -49,9 +64,50 @@ static struct qlcnic_nic_template qlcnic_sriov_vf_ops = {
49 .clear_legacy_intr = qlcnic_83xx_clear_legacy_intr, 64 .clear_legacy_intr = qlcnic_83xx_clear_legacy_intr,
50}; 65};
51 66
67static const struct qlcnic_mailbox_metadata qlcnic_sriov_bc_mbx_tbl[] = {
68 {QLCNIC_BC_CMD_CHANNEL_INIT, 2, 2},
69 {QLCNIC_BC_CMD_CHANNEL_TERM, 2, 2},
70};
71
72static inline bool qlcnic_sriov_bc_msg_check(u32 val)
73{
74 return (val & (1 << QLC_BC_MSG)) ? true : false;
75}
76
77static inline bool qlcnic_sriov_channel_free_check(u32 val)
78{
79 return (val & (1 << QLC_BC_CFREE)) ? true : false;
80}
81
82static inline u8 qlcnic_sriov_target_func_id(u32 val)
83{
84 return (val >> 4) & 0xff;
85}
86
87static int qlcnic_sriov_virtid_fn(struct qlcnic_adapter *adapter, int vf_id)
88{
89 struct pci_dev *dev = adapter->pdev;
90 int pos;
91 u16 stride, offset;
92
93 if (qlcnic_sriov_vf_check(adapter))
94 return 0;
95
96 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
97 pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
98 pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
99
100 return (dev->devfn + offset + stride * vf_id) & 0xff;
101}
102
52int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs) 103int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
53{ 104{
54 struct qlcnic_sriov *sriov; 105 struct qlcnic_sriov *sriov;
106 struct qlcnic_back_channel *bc;
107 struct workqueue_struct *wq;
108 struct qlcnic_vport *vp;
109 struct qlcnic_vf_info *vf;
110 int err, i;
55 111
56 if (!qlcnic_sriov_enable_check(adapter)) 112 if (!qlcnic_sriov_enable_check(adapter))
57 return -EIO; 113 return -EIO;
@@ -62,19 +118,84 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
62 118
63 adapter->ahw->sriov = sriov; 119 adapter->ahw->sriov = sriov;
64 sriov->num_vfs = num_vfs; 120 sriov->num_vfs = num_vfs;
121 bc = &sriov->bc;
122 sriov->vf_info = kzalloc(sizeof(struct qlcnic_vf_info) *
123 num_vfs, GFP_KERNEL);
124 if (!sriov->vf_info) {
125 err = -ENOMEM;
126 goto qlcnic_free_sriov;
127 }
128
129 wq = create_singlethread_workqueue("bc-trans");
130 if (wq == NULL) {
131 err = -ENOMEM;
132 dev_err(&adapter->pdev->dev,
133 "Cannot create bc-trans workqueue\n");
134 goto qlcnic_free_vf_info;
135 }
136
137 bc->bc_trans_wq = wq;
138
139 for (i = 0; i < num_vfs; i++) {
140 vf = &sriov->vf_info[i];
141 vf->adapter = adapter;
142 vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i);
143 mutex_init(&vf->send_cmd_lock);
144 INIT_LIST_HEAD(&vf->rcv_act.wait_list);
145 INIT_LIST_HEAD(&vf->rcv_pend.wait_list);
146 spin_lock_init(&vf->rcv_act.lock);
147 spin_lock_init(&vf->rcv_pend.lock);
148 init_completion(&vf->ch_free_cmpl);
149
150 if (qlcnic_sriov_pf_check(adapter)) {
151 vp = kzalloc(sizeof(struct qlcnic_vport), GFP_KERNEL);
152 if (!vp) {
153 err = -ENOMEM;
154 goto qlcnic_destroy_trans_wq;
155 }
156 sriov->vf_info[i].vp = vp;
157 random_ether_addr(vp->mac);
158 dev_info(&adapter->pdev->dev,
159 "MAC Address %pM is configured for VF %d\n",
160 vp->mac, i);
161 }
162 }
163
65 return 0; 164 return 0;
165
166qlcnic_destroy_trans_wq:
167 destroy_workqueue(bc->bc_trans_wq);
168
169qlcnic_free_vf_info:
170 kfree(sriov->vf_info);
171
172qlcnic_free_sriov:
173 kfree(adapter->ahw->sriov);
174 return err;
66} 175}
67 176
68void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) 177void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
69{ 178{
179 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
180 struct qlcnic_back_channel *bc = &sriov->bc;
181 int i;
182
70 if (!qlcnic_sriov_enable_check(adapter)) 183 if (!qlcnic_sriov_enable_check(adapter))
71 return; 184 return;
72 185
186 destroy_workqueue(bc->bc_trans_wq);
187
188 for (i = 0; i < sriov->num_vfs; i++)
189 kfree(sriov->vf_info[i].vp);
190
191 kfree(sriov->vf_info);
73 kfree(adapter->ahw->sriov); 192 kfree(adapter->ahw->sriov);
74} 193}
75 194
76static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter) 195static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter)
77{ 196{
197 qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
198 qlcnic_sriov_cfg_bc_intr(adapter, 0);
78 __qlcnic_sriov_cleanup(adapter); 199 __qlcnic_sriov_cleanup(adapter);
79} 200}
80 201
@@ -87,6 +208,103 @@ void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
87 qlcnic_sriov_vf_cleanup(adapter); 208 qlcnic_sriov_vf_cleanup(adapter);
88} 209}
89 210
211static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr,
212 u32 *pay, u8 pci_func, u8 size)
213{
214 struct qlcnic_hardware_context *ahw = adapter->ahw;
215 unsigned long flags;
216 u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, val;
217 u16 opcode;
218 u8 mbx_err_code;
219 int i, j;
220
221 opcode = ((struct qlcnic_bc_hdr *)hdr)->cmd_op;
222
223 if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
224 dev_info(&adapter->pdev->dev,
225 "Mailbox cmd attempted, 0x%x\n", opcode);
226 dev_info(&adapter->pdev->dev, "Mailbox detached\n");
227 return 0;
228 }
229
230 spin_lock_irqsave(&ahw->mbx_lock, flags);
231
232 mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
233 if (mbx_val) {
234 QLCDB(adapter, DRV, "Mailbox cmd attempted, 0x%x\n", opcode);
235 spin_unlock_irqrestore(&ahw->mbx_lock, flags);
236 return QLCNIC_RCODE_TIMEOUT;
237 }
238 /* Fill in mailbox registers */
239 val = size + (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
240 mbx_cmd = 0x31 | (val << 16) | (adapter->ahw->fw_hal_version << 29);
241
242 writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
243 mbx_cmd = 0x1 | (1 << 4);
244
245 if (qlcnic_sriov_pf_check(adapter))
246 mbx_cmd |= (pci_func << 5);
247
248 writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 1));
249 for (i = 2, j = 0; j < (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
250 i++, j++) {
251 writel(*(hdr++), QLCNIC_MBX_HOST(ahw, i));
252 }
253 for (j = 0; j < size; j++, i++)
254 writel(*(pay++), QLCNIC_MBX_HOST(ahw, i));
255
256 /* Signal FW about the impending command */
257 QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
258
259 /* Waiting for the mailbox cmd to complete and while waiting here
260 * some AEN might arrive. If more than 5 seconds expire we can
261 * assume something is wrong.
262 */
263poll:
264 rsp = qlcnic_83xx_mbx_poll(adapter);
265 if (rsp != QLCNIC_RCODE_TIMEOUT) {
266 /* Get the FW response data */
267 fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
268 if (fw_data & QLCNIC_MBX_ASYNC_EVENT) {
269 qlcnic_83xx_process_aen(adapter);
270 mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
271 if (mbx_val)
272 goto poll;
273 }
274 mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
275 rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
276 opcode = QLCNIC_MBX_RSP(fw_data);
277
278 switch (mbx_err_code) {
279 case QLCNIC_MBX_RSP_OK:
280 case QLCNIC_MBX_PORT_RSP_OK:
281 rsp = QLCNIC_RCODE_SUCCESS;
282 break;
283 default:
284 if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) {
285 rsp = qlcnic_83xx_mac_rcode(adapter);
286 if (!rsp)
287 goto out;
288 }
289 dev_err(&adapter->pdev->dev,
290 "MBX command 0x%x failed with err:0x%x\n",
291 opcode, mbx_err_code);
292 rsp = mbx_err_code;
293 break;
294 }
295 goto out;
296 }
297
298 dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n",
299 QLCNIC_MBX_RSP(mbx_cmd));
300 rsp = QLCNIC_RCODE_TIMEOUT;
301out:
302 /* clear fw mbx control register */
303 QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
304 spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
305 return rsp;
306}
307
90static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, 308static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
91 int pci_using_dac) 309 int pci_using_dac)
92{ 310{
@@ -110,15 +328,29 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
110 if (err) 328 if (err)
111 goto err_out_disable_mbx_intr; 329 goto err_out_disable_mbx_intr;
112 330
113 err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac); 331 err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
114 if (err) 332 if (err)
115 goto err_out_cleanup_sriov; 333 goto err_out_cleanup_sriov;
116 334
335 err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT);
336 if (err)
337 goto err_out_disable_bc_intr;
338
339 err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac);
340 if (err)
341 goto err_out_send_channel_term;
342
117 pci_set_drvdata(adapter->pdev, adapter); 343 pci_set_drvdata(adapter->pdev, adapter);
118 dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n", 344 dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
119 adapter->netdev->name); 345 adapter->netdev->name);
120 return 0; 346 return 0;
121 347
348err_out_send_channel_term:
349 qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
350
351err_out_disable_bc_intr:
352 qlcnic_sriov_cfg_bc_intr(adapter, 0);
353
122err_out_cleanup_sriov: 354err_out_cleanup_sriov:
123 __qlcnic_sriov_cleanup(adapter); 355 __qlcnic_sriov_cleanup(adapter);
124 356
@@ -173,3 +405,720 @@ void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *ahw)
173 ahw->reg_tbl = (u32 *)qlcnic_83xx_reg_tbl; 405 ahw->reg_tbl = (u32 *)qlcnic_83xx_reg_tbl;
174 ahw->ext_reg_tbl = (u32 *)qlcnic_83xx_ext_reg_tbl; 406 ahw->ext_reg_tbl = (u32 *)qlcnic_83xx_ext_reg_tbl;
175} 407}
408
409static u32 qlcnic_sriov_get_bc_paysize(u32 real_pay_size, u8 curr_frag)
410{
411 u32 pay_size;
412
413 pay_size = real_pay_size / ((curr_frag + 1) * QLC_BC_PAYLOAD_SZ);
414
415 if (pay_size)
416 pay_size = QLC_BC_PAYLOAD_SZ;
417 else
418 pay_size = real_pay_size % QLC_BC_PAYLOAD_SZ;
419
420 return pay_size;
421}
422
423int qlcnic_sriov_func_to_index(struct qlcnic_adapter *adapter, u8 pci_func)
424{
425 struct qlcnic_vf_info *vf_info = adapter->ahw->sriov->vf_info;
426 u8 i;
427
428 if (qlcnic_sriov_vf_check(adapter))
429 return 0;
430
431 for (i = 0; i < adapter->ahw->sriov->num_vfs; i++) {
432 if (vf_info[i].pci_func == pci_func)
433 return i;
434 }
435
436 return -EINVAL;
437}
438
439static inline int qlcnic_sriov_alloc_bc_trans(struct qlcnic_bc_trans **trans)
440{
441 *trans = kzalloc(sizeof(struct qlcnic_bc_trans), GFP_ATOMIC);
442 if (!*trans)
443 return -ENOMEM;
444
445 init_completion(&(*trans)->resp_cmpl);
446 return 0;
447}
448
449static inline int qlcnic_sriov_alloc_bc_msg(struct qlcnic_bc_hdr **hdr,
450 u32 size)
451{
452 *hdr = kzalloc(sizeof(struct qlcnic_bc_hdr) * size, GFP_ATOMIC);
453 if (!*hdr)
454 return -ENOMEM;
455
456 return 0;
457}
458
459static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type)
460{
461 const struct qlcnic_mailbox_metadata *mbx_tbl;
462 int i, size;
463
464 mbx_tbl = qlcnic_sriov_bc_mbx_tbl;
465 size = ARRAY_SIZE(qlcnic_sriov_bc_mbx_tbl);
466
467 for (i = 0; i < size; i++) {
468 if (type == mbx_tbl[i].cmd) {
469 mbx->op_type = QLC_BC_CMD;
470 mbx->req.num = mbx_tbl[i].in_args;
471 mbx->rsp.num = mbx_tbl[i].out_args;
472 mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32),
473 GFP_ATOMIC);
474 if (!mbx->req.arg)
475 return -ENOMEM;
476 mbx->rsp.arg = kcalloc(mbx->rsp.num, sizeof(u32),
477 GFP_ATOMIC);
478 if (!mbx->rsp.arg) {
479 kfree(mbx->req.arg);
480 mbx->req.arg = NULL;
481 return -ENOMEM;
482 }
483 memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
484 memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
485 mbx->req.arg[0] = (type | (mbx->req.num << 16) |
486 (3 << 29));
487 return 0;
488 }
489 }
490 return -EINVAL;
491}
492
493static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans,
494 struct qlcnic_cmd_args *cmd,
495 u16 seq, u8 msg_type)
496{
497 struct qlcnic_bc_hdr *hdr;
498 int i;
499 u32 num_regs, bc_pay_sz;
500 u16 remainder;
501 u8 cmd_op, num_frags, t_num_frags;
502
503 bc_pay_sz = QLC_BC_PAYLOAD_SZ;
504 if (msg_type == QLC_BC_COMMAND) {
505 trans->req_pay = (struct qlcnic_bc_payload *)cmd->req.arg;
506 trans->rsp_pay = (struct qlcnic_bc_payload *)cmd->rsp.arg;
507 num_regs = cmd->req.num;
508 trans->req_pay_size = (num_regs * 4);
509 num_regs = cmd->rsp.num;
510 trans->rsp_pay_size = (num_regs * 4);
511 cmd_op = cmd->req.arg[0] & 0xff;
512 remainder = (trans->req_pay_size) % (bc_pay_sz);
513 num_frags = (trans->req_pay_size) / (bc_pay_sz);
514 if (remainder)
515 num_frags++;
516 t_num_frags = num_frags;
517 if (qlcnic_sriov_alloc_bc_msg(&trans->req_hdr, num_frags))
518 return -ENOMEM;
519 remainder = (trans->rsp_pay_size) % (bc_pay_sz);
520 num_frags = (trans->rsp_pay_size) / (bc_pay_sz);
521 if (remainder)
522 num_frags++;
523 if (qlcnic_sriov_alloc_bc_msg(&trans->rsp_hdr, num_frags))
524 return -ENOMEM;
525 num_frags = t_num_frags;
526 hdr = trans->req_hdr;
527 } else {
528 cmd->req.arg = (u32 *)trans->req_pay;
529 cmd->rsp.arg = (u32 *)trans->rsp_pay;
530 cmd_op = cmd->req.arg[0] & 0xff;
531 remainder = (trans->rsp_pay_size) % (bc_pay_sz);
532 num_frags = (trans->rsp_pay_size) / (bc_pay_sz);
533 if (remainder)
534 num_frags++;
535 cmd->req.num = trans->req_pay_size / 4;
536 cmd->rsp.num = trans->rsp_pay_size / 4;
537 hdr = trans->rsp_hdr;
538 }
539
540 trans->trans_id = seq;
541 trans->cmd_id = cmd_op;
542 for (i = 0; i < num_frags; i++) {
543 hdr[i].version = 2;
544 hdr[i].msg_type = msg_type;
545 hdr[i].op_type = cmd->op_type;
546 hdr[i].num_cmds = 1;
547 hdr[i].num_frags = num_frags;
548 hdr[i].frag_num = i + 1;
549 hdr[i].cmd_op = cmd_op;
550 hdr[i].seq_id = seq;
551 }
552 return 0;
553}
554
555static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *trans)
556{
557 if (!trans)
558 return;
559 kfree(trans->req_hdr);
560 kfree(trans->rsp_hdr);
561 kfree(trans);
562}
563
564static int qlcnic_sriov_clear_trans(struct qlcnic_vf_info *vf,
565 struct qlcnic_bc_trans *trans, u8 type)
566{
567 struct qlcnic_trans_list *t_list;
568 unsigned long flags;
569 int ret = 0;
570
571 if (type == QLC_BC_RESPONSE) {
572 t_list = &vf->rcv_act;
573 spin_lock_irqsave(&t_list->lock, flags);
574 t_list->count--;
575 list_del(&trans->list);
576 if (t_list->count > 0)
577 ret = 1;
578 spin_unlock_irqrestore(&t_list->lock, flags);
579 }
580 if (type == QLC_BC_COMMAND) {
581 while (test_and_set_bit(QLC_BC_VF_SEND, &vf->state))
582 msleep(100);
583 vf->send_cmd = NULL;
584 clear_bit(QLC_BC_VF_SEND, &vf->state);
585 }
586 return ret;
587}
588
589static void qlcnic_sriov_schedule_bc_cmd(struct qlcnic_sriov *sriov,
590 struct qlcnic_vf_info *vf,
591 work_func_t func)
592{
593 INIT_WORK(&vf->trans_work, func);
594 queue_work(sriov->bc.bc_trans_wq, &vf->trans_work);
595}
596
597static inline void qlcnic_sriov_wait_for_resp(struct qlcnic_bc_trans *trans)
598{
599 struct completion *cmpl = &trans->resp_cmpl;
600
601 if (wait_for_completion_timeout(cmpl, QLC_MBOX_RESP_TIMEOUT))
602 trans->trans_state = QLC_END;
603 else
604 trans->trans_state = QLC_ABORT;
605
606 return;
607}
608
609static void qlcnic_sriov_handle_multi_frags(struct qlcnic_bc_trans *trans,
610 u8 type)
611{
612 if (type == QLC_BC_RESPONSE) {
613 trans->curr_rsp_frag++;
614 if (trans->curr_rsp_frag < trans->rsp_hdr->num_frags)
615 trans->trans_state = QLC_INIT;
616 else
617 trans->trans_state = QLC_END;
618 } else {
619 trans->curr_req_frag++;
620 if (trans->curr_req_frag < trans->req_hdr->num_frags)
621 trans->trans_state = QLC_INIT;
622 else
623 trans->trans_state = QLC_WAIT_FOR_RESP;
624 }
625}
626
627static void qlcnic_sriov_wait_for_channel_free(struct qlcnic_bc_trans *trans,
628 u8 type)
629{
630 struct qlcnic_vf_info *vf = trans->vf;
631 struct completion *cmpl = &vf->ch_free_cmpl;
632
633 if (!wait_for_completion_timeout(cmpl, QLC_MBOX_CH_FREE_TIMEOUT)) {
634 trans->trans_state = QLC_ABORT;
635 return;
636 }
637
638 clear_bit(QLC_BC_VF_CHANNEL, &vf->state);
639 qlcnic_sriov_handle_multi_frags(trans, type);
640}
641
642static void qlcnic_sriov_pull_bc_msg(struct qlcnic_adapter *adapter,
643 u32 *hdr, u32 *pay, u32 size)
644{
645 struct qlcnic_hardware_context *ahw = adapter->ahw;
646 u32 fw_mbx;
647 u8 i, max = 2, hdr_size, j;
648
649 hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
650 max = (size / sizeof(u32)) + hdr_size;
651
652 fw_mbx = readl(QLCNIC_MBX_FW(ahw, 0));
653 for (i = 2, j = 0; j < hdr_size; i++, j++)
654 *(hdr++) = readl(QLCNIC_MBX_FW(ahw, i));
655 for (; j < max; i++, j++)
656 *(pay++) = readl(QLCNIC_MBX_FW(ahw, i));
657}
658
659static int __qlcnic_sriov_issue_bc_post(struct qlcnic_vf_info *vf)
660{
661 int ret = -EBUSY;
662 u32 timeout = 10000;
663
664 do {
665 if (!test_and_set_bit(QLC_BC_VF_CHANNEL, &vf->state)) {
666 ret = 0;
667 break;
668 }
669 mdelay(1);
670 } while (--timeout);
671
672 return ret;
673}
674
675static int qlcnic_sriov_issue_bc_post(struct qlcnic_bc_trans *trans, u8 type)
676{
677 struct qlcnic_vf_info *vf = trans->vf;
678 u32 pay_size, hdr_size;
679 u32 *hdr, *pay;
680 int ret;
681 u8 pci_func = trans->func_id;
682
683 if (__qlcnic_sriov_issue_bc_post(vf))
684 return -EBUSY;
685
686 if (type == QLC_BC_COMMAND) {
687 hdr = (u32 *)(trans->req_hdr + trans->curr_req_frag);
688 pay = (u32 *)(trans->req_pay + trans->curr_req_frag);
689 hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
690 pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
691 trans->curr_req_frag);
692 pay_size = (pay_size / sizeof(u32));
693 } else {
694 hdr = (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag);
695 pay = (u32 *)(trans->rsp_pay + trans->curr_rsp_frag);
696 hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
697 pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size,
698 trans->curr_rsp_frag);
699 pay_size = (pay_size / sizeof(u32));
700 }
701
702 ret = qlcnic_sriov_post_bc_msg(vf->adapter, hdr, pay,
703 pci_func, pay_size);
704 return ret;
705}
706
707static int __qlcnic_sriov_send_bc_msg(struct qlcnic_bc_trans *trans,
708 struct qlcnic_vf_info *vf, u8 type)
709{
710 int err;
711 bool flag = true;
712
713 while (flag) {
714 switch (trans->trans_state) {
715 case QLC_INIT:
716 trans->trans_state = QLC_WAIT_FOR_CHANNEL_FREE;
717 if (qlcnic_sriov_issue_bc_post(trans, type))
718 trans->trans_state = QLC_ABORT;
719 break;
720 case QLC_WAIT_FOR_CHANNEL_FREE:
721 qlcnic_sriov_wait_for_channel_free(trans, type);
722 break;
723 case QLC_WAIT_FOR_RESP:
724 qlcnic_sriov_wait_for_resp(trans);
725 break;
726 case QLC_END:
727 err = 0;
728 flag = false;
729 break;
730 case QLC_ABORT:
731 err = -EIO;
732 flag = false;
733 clear_bit(QLC_BC_VF_CHANNEL, &vf->state);
734 break;
735 default:
736 err = -EIO;
737 flag = false;
738 }
739 }
740 return err;
741}
742
743static int qlcnic_sriov_send_bc_cmd(struct qlcnic_adapter *adapter,
744 struct qlcnic_bc_trans *trans, int pci_func)
745{
746 struct qlcnic_vf_info *vf;
747 int err, index = qlcnic_sriov_func_to_index(adapter, pci_func);
748
749 if (index < 0)
750 return -EIO;
751
752 vf = &adapter->ahw->sriov->vf_info[index];
753 trans->vf = vf;
754 trans->func_id = pci_func;
755
756 if (!test_bit(QLC_BC_VF_STATE, &vf->state)) {
757 if (qlcnic_sriov_pf_check(adapter))
758 return -EIO;
759 if (qlcnic_sriov_vf_check(adapter) &&
760 trans->cmd_id != QLCNIC_BC_CMD_CHANNEL_INIT)
761 return -EIO;
762 }
763
764 mutex_lock(&vf->send_cmd_lock);
765 vf->send_cmd = trans;
766 err = __qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_COMMAND);
767 qlcnic_sriov_clear_trans(vf, trans, QLC_BC_COMMAND);
768 mutex_unlock(&vf->send_cmd_lock);
769 return err;
770}
771
772static void __qlcnic_sriov_process_bc_cmd(struct qlcnic_adapter *adapter,
773 struct qlcnic_bc_trans *trans,
774 struct qlcnic_cmd_args *cmd)
775{
776#ifdef CONFIG_QLCNIC_SRIOV
777 if (qlcnic_sriov_pf_check(adapter)) {
778 qlcnic_sriov_pf_process_bc_cmd(adapter, trans, cmd);
779 return;
780 }
781#endif
782 cmd->rsp.arg[0] |= (0x9 << 25);
783 return;
784}
785
786static void qlcnic_sriov_process_bc_cmd(struct work_struct *work)
787{
788 struct qlcnic_vf_info *vf = container_of(work, struct qlcnic_vf_info,
789 trans_work);
790 struct qlcnic_bc_trans *trans = NULL;
791 struct qlcnic_adapter *adapter = vf->adapter;
792 struct qlcnic_cmd_args cmd;
793 u8 req;
794
795 trans = list_first_entry(&vf->rcv_act.wait_list,
796 struct qlcnic_bc_trans, list);
797 adapter = vf->adapter;
798
799 if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, trans->req_hdr->seq_id,
800 QLC_BC_RESPONSE))
801 goto cleanup_trans;
802
803 __qlcnic_sriov_process_bc_cmd(adapter, trans, &cmd);
804 trans->trans_state = QLC_INIT;
805 __qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_RESPONSE);
806
807cleanup_trans:
808 qlcnic_free_mbx_args(&cmd);
809 req = qlcnic_sriov_clear_trans(vf, trans, QLC_BC_RESPONSE);
810 qlcnic_sriov_cleanup_transaction(trans);
811 if (req)
812 qlcnic_sriov_schedule_bc_cmd(adapter->ahw->sriov, vf,
813 qlcnic_sriov_process_bc_cmd);
814}
815
816static void qlcnic_sriov_handle_bc_resp(struct qlcnic_bc_hdr *hdr,
817 struct qlcnic_vf_info *vf)
818{
819 struct qlcnic_bc_trans *trans;
820 u32 pay_size;
821
822 if (test_and_set_bit(QLC_BC_VF_SEND, &vf->state))
823 return;
824
825 trans = vf->send_cmd;
826
827 if (trans == NULL)
828 goto clear_send;
829
830 if (trans->trans_id != hdr->seq_id)
831 goto clear_send;
832
833 pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size,
834 trans->curr_rsp_frag);
835 qlcnic_sriov_pull_bc_msg(vf->adapter,
836 (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag),
837 (u32 *)(trans->rsp_pay + trans->curr_rsp_frag),
838 pay_size);
839 if (++trans->curr_rsp_frag < trans->rsp_hdr->num_frags)
840 goto clear_send;
841
842 complete(&trans->resp_cmpl);
843
844clear_send:
845 clear_bit(QLC_BC_VF_SEND, &vf->state);
846}
847
848static int qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov,
849 struct qlcnic_vf_info *vf,
850 struct qlcnic_bc_trans *trans)
851{
852 struct qlcnic_trans_list *t_list = &vf->rcv_act;
853
854 spin_lock(&t_list->lock);
855 t_list->count++;
856 list_add_tail(&trans->list, &t_list->wait_list);
857 if (t_list->count == 1)
858 qlcnic_sriov_schedule_bc_cmd(sriov, vf,
859 qlcnic_sriov_process_bc_cmd);
860 spin_unlock(&t_list->lock);
861 return 0;
862}
863
864static void qlcnic_sriov_handle_pending_trans(struct qlcnic_sriov *sriov,
865 struct qlcnic_vf_info *vf,
866 struct qlcnic_bc_hdr *hdr)
867{
868 struct qlcnic_bc_trans *trans = NULL;
869 struct list_head *node;
870 u32 pay_size, curr_frag;
871 u8 found = 0, active = 0;
872
873 spin_lock(&vf->rcv_pend.lock);
874 if (vf->rcv_pend.count > 0) {
875 list_for_each(node, &vf->rcv_pend.wait_list) {
876 trans = list_entry(node, struct qlcnic_bc_trans, list);
877 if (trans->trans_id == hdr->seq_id) {
878 found = 1;
879 break;
880 }
881 }
882 }
883
884 if (found) {
885 curr_frag = trans->curr_req_frag;
886 pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
887 curr_frag);
888 qlcnic_sriov_pull_bc_msg(vf->adapter,
889 (u32 *)(trans->req_hdr + curr_frag),
890 (u32 *)(trans->req_pay + curr_frag),
891 pay_size);
892 trans->curr_req_frag++;
893 if (trans->curr_req_frag >= hdr->num_frags) {
894 vf->rcv_pend.count--;
895 list_del(&trans->list);
896 active = 1;
897 }
898 }
899 spin_unlock(&vf->rcv_pend.lock);
900
901 if (active)
902 if (qlcnic_sriov_add_act_list(sriov, vf, trans))
903 qlcnic_sriov_cleanup_transaction(trans);
904
905 return;
906}
907
908static void qlcnic_sriov_handle_bc_cmd(struct qlcnic_sriov *sriov,
909 struct qlcnic_bc_hdr *hdr,
910 struct qlcnic_vf_info *vf)
911{
912 struct qlcnic_bc_trans *trans;
913 struct qlcnic_adapter *adapter = vf->adapter;
914 struct qlcnic_cmd_args cmd;
915 u32 pay_size;
916 int err;
917 u8 cmd_op;
918
919 if (!test_bit(QLC_BC_VF_STATE, &vf->state) &&
920 hdr->op_type != QLC_BC_CMD &&
921 hdr->cmd_op != QLCNIC_BC_CMD_CHANNEL_INIT)
922 return;
923
924 if (hdr->frag_num > 1) {
925 qlcnic_sriov_handle_pending_trans(sriov, vf, hdr);
926 return;
927 }
928
929 cmd_op = hdr->cmd_op;
930 if (qlcnic_sriov_alloc_bc_trans(&trans))
931 return;
932
933 if (hdr->op_type == QLC_BC_CMD)
934 err = qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op);
935 else
936 err = qlcnic_alloc_mbx_args(&cmd, adapter, cmd_op);
937
938 if (err) {
939 qlcnic_sriov_cleanup_transaction(trans);
940 return;
941 }
942
943 cmd.op_type = hdr->op_type;
944 if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, hdr->seq_id,
945 QLC_BC_COMMAND)) {
946 qlcnic_free_mbx_args(&cmd);
947 qlcnic_sriov_cleanup_transaction(trans);
948 return;
949 }
950
951 pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
952 trans->curr_req_frag);
953 qlcnic_sriov_pull_bc_msg(vf->adapter,
954 (u32 *)(trans->req_hdr + trans->curr_req_frag),
955 (u32 *)(trans->req_pay + trans->curr_req_frag),
956 pay_size);
957 trans->func_id = vf->pci_func;
958 trans->vf = vf;
959 trans->trans_id = hdr->seq_id;
960 trans->curr_req_frag++;
961 if (trans->curr_req_frag == trans->req_hdr->num_frags) {
962 if (qlcnic_sriov_add_act_list(sriov, vf, trans)) {
963 qlcnic_free_mbx_args(&cmd);
964 qlcnic_sriov_cleanup_transaction(trans);
965 }
966 } else {
967 spin_lock(&vf->rcv_pend.lock);
968 list_add_tail(&trans->list, &vf->rcv_pend.wait_list);
969 vf->rcv_pend.count++;
970 spin_unlock(&vf->rcv_pend.lock);
971 }
972}
973
974static void qlcnic_sriov_handle_msg_event(struct qlcnic_sriov *sriov,
975 struct qlcnic_vf_info *vf)
976{
977 struct qlcnic_bc_hdr hdr;
978 u32 *ptr = (u32 *)&hdr;
979 u8 msg_type, i;
980
981 for (i = 2; i < 6; i++)
982 ptr[i - 2] = readl(QLCNIC_MBX_FW(vf->adapter->ahw, i));
983 msg_type = hdr.msg_type;
984
985 switch (msg_type) {
986 case QLC_BC_COMMAND:
987 qlcnic_sriov_handle_bc_cmd(sriov, &hdr, vf);
988 break;
989 case QLC_BC_RESPONSE:
990 qlcnic_sriov_handle_bc_resp(&hdr, vf);
991 break;
992 }
993}
994
995void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *adapter, u32 event)
996{
997 struct qlcnic_vf_info *vf;
998 struct qlcnic_sriov *sriov;
999 int index;
1000 u8 pci_func;
1001
1002 sriov = adapter->ahw->sriov;
1003 pci_func = qlcnic_sriov_target_func_id(event);
1004 index = qlcnic_sriov_func_to_index(adapter, pci_func);
1005
1006 if (index < 0)
1007 return;
1008
1009 vf = &sriov->vf_info[index];
1010 vf->pci_func = pci_func;
1011
1012 if (qlcnic_sriov_channel_free_check(event))
1013 complete(&vf->ch_free_cmpl);
1014
1015 if (qlcnic_sriov_bc_msg_check(event))
1016 qlcnic_sriov_handle_msg_event(sriov, vf);
1017}
1018
1019int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *adapter, u8 enable)
1020{
1021 struct qlcnic_cmd_args cmd;
1022 int err;
1023
1024 if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state))
1025 return 0;
1026
1027 if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_BC_EVENT_SETUP))
1028 return -ENOMEM;
1029
1030 if (enable)
1031 cmd.req.arg[1] = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7);
1032
1033 err = qlcnic_83xx_mbx_op(adapter, &cmd);
1034
1035 if (err != QLCNIC_RCODE_SUCCESS) {
1036 dev_err(&adapter->pdev->dev,
1037 "Failed to %s bc events, err=%d\n",
1038 (enable ? "enable" : "disable"), err);
1039 }
1040
1041 qlcnic_free_mbx_args(&cmd);
1042 return err;
1043}
1044
1045static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter,
1046 struct qlcnic_cmd_args *cmd)
1047{
1048 struct qlcnic_bc_trans *trans;
1049 int err;
1050 u32 rsp_data, opcode, mbx_err_code, rsp;
1051 u16 seq = ++adapter->ahw->sriov->bc.trans_counter;
1052
1053 if (qlcnic_sriov_alloc_bc_trans(&trans))
1054 return -ENOMEM;
1055
1056 if (qlcnic_sriov_prepare_bc_hdr(trans, cmd, seq, QLC_BC_COMMAND))
1057 return -ENOMEM;
1058
1059 if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
1060 rsp = -EIO;
1061 QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n",
1062 QLCNIC_MBX_RSP(cmd->req.arg[0]), adapter->ahw->pci_func);
1063 goto err_out;
1064 }
1065
1066 err = qlcnic_sriov_send_bc_cmd(adapter, trans, adapter->ahw->pci_func);
1067 if (err) {
1068 dev_err(&adapter->pdev->dev,
1069 "MBX command 0x%x timed out for VF %d\n",
1070 (cmd->req.arg[0] & 0xffff), adapter->ahw->pci_func);
1071 rsp = QLCNIC_RCODE_TIMEOUT;
1072 goto err_out;
1073 }
1074
1075 rsp_data = cmd->rsp.arg[0];
1076 mbx_err_code = QLCNIC_MBX_STATUS(rsp_data);
1077 opcode = QLCNIC_MBX_RSP(cmd->req.arg[0]);
1078
1079 if ((mbx_err_code == QLCNIC_MBX_RSP_OK) ||
1080 (mbx_err_code == QLCNIC_MBX_PORT_RSP_OK)) {
1081 rsp = QLCNIC_RCODE_SUCCESS;
1082 } else {
1083 rsp = mbx_err_code;
1084 if (!rsp)
1085 rsp = 1;
1086 dev_err(&adapter->pdev->dev,
1087 "MBX command 0x%x failed with err:0x%x for VF %d\n",
1088 opcode, mbx_err_code, adapter->ahw->pci_func);
1089 }
1090
1091err_out:
1092 qlcnic_sriov_cleanup_transaction(trans);
1093 return rsp;
1094}
1095
1096int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op)
1097{
1098 struct qlcnic_cmd_args cmd;
1099 struct qlcnic_vf_info *vf = &adapter->ahw->sriov->vf_info[0];
1100 int ret;
1101
1102 if (qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op))
1103 return -ENOMEM;
1104
1105 ret = qlcnic_issue_cmd(adapter, &cmd);
1106 if (ret) {
1107 dev_err(&adapter->pdev->dev,
1108 "Failed bc channel %s %d\n", cmd_op ? "term" : "init",
1109 ret);
1110 goto out;
1111 }
1112
1113 cmd_op = (cmd.rsp.arg[0] & 0xff);
1114 if (cmd.rsp.arg[0] >> 25 == 2)
1115 return 2;
1116 if (cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT)
1117 set_bit(QLC_BC_VF_STATE, &vf->state);
1118 else
1119 clear_bit(QLC_BC_VF_STATE, &vf->state);
1120
1121out:
1122 qlcnic_free_mbx_args(&cmd);
1123 return ret;
1124}