diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 110 |
1 files changed, 56 insertions, 54 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b18596fed903..be14cd942a53 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -1399,13 +1399,16 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) | |||
1399 | hw_rf_kill ? "disable radio" : "enable radio"); | 1399 | hw_rf_kill ? "disable radio" : "enable radio"); |
1400 | 1400 | ||
1401 | /* driver only loads ucode once setting the interface up. | 1401 | /* driver only loads ucode once setting the interface up. |
1402 | * the driver as well won't allow loading if RFKILL is set | 1402 | * the driver allows loading the ucode even if the radio |
1403 | * therefore no need to restart the driver from this handler | 1403 | * is killed. Hence update the killswitch state here. The |
1404 | * rfkill handler will care about restarting if needed. | ||
1404 | */ | 1405 | */ |
1405 | if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { | 1406 | if (!test_bit(STATUS_ALIVE, &priv->status)) { |
1406 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | 1407 | if (hw_rf_kill) |
1407 | if (priv->is_open && !iwl_is_rfkill(priv)) | 1408 | set_bit(STATUS_RF_KILL_HW, &priv->status); |
1408 | queue_work(priv->workqueue, &priv->up); | 1409 | else |
1410 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | ||
1411 | queue_work(priv->workqueue, &priv->rf_kill); | ||
1409 | } | 1412 | } |
1410 | 1413 | ||
1411 | handled |= CSR_INT_BIT_RF_KILL; | 1414 | handled |= CSR_INT_BIT_RF_KILL; |
@@ -2158,7 +2161,8 @@ static void iwl_bg_rf_kill(struct work_struct *work) | |||
2158 | IWL_DEBUG(IWL_DL_RF_KILL, | 2161 | IWL_DEBUG(IWL_DL_RF_KILL, |
2159 | "HW and/or SW RF Kill no longer active, restarting " | 2162 | "HW and/or SW RF Kill no longer active, restarting " |
2160 | "device\n"); | 2163 | "device\n"); |
2161 | if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2164 | if (!test_bit(STATUS_EXIT_PENDING, &priv->status) && |
2165 | test_bit(STATUS_ALIVE, &priv->status)) | ||
2162 | queue_work(priv->workqueue, &priv->restart); | 2166 | queue_work(priv->workqueue, &priv->restart); |
2163 | } else { | 2167 | } else { |
2164 | /* make sure mac80211 stop sending Tx frame */ | 2168 | /* make sure mac80211 stop sending Tx frame */ |
@@ -2355,31 +2359,9 @@ static int iwl_mac_start(struct ieee80211_hw *hw) | |||
2355 | { | 2359 | { |
2356 | struct iwl_priv *priv = hw->priv; | 2360 | struct iwl_priv *priv = hw->priv; |
2357 | int ret; | 2361 | int ret; |
2358 | u16 pci_cmd; | ||
2359 | 2362 | ||
2360 | IWL_DEBUG_MAC80211("enter\n"); | 2363 | IWL_DEBUG_MAC80211("enter\n"); |
2361 | 2364 | ||
2362 | if (pci_enable_device(priv->pci_dev)) { | ||
2363 | IWL_ERR(priv, "Fail to pci_enable_device\n"); | ||
2364 | return -ENODEV; | ||
2365 | } | ||
2366 | pci_restore_state(priv->pci_dev); | ||
2367 | pci_enable_msi(priv->pci_dev); | ||
2368 | |||
2369 | /* enable interrupts if needed: hw bug w/a */ | ||
2370 | pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); | ||
2371 | if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { | ||
2372 | pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; | ||
2373 | pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); | ||
2374 | } | ||
2375 | |||
2376 | ret = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, | ||
2377 | DRV_NAME, priv); | ||
2378 | if (ret) { | ||
2379 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); | ||
2380 | goto out_disable_msi; | ||
2381 | } | ||
2382 | |||
2383 | /* we should be verifying the device is ready to be opened */ | 2365 | /* we should be verifying the device is ready to be opened */ |
2384 | mutex_lock(&priv->mutex); | 2366 | mutex_lock(&priv->mutex); |
2385 | 2367 | ||
@@ -2392,7 +2374,7 @@ static int iwl_mac_start(struct ieee80211_hw *hw) | |||
2392 | if (ret) { | 2374 | if (ret) { |
2393 | IWL_ERR(priv, "Could not read microcode: %d\n", ret); | 2375 | IWL_ERR(priv, "Could not read microcode: %d\n", ret); |
2394 | mutex_unlock(&priv->mutex); | 2376 | mutex_unlock(&priv->mutex); |
2395 | goto out_release_irq; | 2377 | return ret; |
2396 | } | 2378 | } |
2397 | } | 2379 | } |
2398 | 2380 | ||
@@ -2403,7 +2385,7 @@ static int iwl_mac_start(struct ieee80211_hw *hw) | |||
2403 | iwl_rfkill_set_hw_state(priv); | 2385 | iwl_rfkill_set_hw_state(priv); |
2404 | 2386 | ||
2405 | if (ret) | 2387 | if (ret) |
2406 | goto out_release_irq; | 2388 | return ret; |
2407 | 2389 | ||
2408 | if (iwl_is_rfkill(priv)) | 2390 | if (iwl_is_rfkill(priv)) |
2409 | goto out; | 2391 | goto out; |
@@ -2422,8 +2404,7 @@ static int iwl_mac_start(struct ieee80211_hw *hw) | |||
2422 | if (!test_bit(STATUS_READY, &priv->status)) { | 2404 | if (!test_bit(STATUS_READY, &priv->status)) { |
2423 | IWL_ERR(priv, "START_ALIVE timeout after %dms.\n", | 2405 | IWL_ERR(priv, "START_ALIVE timeout after %dms.\n", |
2424 | jiffies_to_msecs(UCODE_READY_TIMEOUT)); | 2406 | jiffies_to_msecs(UCODE_READY_TIMEOUT)); |
2425 | ret = -ETIMEDOUT; | 2407 | return -ETIMEDOUT; |
2426 | goto out_release_irq; | ||
2427 | } | 2408 | } |
2428 | } | 2409 | } |
2429 | 2410 | ||
@@ -2431,15 +2412,6 @@ out: | |||
2431 | priv->is_open = 1; | 2412 | priv->is_open = 1; |
2432 | IWL_DEBUG_MAC80211("leave\n"); | 2413 | IWL_DEBUG_MAC80211("leave\n"); |
2433 | return 0; | 2414 | return 0; |
2434 | |||
2435 | out_release_irq: | ||
2436 | free_irq(priv->pci_dev->irq, priv); | ||
2437 | out_disable_msi: | ||
2438 | pci_disable_msi(priv->pci_dev); | ||
2439 | pci_disable_device(priv->pci_dev); | ||
2440 | priv->is_open = 0; | ||
2441 | IWL_DEBUG_MAC80211("leave - failed\n"); | ||
2442 | return ret; | ||
2443 | } | 2415 | } |
2444 | 2416 | ||
2445 | static void iwl_mac_stop(struct ieee80211_hw *hw) | 2417 | static void iwl_mac_stop(struct ieee80211_hw *hw) |
@@ -2467,10 +2439,10 @@ static void iwl_mac_stop(struct ieee80211_hw *hw) | |||
2467 | iwl_down(priv); | 2439 | iwl_down(priv); |
2468 | 2440 | ||
2469 | flush_workqueue(priv->workqueue); | 2441 | flush_workqueue(priv->workqueue); |
2470 | free_irq(priv->pci_dev->irq, priv); | 2442 | |
2471 | pci_disable_msi(priv->pci_dev); | 2443 | /* enable interrupts again in order to receive rfkill changes */ |
2472 | pci_save_state(priv->pci_dev); | 2444 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); |
2473 | pci_disable_device(priv->pci_dev); | 2445 | iwl_enable_interrupts(priv); |
2474 | 2446 | ||
2475 | IWL_DEBUG_MAC80211("leave\n"); | 2447 | IWL_DEBUG_MAC80211("leave\n"); |
2476 | } | 2448 | } |
@@ -3729,6 +3701,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3729 | struct ieee80211_hw *hw; | 3701 | struct ieee80211_hw *hw; |
3730 | struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); | 3702 | struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); |
3731 | unsigned long flags; | 3703 | unsigned long flags; |
3704 | u16 pci_cmd; | ||
3732 | 3705 | ||
3733 | /************************ | 3706 | /************************ |
3734 | * 1. Allocating HW data | 3707 | * 1. Allocating HW data |
@@ -3872,26 +3845,36 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3872 | iwl_disable_interrupts(priv); | 3845 | iwl_disable_interrupts(priv); |
3873 | spin_unlock_irqrestore(&priv->lock, flags); | 3846 | spin_unlock_irqrestore(&priv->lock, flags); |
3874 | 3847 | ||
3848 | pci_enable_msi(priv->pci_dev); | ||
3849 | |||
3850 | err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, | ||
3851 | DRV_NAME, priv); | ||
3852 | if (err) { | ||
3853 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); | ||
3854 | goto out_disable_msi; | ||
3855 | } | ||
3875 | err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); | 3856 | err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); |
3876 | if (err) { | 3857 | if (err) { |
3877 | IWL_ERR(priv, "failed to create sysfs device attributes\n"); | 3858 | IWL_ERR(priv, "failed to create sysfs device attributes\n"); |
3878 | goto out_uninit_drv; | 3859 | goto out_uninit_drv; |
3879 | } | 3860 | } |
3880 | 3861 | ||
3881 | |||
3882 | iwl_setup_deferred_work(priv); | 3862 | iwl_setup_deferred_work(priv); |
3883 | iwl_setup_rx_handlers(priv); | 3863 | iwl_setup_rx_handlers(priv); |
3884 | 3864 | ||
3885 | /******************** | ||
3886 | * 9. Conclude | ||
3887 | ********************/ | ||
3888 | pci_save_state(pdev); | ||
3889 | pci_disable_device(pdev); | ||
3890 | |||
3891 | /********************************** | 3865 | /********************************** |
3892 | * 10. Setup and register mac80211 | 3866 | * 9. Setup and register mac80211 |
3893 | **********************************/ | 3867 | **********************************/ |
3894 | 3868 | ||
3869 | /* enable interrupts if needed: hw bug w/a */ | ||
3870 | pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); | ||
3871 | if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { | ||
3872 | pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; | ||
3873 | pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); | ||
3874 | } | ||
3875 | |||
3876 | iwl_enable_interrupts(priv); | ||
3877 | |||
3895 | err = iwl_setup_mac(priv); | 3878 | err = iwl_setup_mac(priv); |
3896 | if (err) | 3879 | if (err) |
3897 | goto out_remove_sysfs; | 3880 | goto out_remove_sysfs; |
@@ -3900,15 +3883,27 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3900 | if (err) | 3883 | if (err) |
3901 | IWL_ERR(priv, "failed to create debugfs files\n"); | 3884 | IWL_ERR(priv, "failed to create debugfs files\n"); |
3902 | 3885 | ||
3886 | /* If platform's RF_KILL switch is NOT set to KILL */ | ||
3887 | if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) | ||
3888 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | ||
3889 | else | ||
3890 | set_bit(STATUS_RF_KILL_HW, &priv->status); | ||
3891 | |||
3903 | err = iwl_rfkill_init(priv); | 3892 | err = iwl_rfkill_init(priv); |
3904 | if (err) | 3893 | if (err) |
3905 | IWL_ERR(priv, "Unable to initialize RFKILL system. " | 3894 | IWL_ERR(priv, "Unable to initialize RFKILL system. " |
3906 | "Ignoring error: %d\n", err); | 3895 | "Ignoring error: %d\n", err); |
3896 | else | ||
3897 | iwl_rfkill_set_hw_state(priv); | ||
3898 | |||
3907 | iwl_power_initialize(priv); | 3899 | iwl_power_initialize(priv); |
3908 | return 0; | 3900 | return 0; |
3909 | 3901 | ||
3910 | out_remove_sysfs: | 3902 | out_remove_sysfs: |
3911 | sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); | 3903 | sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); |
3904 | out_disable_msi: | ||
3905 | pci_disable_msi(priv->pci_dev); | ||
3906 | pci_disable_device(priv->pci_dev); | ||
3912 | out_uninit_drv: | 3907 | out_uninit_drv: |
3913 | iwl_uninit_drv(priv); | 3908 | iwl_uninit_drv(priv); |
3914 | out_free_eeprom: | 3909 | out_free_eeprom: |
@@ -3980,6 +3975,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) | |||
3980 | destroy_workqueue(priv->workqueue); | 3975 | destroy_workqueue(priv->workqueue); |
3981 | priv->workqueue = NULL; | 3976 | priv->workqueue = NULL; |
3982 | 3977 | ||
3978 | free_irq(priv->pci_dev->irq, priv); | ||
3979 | pci_disable_msi(priv->pci_dev); | ||
3983 | pci_iounmap(pdev, priv->hw_base); | 3980 | pci_iounmap(pdev, priv->hw_base); |
3984 | pci_release_regions(pdev); | 3981 | pci_release_regions(pdev); |
3985 | pci_disable_device(pdev); | 3982 | pci_disable_device(pdev); |
@@ -4005,6 +4002,8 @@ static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
4005 | priv->is_open = 1; | 4002 | priv->is_open = 1; |
4006 | } | 4003 | } |
4007 | 4004 | ||
4005 | pci_save_state(pdev); | ||
4006 | pci_disable_device(pdev); | ||
4008 | pci_set_power_state(pdev, PCI_D3hot); | 4007 | pci_set_power_state(pdev, PCI_D3hot); |
4009 | 4008 | ||
4010 | return 0; | 4009 | return 0; |
@@ -4015,6 +4014,9 @@ static int iwl_pci_resume(struct pci_dev *pdev) | |||
4015 | struct iwl_priv *priv = pci_get_drvdata(pdev); | 4014 | struct iwl_priv *priv = pci_get_drvdata(pdev); |
4016 | 4015 | ||
4017 | pci_set_power_state(pdev, PCI_D0); | 4016 | pci_set_power_state(pdev, PCI_D0); |
4017 | pci_enable_device(pdev); | ||
4018 | pci_restore_state(pdev); | ||
4019 | iwl_enable_interrupts(priv); | ||
4018 | 4020 | ||
4019 | if (priv->is_open) | 4021 | if (priv->is_open) |
4020 | iwl_mac_start(priv->hw); | 4022 | iwl_mac_start(priv->hw); |