aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/qlcnic
diff options
context:
space:
mode:
authorAmit Kumar Salecha <amit.salecha@qlogic.com>2010-10-07 19:46:06 -0400
committerDavid S. Miller <davem@davemloft.net>2010-10-08 16:59:08 -0400
commitb8c17620458b82fd868f4813e1ff18368a832b7c (patch)
tree3ddb3763c05bb4fae4e33c0f8b6041287235de1d /drivers/net/qlcnic
parentf7ec804a3edd2f7cf98a42bcad741d89d547c117 (diff)
qlcnic: support quiescent mode
Put device in quiescent mode during internal loopback test. Before running test, set state to NEED_QUISCENT. After getting ack from all function, change state to QUISCENT and perform test. Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlcnic')
-rw-r--r--drivers/net/qlcnic/qlcnic.h2
-rw-r--r--drivers/net/qlcnic/qlcnic_ethtool.c6
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c83
3 files changed, 74 insertions, 17 deletions
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index a1fabdc10b59..6909cfc6d2bd 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -1313,6 +1313,8 @@ int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
1313void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *); 1313void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);
1314 1314
1315/* Functions from qlcnic_main.c */ 1315/* Functions from qlcnic_main.c */
1316int qlcnic_request_quiscent_mode(struct qlcnic_adapter *adapter);
1317void qlcnic_clear_quiscent_mode(struct qlcnic_adapter *adapter);
1316int qlcnic_reset_context(struct qlcnic_adapter *); 1318int qlcnic_reset_context(struct qlcnic_adapter *);
1317u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter, 1319u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
1318 u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd); 1320 u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd);
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 6a760140f792..018130193b5b 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -706,6 +706,11 @@ static int qlcnic_loopback_test(struct net_device *netdev)
706 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) 706 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
707 return -EIO; 707 return -EIO;
708 708
709 if (qlcnic_request_quiscent_mode(adapter)) {
710 clear_bit(__QLCNIC_RESETTING, &adapter->state);
711 return -EIO;
712 }
713
709 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST); 714 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
710 if (ret) 715 if (ret)
711 goto clear_it; 716 goto clear_it;
@@ -722,6 +727,7 @@ done:
722 qlcnic_diag_free_res(netdev, max_sds_rings); 727 qlcnic_diag_free_res(netdev, max_sds_rings);
723 728
724clear_it: 729clear_it:
730 qlcnic_clear_quiscent_mode(adapter);
725 adapter->max_sds_rings = max_sds_rings; 731 adapter->max_sds_rings = max_sds_rings;
726 clear_bit(__QLCNIC_RESETTING, &adapter->state); 732 clear_bit(__QLCNIC_RESETTING, &adapter->state);
727 return ret; 733 return ret;
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 7503c487075c..9b0acfb23e4c 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -2712,7 +2712,8 @@ qlcnic_fwinit_work(struct work_struct *work)
2712 goto err_ret; 2712 goto err_ret;
2713 2713
2714 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); 2714 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2715 if (dev_state == QLCNIC_DEV_QUISCENT) { 2715 if (dev_state == QLCNIC_DEV_QUISCENT ||
2716 dev_state == QLCNIC_DEV_NEED_QUISCENT) {
2716 qlcnic_api_unlock(adapter); 2717 qlcnic_api_unlock(adapter);
2717 qlcnic_schedule_work(adapter, qlcnic_fwinit_work, 2718 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2718 FW_POLL_DELAY * 2); 2719 FW_POLL_DELAY * 2);
@@ -2734,18 +2735,6 @@ qlcnic_fwinit_work(struct work_struct *work)
2734skip_ack_check: 2735skip_ack_check:
2735 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); 2736 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2736 2737
2737 if (dev_state == QLCNIC_DEV_NEED_QUISCENT) {
2738 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2739 QLCNIC_DEV_QUISCENT);
2740 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2741 FW_POLL_DELAY * 2);
2742 QLCDB(adapter, DRV, "Quiscing the driver\n");
2743 qlcnic_idc_debug_info(adapter, 0);
2744
2745 qlcnic_api_unlock(adapter);
2746 return;
2747 }
2748
2749 if (dev_state == QLCNIC_DEV_NEED_RESET) { 2738 if (dev_state == QLCNIC_DEV_NEED_RESET) {
2750 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, 2739 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2751 QLCNIC_DEV_INITIALIZING); 2740 QLCNIC_DEV_INITIALIZING);
@@ -2802,7 +2791,12 @@ qlcnic_detach_work(struct work_struct *work)
2802 2791
2803 netif_device_detach(netdev); 2792 netif_device_detach(netdev);
2804 2793
2805 qlcnic_down(adapter, netdev); 2794 /* Dont grab rtnl lock during Quiscent mode */
2795 if (adapter->dev_state == QLCNIC_DEV_NEED_QUISCENT) {
2796 if (netif_running(netdev))
2797 __qlcnic_down(adapter, netdev);
2798 } else
2799 qlcnic_down(adapter, netdev);
2806 2800
2807 status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1); 2801 status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
2808 2802
@@ -2844,6 +2838,61 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
2844 qlcnic_api_unlock(adapter); 2838 qlcnic_api_unlock(adapter);
2845} 2839}
2846 2840
2841/* Caller should held RESETTING bit.
2842 * This should be call in sync with qlcnic_request_quiscent_mode.
2843 */
2844void qlcnic_clear_quiscent_mode(struct qlcnic_adapter *adapter)
2845{
2846 qlcnic_clr_drv_state(adapter);
2847 qlcnic_api_lock(adapter);
2848 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
2849 qlcnic_api_unlock(adapter);
2850}
2851
2852/* Caller should held RESETTING bit.
2853 */
2854int qlcnic_request_quiscent_mode(struct qlcnic_adapter *adapter)
2855{
2856 u8 timeo = adapter->dev_init_timeo / 2;
2857 u32 state;
2858
2859 if (qlcnic_api_lock(adapter))
2860 return -EIO;
2861
2862 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2863 if (state != QLCNIC_DEV_READY)
2864 return -EIO;
2865
2866 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_QUISCENT);
2867 qlcnic_api_unlock(adapter);
2868 QLCDB(adapter, DRV, "NEED QUISCENT state set\n");
2869 qlcnic_idc_debug_info(adapter, 0);
2870
2871 qlcnic_set_drv_state(adapter, QLCNIC_DEV_NEED_QUISCENT);
2872
2873 do {
2874 msleep(2000);
2875 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2876 if (state == QLCNIC_DEV_QUISCENT)
2877 return 0;
2878 if (!qlcnic_check_drv_state(adapter)) {
2879 if (qlcnic_api_lock(adapter))
2880 return -EIO;
2881 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2882 QLCNIC_DEV_QUISCENT);
2883 qlcnic_api_unlock(adapter);
2884 QLCDB(adapter, DRV, "QUISCENT mode set\n");
2885 return 0;
2886 }
2887 } while (--timeo);
2888
2889 dev_err(&adapter->pdev->dev, "Failed to quiesce device, DRV_STATE=%08x"
2890 " DRV_ACTIVE=%08x\n", QLCRD32(adapter, QLCNIC_CRB_DRV_STATE),
2891 QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE));
2892 qlcnic_clear_quiscent_mode(adapter);
2893 return -EIO;
2894}
2895
2847/*Transit to RESET state from READY state only */ 2896/*Transit to RESET state from READY state only */
2848static void 2897static void
2849qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) 2898qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
@@ -2951,11 +3000,11 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
2951 qlcnic_dev_request_reset(adapter); 3000 qlcnic_dev_request_reset(adapter);
2952 3001
2953 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); 3002 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2954 if (state == QLCNIC_DEV_NEED_RESET || 3003 if (state == QLCNIC_DEV_NEED_RESET) {
2955 state == QLCNIC_DEV_NEED_QUISCENT) {
2956 qlcnic_set_npar_non_operational(adapter); 3004 qlcnic_set_npar_non_operational(adapter);
2957 adapter->need_fw_reset = 1; 3005 adapter->need_fw_reset = 1;
2958 } 3006 } else if (state == QLCNIC_DEV_NEED_QUISCENT)
3007 goto detach;
2959 3008
2960 heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); 3009 heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
2961 if (heartbeat != adapter->heartbeat) { 3010 if (heartbeat != adapter->heartbeat) {