diff options
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c')
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 743 |
1 files changed, 572 insertions, 171 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 9d4bb7f83904..a1818dae47b6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/ipv6.h> | 11 | #include <linux/ipv6.h> |
12 | #include <linux/ethtool.h> | 12 | #include <linux/ethtool.h> |
13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
14 | #include <linux/aer.h> | ||
14 | 15 | ||
15 | #define QLCNIC_MAX_TX_QUEUES 1 | 16 | #define QLCNIC_MAX_TX_QUEUES 1 |
16 | #define RSS_HASHTYPE_IP_TCP 0x3 | 17 | #define RSS_HASHTYPE_IP_TCP 0x3 |
@@ -67,6 +68,8 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { | |||
67 | {QLCNIC_CMD_ADD_RCV_RINGS, 130, 26}, | 68 | {QLCNIC_CMD_ADD_RCV_RINGS, 130, 26}, |
68 | {QLCNIC_CMD_CONFIG_VPORT, 4, 4}, | 69 | {QLCNIC_CMD_CONFIG_VPORT, 4, 4}, |
69 | {QLCNIC_CMD_BC_EVENT_SETUP, 2, 1}, | 70 | {QLCNIC_CMD_BC_EVENT_SETUP, 2, 1}, |
71 | {QLCNIC_CMD_DCB_QUERY_CAP, 1, 2}, | ||
72 | {QLCNIC_CMD_DCB_QUERY_PARAM, 2, 50}, | ||
70 | }; | 73 | }; |
71 | 74 | ||
72 | const u32 qlcnic_83xx_ext_reg_tbl[] = { | 75 | const u32 qlcnic_83xx_ext_reg_tbl[] = { |
@@ -149,7 +152,7 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = { | |||
149 | .get_mac_address = qlcnic_83xx_get_mac_address, | 152 | .get_mac_address = qlcnic_83xx_get_mac_address, |
150 | .setup_intr = qlcnic_83xx_setup_intr, | 153 | .setup_intr = qlcnic_83xx_setup_intr, |
151 | .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args, | 154 | .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args, |
152 | .mbx_cmd = qlcnic_83xx_mbx_op, | 155 | .mbx_cmd = qlcnic_83xx_issue_cmd, |
153 | .get_func_no = qlcnic_83xx_get_func_no, | 156 | .get_func_no = qlcnic_83xx_get_func_no, |
154 | .api_lock = qlcnic_83xx_cam_lock, | 157 | .api_lock = qlcnic_83xx_cam_lock, |
155 | .api_unlock = qlcnic_83xx_cam_unlock, | 158 | .api_unlock = qlcnic_83xx_cam_unlock, |
@@ -175,6 +178,10 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = { | |||
175 | .get_board_info = qlcnic_83xx_get_port_info, | 178 | .get_board_info = qlcnic_83xx_get_port_info, |
176 | .set_mac_filter_count = qlcnic_83xx_set_mac_filter_count, | 179 | .set_mac_filter_count = qlcnic_83xx_set_mac_filter_count, |
177 | .free_mac_list = qlcnic_82xx_free_mac_list, | 180 | .free_mac_list = qlcnic_82xx_free_mac_list, |
181 | .io_error_detected = qlcnic_83xx_io_error_detected, | ||
182 | .io_slot_reset = qlcnic_83xx_io_slot_reset, | ||
183 | .io_resume = qlcnic_83xx_io_resume, | ||
184 | |||
178 | }; | 185 | }; |
179 | 186 | ||
180 | static struct qlcnic_nic_template qlcnic_83xx_ops = { | 187 | static struct qlcnic_nic_template qlcnic_83xx_ops = { |
@@ -261,7 +268,7 @@ int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr, | |||
261 | } | 268 | } |
262 | } | 269 | } |
263 | 270 | ||
264 | int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr) | 271 | int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr, int txq) |
265 | { | 272 | { |
266 | int err, i, num_msix; | 273 | int err, i, num_msix; |
267 | struct qlcnic_hardware_context *ahw = adapter->ahw; | 274 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
@@ -362,6 +369,10 @@ static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter, | |||
362 | struct qlcnic_cmd_args *cmd) | 369 | struct qlcnic_cmd_args *cmd) |
363 | { | 370 | { |
364 | int i; | 371 | int i; |
372 | |||
373 | if (cmd->op_type == QLC_83XX_MBX_POST_BC_OP) | ||
374 | return; | ||
375 | |||
365 | for (i = 0; i < cmd->rsp.num; i++) | 376 | for (i = 0; i < cmd->rsp.num; i++) |
366 | cmd->rsp.arg[i] = readl(QLCNIC_MBX_FW(adapter->ahw, i)); | 377 | cmd->rsp.arg[i] = readl(QLCNIC_MBX_FW(adapter->ahw, i)); |
367 | } | 378 | } |
@@ -398,24 +409,33 @@ irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter) | |||
398 | return IRQ_HANDLED; | 409 | return IRQ_HANDLED; |
399 | } | 410 | } |
400 | 411 | ||
412 | static inline void qlcnic_83xx_notify_mbx_response(struct qlcnic_mailbox *mbx) | ||
413 | { | ||
414 | atomic_set(&mbx->rsp_status, QLC_83XX_MBX_RESPONSE_ARRIVED); | ||
415 | complete(&mbx->completion); | ||
416 | } | ||
417 | |||
401 | static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter) | 418 | static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter) |
402 | { | 419 | { |
403 | u32 resp, event; | 420 | u32 resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED; |
421 | struct qlcnic_mailbox *mbx = adapter->ahw->mailbox; | ||
404 | unsigned long flags; | 422 | unsigned long flags; |
405 | 423 | ||
406 | spin_lock_irqsave(&adapter->ahw->mbx_lock, flags); | 424 | spin_lock_irqsave(&mbx->aen_lock, flags); |
407 | |||
408 | resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL); | 425 | resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL); |
409 | if (!(resp & QLCNIC_SET_OWNER)) | 426 | if (!(resp & QLCNIC_SET_OWNER)) |
410 | goto out; | 427 | goto out; |
411 | 428 | ||
412 | event = readl(QLCNIC_MBX_FW(adapter->ahw, 0)); | 429 | event = readl(QLCNIC_MBX_FW(adapter->ahw, 0)); |
413 | if (event & QLCNIC_MBX_ASYNC_EVENT) | 430 | if (event & QLCNIC_MBX_ASYNC_EVENT) { |
414 | __qlcnic_83xx_process_aen(adapter); | 431 | __qlcnic_83xx_process_aen(adapter); |
415 | 432 | } else { | |
433 | if (atomic_read(&mbx->rsp_status) != rsp_status) | ||
434 | qlcnic_83xx_notify_mbx_response(mbx); | ||
435 | } | ||
416 | out: | 436 | out: |
417 | qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter); | 437 | qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter); |
418 | spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags); | 438 | spin_unlock_irqrestore(&mbx->aen_lock, flags); |
419 | } | 439 | } |
420 | 440 | ||
421 | irqreturn_t qlcnic_83xx_intr(int irq, void *data) | 441 | irqreturn_t qlcnic_83xx_intr(int irq, void *data) |
@@ -515,7 +535,7 @@ int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter) | |||
515 | } | 535 | } |
516 | 536 | ||
517 | /* Enable mailbox interrupt */ | 537 | /* Enable mailbox interrupt */ |
518 | qlcnic_83xx_enable_mbx_intrpt(adapter); | 538 | qlcnic_83xx_enable_mbx_interrupt(adapter); |
519 | 539 | ||
520 | return err; | 540 | return err; |
521 | } | 541 | } |
@@ -628,7 +648,7 @@ void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *adapter) | |||
628 | ahw->max_uc_count = count; | 648 | ahw->max_uc_count = count; |
629 | } | 649 | } |
630 | 650 | ||
631 | void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *adapter) | 651 | void qlcnic_83xx_enable_mbx_interrupt(struct qlcnic_adapter *adapter) |
632 | { | 652 | { |
633 | u32 val; | 653 | u32 val; |
634 | 654 | ||
@@ -682,11 +702,14 @@ static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter, | |||
682 | static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter, | 702 | static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter, |
683 | u32 data[]); | 703 | u32 data[]); |
684 | 704 | ||
685 | static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter, | 705 | void qlcnic_dump_mbx(struct qlcnic_adapter *adapter, |
686 | struct qlcnic_cmd_args *cmd) | 706 | struct qlcnic_cmd_args *cmd) |
687 | { | 707 | { |
688 | int i; | 708 | int i; |
689 | 709 | ||
710 | if (cmd->op_type == QLC_83XX_MBX_POST_BC_OP) | ||
711 | return; | ||
712 | |||
690 | dev_info(&adapter->pdev->dev, | 713 | dev_info(&adapter->pdev->dev, |
691 | "Host MBX regs(%d)\n", cmd->req.num); | 714 | "Host MBX regs(%d)\n", cmd->req.num); |
692 | for (i = 0; i < cmd->req.num; i++) { | 715 | for (i = 0; i < cmd->req.num; i++) { |
@@ -705,120 +728,73 @@ static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter, | |||
705 | pr_info("\n"); | 728 | pr_info("\n"); |
706 | } | 729 | } |
707 | 730 | ||
708 | /* Mailbox response for mac rcode */ | 731 | static void qlcnic_83xx_poll_for_mbx_completion(struct qlcnic_adapter *adapter, |
709 | u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter) | 732 | struct qlcnic_cmd_args *cmd) |
710 | { | 733 | { |
711 | u32 fw_data; | 734 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
712 | u8 mac_cmd_rcode; | 735 | int opcode = LSW(cmd->req.arg[0]); |
736 | unsigned long max_loops; | ||
713 | 737 | ||
714 | fw_data = readl(QLCNIC_MBX_FW(adapter->ahw, 2)); | 738 | max_loops = cmd->total_cmds * QLC_83XX_MBX_CMD_LOOP; |
715 | mac_cmd_rcode = (u8)fw_data; | ||
716 | if (mac_cmd_rcode == QLC_83XX_NO_NIC_RESOURCE || | ||
717 | mac_cmd_rcode == QLC_83XX_MAC_PRESENT || | ||
718 | mac_cmd_rcode == QLC_83XX_MAC_ABSENT) | ||
719 | return QLCNIC_RCODE_SUCCESS; | ||
720 | return 1; | ||
721 | } | ||
722 | 739 | ||
723 | u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter, u32 *wait_time) | 740 | for (; max_loops; max_loops--) { |
724 | { | 741 | if (atomic_read(&cmd->rsp_status) == |
725 | u32 data; | 742 | QLC_83XX_MBX_RESPONSE_ARRIVED) |
726 | struct qlcnic_hardware_context *ahw = adapter->ahw; | 743 | return; |
727 | /* wait for mailbox completion */ | 744 | |
728 | do { | 745 | udelay(1); |
729 | data = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL); | 746 | } |
730 | if (++(*wait_time) > QLCNIC_MBX_TIMEOUT) { | 747 | |
731 | data = QLCNIC_RCODE_TIMEOUT; | 748 | dev_err(&adapter->pdev->dev, |
732 | break; | 749 | "%s: Mailbox command timed out, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n", |
733 | } | 750 | __func__, opcode, cmd->type, ahw->pci_func, ahw->op_mode); |
734 | mdelay(1); | 751 | flush_workqueue(ahw->mailbox->work_q); |
735 | } while (!data); | 752 | return; |
736 | return data; | ||
737 | } | 753 | } |
738 | 754 | ||
739 | int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter, | 755 | int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *adapter, |
740 | struct qlcnic_cmd_args *cmd) | 756 | struct qlcnic_cmd_args *cmd) |
741 | { | 757 | { |
742 | int i; | 758 | struct qlcnic_mailbox *mbx = adapter->ahw->mailbox; |
743 | u16 opcode; | ||
744 | u8 mbx_err_code; | ||
745 | unsigned long flags; | ||
746 | struct qlcnic_hardware_context *ahw = adapter->ahw; | 759 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
747 | u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, wait_time = 0; | 760 | int cmd_type, err, opcode; |
761 | unsigned long timeout; | ||
748 | 762 | ||
749 | opcode = LSW(cmd->req.arg[0]); | 763 | opcode = LSW(cmd->req.arg[0]); |
750 | if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) { | 764 | cmd_type = cmd->type; |
751 | dev_info(&adapter->pdev->dev, | 765 | err = mbx->ops->enqueue_cmd(adapter, cmd, &timeout); |
752 | "Mailbox cmd attempted, 0x%x\n", opcode); | 766 | if (err) { |
753 | dev_info(&adapter->pdev->dev, "Mailbox detached\n"); | 767 | dev_err(&adapter->pdev->dev, |
754 | return 0; | 768 | "%s: Mailbox not available, cmd_op=0x%x, cmd_context=0x%x, pci_func=0x%x, op_mode=0x%x\n", |
769 | __func__, opcode, cmd->type, ahw->pci_func, | ||
770 | ahw->op_mode); | ||
771 | return err; | ||
755 | } | 772 | } |
756 | 773 | ||
757 | spin_lock_irqsave(&adapter->ahw->mbx_lock, flags); | 774 | switch (cmd_type) { |
758 | mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL); | 775 | case QLC_83XX_MBX_CMD_WAIT: |
759 | 776 | if (!wait_for_completion_timeout(&cmd->completion, timeout)) { | |
760 | if (mbx_val) { | ||
761 | QLCDB(adapter, DRV, | ||
762 | "Mailbox cmd attempted, 0x%x\n", opcode); | ||
763 | QLCDB(adapter, DRV, | ||
764 | "Mailbox not available, 0x%x, collect FW dump\n", | ||
765 | mbx_val); | ||
766 | cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT; | ||
767 | spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags); | ||
768 | return cmd->rsp.arg[0]; | ||
769 | } | ||
770 | |||
771 | /* Fill in mailbox registers */ | ||
772 | mbx_cmd = cmd->req.arg[0]; | ||
773 | writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0)); | ||
774 | for (i = 1; i < cmd->req.num; i++) | ||
775 | writel(cmd->req.arg[i], QLCNIC_MBX_HOST(ahw, i)); | ||
776 | |||
777 | /* Signal FW about the impending command */ | ||
778 | QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER); | ||
779 | poll: | ||
780 | rsp = qlcnic_83xx_mbx_poll(adapter, &wait_time); | ||
781 | if (rsp != QLCNIC_RCODE_TIMEOUT) { | ||
782 | /* Get the FW response data */ | ||
783 | fw_data = readl(QLCNIC_MBX_FW(ahw, 0)); | ||
784 | if (fw_data & QLCNIC_MBX_ASYNC_EVENT) { | ||
785 | __qlcnic_83xx_process_aen(adapter); | ||
786 | goto poll; | ||
787 | } | ||
788 | mbx_err_code = QLCNIC_MBX_STATUS(fw_data); | ||
789 | rsp_num = QLCNIC_MBX_NUM_REGS(fw_data); | ||
790 | opcode = QLCNIC_MBX_RSP(fw_data); | ||
791 | qlcnic_83xx_get_mbx_data(adapter, cmd); | ||
792 | |||
793 | switch (mbx_err_code) { | ||
794 | case QLCNIC_MBX_RSP_OK: | ||
795 | case QLCNIC_MBX_PORT_RSP_OK: | ||
796 | rsp = QLCNIC_RCODE_SUCCESS; | ||
797 | break; | ||
798 | default: | ||
799 | if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) { | ||
800 | rsp = qlcnic_83xx_mac_rcode(adapter); | ||
801 | if (!rsp) | ||
802 | goto out; | ||
803 | } | ||
804 | dev_err(&adapter->pdev->dev, | 777 | dev_err(&adapter->pdev->dev, |
805 | "MBX command 0x%x failed with err:0x%x\n", | 778 | "%s: Mailbox command timed out, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n", |
806 | opcode, mbx_err_code); | 779 | __func__, opcode, cmd_type, ahw->pci_func, |
807 | rsp = mbx_err_code; | 780 | ahw->op_mode); |
808 | qlcnic_dump_mbx(adapter, cmd); | 781 | flush_workqueue(mbx->work_q); |
809 | break; | ||
810 | } | 782 | } |
811 | goto out; | 783 | break; |
784 | case QLC_83XX_MBX_CMD_NO_WAIT: | ||
785 | return 0; | ||
786 | case QLC_83XX_MBX_CMD_BUSY_WAIT: | ||
787 | qlcnic_83xx_poll_for_mbx_completion(adapter, cmd); | ||
788 | break; | ||
789 | default: | ||
790 | dev_err(&adapter->pdev->dev, | ||
791 | "%s: Invalid mailbox command, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n", | ||
792 | __func__, opcode, cmd_type, ahw->pci_func, | ||
793 | ahw->op_mode); | ||
794 | qlcnic_83xx_detach_mailbox_work(adapter); | ||
812 | } | 795 | } |
813 | 796 | ||
814 | dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n", | 797 | return cmd->rsp_opcode; |
815 | QLCNIC_MBX_RSP(mbx_cmd)); | ||
816 | rsp = QLCNIC_RCODE_TIMEOUT; | ||
817 | out: | ||
818 | /* clear fw mbx control register */ | ||
819 | QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER); | ||
820 | spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags); | ||
821 | return rsp; | ||
822 | } | 798 | } |
823 | 799 | ||
824 | int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx, | 800 | int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx, |
@@ -828,6 +804,7 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx, | |||
828 | u32 temp; | 804 | u32 temp; |
829 | const struct qlcnic_mailbox_metadata *mbx_tbl; | 805 | const struct qlcnic_mailbox_metadata *mbx_tbl; |
830 | 806 | ||
807 | memset(mbx, 0, sizeof(struct qlcnic_cmd_args)); | ||
831 | mbx_tbl = qlcnic_83xx_mbx_tbl; | 808 | mbx_tbl = qlcnic_83xx_mbx_tbl; |
832 | size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl); | 809 | size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl); |
833 | for (i = 0; i < size; i++) { | 810 | for (i = 0; i < size; i++) { |
@@ -850,6 +827,7 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx, | |||
850 | memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num); | 827 | memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num); |
851 | temp = adapter->ahw->fw_hal_version << 29; | 828 | temp = adapter->ahw->fw_hal_version << 29; |
852 | mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp); | 829 | mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp); |
830 | mbx->cmd_op = type; | ||
853 | return 0; | 831 | return 0; |
854 | } | 832 | } |
855 | } | 833 | } |
@@ -888,9 +866,9 @@ static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter, | |||
888 | 866 | ||
889 | void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) | 867 | void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) |
890 | { | 868 | { |
869 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
891 | u32 event[QLC_83XX_MBX_AEN_CNT]; | 870 | u32 event[QLC_83XX_MBX_AEN_CNT]; |
892 | int i; | 871 | int i; |
893 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
894 | 872 | ||
895 | for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++) | 873 | for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++) |
896 | event[i] = readl(QLCNIC_MBX_FW(ahw, i)); | 874 | event[i] = readl(QLCNIC_MBX_FW(ahw, i)); |
@@ -910,6 +888,7 @@ void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) | |||
910 | &adapter->idc_aen_work, 0); | 888 | &adapter->idc_aen_work, 0); |
911 | break; | 889 | break; |
912 | case QLCNIC_MBX_TIME_EXTEND_EVENT: | 890 | case QLCNIC_MBX_TIME_EXTEND_EVENT: |
891 | ahw->extend_lb_time = event[1] >> 8 & 0xf; | ||
913 | break; | 892 | break; |
914 | case QLCNIC_MBX_BC_EVENT: | 893 | case QLCNIC_MBX_BC_EVENT: |
915 | qlcnic_sriov_handle_bc_event(adapter, event[1]); | 894 | qlcnic_sriov_handle_bc_event(adapter, event[1]); |
@@ -922,6 +901,9 @@ void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) | |||
922 | dev_info(&adapter->pdev->dev, "SFP Removed AEN:0x%x.\n", | 901 | dev_info(&adapter->pdev->dev, "SFP Removed AEN:0x%x.\n", |
923 | QLCNIC_MBX_RSP(event[0])); | 902 | QLCNIC_MBX_RSP(event[0])); |
924 | break; | 903 | break; |
904 | case QLCNIC_MBX_DCBX_CONFIG_CHANGE_EVENT: | ||
905 | qlcnic_dcb_handle_aen(adapter, (void *)&event[1]); | ||
906 | break; | ||
925 | default: | 907 | default: |
926 | dev_dbg(&adapter->pdev->dev, "Unsupported AEN:0x%x.\n", | 908 | dev_dbg(&adapter->pdev->dev, "Unsupported AEN:0x%x.\n", |
927 | QLCNIC_MBX_RSP(event[0])); | 909 | QLCNIC_MBX_RSP(event[0])); |
@@ -933,20 +915,23 @@ void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) | |||
933 | 915 | ||
934 | static void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) | 916 | static void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) |
935 | { | 917 | { |
918 | u32 resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED; | ||
936 | struct qlcnic_hardware_context *ahw = adapter->ahw; | 919 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
937 | u32 resp, event; | 920 | struct qlcnic_mailbox *mbx = ahw->mailbox; |
938 | unsigned long flags; | 921 | unsigned long flags; |
939 | 922 | ||
940 | spin_lock_irqsave(&ahw->mbx_lock, flags); | 923 | spin_lock_irqsave(&mbx->aen_lock, flags); |
941 | |||
942 | resp = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL); | 924 | resp = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL); |
943 | if (resp & QLCNIC_SET_OWNER) { | 925 | if (resp & QLCNIC_SET_OWNER) { |
944 | event = readl(QLCNIC_MBX_FW(ahw, 0)); | 926 | event = readl(QLCNIC_MBX_FW(ahw, 0)); |
945 | if (event & QLCNIC_MBX_ASYNC_EVENT) | 927 | if (event & QLCNIC_MBX_ASYNC_EVENT) { |
946 | __qlcnic_83xx_process_aen(adapter); | 928 | __qlcnic_83xx_process_aen(adapter); |
929 | } else { | ||
930 | if (atomic_read(&mbx->rsp_status) != rsp_status) | ||
931 | qlcnic_83xx_notify_mbx_response(mbx); | ||
932 | } | ||
947 | } | 933 | } |
948 | 934 | spin_unlock_irqrestore(&mbx->aen_lock, flags); | |
949 | spin_unlock_irqrestore(&ahw->mbx_lock, flags); | ||
950 | } | 935 | } |
951 | 936 | ||
952 | static void qlcnic_83xx_mbx_poll_work(struct work_struct *work) | 937 | static void qlcnic_83xx_mbx_poll_work(struct work_struct *work) |
@@ -969,6 +954,7 @@ void qlcnic_83xx_enable_mbx_poll(struct qlcnic_adapter *adapter) | |||
969 | return; | 954 | return; |
970 | 955 | ||
971 | INIT_DELAYED_WORK(&adapter->mbx_poll_work, qlcnic_83xx_mbx_poll_work); | 956 | INIT_DELAYED_WORK(&adapter->mbx_poll_work, qlcnic_83xx_mbx_poll_work); |
957 | queue_delayed_work(adapter->qlcnic_wq, &adapter->mbx_poll_work, 0); | ||
972 | } | 958 | } |
973 | 959 | ||
974 | void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *adapter) | 960 | void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *adapter) |
@@ -1355,8 +1341,10 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test, | |||
1355 | 1341 | ||
1356 | if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) { | 1342 | if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) { |
1357 | /* disable and free mailbox interrupt */ | 1343 | /* disable and free mailbox interrupt */ |
1358 | if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) | 1344 | if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { |
1345 | qlcnic_83xx_enable_mbx_poll(adapter); | ||
1359 | qlcnic_83xx_free_mbx_intr(adapter); | 1346 | qlcnic_83xx_free_mbx_intr(adapter); |
1347 | } | ||
1360 | adapter->ahw->loopback_state = 0; | 1348 | adapter->ahw->loopback_state = 0; |
1361 | adapter->ahw->hw_ops->setup_link_event(adapter, 1); | 1349 | adapter->ahw->hw_ops->setup_link_event(adapter, 1); |
1362 | } | 1350 | } |
@@ -1377,6 +1365,8 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev, | |||
1377 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { | 1365 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { |
1378 | sds_ring = &adapter->recv_ctx->sds_rings[ring]; | 1366 | sds_ring = &adapter->recv_ctx->sds_rings[ring]; |
1379 | qlcnic_83xx_disable_intr(adapter, sds_ring); | 1367 | qlcnic_83xx_disable_intr(adapter, sds_ring); |
1368 | if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) | ||
1369 | qlcnic_83xx_enable_mbx_poll(adapter); | ||
1380 | } | 1370 | } |
1381 | } | 1371 | } |
1382 | 1372 | ||
@@ -1386,6 +1376,7 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev, | |||
1386 | if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) { | 1376 | if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) { |
1387 | if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { | 1377 | if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { |
1388 | err = qlcnic_83xx_setup_mbx_intr(adapter); | 1378 | err = qlcnic_83xx_setup_mbx_intr(adapter); |
1379 | qlcnic_83xx_disable_mbx_poll(adapter); | ||
1389 | if (err) { | 1380 | if (err) { |
1390 | dev_err(&adapter->pdev->dev, | 1381 | dev_err(&adapter->pdev->dev, |
1391 | "%s: failed to setup mbx interrupt\n", | 1382 | "%s: failed to setup mbx interrupt\n", |
@@ -1402,6 +1393,10 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev, | |||
1402 | 1393 | ||
1403 | if (netif_running(netdev)) | 1394 | if (netif_running(netdev)) |
1404 | __qlcnic_up(adapter, netdev); | 1395 | __qlcnic_up(adapter, netdev); |
1396 | |||
1397 | if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST && | ||
1398 | !(adapter->flags & QLCNIC_MSIX_ENABLED)) | ||
1399 | qlcnic_83xx_disable_mbx_poll(adapter); | ||
1405 | out: | 1400 | out: |
1406 | netif_device_attach(netdev); | 1401 | netif_device_attach(netdev); |
1407 | } | 1402 | } |
@@ -1619,26 +1614,33 @@ static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter, | |||
1619 | 1614 | ||
1620 | int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) | 1615 | int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) |
1621 | { | 1616 | { |
1622 | int err; | 1617 | struct qlcnic_cmd_args *cmd = NULL; |
1623 | u32 temp = 0; | 1618 | u32 temp = 0; |
1624 | struct qlcnic_cmd_args cmd; | 1619 | int err; |
1625 | 1620 | ||
1626 | if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED) | 1621 | if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED) |
1627 | return -EIO; | 1622 | return -EIO; |
1628 | 1623 | ||
1629 | err = qlcnic_alloc_mbx_args(&cmd, adapter, | 1624 | cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); |
1625 | if (!cmd) | ||
1626 | return -ENOMEM; | ||
1627 | |||
1628 | err = qlcnic_alloc_mbx_args(cmd, adapter, | ||
1630 | QLCNIC_CMD_CONFIGURE_MAC_RX_MODE); | 1629 | QLCNIC_CMD_CONFIGURE_MAC_RX_MODE); |
1631 | if (err) | 1630 | if (err) |
1632 | return err; | 1631 | goto out; |
1633 | 1632 | ||
1633 | cmd->type = QLC_83XX_MBX_CMD_NO_WAIT; | ||
1634 | qlcnic_83xx_set_interface_id_promisc(adapter, &temp); | 1634 | qlcnic_83xx_set_interface_id_promisc(adapter, &temp); |
1635 | cmd.req.arg[1] = (mode ? 1 : 0) | temp; | 1635 | cmd->req.arg[1] = (mode ? 1 : 0) | temp; |
1636 | err = qlcnic_issue_cmd(adapter, &cmd); | 1636 | err = qlcnic_issue_cmd(adapter, cmd); |
1637 | if (err) | 1637 | if (!err) |
1638 | dev_info(&adapter->pdev->dev, | 1638 | return err; |
1639 | "Promiscous mode config failed\n"); | ||
1640 | 1639 | ||
1641 | qlcnic_free_mbx_args(&cmd); | 1640 | qlcnic_free_mbx_args(cmd); |
1641 | |||
1642 | out: | ||
1643 | kfree(cmd); | ||
1642 | return err; | 1644 | return err; |
1643 | } | 1645 | } |
1644 | 1646 | ||
@@ -1651,7 +1653,7 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode) | |||
1651 | if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) { | 1653 | if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) { |
1652 | netdev_warn(netdev, | 1654 | netdev_warn(netdev, |
1653 | "Loopback test not supported in non privileged mode\n"); | 1655 | "Loopback test not supported in non privileged mode\n"); |
1654 | return ret; | 1656 | return -ENOTSUPP; |
1655 | } | 1657 | } |
1656 | 1658 | ||
1657 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) { | 1659 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) { |
@@ -1679,19 +1681,17 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode) | |||
1679 | /* Poll for link up event before running traffic */ | 1681 | /* Poll for link up event before running traffic */ |
1680 | do { | 1682 | do { |
1681 | msleep(QLC_83XX_LB_MSLEEP_COUNT); | 1683 | msleep(QLC_83XX_LB_MSLEEP_COUNT); |
1682 | if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) | ||
1683 | qlcnic_83xx_process_aen(adapter); | ||
1684 | 1684 | ||
1685 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) { | 1685 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) { |
1686 | netdev_info(netdev, | 1686 | netdev_info(netdev, |
1687 | "Device is resetting, free LB test resources\n"); | 1687 | "Device is resetting, free LB test resources\n"); |
1688 | ret = -EIO; | 1688 | ret = -EBUSY; |
1689 | goto free_diag_res; | 1689 | goto free_diag_res; |
1690 | } | 1690 | } |
1691 | if (loop++ > QLC_83XX_LB_WAIT_COUNT) { | 1691 | if (loop++ > QLC_83XX_LB_WAIT_COUNT) { |
1692 | netdev_info(netdev, | 1692 | netdev_info(netdev, |
1693 | "Firmware didn't sent link up event to loopback request\n"); | 1693 | "Firmware didn't sent link up event to loopback request\n"); |
1694 | ret = -QLCNIC_FW_NOT_RESPOND; | 1694 | ret = -ETIMEDOUT; |
1695 | qlcnic_83xx_clear_lb_mode(adapter, mode); | 1695 | qlcnic_83xx_clear_lb_mode(adapter, mode); |
1696 | goto free_diag_res; | 1696 | goto free_diag_res; |
1697 | } | 1697 | } |
@@ -1700,7 +1700,7 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode) | |||
1700 | /* Make sure carrier is off and queue is stopped during loopback */ | 1700 | /* Make sure carrier is off and queue is stopped during loopback */ |
1701 | if (netif_running(netdev)) { | 1701 | if (netif_running(netdev)) { |
1702 | netif_carrier_off(netdev); | 1702 | netif_carrier_off(netdev); |
1703 | netif_stop_queue(netdev); | 1703 | netif_tx_stop_all_queues(netdev); |
1704 | } | 1704 | } |
1705 | 1705 | ||
1706 | ret = qlcnic_do_lb_test(adapter, mode); | 1706 | ret = qlcnic_do_lb_test(adapter, mode); |
@@ -1716,18 +1716,42 @@ fail_diag_alloc: | |||
1716 | return ret; | 1716 | return ret; |
1717 | } | 1717 | } |
1718 | 1718 | ||
1719 | static void qlcnic_extend_lb_idc_cmpltn_wait(struct qlcnic_adapter *adapter, | ||
1720 | u32 *max_wait_count) | ||
1721 | { | ||
1722 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
1723 | int temp; | ||
1724 | |||
1725 | netdev_info(adapter->netdev, "Recieved loopback IDC time extend event for 0x%x seconds\n", | ||
1726 | ahw->extend_lb_time); | ||
1727 | temp = ahw->extend_lb_time * 1000; | ||
1728 | *max_wait_count += temp / QLC_83XX_LB_MSLEEP_COUNT; | ||
1729 | ahw->extend_lb_time = 0; | ||
1730 | } | ||
1731 | |||
1719 | int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode) | 1732 | int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode) |
1720 | { | 1733 | { |
1721 | struct qlcnic_hardware_context *ahw = adapter->ahw; | 1734 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
1722 | struct net_device *netdev = adapter->netdev; | 1735 | struct net_device *netdev = adapter->netdev; |
1736 | u32 config, max_wait_count; | ||
1723 | int status = 0, loop = 0; | 1737 | int status = 0, loop = 0; |
1724 | u32 config; | ||
1725 | 1738 | ||
1739 | ahw->extend_lb_time = 0; | ||
1740 | max_wait_count = QLC_83XX_LB_WAIT_COUNT; | ||
1726 | status = qlcnic_83xx_get_port_config(adapter); | 1741 | status = qlcnic_83xx_get_port_config(adapter); |
1727 | if (status) | 1742 | if (status) |
1728 | return status; | 1743 | return status; |
1729 | 1744 | ||
1730 | config = ahw->port_config; | 1745 | config = ahw->port_config; |
1746 | |||
1747 | /* Check if port is already in loopback mode */ | ||
1748 | if ((config & QLC_83XX_CFG_LOOPBACK_HSS) || | ||
1749 | (config & QLC_83XX_CFG_LOOPBACK_EXT)) { | ||
1750 | netdev_err(netdev, | ||
1751 | "Port already in Loopback mode.\n"); | ||
1752 | return -EINPROGRESS; | ||
1753 | } | ||
1754 | |||
1731 | set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); | 1755 | set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); |
1732 | 1756 | ||
1733 | if (mode == QLCNIC_ILB_MODE) | 1757 | if (mode == QLCNIC_ILB_MODE) |
@@ -1748,21 +1772,24 @@ int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode) | |||
1748 | /* Wait for Link and IDC Completion AEN */ | 1772 | /* Wait for Link and IDC Completion AEN */ |
1749 | do { | 1773 | do { |
1750 | msleep(QLC_83XX_LB_MSLEEP_COUNT); | 1774 | msleep(QLC_83XX_LB_MSLEEP_COUNT); |
1751 | if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) | ||
1752 | qlcnic_83xx_process_aen(adapter); | ||
1753 | 1775 | ||
1754 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) { | 1776 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) { |
1755 | netdev_info(netdev, | 1777 | netdev_info(netdev, |
1756 | "Device is resetting, free LB test resources\n"); | 1778 | "Device is resetting, free LB test resources\n"); |
1757 | clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); | 1779 | clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); |
1758 | return -EIO; | 1780 | return -EBUSY; |
1759 | } | 1781 | } |
1760 | if (loop++ > QLC_83XX_LB_WAIT_COUNT) { | 1782 | |
1761 | netdev_err(netdev, | 1783 | if (ahw->extend_lb_time) |
1762 | "Did not receive IDC completion AEN\n"); | 1784 | qlcnic_extend_lb_idc_cmpltn_wait(adapter, |
1785 | &max_wait_count); | ||
1786 | |||
1787 | if (loop++ > max_wait_count) { | ||
1788 | netdev_err(netdev, "%s: Did not receive loopback IDC completion AEN\n", | ||
1789 | __func__); | ||
1763 | clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); | 1790 | clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); |
1764 | qlcnic_83xx_clear_lb_mode(adapter, mode); | 1791 | qlcnic_83xx_clear_lb_mode(adapter, mode); |
1765 | return -EIO; | 1792 | return -ETIMEDOUT; |
1766 | } | 1793 | } |
1767 | } while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status)); | 1794 | } while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status)); |
1768 | 1795 | ||
@@ -1774,10 +1801,12 @@ int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode) | |||
1774 | int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode) | 1801 | int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode) |
1775 | { | 1802 | { |
1776 | struct qlcnic_hardware_context *ahw = adapter->ahw; | 1803 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
1804 | u32 config = ahw->port_config, max_wait_count; | ||
1777 | struct net_device *netdev = adapter->netdev; | 1805 | struct net_device *netdev = adapter->netdev; |
1778 | int status = 0, loop = 0; | 1806 | int status = 0, loop = 0; |
1779 | u32 config = ahw->port_config; | ||
1780 | 1807 | ||
1808 | ahw->extend_lb_time = 0; | ||
1809 | max_wait_count = QLC_83XX_LB_WAIT_COUNT; | ||
1781 | set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); | 1810 | set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); |
1782 | if (mode == QLCNIC_ILB_MODE) | 1811 | if (mode == QLCNIC_ILB_MODE) |
1783 | ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_HSS; | 1812 | ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_HSS; |
@@ -1797,21 +1826,23 @@ int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode) | |||
1797 | /* Wait for Link and IDC Completion AEN */ | 1826 | /* Wait for Link and IDC Completion AEN */ |
1798 | do { | 1827 | do { |
1799 | msleep(QLC_83XX_LB_MSLEEP_COUNT); | 1828 | msleep(QLC_83XX_LB_MSLEEP_COUNT); |
1800 | if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) | ||
1801 | qlcnic_83xx_process_aen(adapter); | ||
1802 | 1829 | ||
1803 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) { | 1830 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) { |
1804 | netdev_info(netdev, | 1831 | netdev_info(netdev, |
1805 | "Device is resetting, free LB test resources\n"); | 1832 | "Device is resetting, free LB test resources\n"); |
1806 | clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); | 1833 | clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); |
1807 | return -EIO; | 1834 | return -EBUSY; |
1808 | } | 1835 | } |
1809 | 1836 | ||
1810 | if (loop++ > QLC_83XX_LB_WAIT_COUNT) { | 1837 | if (ahw->extend_lb_time) |
1811 | netdev_err(netdev, | 1838 | qlcnic_extend_lb_idc_cmpltn_wait(adapter, |
1812 | "Did not receive IDC completion AEN\n"); | 1839 | &max_wait_count); |
1840 | |||
1841 | if (loop++ > max_wait_count) { | ||
1842 | netdev_err(netdev, "%s: Did not receive loopback IDC completion AEN\n", | ||
1843 | __func__); | ||
1813 | clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); | 1844 | clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status); |
1814 | return -EIO; | 1845 | return -ETIMEDOUT; |
1815 | } | 1846 | } |
1816 | } while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status)); | 1847 | } while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status)); |
1817 | 1848 | ||
@@ -1950,25 +1981,31 @@ static void qlcnic_83xx_set_interface_id_macaddr(struct qlcnic_adapter *adapter, | |||
1950 | int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, | 1981 | int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, |
1951 | u16 vlan_id, u8 op) | 1982 | u16 vlan_id, u8 op) |
1952 | { | 1983 | { |
1953 | int err; | 1984 | struct qlcnic_cmd_args *cmd = NULL; |
1954 | u32 *buf, temp = 0; | ||
1955 | struct qlcnic_cmd_args cmd; | ||
1956 | struct qlcnic_macvlan_mbx mv; | 1985 | struct qlcnic_macvlan_mbx mv; |
1986 | u32 *buf, temp = 0; | ||
1987 | int err; | ||
1957 | 1988 | ||
1958 | if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED) | 1989 | if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED) |
1959 | return -EIO; | 1990 | return -EIO; |
1960 | 1991 | ||
1961 | err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN); | 1992 | cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); |
1993 | if (!cmd) | ||
1994 | return -ENOMEM; | ||
1995 | |||
1996 | err = qlcnic_alloc_mbx_args(cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN); | ||
1962 | if (err) | 1997 | if (err) |
1963 | return err; | 1998 | goto out; |
1999 | |||
2000 | cmd->type = QLC_83XX_MBX_CMD_NO_WAIT; | ||
1964 | 2001 | ||
1965 | if (vlan_id) | 2002 | if (vlan_id) |
1966 | op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ? | 2003 | op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ? |
1967 | QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL; | 2004 | QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL; |
1968 | 2005 | ||
1969 | cmd.req.arg[1] = op | (1 << 8); | 2006 | cmd->req.arg[1] = op | (1 << 8); |
1970 | qlcnic_83xx_set_interface_id_macaddr(adapter, &temp); | 2007 | qlcnic_83xx_set_interface_id_macaddr(adapter, &temp); |
1971 | cmd.req.arg[1] |= temp; | 2008 | cmd->req.arg[1] |= temp; |
1972 | mv.vlan = vlan_id; | 2009 | mv.vlan = vlan_id; |
1973 | mv.mac_addr0 = addr[0]; | 2010 | mv.mac_addr0 = addr[0]; |
1974 | mv.mac_addr1 = addr[1]; | 2011 | mv.mac_addr1 = addr[1]; |
@@ -1976,14 +2013,15 @@ int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, | |||
1976 | mv.mac_addr3 = addr[3]; | 2013 | mv.mac_addr3 = addr[3]; |
1977 | mv.mac_addr4 = addr[4]; | 2014 | mv.mac_addr4 = addr[4]; |
1978 | mv.mac_addr5 = addr[5]; | 2015 | mv.mac_addr5 = addr[5]; |
1979 | buf = &cmd.req.arg[2]; | 2016 | buf = &cmd->req.arg[2]; |
1980 | memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx)); | 2017 | memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx)); |
1981 | err = qlcnic_issue_cmd(adapter, &cmd); | 2018 | err = qlcnic_issue_cmd(adapter, cmd); |
1982 | if (err) | 2019 | if (!err) |
1983 | dev_err(&adapter->pdev->dev, | 2020 | return err; |
1984 | "MAC-VLAN %s to CAM failed, err=%d.\n", | 2021 | |
1985 | ((op == 1) ? "add " : "delete "), err); | 2022 | qlcnic_free_mbx_args(cmd); |
1986 | qlcnic_free_mbx_args(&cmd); | 2023 | out: |
2024 | kfree(cmd); | ||
1987 | return err; | 2025 | return err; |
1988 | } | 2026 | } |
1989 | 2027 | ||
@@ -2008,12 +2046,14 @@ void qlcnic_83xx_configure_mac(struct qlcnic_adapter *adapter, u8 *mac, | |||
2008 | cmd->req.arg[1] = type; | 2046 | cmd->req.arg[1] = type; |
2009 | } | 2047 | } |
2010 | 2048 | ||
2011 | int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac) | 2049 | int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac, |
2050 | u8 function) | ||
2012 | { | 2051 | { |
2013 | int err, i; | 2052 | int err, i; |
2014 | struct qlcnic_cmd_args cmd; | 2053 | struct qlcnic_cmd_args cmd; |
2015 | u32 mac_low, mac_high; | 2054 | u32 mac_low, mac_high; |
2016 | 2055 | ||
2056 | function = 0; | ||
2017 | err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS); | 2057 | err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS); |
2018 | if (err) | 2058 | if (err) |
2019 | return err; | 2059 | return err; |
@@ -2099,10 +2139,12 @@ static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter, | |||
2099 | irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data) | 2139 | irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data) |
2100 | { | 2140 | { |
2101 | struct qlcnic_adapter *adapter = data; | 2141 | struct qlcnic_adapter *adapter = data; |
2102 | unsigned long flags; | 2142 | struct qlcnic_mailbox *mbx; |
2103 | u32 mask, resp, event; | 2143 | u32 mask, resp, event; |
2144 | unsigned long flags; | ||
2104 | 2145 | ||
2105 | spin_lock_irqsave(&adapter->ahw->mbx_lock, flags); | 2146 | mbx = adapter->ahw->mailbox; |
2147 | spin_lock_irqsave(&mbx->aen_lock, flags); | ||
2106 | resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL); | 2148 | resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL); |
2107 | if (!(resp & QLCNIC_SET_OWNER)) | 2149 | if (!(resp & QLCNIC_SET_OWNER)) |
2108 | goto out; | 2150 | goto out; |
@@ -2110,11 +2152,13 @@ irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data) | |||
2110 | event = readl(QLCNIC_MBX_FW(adapter->ahw, 0)); | 2152 | event = readl(QLCNIC_MBX_FW(adapter->ahw, 0)); |
2111 | if (event & QLCNIC_MBX_ASYNC_EVENT) | 2153 | if (event & QLCNIC_MBX_ASYNC_EVENT) |
2112 | __qlcnic_83xx_process_aen(adapter); | 2154 | __qlcnic_83xx_process_aen(adapter); |
2155 | else | ||
2156 | qlcnic_83xx_notify_mbx_response(mbx); | ||
2157 | |||
2113 | out: | 2158 | out: |
2114 | mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK); | 2159 | mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK); |
2115 | writel(0, adapter->ahw->pci_base0 + mask); | 2160 | writel(0, adapter->ahw->pci_base0 + mask); |
2116 | spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags); | 2161 | spin_unlock_irqrestore(&mbx->aen_lock, flags); |
2117 | |||
2118 | return IRQ_HANDLED; | 2162 | return IRQ_HANDLED; |
2119 | } | 2163 | } |
2120 | 2164 | ||
@@ -2287,7 +2331,7 @@ int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter, | |||
2287 | pci_info->tx_max_bw, pci_info->mac); | 2331 | pci_info->tx_max_bw, pci_info->mac); |
2288 | } | 2332 | } |
2289 | if (ahw->op_mode == QLCNIC_MGMT_FUNC) | 2333 | if (ahw->op_mode == QLCNIC_MGMT_FUNC) |
2290 | dev_info(dev, "Max vNIC functions = %d, active vNIC functions = %d\n", | 2334 | dev_info(dev, "Max functions = %d, active functions = %d\n", |
2291 | ahw->max_pci_func, ahw->act_pci_func); | 2335 | ahw->max_pci_func, ahw->act_pci_func); |
2292 | 2336 | ||
2293 | } else { | 2337 | } else { |
@@ -3477,3 +3521,360 @@ int qlcnic_83xx_resume(struct qlcnic_adapter *adapter) | |||
3477 | idc->delay); | 3521 | idc->delay); |
3478 | return err; | 3522 | return err; |
3479 | } | 3523 | } |
3524 | |||
3525 | void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx) | ||
3526 | { | ||
3527 | INIT_COMPLETION(mbx->completion); | ||
3528 | set_bit(QLC_83XX_MBX_READY, &mbx->status); | ||
3529 | } | ||
3530 | |||
3531 | void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx) | ||
3532 | { | ||
3533 | destroy_workqueue(mbx->work_q); | ||
3534 | kfree(mbx); | ||
3535 | } | ||
3536 | |||
3537 | static inline void | ||
3538 | qlcnic_83xx_notify_cmd_completion(struct qlcnic_adapter *adapter, | ||
3539 | struct qlcnic_cmd_args *cmd) | ||
3540 | { | ||
3541 | atomic_set(&cmd->rsp_status, QLC_83XX_MBX_RESPONSE_ARRIVED); | ||
3542 | |||
3543 | if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT) { | ||
3544 | qlcnic_free_mbx_args(cmd); | ||
3545 | kfree(cmd); | ||
3546 | return; | ||
3547 | } | ||
3548 | complete(&cmd->completion); | ||
3549 | } | ||
3550 | |||
3551 | static void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter) | ||
3552 | { | ||
3553 | struct qlcnic_mailbox *mbx = adapter->ahw->mailbox; | ||
3554 | struct list_head *head = &mbx->cmd_q; | ||
3555 | struct qlcnic_cmd_args *cmd = NULL; | ||
3556 | |||
3557 | spin_lock(&mbx->queue_lock); | ||
3558 | |||
3559 | while (!list_empty(head)) { | ||
3560 | cmd = list_entry(head->next, struct qlcnic_cmd_args, list); | ||
3561 | dev_info(&adapter->pdev->dev, "%s: Mailbox command 0x%x\n", | ||
3562 | __func__, cmd->cmd_op); | ||
3563 | list_del(&cmd->list); | ||
3564 | mbx->num_cmds--; | ||
3565 | qlcnic_83xx_notify_cmd_completion(adapter, cmd); | ||
3566 | } | ||
3567 | |||
3568 | spin_unlock(&mbx->queue_lock); | ||
3569 | } | ||
3570 | |||
3571 | static int qlcnic_83xx_check_mbx_status(struct qlcnic_adapter *adapter) | ||
3572 | { | ||
3573 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
3574 | struct qlcnic_mailbox *mbx = ahw->mailbox; | ||
3575 | u32 host_mbx_ctrl; | ||
3576 | |||
3577 | if (!test_bit(QLC_83XX_MBX_READY, &mbx->status)) | ||
3578 | return -EBUSY; | ||
3579 | |||
3580 | host_mbx_ctrl = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL); | ||
3581 | if (host_mbx_ctrl) { | ||
3582 | clear_bit(QLC_83XX_MBX_READY, &mbx->status); | ||
3583 | ahw->idc.collect_dump = 1; | ||
3584 | return -EIO; | ||
3585 | } | ||
3586 | |||
3587 | return 0; | ||
3588 | } | ||
3589 | |||
3590 | static inline void qlcnic_83xx_signal_mbx_cmd(struct qlcnic_adapter *adapter, | ||
3591 | u8 issue_cmd) | ||
3592 | { | ||
3593 | if (issue_cmd) | ||
3594 | QLCWRX(adapter->ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER); | ||
3595 | else | ||
3596 | QLCWRX(adapter->ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER); | ||
3597 | } | ||
3598 | |||
3599 | static void qlcnic_83xx_dequeue_mbx_cmd(struct qlcnic_adapter *adapter, | ||
3600 | struct qlcnic_cmd_args *cmd) | ||
3601 | { | ||
3602 | struct qlcnic_mailbox *mbx = adapter->ahw->mailbox; | ||
3603 | |||
3604 | spin_lock(&mbx->queue_lock); | ||
3605 | |||
3606 | list_del(&cmd->list); | ||
3607 | mbx->num_cmds--; | ||
3608 | |||
3609 | spin_unlock(&mbx->queue_lock); | ||
3610 | |||
3611 | qlcnic_83xx_notify_cmd_completion(adapter, cmd); | ||
3612 | } | ||
3613 | |||
3614 | static void qlcnic_83xx_encode_mbx_cmd(struct qlcnic_adapter *adapter, | ||
3615 | struct qlcnic_cmd_args *cmd) | ||
3616 | { | ||
3617 | u32 mbx_cmd, fw_hal_version, hdr_size, total_size, tmp; | ||
3618 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
3619 | int i, j; | ||
3620 | |||
3621 | if (cmd->op_type != QLC_83XX_MBX_POST_BC_OP) { | ||
3622 | mbx_cmd = cmd->req.arg[0]; | ||
3623 | writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0)); | ||
3624 | for (i = 1; i < cmd->req.num; i++) | ||
3625 | writel(cmd->req.arg[i], QLCNIC_MBX_HOST(ahw, i)); | ||
3626 | } else { | ||
3627 | fw_hal_version = ahw->fw_hal_version; | ||
3628 | hdr_size = sizeof(struct qlcnic_bc_hdr) / sizeof(u32); | ||
3629 | total_size = cmd->pay_size + hdr_size; | ||
3630 | tmp = QLCNIC_CMD_BC_EVENT_SETUP | total_size << 16; | ||
3631 | mbx_cmd = tmp | fw_hal_version << 29; | ||
3632 | writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0)); | ||
3633 | |||
3634 | /* Back channel specific operations bits */ | ||
3635 | mbx_cmd = 0x1 | 1 << 4; | ||
3636 | |||
3637 | if (qlcnic_sriov_pf_check(adapter)) | ||
3638 | mbx_cmd |= cmd->func_num << 5; | ||
3639 | |||
3640 | writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 1)); | ||
3641 | |||
3642 | for (i = 2, j = 0; j < hdr_size; i++, j++) | ||
3643 | writel(*(cmd->hdr++), QLCNIC_MBX_HOST(ahw, i)); | ||
3644 | for (j = 0; j < cmd->pay_size; j++, i++) | ||
3645 | writel(*(cmd->pay++), QLCNIC_MBX_HOST(ahw, i)); | ||
3646 | } | ||
3647 | } | ||
3648 | |||
3649 | void qlcnic_83xx_detach_mailbox_work(struct qlcnic_adapter *adapter) | ||
3650 | { | ||
3651 | struct qlcnic_mailbox *mbx = adapter->ahw->mailbox; | ||
3652 | |||
3653 | clear_bit(QLC_83XX_MBX_READY, &mbx->status); | ||
3654 | complete(&mbx->completion); | ||
3655 | cancel_work_sync(&mbx->work); | ||
3656 | flush_workqueue(mbx->work_q); | ||
3657 | qlcnic_83xx_flush_mbx_queue(adapter); | ||
3658 | } | ||
3659 | |||
3660 | static int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter, | ||
3661 | struct qlcnic_cmd_args *cmd, | ||
3662 | unsigned long *timeout) | ||
3663 | { | ||
3664 | struct qlcnic_mailbox *mbx = adapter->ahw->mailbox; | ||
3665 | |||
3666 | if (test_bit(QLC_83XX_MBX_READY, &mbx->status)) { | ||
3667 | atomic_set(&cmd->rsp_status, QLC_83XX_MBX_RESPONSE_WAIT); | ||
3668 | init_completion(&cmd->completion); | ||
3669 | cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_UNKNOWN; | ||
3670 | |||
3671 | spin_lock(&mbx->queue_lock); | ||
3672 | |||
3673 | list_add_tail(&cmd->list, &mbx->cmd_q); | ||
3674 | mbx->num_cmds++; | ||
3675 | cmd->total_cmds = mbx->num_cmds; | ||
3676 | *timeout = cmd->total_cmds * QLC_83XX_MBX_TIMEOUT; | ||
3677 | queue_work(mbx->work_q, &mbx->work); | ||
3678 | |||
3679 | spin_unlock(&mbx->queue_lock); | ||
3680 | |||
3681 | return 0; | ||
3682 | } | ||
3683 | |||
3684 | return -EBUSY; | ||
3685 | } | ||
3686 | |||
3687 | static int qlcnic_83xx_check_mac_rcode(struct qlcnic_adapter *adapter, | ||
3688 | struct qlcnic_cmd_args *cmd) | ||
3689 | { | ||
3690 | u8 mac_cmd_rcode; | ||
3691 | u32 fw_data; | ||
3692 | |||
3693 | if (cmd->cmd_op == QLCNIC_CMD_CONFIG_MAC_VLAN) { | ||
3694 | fw_data = readl(QLCNIC_MBX_FW(adapter->ahw, 2)); | ||
3695 | mac_cmd_rcode = (u8)fw_data; | ||
3696 | if (mac_cmd_rcode == QLC_83XX_NO_NIC_RESOURCE || | ||
3697 | mac_cmd_rcode == QLC_83XX_MAC_PRESENT || | ||
3698 | mac_cmd_rcode == QLC_83XX_MAC_ABSENT) { | ||
3699 | cmd->rsp_opcode = QLCNIC_RCODE_SUCCESS; | ||
3700 | return QLCNIC_RCODE_SUCCESS; | ||
3701 | } | ||
3702 | } | ||
3703 | |||
3704 | return -EINVAL; | ||
3705 | } | ||
3706 | |||
3707 | static void qlcnic_83xx_decode_mbx_rsp(struct qlcnic_adapter *adapter, | ||
3708 | struct qlcnic_cmd_args *cmd) | ||
3709 | { | ||
3710 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
3711 | struct device *dev = &adapter->pdev->dev; | ||
3712 | u8 mbx_err_code; | ||
3713 | u32 fw_data; | ||
3714 | |||
3715 | fw_data = readl(QLCNIC_MBX_FW(ahw, 0)); | ||
3716 | mbx_err_code = QLCNIC_MBX_STATUS(fw_data); | ||
3717 | qlcnic_83xx_get_mbx_data(adapter, cmd); | ||
3718 | |||
3719 | switch (mbx_err_code) { | ||
3720 | case QLCNIC_MBX_RSP_OK: | ||
3721 | case QLCNIC_MBX_PORT_RSP_OK: | ||
3722 | cmd->rsp_opcode = QLCNIC_RCODE_SUCCESS; | ||
3723 | break; | ||
3724 | default: | ||
3725 | if (!qlcnic_83xx_check_mac_rcode(adapter, cmd)) | ||
3726 | break; | ||
3727 | |||
3728 | 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", | ||
3729 | __func__, cmd->cmd_op, cmd->type, ahw->pci_func, | ||
3730 | ahw->op_mode, mbx_err_code); | ||
3731 | cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_FAILED; | ||
3732 | qlcnic_dump_mbx(adapter, cmd); | ||
3733 | } | ||
3734 | |||
3735 | return; | ||
3736 | } | ||
3737 | |||
3738 | static void qlcnic_83xx_mailbox_worker(struct work_struct *work) | ||
3739 | { | ||
3740 | struct qlcnic_mailbox *mbx = container_of(work, struct qlcnic_mailbox, | ||
3741 | work); | ||
3742 | struct qlcnic_adapter *adapter = mbx->adapter; | ||
3743 | struct qlcnic_mbx_ops *mbx_ops = mbx->ops; | ||
3744 | struct device *dev = &adapter->pdev->dev; | ||
3745 | atomic_t *rsp_status = &mbx->rsp_status; | ||
3746 | struct list_head *head = &mbx->cmd_q; | ||
3747 | struct qlcnic_hardware_context *ahw; | ||
3748 | struct qlcnic_cmd_args *cmd = NULL; | ||
3749 | |||
3750 | ahw = adapter->ahw; | ||
3751 | |||
3752 | while (true) { | ||
3753 | if (qlcnic_83xx_check_mbx_status(adapter)) { | ||
3754 | qlcnic_83xx_flush_mbx_queue(adapter); | ||
3755 | return; | ||
3756 | } | ||
3757 | |||
3758 | atomic_set(rsp_status, QLC_83XX_MBX_RESPONSE_WAIT); | ||
3759 | |||
3760 | spin_lock(&mbx->queue_lock); | ||
3761 | |||
3762 | if (list_empty(head)) { | ||
3763 | spin_unlock(&mbx->queue_lock); | ||
3764 | return; | ||
3765 | } | ||
3766 | cmd = list_entry(head->next, struct qlcnic_cmd_args, list); | ||
3767 | |||
3768 | spin_unlock(&mbx->queue_lock); | ||
3769 | |||
3770 | mbx_ops->encode_cmd(adapter, cmd); | ||
3771 | mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_REQUEST); | ||
3772 | |||
3773 | if (wait_for_completion_timeout(&mbx->completion, | ||
3774 | QLC_83XX_MBX_TIMEOUT)) { | ||
3775 | mbx_ops->decode_resp(adapter, cmd); | ||
3776 | mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_COMPLETION); | ||
3777 | } else { | ||
3778 | dev_err(dev, "%s: Mailbox command timeout, opcode=0x%x, cmd_type=0x%x, func=0x%x, op_mode=0x%x\n", | ||
3779 | __func__, cmd->cmd_op, cmd->type, ahw->pci_func, | ||
3780 | ahw->op_mode); | ||
3781 | clear_bit(QLC_83XX_MBX_READY, &mbx->status); | ||
3782 | qlcnic_dump_mbx(adapter, cmd); | ||
3783 | qlcnic_83xx_idc_request_reset(adapter, | ||
3784 | QLCNIC_FORCE_FW_DUMP_KEY); | ||
3785 | cmd->rsp_opcode = QLCNIC_RCODE_TIMEOUT; | ||
3786 | } | ||
3787 | mbx_ops->dequeue_cmd(adapter, cmd); | ||
3788 | } | ||
3789 | } | ||
3790 | |||
3791 | static struct qlcnic_mbx_ops qlcnic_83xx_mbx_ops = { | ||
3792 | .enqueue_cmd = qlcnic_83xx_enqueue_mbx_cmd, | ||
3793 | .dequeue_cmd = qlcnic_83xx_dequeue_mbx_cmd, | ||
3794 | .decode_resp = qlcnic_83xx_decode_mbx_rsp, | ||
3795 | .encode_cmd = qlcnic_83xx_encode_mbx_cmd, | ||
3796 | .nofity_fw = qlcnic_83xx_signal_mbx_cmd, | ||
3797 | }; | ||
3798 | |||
3799 | int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *adapter) | ||
3800 | { | ||
3801 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
3802 | struct qlcnic_mailbox *mbx; | ||
3803 | |||
3804 | ahw->mailbox = kzalloc(sizeof(*mbx), GFP_KERNEL); | ||
3805 | if (!ahw->mailbox) | ||
3806 | return -ENOMEM; | ||
3807 | |||
3808 | mbx = ahw->mailbox; | ||
3809 | mbx->ops = &qlcnic_83xx_mbx_ops; | ||
3810 | mbx->adapter = adapter; | ||
3811 | |||
3812 | spin_lock_init(&mbx->queue_lock); | ||
3813 | spin_lock_init(&mbx->aen_lock); | ||
3814 | INIT_LIST_HEAD(&mbx->cmd_q); | ||
3815 | init_completion(&mbx->completion); | ||
3816 | |||
3817 | mbx->work_q = create_singlethread_workqueue("qlcnic_mailbox"); | ||
3818 | if (mbx->work_q == NULL) { | ||
3819 | kfree(mbx); | ||
3820 | return -ENOMEM; | ||
3821 | } | ||
3822 | |||
3823 | INIT_WORK(&mbx->work, qlcnic_83xx_mailbox_worker); | ||
3824 | set_bit(QLC_83XX_MBX_READY, &mbx->status); | ||
3825 | return 0; | ||
3826 | } | ||
3827 | |||
3828 | pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *pdev, | ||
3829 | pci_channel_state_t state) | ||
3830 | { | ||
3831 | struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); | ||
3832 | |||
3833 | if (state == pci_channel_io_perm_failure) | ||
3834 | return PCI_ERS_RESULT_DISCONNECT; | ||
3835 | |||
3836 | if (state == pci_channel_io_normal) | ||
3837 | return PCI_ERS_RESULT_RECOVERED; | ||
3838 | |||
3839 | set_bit(__QLCNIC_AER, &adapter->state); | ||
3840 | set_bit(__QLCNIC_RESETTING, &adapter->state); | ||
3841 | |||
3842 | qlcnic_83xx_aer_stop_poll_work(adapter); | ||
3843 | |||
3844 | pci_save_state(pdev); | ||
3845 | pci_disable_device(pdev); | ||
3846 | |||
3847 | return PCI_ERS_RESULT_NEED_RESET; | ||
3848 | } | ||
3849 | |||
3850 | pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *pdev) | ||
3851 | { | ||
3852 | struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); | ||
3853 | int err = 0; | ||
3854 | |||
3855 | pdev->error_state = pci_channel_io_normal; | ||
3856 | err = pci_enable_device(pdev); | ||
3857 | if (err) | ||
3858 | goto disconnect; | ||
3859 | |||
3860 | pci_set_power_state(pdev, PCI_D0); | ||
3861 | pci_set_master(pdev); | ||
3862 | pci_restore_state(pdev); | ||
3863 | |||
3864 | err = qlcnic_83xx_aer_reset(adapter); | ||
3865 | if (err == 0) | ||
3866 | return PCI_ERS_RESULT_RECOVERED; | ||
3867 | disconnect: | ||
3868 | clear_bit(__QLCNIC_AER, &adapter->state); | ||
3869 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | ||
3870 | return PCI_ERS_RESULT_DISCONNECT; | ||
3871 | } | ||
3872 | |||
3873 | void qlcnic_83xx_io_resume(struct pci_dev *pdev) | ||
3874 | { | ||
3875 | struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); | ||
3876 | |||
3877 | pci_cleanup_aer_uncorrect_error_status(pdev); | ||
3878 | if (test_and_clear_bit(__QLCNIC_AER, &adapter->state)) | ||
3879 | qlcnic_83xx_aer_start_poll_work(adapter); | ||
3880 | } | ||