diff options
author | Zhu Yi <yi.zhu@intel.com> | 2008-01-24 05:19:38 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:09:58 -0500 |
commit | e655b9f03f41c7a84fb74d6619abf844d7f2ab65 (patch) | |
tree | 219be4a1e49e9d630874684b6996e9d0a73d166c /drivers/net/wireless | |
parent | 5a66926aa9230810704fd5a127966215fd58881e (diff) |
iwlwifi: fix problem when rf_killswitch change during suspend/resume
After we delay device initialization until interface up, there are more
conditions for the hardware rf_kill switch states during suspend and
resume. For example, before suspend we can have interface up or down,
rf_kill enable or disable; before resume we can have rf_kill enable or
disable. So there are totally 2^3 = 8 conditions to handle. This patch
addressed this problem and makes sure every condition works correctly.
This patch also merges the device suspend and resume handlers with the
mac_start and mac_stop code since they are basically doing the same
thing.
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 124 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl4965-base.c | 133 |
2 files changed, 90 insertions, 167 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e0e9bbdf140f..b9a74f5eea51 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -6340,7 +6340,19 @@ static int __iwl3945_up(struct iwl3945_priv *priv) | |||
6340 | if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { | 6340 | if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { |
6341 | IWL_WARNING("Radio disabled by SW RF kill (module " | 6341 | IWL_WARNING("Radio disabled by SW RF kill (module " |
6342 | "parameter)\n"); | 6342 | "parameter)\n"); |
6343 | return 0; | 6343 | return -ENODEV; |
6344 | } | ||
6345 | |||
6346 | /* If platform's RF_KILL switch is NOT set to KILL */ | ||
6347 | if (iwl3945_read32(priv, CSR_GP_CNTRL) & | ||
6348 | CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) | ||
6349 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | ||
6350 | else { | ||
6351 | set_bit(STATUS_RF_KILL_HW, &priv->status); | ||
6352 | if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) { | ||
6353 | IWL_WARNING("Radio disabled by HW RF Kill switch\n"); | ||
6354 | return -ENODEV; | ||
6355 | } | ||
6344 | } | 6356 | } |
6345 | 6357 | ||
6346 | if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { | 6358 | if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { |
@@ -6375,6 +6387,10 @@ static int __iwl3945_up(struct iwl3945_priv *priv) | |||
6375 | memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, | 6387 | memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, |
6376 | priv->ucode_data.len); | 6388 | priv->ucode_data.len); |
6377 | 6389 | ||
6390 | /* We return success when we resume from suspend and rf_kill is on. */ | ||
6391 | if (test_bit(STATUS_RF_KILL_HW, &priv->status)) | ||
6392 | return 0; | ||
6393 | |||
6378 | for (i = 0; i < MAX_HW_RESTARTS; i++) { | 6394 | for (i = 0; i < MAX_HW_RESTARTS; i++) { |
6379 | 6395 | ||
6380 | iwl3945_clear_stations_table(priv); | 6396 | iwl3945_clear_stations_table(priv); |
@@ -6919,12 +6935,18 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) | |||
6919 | } | 6935 | } |
6920 | } | 6936 | } |
6921 | 6937 | ||
6922 | IWL_DEBUG_INFO("Start UP work.\n"); | 6938 | ret = __iwl3945_up(priv); |
6923 | __iwl3945_up(priv); | ||
6924 | 6939 | ||
6925 | priv->is_open = 1; | ||
6926 | mutex_unlock(&priv->mutex); | 6940 | mutex_unlock(&priv->mutex); |
6927 | 6941 | ||
6942 | if (ret) | ||
6943 | goto out_release_irq; | ||
6944 | |||
6945 | IWL_DEBUG_INFO("Start UP work.\n"); | ||
6946 | |||
6947 | if (test_bit(STATUS_IN_SUSPEND, &priv->status)) | ||
6948 | return 0; | ||
6949 | |||
6928 | /* Wait for START_ALIVE from ucode. Otherwise callbacks from | 6950 | /* Wait for START_ALIVE from ucode. Otherwise callbacks from |
6929 | * mac80211 will not be run successfully. */ | 6951 | * mac80211 will not be run successfully. */ |
6930 | ret = wait_event_interruptible_timeout(priv->wait_command_queue, | 6952 | ret = wait_event_interruptible_timeout(priv->wait_command_queue, |
@@ -6939,6 +6961,7 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) | |||
6939 | } | 6961 | } |
6940 | } | 6962 | } |
6941 | 6963 | ||
6964 | priv->is_open = 1; | ||
6942 | IWL_DEBUG_MAC80211("leave\n"); | 6965 | IWL_DEBUG_MAC80211("leave\n"); |
6943 | return 0; | 6966 | return 0; |
6944 | 6967 | ||
@@ -6946,6 +6969,9 @@ out_release_irq: | |||
6946 | free_irq(priv->pci_dev->irq, priv); | 6969 | free_irq(priv->pci_dev->irq, priv); |
6947 | out_disable_msi: | 6970 | out_disable_msi: |
6948 | pci_disable_msi(priv->pci_dev); | 6971 | pci_disable_msi(priv->pci_dev); |
6972 | pci_disable_device(priv->pci_dev); | ||
6973 | priv->is_open = 0; | ||
6974 | IWL_DEBUG_MAC80211("leave - failed\n"); | ||
6949 | return ret; | 6975 | return ret; |
6950 | } | 6976 | } |
6951 | 6977 | ||
@@ -6955,12 +6981,17 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw) | |||
6955 | 6981 | ||
6956 | IWL_DEBUG_MAC80211("enter\n"); | 6982 | IWL_DEBUG_MAC80211("enter\n"); |
6957 | 6983 | ||
6958 | /* stop mac, cancel any scan request and clear | 6984 | if (!priv->is_open) { |
6959 | * RXON_FILTER_ASSOC_MSK BIT | 6985 | IWL_DEBUG_MAC80211("leave - skip\n"); |
6960 | */ | 6986 | return; |
6987 | } | ||
6988 | |||
6961 | priv->is_open = 0; | 6989 | priv->is_open = 0; |
6962 | 6990 | ||
6963 | if (iwl3945_is_ready_rf(priv)) { | 6991 | if (iwl3945_is_ready_rf(priv)) { |
6992 | /* stop mac, cancel any scan request and clear | ||
6993 | * RXON_FILTER_ASSOC_MSK BIT | ||
6994 | */ | ||
6964 | mutex_lock(&priv->mutex); | 6995 | mutex_lock(&priv->mutex); |
6965 | iwl3945_scan_cancel_timeout(priv, 100); | 6996 | iwl3945_scan_cancel_timeout(priv, 100); |
6966 | cancel_delayed_work(&priv->post_associate); | 6997 | cancel_delayed_work(&priv->post_associate); |
@@ -7334,7 +7365,6 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, | |||
7334 | mutex_unlock(&priv->mutex); | 7365 | mutex_unlock(&priv->mutex); |
7335 | 7366 | ||
7336 | IWL_DEBUG_MAC80211("leave\n"); | 7367 | IWL_DEBUG_MAC80211("leave\n"); |
7337 | |||
7338 | } | 7368 | } |
7339 | 7369 | ||
7340 | static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) | 7370 | static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) |
@@ -8731,89 +8761,27 @@ static int iwl3945_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
8731 | { | 8761 | { |
8732 | struct iwl3945_priv *priv = pci_get_drvdata(pdev); | 8762 | struct iwl3945_priv *priv = pci_get_drvdata(pdev); |
8733 | 8763 | ||
8734 | set_bit(STATUS_IN_SUSPEND, &priv->status); | 8764 | if (priv->is_open) { |
8735 | 8765 | set_bit(STATUS_IN_SUSPEND, &priv->status); | |
8736 | /* Take down the device; powers it off, etc. */ | 8766 | iwl3945_mac_stop(priv->hw); |
8737 | iwl3945_down(priv); | 8767 | priv->is_open = 1; |
8738 | 8768 | } | |
8739 | if (priv->mac80211_registered) | ||
8740 | ieee80211_stop_queues(priv->hw); | ||
8741 | 8769 | ||
8742 | pci_save_state(pdev); | ||
8743 | pci_disable_device(pdev); | ||
8744 | pci_set_power_state(pdev, PCI_D3hot); | 8770 | pci_set_power_state(pdev, PCI_D3hot); |
8745 | 8771 | ||
8746 | return 0; | 8772 | return 0; |
8747 | } | 8773 | } |
8748 | 8774 | ||
8749 | static void iwl3945_resume(struct iwl3945_priv *priv) | ||
8750 | { | ||
8751 | unsigned long flags; | ||
8752 | |||
8753 | /* The following it a temporary work around due to the | ||
8754 | * suspend / resume not fully initializing the NIC correctly. | ||
8755 | * Without all of the following, resume will not attempt to take | ||
8756 | * down the NIC (it shouldn't really need to) and will just try | ||
8757 | * and bring the NIC back up. However that fails during the | ||
8758 | * ucode verification process. This then causes iwl3945_down to be | ||
8759 | * called *after* iwl3945_hw_nic_init() has succeeded -- which | ||
8760 | * then lets the next init sequence succeed. So, we've | ||
8761 | * replicated all of that NIC init code here... */ | ||
8762 | |||
8763 | iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF); | ||
8764 | |||
8765 | iwl3945_hw_nic_init(priv); | ||
8766 | |||
8767 | iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | ||
8768 | iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, | ||
8769 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | ||
8770 | iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF); | ||
8771 | iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | ||
8772 | iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | ||
8773 | |||
8774 | /* tell the device to stop sending interrupts */ | ||
8775 | iwl3945_disable_interrupts(priv); | ||
8776 | |||
8777 | spin_lock_irqsave(&priv->lock, flags); | ||
8778 | iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
8779 | |||
8780 | if (!iwl3945_grab_nic_access(priv)) { | ||
8781 | iwl3945_write_prph(priv, APMG_CLK_DIS_REG, | ||
8782 | APMG_CLK_VAL_DMA_CLK_RQT); | ||
8783 | iwl3945_release_nic_access(priv); | ||
8784 | } | ||
8785 | spin_unlock_irqrestore(&priv->lock, flags); | ||
8786 | |||
8787 | udelay(5); | ||
8788 | |||
8789 | iwl3945_hw_nic_reset(priv); | ||
8790 | |||
8791 | /* Bring the device back up */ | ||
8792 | clear_bit(STATUS_IN_SUSPEND, &priv->status); | ||
8793 | queue_work(priv->workqueue, &priv->up); | ||
8794 | } | ||
8795 | |||
8796 | static int iwl3945_pci_resume(struct pci_dev *pdev) | 8775 | static int iwl3945_pci_resume(struct pci_dev *pdev) |
8797 | { | 8776 | { |
8798 | struct iwl3945_priv *priv = pci_get_drvdata(pdev); | 8777 | struct iwl3945_priv *priv = pci_get_drvdata(pdev); |
8799 | int err; | ||
8800 | |||
8801 | printk(KERN_INFO "Coming out of suspend...\n"); | ||
8802 | 8778 | ||
8803 | pci_set_power_state(pdev, PCI_D0); | 8779 | pci_set_power_state(pdev, PCI_D0); |
8804 | err = pci_enable_device(pdev); | ||
8805 | pci_restore_state(pdev); | ||
8806 | 8780 | ||
8807 | /* | 8781 | if (priv->is_open) |
8808 | * Suspend/Resume resets the PCI configuration space, so we have to | 8782 | iwl3945_mac_start(priv->hw); |
8809 | * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries | ||
8810 | * from interfering with C3 CPU state. pci_restore_state won't help | ||
8811 | * here since it only restores the first 64 bytes pci config header. | ||
8812 | */ | ||
8813 | pci_write_config_byte(pdev, 0x41, 0x00); | ||
8814 | |||
8815 | iwl3945_resume(priv); | ||
8816 | 8783 | ||
8784 | clear_bit(STATUS_IN_SUSPEND, &priv->status); | ||
8817 | return 0; | 8785 | return 0; |
8818 | } | 8786 | } |
8819 | 8787 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 98f09e6e9f8c..811e41b7f664 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c | |||
@@ -6761,7 +6761,6 @@ static void iwl4965_down(struct iwl4965_priv *priv) | |||
6761 | static int __iwl4965_up(struct iwl4965_priv *priv) | 6761 | static int __iwl4965_up(struct iwl4965_priv *priv) |
6762 | { | 6762 | { |
6763 | int rc, i; | 6763 | int rc, i; |
6764 | u32 hw_rf_kill = 0; | ||
6765 | 6764 | ||
6766 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { | 6765 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { |
6767 | IWL_WARNING("Exit pending; will not bring the NIC up\n"); | 6766 | IWL_WARNING("Exit pending; will not bring the NIC up\n"); |
@@ -6771,7 +6770,19 @@ static int __iwl4965_up(struct iwl4965_priv *priv) | |||
6771 | if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { | 6770 | if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { |
6772 | IWL_WARNING("Radio disabled by SW RF kill (module " | 6771 | IWL_WARNING("Radio disabled by SW RF kill (module " |
6773 | "parameter)\n"); | 6772 | "parameter)\n"); |
6774 | return 0; | 6773 | return -ENODEV; |
6774 | } | ||
6775 | |||
6776 | /* If platform's RF_KILL switch is NOT set to KILL */ | ||
6777 | if (iwl4965_read32(priv, CSR_GP_CNTRL) & | ||
6778 | CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) | ||
6779 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | ||
6780 | else { | ||
6781 | set_bit(STATUS_RF_KILL_HW, &priv->status); | ||
6782 | if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) { | ||
6783 | IWL_WARNING("Radio disabled by HW RF Kill switch\n"); | ||
6784 | return -ENODEV; | ||
6785 | } | ||
6775 | } | 6786 | } |
6776 | 6787 | ||
6777 | if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { | 6788 | if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { |
@@ -6806,17 +6817,9 @@ static int __iwl4965_up(struct iwl4965_priv *priv) | |||
6806 | memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, | 6817 | memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, |
6807 | priv->ucode_data.len); | 6818 | priv->ucode_data.len); |
6808 | 6819 | ||
6809 | /* If platform's RF_KILL switch is set to KILL, | 6820 | /* We return success when we resume from suspend and rf_kill is on. */ |
6810 | * wait for BIT_INT_RF_KILL interrupt before loading uCode | 6821 | if (test_bit(STATUS_RF_KILL_HW, &priv->status)) |
6811 | * and getting things started */ | ||
6812 | if (!(iwl4965_read32(priv, CSR_GP_CNTRL) & | ||
6813 | CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) | ||
6814 | hw_rf_kill = 1; | ||
6815 | |||
6816 | if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) { | ||
6817 | IWL_WARNING("Radio disabled by HW RF Kill switch\n"); | ||
6818 | return 0; | 6822 | return 0; |
6819 | } | ||
6820 | 6823 | ||
6821 | for (i = 0; i < MAX_HW_RESTARTS; i++) { | 6824 | for (i = 0; i < MAX_HW_RESTARTS; i++) { |
6822 | 6825 | ||
@@ -7379,12 +7382,18 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) | |||
7379 | } | 7382 | } |
7380 | } | 7383 | } |
7381 | 7384 | ||
7382 | IWL_DEBUG_INFO("Start UP work.\n"); | 7385 | ret = __iwl4965_up(priv); |
7383 | __iwl4965_up(priv); | ||
7384 | 7386 | ||
7385 | priv->is_open = 1; | ||
7386 | mutex_unlock(&priv->mutex); | 7387 | mutex_unlock(&priv->mutex); |
7387 | 7388 | ||
7389 | if (ret) | ||
7390 | goto out_release_irq; | ||
7391 | |||
7392 | IWL_DEBUG_INFO("Start UP work done.\n"); | ||
7393 | |||
7394 | if (test_bit(STATUS_IN_SUSPEND, &priv->status)) | ||
7395 | return 0; | ||
7396 | |||
7388 | /* Wait for START_ALIVE from ucode. Otherwise callbacks from | 7397 | /* Wait for START_ALIVE from ucode. Otherwise callbacks from |
7389 | * mac80211 will not be run successfully. */ | 7398 | * mac80211 will not be run successfully. */ |
7390 | ret = wait_event_interruptible_timeout(priv->wait_command_queue, | 7399 | ret = wait_event_interruptible_timeout(priv->wait_command_queue, |
@@ -7399,6 +7408,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) | |||
7399 | } | 7408 | } |
7400 | } | 7409 | } |
7401 | 7410 | ||
7411 | priv->is_open = 1; | ||
7402 | IWL_DEBUG_MAC80211("leave\n"); | 7412 | IWL_DEBUG_MAC80211("leave\n"); |
7403 | return 0; | 7413 | return 0; |
7404 | 7414 | ||
@@ -7406,6 +7416,9 @@ out_release_irq: | |||
7406 | free_irq(priv->pci_dev->irq, priv); | 7416 | free_irq(priv->pci_dev->irq, priv); |
7407 | out_disable_msi: | 7417 | out_disable_msi: |
7408 | pci_disable_msi(priv->pci_dev); | 7418 | pci_disable_msi(priv->pci_dev); |
7419 | pci_disable_device(priv->pci_dev); | ||
7420 | priv->is_open = 0; | ||
7421 | IWL_DEBUG_MAC80211("leave - failed\n"); | ||
7409 | return ret; | 7422 | return ret; |
7410 | } | 7423 | } |
7411 | 7424 | ||
@@ -7415,12 +7428,17 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) | |||
7415 | 7428 | ||
7416 | IWL_DEBUG_MAC80211("enter\n"); | 7429 | IWL_DEBUG_MAC80211("enter\n"); |
7417 | 7430 | ||
7418 | /* stop mac, cancel any scan request and clear | 7431 | if (!priv->is_open) { |
7419 | * RXON_FILTER_ASSOC_MSK BIT | 7432 | IWL_DEBUG_MAC80211("leave - skip\n"); |
7420 | */ | 7433 | return; |
7434 | } | ||
7435 | |||
7421 | priv->is_open = 0; | 7436 | priv->is_open = 0; |
7422 | 7437 | ||
7423 | if (iwl4965_is_ready_rf(priv)) { | 7438 | if (iwl4965_is_ready_rf(priv)) { |
7439 | /* stop mac, cancel any scan request and clear | ||
7440 | * RXON_FILTER_ASSOC_MSK BIT | ||
7441 | */ | ||
7424 | mutex_lock(&priv->mutex); | 7442 | mutex_lock(&priv->mutex); |
7425 | iwl4965_scan_cancel_timeout(priv, 100); | 7443 | iwl4965_scan_cancel_timeout(priv, 100); |
7426 | cancel_delayed_work(&priv->post_associate); | 7444 | cancel_delayed_work(&priv->post_associate); |
@@ -8152,7 +8170,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) | |||
8152 | mutex_unlock(&priv->mutex); | 8170 | mutex_unlock(&priv->mutex); |
8153 | 8171 | ||
8154 | IWL_DEBUG_MAC80211("leave\n"); | 8172 | IWL_DEBUG_MAC80211("leave\n"); |
8155 | |||
8156 | } | 8173 | } |
8157 | 8174 | ||
8158 | static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, | 8175 | static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, |
@@ -9327,89 +9344,27 @@ static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
9327 | { | 9344 | { |
9328 | struct iwl4965_priv *priv = pci_get_drvdata(pdev); | 9345 | struct iwl4965_priv *priv = pci_get_drvdata(pdev); |
9329 | 9346 | ||
9330 | set_bit(STATUS_IN_SUSPEND, &priv->status); | 9347 | if (priv->is_open) { |
9331 | 9348 | set_bit(STATUS_IN_SUSPEND, &priv->status); | |
9332 | /* Take down the device; powers it off, etc. */ | 9349 | iwl4965_mac_stop(priv->hw); |
9333 | iwl4965_down(priv); | 9350 | priv->is_open = 1; |
9334 | 9351 | } | |
9335 | if (priv->mac80211_registered) | ||
9336 | ieee80211_stop_queues(priv->hw); | ||
9337 | 9352 | ||
9338 | pci_save_state(pdev); | ||
9339 | pci_disable_device(pdev); | ||
9340 | pci_set_power_state(pdev, PCI_D3hot); | 9353 | pci_set_power_state(pdev, PCI_D3hot); |
9341 | 9354 | ||
9342 | return 0; | 9355 | return 0; |
9343 | } | 9356 | } |
9344 | 9357 | ||
9345 | static void iwl4965_resume(struct iwl4965_priv *priv) | ||
9346 | { | ||
9347 | unsigned long flags; | ||
9348 | |||
9349 | /* The following it a temporary work around due to the | ||
9350 | * suspend / resume not fully initializing the NIC correctly. | ||
9351 | * Without all of the following, resume will not attempt to take | ||
9352 | * down the NIC (it shouldn't really need to) and will just try | ||
9353 | * and bring the NIC back up. However that fails during the | ||
9354 | * ucode verification process. This then causes iwl4965_down to be | ||
9355 | * called *after* iwl4965_hw_nic_init() has succeeded -- which | ||
9356 | * then lets the next init sequence succeed. So, we've | ||
9357 | * replicated all of that NIC init code here... */ | ||
9358 | |||
9359 | iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF); | ||
9360 | |||
9361 | iwl4965_hw_nic_init(priv); | ||
9362 | |||
9363 | iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | ||
9364 | iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, | ||
9365 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | ||
9366 | iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF); | ||
9367 | iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | ||
9368 | iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | ||
9369 | |||
9370 | /* tell the device to stop sending interrupts */ | ||
9371 | iwl4965_disable_interrupts(priv); | ||
9372 | |||
9373 | spin_lock_irqsave(&priv->lock, flags); | ||
9374 | iwl4965_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
9375 | |||
9376 | if (!iwl4965_grab_nic_access(priv)) { | ||
9377 | iwl4965_write_prph(priv, APMG_CLK_DIS_REG, | ||
9378 | APMG_CLK_VAL_DMA_CLK_RQT); | ||
9379 | iwl4965_release_nic_access(priv); | ||
9380 | } | ||
9381 | spin_unlock_irqrestore(&priv->lock, flags); | ||
9382 | |||
9383 | udelay(5); | ||
9384 | |||
9385 | iwl4965_hw_nic_reset(priv); | ||
9386 | |||
9387 | /* Bring the device back up */ | ||
9388 | clear_bit(STATUS_IN_SUSPEND, &priv->status); | ||
9389 | queue_work(priv->workqueue, &priv->up); | ||
9390 | } | ||
9391 | |||
9392 | static int iwl4965_pci_resume(struct pci_dev *pdev) | 9358 | static int iwl4965_pci_resume(struct pci_dev *pdev) |
9393 | { | 9359 | { |
9394 | struct iwl4965_priv *priv = pci_get_drvdata(pdev); | 9360 | struct iwl4965_priv *priv = pci_get_drvdata(pdev); |
9395 | int err; | ||
9396 | |||
9397 | printk(KERN_INFO "Coming out of suspend...\n"); | ||
9398 | 9361 | ||
9399 | pci_set_power_state(pdev, PCI_D0); | 9362 | pci_set_power_state(pdev, PCI_D0); |
9400 | err = pci_enable_device(pdev); | ||
9401 | pci_restore_state(pdev); | ||
9402 | 9363 | ||
9403 | /* | 9364 | if (priv->is_open) |
9404 | * Suspend/Resume resets the PCI configuration space, so we have to | 9365 | iwl4965_mac_start(priv->hw); |
9405 | * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries | ||
9406 | * from interfering with C3 CPU state. pci_restore_state won't help | ||
9407 | * here since it only restores the first 64 bytes pci config header. | ||
9408 | */ | ||
9409 | pci_write_config_byte(pdev, 0x41, 0x00); | ||
9410 | |||
9411 | iwl4965_resume(priv); | ||
9412 | 9366 | ||
9367 | clear_bit(STATUS_IN_SUSPEND, &priv->status); | ||
9413 | return 0; | 9368 | return 0; |
9414 | } | 9369 | } |
9415 | 9370 | ||