aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
authorManish Chopra <manish.chopra@qlogic.com>2013-08-02 00:57:40 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-02 02:04:27 -0400
commite5c4e6c696aea58fbea5758e8b2841d2b0309cf7 (patch)
tree7ca3ca10c3c0b1adbcfe2b223b2cdbb1494126b4 /drivers/net/ethernet
parentb9c119844c42a46a6c6006d158ee33af81fe76ae (diff)
qlcnic: Interrupt based driver firmware mailbox mechanism
o Driver firmware mailbox interface was operating in polling mode because of limitations with the earlier versions of 83xx adapter firmware. These issues are resolved and we are implementing interrupt based mailbox mechanism. o Data structures and API's for interrupt mode mailbox mechanism. Signed-off-by: Manish Chopra <manish.chopra@qlogic.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h48
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c314
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h25
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c18
5 files changed, 388 insertions, 21 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index aa0e68e1af73..5a49b64a93b4 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -20,7 +20,6 @@
20#include <linux/tcp.h> 20#include <linux/tcp.h>
21#include <linux/skbuff.h> 21#include <linux/skbuff.h>
22#include <linux/firmware.h> 22#include <linux/firmware.h>
23
24#include <linux/ethtool.h> 23#include <linux/ethtool.h>
25#include <linux/mii.h> 24#include <linux/mii.h>
26#include <linux/timer.h> 25#include <linux/timer.h>
@@ -468,6 +467,7 @@ struct qlcnic_hardware_context {
468 u32 mbox_aen[QLC_83XX_MBX_AEN_CNT]; 467 u32 mbox_aen[QLC_83XX_MBX_AEN_CNT];
469 u32 mbox_reg[4]; 468 u32 mbox_reg[4];
470 spinlock_t mbx_lock; 469 spinlock_t mbx_lock;
470 struct qlcnic_mailbox *mailbox;
471}; 471};
472 472
473struct qlcnic_adapter_stats { 473struct qlcnic_adapter_stats {
@@ -966,6 +966,21 @@ struct qlcnic_filter_hash {
966 u16 fbucket_size; 966 u16 fbucket_size;
967}; 967};
968 968
969/* Mailbox specific data structures */
970struct qlcnic_mailbox {
971 struct workqueue_struct *work_q;
972 struct qlcnic_adapter *adapter;
973 struct qlcnic_mbx_ops *ops;
974 struct work_struct work;
975 struct completion completion;
976 struct list_head cmd_q;
977 unsigned long status;
978 spinlock_t queue_lock; /* Mailbox queue lock */
979 spinlock_t aen_lock; /* Mailbox response/AEN lock */
980 atomic_t rsp_status;
981 u32 num_cmds;
982};
983
969struct qlcnic_adapter { 984struct qlcnic_adapter {
970 struct qlcnic_hardware_context *ahw; 985 struct qlcnic_hardware_context *ahw;
971 struct qlcnic_recv_context *recv_ctx; 986 struct qlcnic_recv_context *recv_ctx;
@@ -1379,9 +1394,20 @@ struct _cdrp_cmd {
1379}; 1394};
1380 1395
1381struct qlcnic_cmd_args { 1396struct qlcnic_cmd_args {
1382 struct _cdrp_cmd req; 1397 struct completion completion;
1383 struct _cdrp_cmd rsp; 1398 struct list_head list;
1384 int op_type; 1399 struct _cdrp_cmd req;
1400 struct _cdrp_cmd rsp;
1401 atomic_t rsp_status;
1402 int pay_size;
1403 u32 rsp_opcode;
1404 u32 total_cmds;
1405 u32 op_type;
1406 u32 type;
1407 u32 cmd_op;
1408 u32 *hdr; /* Back channel message header */
1409 u32 *pay; /* Back channel message payload */
1410 u8 func_num;
1385}; 1411};
1386 1412
1387int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter); 1413int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
@@ -1594,6 +1620,20 @@ struct qlcnic_nic_template {
1594 int (*resume)(struct qlcnic_adapter *); 1620 int (*resume)(struct qlcnic_adapter *);
1595}; 1621};
1596 1622
1623struct qlcnic_mbx_ops {
1624 int (*enqueue_cmd) (struct qlcnic_adapter *,
1625 struct qlcnic_cmd_args *, unsigned long *);
1626 void (*dequeue_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *);
1627 void (*decode_resp) (struct qlcnic_adapter *, struct qlcnic_cmd_args *);
1628 void (*encode_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *);
1629 void (*nofity_fw) (struct qlcnic_adapter *, u8);
1630};
1631
1632int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *);
1633void qlcnic_83xx_detach_mailbox_work(struct qlcnic_adapter *);
1634void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx);
1635void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx);
1636
1597/* Adapter hardware abstraction */ 1637/* Adapter hardware abstraction */
1598struct qlcnic_hardware_ops { 1638struct qlcnic_hardware_ops {
1599 void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t); 1639 void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index cda188d1dda5..74c8d84dc43d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -149,7 +149,7 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
149 .get_mac_address = qlcnic_83xx_get_mac_address, 149 .get_mac_address = qlcnic_83xx_get_mac_address,
150 .setup_intr = qlcnic_83xx_setup_intr, 150 .setup_intr = qlcnic_83xx_setup_intr,
151 .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args, 151 .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args,
152 .mbx_cmd = qlcnic_83xx_mbx_op, 152 .mbx_cmd = qlcnic_83xx_issue_cmd,
153 .get_func_no = qlcnic_83xx_get_func_no, 153 .get_func_no = qlcnic_83xx_get_func_no,
154 .api_lock = qlcnic_83xx_cam_lock, 154 .api_lock = qlcnic_83xx_cam_lock,
155 .api_unlock = qlcnic_83xx_cam_unlock, 155 .api_unlock = qlcnic_83xx_cam_unlock,
@@ -398,6 +398,12 @@ irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
398 return IRQ_HANDLED; 398 return IRQ_HANDLED;
399} 399}
400 400
401static inline void qlcnic_83xx_notify_mbx_response(struct qlcnic_mailbox *mbx)
402{
403 atomic_set(&mbx->rsp_status, QLC_83XX_MBX_RESPONSE_ARRIVED);
404 complete(&mbx->completion);
405}
406
401static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter) 407static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
402{ 408{
403 u32 resp, event; 409 u32 resp, event;
@@ -515,7 +521,7 @@ int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
515 } 521 }
516 522
517 /* Enable mailbox interrupt */ 523 /* Enable mailbox interrupt */
518 qlcnic_83xx_enable_mbx_intrpt(adapter); 524 qlcnic_83xx_enable_mbx_interrupt(adapter);
519 525
520 return err; 526 return err;
521} 527}
@@ -629,7 +635,7 @@ void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *adapter)
629 ahw->max_uc_count = count; 635 ahw->max_uc_count = count;
630} 636}
631 637
632void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *adapter) 638void qlcnic_83xx_enable_mbx_interrupt(struct qlcnic_adapter *adapter)
633{ 639{
634 u32 val; 640 u32 val;
635 641
@@ -737,8 +743,8 @@ u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter, u32 *wait_time)
737 return data; 743 return data;
738} 744}
739 745
740int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter, 746int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *adapter,
741 struct qlcnic_cmd_args *cmd) 747 struct qlcnic_cmd_args *cmd)
742{ 748{
743 int i; 749 int i;
744 u16 opcode; 750 u16 opcode;
@@ -829,6 +835,7 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
829 u32 temp; 835 u32 temp;
830 const struct qlcnic_mailbox_metadata *mbx_tbl; 836 const struct qlcnic_mailbox_metadata *mbx_tbl;
831 837
838 memset(mbx, 0, sizeof(struct qlcnic_cmd_args));
832 mbx_tbl = qlcnic_83xx_mbx_tbl; 839 mbx_tbl = qlcnic_83xx_mbx_tbl;
833 size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl); 840 size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl);
834 for (i = 0; i < size; i++) { 841 for (i = 0; i < size; i++) {
@@ -3455,3 +3462,300 @@ int qlcnic_83xx_resume(struct qlcnic_adapter *adapter)
3455 idc->delay); 3462 idc->delay);
3456 return err; 3463 return err;
3457} 3464}
3465
3466void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx)
3467{
3468 INIT_COMPLETION(mbx->completion);
3469 set_bit(QLC_83XX_MBX_READY, &mbx->status);
3470}
3471
3472void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx)
3473{
3474 destroy_workqueue(mbx->work_q);
3475 kfree(mbx);
3476}
3477
3478static inline void
3479qlcnic_83xx_notify_cmd_completion(struct qlcnic_adapter *adapter,
3480 struct qlcnic_cmd_args *cmd)
3481{
3482 atomic_set(&cmd->rsp_status, QLC_83XX_MBX_RESPONSE_ARRIVED);
3483
3484 if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT) {
3485 qlcnic_free_mbx_args(cmd);
3486 kfree(cmd);
3487 return;
3488 }
3489 complete(&cmd->completion);
3490}
3491
3492static inline void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter)
3493{
3494 struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
3495 struct list_head *head = &mbx->cmd_q;
3496 struct qlcnic_cmd_args *cmd = NULL;
3497
3498 spin_lock(&mbx->queue_lock);
3499
3500 while (!list_empty(head)) {
3501 cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
3502 list_del(&cmd->list);
3503 mbx->num_cmds--;
3504 qlcnic_83xx_notify_cmd_completion(adapter, cmd);
3505 }
3506
3507 spin_unlock(&mbx->queue_lock);
3508}
3509
3510static inline int qlcnic_83xx_check_mbx_status(struct qlcnic_adapter *adapter)
3511{
3512 struct qlcnic_hardware_context *ahw = adapter->ahw;
3513 struct qlcnic_mailbox *mbx = ahw->mailbox;
3514 u32 host_mbx_ctrl;
3515
3516 if (!test_bit(QLC_83XX_MBX_READY, &mbx->status))
3517 return -EBUSY;
3518
3519 host_mbx_ctrl = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
3520 if (host_mbx_ctrl) {
3521 ahw->idc.collect_dump = 1;
3522 return -EIO;
3523 }
3524
3525 return 0;
3526}
3527
3528static inline void qlcnic_83xx_signal_mbx_cmd(struct qlcnic_adapter *adapter,
3529 u8 issue_cmd)
3530{
3531 if (issue_cmd)
3532 QLCWRX(adapter->ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
3533 else
3534 QLCWRX(adapter->ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
3535}
3536
3537static inline void qlcnic_83xx_dequeue_mbx_cmd(struct qlcnic_adapter *adapter,
3538 struct qlcnic_cmd_args *cmd)
3539{
3540 struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
3541
3542 spin_lock(&mbx->queue_lock);
3543
3544 list_del(&cmd->list);
3545 mbx->num_cmds--;
3546
3547 spin_unlock(&mbx->queue_lock);
3548
3549 qlcnic_83xx_notify_cmd_completion(adapter, cmd);
3550}
3551
3552static void qlcnic_83xx_encode_mbx_cmd(struct qlcnic_adapter *adapter,
3553 struct qlcnic_cmd_args *cmd)
3554{
3555 u32 mbx_cmd, fw_hal_version, hdr_size, total_size, tmp;
3556 struct qlcnic_hardware_context *ahw = adapter->ahw;
3557 int i, j;
3558
3559 if (cmd->op_type != QLC_83XX_MBX_POST_BC_OP) {
3560 mbx_cmd = cmd->req.arg[0];
3561 writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
3562 for (i = 1; i < cmd->req.num; i++)
3563 writel(cmd->req.arg[i], QLCNIC_MBX_HOST(ahw, i));
3564 } else {
3565 fw_hal_version = ahw->fw_hal_version;
3566 hdr_size = sizeof(struct qlcnic_bc_hdr) / sizeof(u32);
3567 total_size = cmd->pay_size + hdr_size;
3568 tmp = QLCNIC_CMD_BC_EVENT_SETUP | total_size << 16;
3569 mbx_cmd = tmp | fw_hal_version << 29;
3570 writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
3571
3572 /* Back channel specific operations bits */
3573 mbx_cmd = 0x1 | 1 << 4;
3574
3575 if (qlcnic_sriov_pf_check(adapter))
3576 mbx_cmd |= cmd->func_num << 5;
3577
3578 writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 1));
3579
3580 for (i = 2, j = 0; j < hdr_size; i++, j++)
3581 writel(*(cmd->hdr++), QLCNIC_MBX_HOST(ahw, i));
3582 for (j = 0; j < cmd->pay_size; j++, i++)
3583 writel(*(cmd->pay++), QLCNIC_MBX_HOST(ahw, i));
3584 }
3585}
3586
3587void qlcnic_83xx_detach_mailbox_work(struct qlcnic_adapter *adapter)
3588{
3589 struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
3590
3591 clear_bit(QLC_83XX_MBX_READY, &mbx->status);
3592 complete(&mbx->completion);
3593 cancel_work_sync(&mbx->work);
3594 flush_workqueue(mbx->work_q);
3595 qlcnic_83xx_flush_mbx_queue(adapter);
3596}
3597
3598static inline int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter,
3599 struct qlcnic_cmd_args *cmd,
3600 unsigned long *timeout)
3601{
3602 struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
3603
3604 if (test_bit(QLC_83XX_MBX_READY, &mbx->status)) {
3605 atomic_set(&cmd->rsp_status, QLC_83XX_MBX_RESPONSE_WAIT);
3606 init_completion(&cmd->completion);
3607 cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_UNKNOWN;
3608
3609 spin_lock(&mbx->queue_lock);
3610
3611 list_add_tail(&cmd->list, &mbx->cmd_q);
3612 mbx->num_cmds++;
3613 cmd->total_cmds = mbx->num_cmds;
3614 *timeout = cmd->total_cmds * QLC_83XX_MBX_TIMEOUT;
3615 queue_work(mbx->work_q, &mbx->work);
3616
3617 spin_unlock(&mbx->queue_lock);
3618
3619 return 0;
3620 }
3621
3622 return -EBUSY;
3623}
3624
3625static inline int qlcnic_83xx_check_mac_rcode(struct qlcnic_adapter *adapter,
3626 struct qlcnic_cmd_args *cmd)
3627{
3628 u8 mac_cmd_rcode;
3629 u32 fw_data;
3630
3631 if (cmd->cmd_op == QLCNIC_CMD_CONFIG_MAC_VLAN) {
3632 fw_data = readl(QLCNIC_MBX_FW(adapter->ahw, 2));
3633 mac_cmd_rcode = (u8)fw_data;
3634 if (mac_cmd_rcode == QLC_83XX_NO_NIC_RESOURCE ||
3635 mac_cmd_rcode == QLC_83XX_MAC_PRESENT ||
3636 mac_cmd_rcode == QLC_83XX_MAC_ABSENT) {
3637 cmd->rsp_opcode = QLCNIC_RCODE_SUCCESS;
3638 return QLCNIC_RCODE_SUCCESS;
3639 }
3640 }
3641
3642 return -EINVAL;
3643}
3644
3645static void qlcnic_83xx_decode_mbx_rsp(struct qlcnic_adapter *adapter,
3646 struct qlcnic_cmd_args *cmd)
3647{
3648 struct qlcnic_hardware_context *ahw = adapter->ahw;
3649 struct device *dev = &adapter->pdev->dev;
3650 u8 mbx_err_code;
3651 u32 fw_data;
3652
3653 fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
3654 mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
3655 qlcnic_83xx_get_mbx_data(adapter, cmd);
3656
3657 switch (mbx_err_code) {
3658 case QLCNIC_MBX_RSP_OK:
3659 case QLCNIC_MBX_PORT_RSP_OK:
3660 cmd->rsp_opcode = QLCNIC_RCODE_SUCCESS;
3661 break;
3662 default:
3663 if (!qlcnic_83xx_check_mac_rcode(adapter, cmd))
3664 break;
3665
3666 dev_err(dev, "%s: Mailbox command failed, opcode=0x%x, cmd_type=0x%x, func=0x%x, op_mode=0x%x, error=0x%x\n",
3667 __func__, cmd->cmd_op, cmd->type, ahw->pci_func,
3668 ahw->op_mode, mbx_err_code);
3669 cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_FAILED;
3670 qlcnic_dump_mbx(adapter, cmd);
3671 }
3672
3673 return;
3674}
3675
3676static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
3677{
3678 struct qlcnic_mailbox *mbx = container_of(work, struct qlcnic_mailbox,
3679 work);
3680 struct qlcnic_adapter *adapter = mbx->adapter;
3681 struct qlcnic_mbx_ops *mbx_ops = mbx->ops;
3682 struct device *dev = &adapter->pdev->dev;
3683 atomic_t *rsp_status = &mbx->rsp_status;
3684 struct list_head *head = &mbx->cmd_q;
3685 struct qlcnic_hardware_context *ahw;
3686 struct qlcnic_cmd_args *cmd = NULL;
3687
3688 ahw = adapter->ahw;
3689
3690 while (true) {
3691 if (qlcnic_83xx_check_mbx_status(adapter))
3692 return;
3693
3694 atomic_set(rsp_status, QLC_83XX_MBX_RESPONSE_WAIT);
3695
3696 spin_lock(&mbx->queue_lock);
3697
3698 if (list_empty(head)) {
3699 spin_unlock(&mbx->queue_lock);
3700 return;
3701 }
3702 cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
3703
3704 spin_unlock(&mbx->queue_lock);
3705
3706 mbx_ops->encode_cmd(adapter, cmd);
3707 mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_REQUEST);
3708
3709 if (wait_for_completion_timeout(&mbx->completion,
3710 QLC_83XX_MBX_TIMEOUT)) {
3711 mbx_ops->decode_resp(adapter, cmd);
3712 mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_COMPLETION);
3713 } else {
3714 dev_err(dev, "%s: Mailbox command timeout, opcode=0x%x, cmd_type=0x%x, func=0x%x, op_mode=0x%x\n",
3715 __func__, cmd->cmd_op, cmd->type, ahw->pci_func,
3716 ahw->op_mode);
3717 clear_bit(QLC_83XX_MBX_READY, &mbx->status);
3718 qlcnic_83xx_idc_request_reset(adapter,
3719 QLCNIC_FORCE_FW_DUMP_KEY);
3720 cmd->rsp_opcode = QLCNIC_RCODE_TIMEOUT;
3721 }
3722 mbx_ops->dequeue_cmd(adapter, cmd);
3723 }
3724}
3725
3726static struct qlcnic_mbx_ops qlcnic_83xx_mbx_ops = {
3727 .enqueue_cmd = qlcnic_83xx_enqueue_mbx_cmd,
3728 .dequeue_cmd = qlcnic_83xx_dequeue_mbx_cmd,
3729 .decode_resp = qlcnic_83xx_decode_mbx_rsp,
3730 .encode_cmd = qlcnic_83xx_encode_mbx_cmd,
3731 .nofity_fw = qlcnic_83xx_signal_mbx_cmd,
3732};
3733
3734int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *adapter)
3735{
3736 struct qlcnic_hardware_context *ahw = adapter->ahw;
3737 struct qlcnic_mailbox *mbx;
3738
3739 ahw->mailbox = kzalloc(sizeof(*mbx), GFP_KERNEL);
3740 if (!ahw->mailbox)
3741 return -ENOMEM;
3742
3743 mbx = ahw->mailbox;
3744 mbx->ops = &qlcnic_83xx_mbx_ops;
3745 mbx->adapter = adapter;
3746
3747 spin_lock_init(&mbx->queue_lock);
3748 spin_lock_init(&mbx->aen_lock);
3749 INIT_LIST_HEAD(&mbx->cmd_q);
3750 init_completion(&mbx->completion);
3751
3752 mbx->work_q = create_singlethread_workqueue("qlcnic_mailbox");
3753 if (mbx->work_q == NULL) {
3754 kfree(mbx);
3755 return -ENOMEM;
3756 }
3757
3758 INIT_WORK(&mbx->work, qlcnic_83xx_mailbox_worker);
3759 set_bit(QLC_83XX_MBX_READY, &mbx->status);
3760 return 0;
3761}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index 2548d1403d75..542b58d4d2cc 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -89,6 +89,13 @@
89 89
90#define QLC_83XX_MAX_RESET_SEQ_ENTRIES 16 90#define QLC_83XX_MAX_RESET_SEQ_ENTRIES 16
91 91
92#define QLC_83XX_MBX_POST_BC_OP 0x1
93#define QLC_83XX_MBX_COMPLETION 0x0
94#define QLC_83XX_MBX_REQUEST 0x1
95
96#define QLC_83XX_MBX_TIMEOUT (5 * HZ)
97#define QLC_83XX_MBX_CMD_LOOP 5000000
98
92/* status descriptor mailbox data 99/* status descriptor mailbox data
93 * @phy_addr_{low|high}: physical address of buffer 100 * @phy_addr_{low|high}: physical address of buffer
94 * @sds_ring_size: buffer size 101 * @sds_ring_size: buffer size
@@ -449,6 +456,20 @@ enum qlcnic_83xx_states {
449#define QLC_83xx_FLASH_MAX_WAIT_USEC 100 456#define QLC_83xx_FLASH_MAX_WAIT_USEC 100
450#define QLC_83XX_FLASH_LOCK_TIMEOUT 10000 457#define QLC_83XX_FLASH_LOCK_TIMEOUT 10000
451 458
459enum qlc_83xx_mbx_cmd_type {
460 QLC_83XX_MBX_CMD_WAIT = 0,
461 QLC_83XX_MBX_CMD_NO_WAIT,
462 QLC_83XX_MBX_CMD_BUSY_WAIT,
463};
464
465enum qlc_83xx_mbx_response_states {
466 QLC_83XX_MBX_RESPONSE_WAIT = 0,
467 QLC_83XX_MBX_RESPONSE_ARRIVED,
468};
469
470#define QLC_83XX_MBX_RESPONSE_FAILED 0x2
471#define QLC_83XX_MBX_RESPONSE_UNKNOWN 0x3
472
452/* Additional registers in 83xx */ 473/* Additional registers in 83xx */
453enum qlc_83xx_ext_regs { 474enum qlc_83xx_ext_regs {
454 QLCNIC_GLOBAL_RESET = 0, 475 QLCNIC_GLOBAL_RESET = 0,
@@ -498,7 +519,7 @@ enum qlc_83xx_ext_regs {
498 519
499/* 83xx funcitons */ 520/* 83xx funcitons */
500int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *); 521int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *);
501int qlcnic_83xx_mbx_op(struct qlcnic_adapter *, struct qlcnic_cmd_args *); 522int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *, struct qlcnic_cmd_args *);
502int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8); 523int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8);
503void qlcnic_83xx_get_func_no(struct qlcnic_adapter *); 524void qlcnic_83xx_get_func_no(struct qlcnic_adapter *);
504int qlcnic_83xx_cam_lock(struct qlcnic_adapter *); 525int qlcnic_83xx_cam_lock(struct qlcnic_adapter *);
@@ -551,7 +572,7 @@ void qlcnic_set_npar_data(struct qlcnic_adapter *, const struct qlcnic_info *,
551void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *); 572void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *);
552irqreturn_t qlcnic_83xx_handle_aen(int, void *); 573irqreturn_t qlcnic_83xx_handle_aen(int, void *);
553int qlcnic_83xx_get_port_info(struct qlcnic_adapter *); 574int qlcnic_83xx_get_port_info(struct qlcnic_adapter *);
554void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *); 575void qlcnic_83xx_enable_mbx_interrupt(struct qlcnic_adapter *);
555void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *); 576void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *);
556irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *); 577irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *);
557irqreturn_t qlcnic_83xx_intr(int, void *); 578irqreturn_t qlcnic_83xx_intr(int, void *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index f41dfab1e9a3..0c5110c74311 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -617,7 +617,7 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
617 if (err) 617 if (err)
618 return err; 618 return err;
619 619
620 qlcnic_83xx_enable_mbx_intrpt(adapter); 620 qlcnic_83xx_enable_mbx_interrupt(adapter);
621 621
622 if (qlcnic_83xx_configure_opmode(adapter)) { 622 if (qlcnic_83xx_configure_opmode(adapter)) {
623 qlcnic_83xx_idc_enter_failed_state(adapter, 1); 623 qlcnic_83xx_idc_enter_failed_state(adapter, 1);
@@ -2120,7 +2120,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
2120 /* Initilaize 83xx mailbox spinlock */ 2120 /* Initilaize 83xx mailbox spinlock */
2121 spin_lock_init(&ahw->mbx_lock); 2121 spin_lock_init(&ahw->mbx_lock);
2122 2122
2123 set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status); 2123 set_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
2124 qlcnic_83xx_clear_function_resources(adapter); 2124 qlcnic_83xx_clear_function_resources(adapter);
2125 2125
2126 /* register for NIC IDC AEN Events */ 2126 /* register for NIC IDC AEN Events */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 62380ce89905..d9c6ae5e0d3b 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -33,7 +33,7 @@ static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *, u32);
33static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *); 33static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *);
34static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *); 34static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *);
35static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *); 35static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *);
36static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *, 36static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *,
37 struct qlcnic_cmd_args *); 37 struct qlcnic_cmd_args *);
38static void qlcnic_sriov_process_bc_cmd(struct work_struct *); 38static void qlcnic_sriov_process_bc_cmd(struct work_struct *);
39 39
@@ -45,7 +45,7 @@ static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {
45 .get_mac_address = qlcnic_83xx_get_mac_address, 45 .get_mac_address = qlcnic_83xx_get_mac_address,
46 .setup_intr = qlcnic_83xx_setup_intr, 46 .setup_intr = qlcnic_83xx_setup_intr,
47 .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args, 47 .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args,
48 .mbx_cmd = qlcnic_sriov_vf_mbx_op, 48 .mbx_cmd = qlcnic_sriov_issue_cmd,
49 .get_func_no = qlcnic_83xx_get_func_no, 49 .get_func_no = qlcnic_83xx_get_func_no,
50 .api_lock = qlcnic_83xx_cam_lock, 50 .api_lock = qlcnic_83xx_cam_lock,
51 .api_unlock = qlcnic_83xx_cam_unlock, 51 .api_unlock = qlcnic_83xx_cam_unlock,
@@ -295,7 +295,7 @@ static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr,
295 295
296 opcode = ((struct qlcnic_bc_hdr *)hdr)->cmd_op; 296 opcode = ((struct qlcnic_bc_hdr *)hdr)->cmd_op;
297 297
298 if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) { 298 if (!test_bit(QLC_83XX_MBX_READY, &ahw->idc.status)) {
299 dev_info(&adapter->pdev->dev, 299 dev_info(&adapter->pdev->dev,
300 "Mailbox cmd attempted, 0x%x\n", opcode); 300 "Mailbox cmd attempted, 0x%x\n", opcode);
301 dev_info(&adapter->pdev->dev, "Mailbox detached\n"); 301 dev_info(&adapter->pdev->dev, "Mailbox detached\n");
@@ -1083,6 +1083,7 @@ static void qlcnic_sriov_process_bc_cmd(struct work_struct *work)
1083 if (test_bit(QLC_BC_VF_FLR, &vf->state)) 1083 if (test_bit(QLC_BC_VF_FLR, &vf->state))
1084 return; 1084 return;
1085 1085
1086 memset(&cmd, 0, sizeof(struct qlcnic_cmd_args));
1086 trans = list_first_entry(&vf->rcv_act.wait_list, 1087 trans = list_first_entry(&vf->rcv_act.wait_list,
1087 struct qlcnic_bc_trans, list); 1088 struct qlcnic_bc_trans, list);
1088 adapter = vf->adapter; 1089 adapter = vf->adapter;
@@ -1232,6 +1233,7 @@ static void qlcnic_sriov_handle_bc_cmd(struct qlcnic_sriov *sriov,
1232 return; 1233 return;
1233 } 1234 }
1234 1235
1236 memset(&cmd, 0, sizeof(struct qlcnic_cmd_args));
1235 cmd_op = hdr->cmd_op; 1237 cmd_op = hdr->cmd_op;
1236 if (qlcnic_sriov_alloc_bc_trans(&trans)) 1238 if (qlcnic_sriov_alloc_bc_trans(&trans))
1237 return; 1239 return;
@@ -1357,7 +1359,7 @@ int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *adapter, u8 enable)
1357 if (enable) 1359 if (enable)
1358 cmd.req.arg[1] = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7); 1360 cmd.req.arg[1] = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7);
1359 1361
1360 err = qlcnic_83xx_mbx_op(adapter, &cmd); 1362 err = qlcnic_83xx_issue_cmd(adapter, &cmd);
1361 1363
1362 if (err != QLCNIC_RCODE_SUCCESS) { 1364 if (err != QLCNIC_RCODE_SUCCESS) {
1363 dev_err(&adapter->pdev->dev, 1365 dev_err(&adapter->pdev->dev,
@@ -1389,7 +1391,7 @@ static int qlcnic_sriov_retry_bc_cmd(struct qlcnic_adapter *adapter,
1389 return -EIO; 1391 return -EIO;
1390} 1392}
1391 1393
1392static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter, 1394static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,
1393 struct qlcnic_cmd_args *cmd) 1395 struct qlcnic_cmd_args *cmd)
1394{ 1396{
1395 struct qlcnic_hardware_context *ahw = adapter->ahw; 1397 struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -1409,7 +1411,7 @@ static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter,
1409 goto cleanup_transaction; 1411 goto cleanup_transaction;
1410 1412
1411retry: 1413retry:
1412 if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) { 1414 if (!test_bit(QLC_83XX_MBX_READY, &ahw->idc.status)) {
1413 rsp = -EIO; 1415 rsp = -EIO;
1414 QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n", 1416 QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n",
1415 QLCNIC_MBX_RSP(cmd->req.arg[0]), func); 1417 QLCNIC_MBX_RSP(cmd->req.arg[0]), func);
@@ -1612,7 +1614,7 @@ static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter)
1612 int err; 1614 int err;
1613 1615
1614 set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status); 1616 set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
1615 qlcnic_83xx_enable_mbx_intrpt(adapter); 1617 qlcnic_83xx_enable_mbx_interrupt(adapter);
1616 1618
1617 err = qlcnic_sriov_cfg_bc_intr(adapter, 1); 1619 err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
1618 if (err) 1620 if (err)
@@ -1988,7 +1990,7 @@ int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter)
1988 int err; 1990 int err;
1989 1991
1990 set_bit(QLC_83XX_MODULE_LOADED, &idc->status); 1992 set_bit(QLC_83XX_MODULE_LOADED, &idc->status);
1991 qlcnic_83xx_enable_mbx_intrpt(adapter); 1993 qlcnic_83xx_enable_mbx_interrupt(adapter);
1992 err = qlcnic_sriov_cfg_bc_intr(adapter, 1); 1994 err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
1993 if (err) 1995 if (err)
1994 return err; 1996 return err;