diff options
author | Amit Kumar Salecha <amit.salecha@qlogic.com> | 2010-10-07 19:46:06 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-10-08 16:59:08 -0400 |
commit | b8c17620458b82fd868f4813e1ff18368a832b7c (patch) | |
tree | 3ddb3763c05bb4fae4e33c0f8b6041287235de1d /drivers/net/qlcnic | |
parent | f7ec804a3edd2f7cf98a42bcad741d89d547c117 (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.h | 2 | ||||
-rw-r--r-- | drivers/net/qlcnic/qlcnic_ethtool.c | 6 | ||||
-rw-r--r-- | drivers/net/qlcnic/qlcnic_main.c | 83 |
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); | |||
1313 | void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *); | 1313 | void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *); |
1314 | 1314 | ||
1315 | /* Functions from qlcnic_main.c */ | 1315 | /* Functions from qlcnic_main.c */ |
1316 | int qlcnic_request_quiscent_mode(struct qlcnic_adapter *adapter); | ||
1317 | void qlcnic_clear_quiscent_mode(struct qlcnic_adapter *adapter); | ||
1316 | int qlcnic_reset_context(struct qlcnic_adapter *); | 1318 | int qlcnic_reset_context(struct qlcnic_adapter *); |
1317 | u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter, | 1319 | u32 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 | ||
724 | clear_it: | 729 | clear_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) | |||
2734 | skip_ack_check: | 2735 | skip_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 | */ | ||
2844 | void 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 | */ | ||
2854 | int 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 */ |
2848 | static void | 2897 | static void |
2849 | qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) | 2898 | qlcnic_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) { |