FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Ubuntu > Ubuntu Kernel Team

 
 
LinkBack Thread Tools
 
Old 02-11-2009, 12:26 AM
Huaxu Wan
 
Default LP#193970 iwlagn: fix hw-rfkill while the interface is down

Backport from http://marc.info/?l=linux-wireless&m=123236704016931&w=2

Fix the bug #193970 in Jaunty Alpha 4

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>
Signed-off-by: Huaxu Wan <huaxu.wan@intel.com>

---
drivers/net/wireless/iwlwifi/iwl-agn.c | 112 +++++++++++++++--------------
drivers/net/wireless/iwlwifi/iwlagn.mod.c | 2 +-
2 files changed, 59 insertions(+), 55 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index fff20a3..3fb64ad 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1645,13 +1645,16 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
hw_rf_kill ? "disable radio":"enable radio");

/* driver only loads ucode once setting the interface up.
- * the driver as well won't allow loading if RFKILL is set
- * therefore no need to restart the driver from this handler
+ * the driver allows loading the ucode even if the radio
+ * is killed. Hence update the killswitch state here. The
+ * rfkill handler will care about restarting if needed.
*/
- if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) {
- clear_bit(STATUS_RF_KILL_HW, &priv->status);
- if (priv->is_open && !iwl_is_rfkill(priv))
- queue_work(priv->workqueue, &priv->up);
+ if (!test_bit(STATUS_ALIVE, &priv->status)) {
+ if (hw_rf_kill)
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
+ queue_work(priv->workqueue, &priv->rf_kill);
}

handled |= CSR_INT_BIT_RF_KILL;
@@ -2353,7 +2356,8 @@ static void iwl4965_bg_rf_kill(struct work_struct *work)
IWL_DEBUG(IWL_DL_RF_KILL,
"HW and/or SW RF Kill no longer active, restarting "
"device
");
- if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status) &&
+ test_bit(STATUS_ALIVE, &priv->status))
queue_work(priv->workqueue, &priv->restart);
} else {
/* make sure mac80211 stop sending Tx frame */
@@ -2575,31 +2579,9 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
int ret;
- u16 pci_cmd;

IWL_DEBUG_MAC80211("enter
");

- if (pci_enable_device(priv->pci_dev)) {
- IWL_ERROR("Fail to pci_enable_device
");
- return -ENODEV;
- }
- pci_restore_state(priv->pci_dev);
- pci_enable_msi(priv->pci_dev);
-
- /* enable interrupts if needed: hw bug w/a */
- pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd);
- if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
- pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
- pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
- }
-
- ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED,
- DRV_NAME, priv);
- if (ret) {
- IWL_ERROR("Error allocating IRQ %d
", priv->pci_dev->irq);
- goto out_disable_msi;
- }
-
/* we should be verifying the device is ready to be opened */
mutex_lock(&priv->mutex);

@@ -2612,7 +2594,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
if (ret) {
IWL_ERROR("Could not read microcode: %d
", ret);
mutex_unlock(&priv->mutex);
- goto out_release_irq;
+ return ret;
}
}

@@ -2623,7 +2605,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
iwl_rfkill_set_hw_state(priv);

if (ret)
- goto out_release_irq;
+ return ret;

if (iwl_is_rfkill(priv))
goto out;
@@ -2642,8 +2624,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
if (!test_bit(STATUS_READY, &priv->status)) {
IWL_ERROR("START_ALIVE timeout after %dms.
",
jiffies_to_msecs(UCODE_READY_TIMEOUT));
- ret = -ETIMEDOUT;
- goto out_release_irq;
+ return -ETIMEDOUT;
}
}

@@ -2651,15 +2632,6 @@ out:
priv->is_open = 1;
IWL_DEBUG_MAC80211("leave
");
return 0;
-
-out_release_irq:
- free_irq(priv->pci_dev->irq, priv);
-out_disable_msi:
- pci_disable_msi(priv->pci_dev);
- pci_disable_device(priv->pci_dev);
- priv->is_open = 0;
- IWL_DEBUG_MAC80211("leave - failed
");
- return ret;
}

static void iwl4965_mac_stop(struct ieee80211_hw *hw)
@@ -2687,10 +2659,10 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
iwl4965_down(priv);

flush_workqueue(priv->workqueue);
- free_irq(priv->pci_dev->irq, priv);
- pci_disable_msi(priv->pci_dev);
- pci_save_state(priv->pci_dev);
- pci_disable_device(priv->pci_dev);
+
+ /* enable interrupts again in order to receive rfkill changes */
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ iwl4965_enable_interrupts(priv);

IWL_DEBUG_MAC80211("leave
");
}
@@ -4169,6 +4141,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
struct ieee80211_hw *hw;
struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
unsigned long flags;
+ u16 pci_cmd;
+
DECLARE_MAC_BUF(mac);

/************************
@@ -4314,7 +4288,14 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
spin_lock_irqsave(&priv->lock, flags);
iwl4965_disable_interrupts(priv);
spin_unlock_irqrestore(&priv->lock, flags);
-
+ pci_enable_msi(priv->pci_dev);
+
+ err = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED,
+ DRV_NAME, priv);
+ if (err) {
+ IWL_ERROR("Error allocating IRQ %d
", priv->pci_dev->irq);
+ goto out_disable_msi;
+ }
err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
if (err) {
IWL_ERROR("failed to create sysfs device attributes
");
@@ -4325,15 +4306,18 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
iwl_setup_deferred_work(priv);
iwl_setup_rx_handlers(priv);

- /********************
- * 9. Conclude
- ********************/
- pci_save_state(pdev);
- pci_disable_device(pdev);
-
/**********************************
- * 10. Setup and register mac80211
+ * 9. Setup and register mac80211
**********************************/
+
+ /* enable interrupts if needed: hw bug w/a */
+ pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd);
+ if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
+ pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
+ }
+
+ iwl4965_enable_interrupts(priv);

err = iwl_setup_mac(priv);
if (err)
@@ -4343,15 +4327,28 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
if (err)
IWL_ERROR("failed to create debugfs files
");

+
+ /* If platform's RF_KILL switch is NOT set to KILL */
+ if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
+ else
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+
err = iwl_rfkill_init(priv);
if (err)
IWL_ERROR("Unable to initialize RFKILL system. "
"Ignoring error: %d
", err);
+ else
+ iwl_rfkill_set_hw_state(priv);
+
iwl_power_initialize(priv);
return 0;

out_remove_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+ out_disable_msi:
+ pci_disable_msi(priv->pci_dev);
+ pci_disable_device(priv->pci_dev);
out_uninit_drv:
iwl_uninit_drv(priv);
out_free_eeprom:
@@ -4423,6 +4420,8 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;

+ free_irq(priv->pci_dev->irq, priv);
+ pci_disable_msi(priv->pci_dev);
pci_iounmap(pdev, priv->hw_base);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -4448,6 +4447,8 @@ static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state)
priv->is_open = 1;
}

+ pci_save_state(pdev);
+ pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);

return 0;
@@ -4458,6 +4459,9 @@ static int iwl4965_pci_resume(struct pci_dev *pdev)
struct iwl_priv *priv = pci_get_drvdata(pdev);

pci_set_power_state(pdev, PCI_D0);
+ pci_enable_device(pdev);
+ pci_restore_state(pdev);
+ iwl4965_enable_interrupts(priv);

if (priv->is_open)
iwl4965_mac_start(priv->hw);

--
1.6.0.4


--
kernel-team mailing list
kernel-team@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/kernel-team
 

Thread Tools




All times are GMT. The time now is 10:03 PM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org