diff options
author | Helmut Schaa <helmut.schaa@googlemail.com> | 2009-01-19 07:10:07 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 16:00:50 -0500 |
commit | 6cd0b1cb872b3bf9fc5de4536404206ab74bafdd (patch) | |
tree | 8ab5376e3f5750b053465bb18a8417608e2e31bc /drivers/net/wireless/iwlwifi/iwl-agn.c | |
parent | c7e035a95d68819491b5250c6854f144c941e305 (diff) |
iwlagn: fix hw-rfkill while the interface is down
Currently iwlagn is not able to report hw-killswitch events while the
interface is down. This has implications on user space tools (like
NetworkManager) relying on rfkill notifications to bring the interface
up once the wireless gets enabled through a hw killswitch.
Thus, enable the device already in iwl_pci_probe instead of iwl_up
and enable interrups while the interface is down in order to get
notified about killswitch state changes. The firmware loading is still
done in iwl_up.
Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
Acked-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-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); |