Skip to content

Commit

Permalink
iwl3945: report killswitch changes even if the interface is down
Browse files Browse the repository at this point in the history
Currently iwl3945 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 iwl3945_pci_probe instead of iwl3945_up
and poll the CSR_GP_CNTRL register to update the killswitch state every
two seconds. The polling is only needed on 3945 hardware as this adapter
does not use interrupts to signal rfkill changes to the driver (in case no
firmware is loaded). The firmware loading is still done in iwl3945_up.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
Acked-by: Samuel Ortiz <samuel.ortiz@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Helmut Schaa authored and John W. Linville committed Jan 29, 2009
1 parent c95741d commit 2663516
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 32 deletions.
1 change: 1 addition & 0 deletions drivers/net/wireless/iwlwifi/iwl-dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@ struct iwl_priv {

/*For 3945 only*/
struct delayed_work thermal_periodic;
struct delayed_work rfkill_poll;

/* TX Power */
s8 tx_power_user_lmt;
Expand Down
88 changes: 56 additions & 32 deletions drivers/net/wireless/iwlwifi/iwl3945-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -5479,7 +5479,8 @@ static void iwl3945_bg_rf_kill(struct work_struct *work)
IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
"HW and/or SW RF Kill no longer active, restarting "
"device\n");
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 {

Expand All @@ -5496,6 +5497,25 @@ static void iwl3945_bg_rf_kill(struct work_struct *work)
iwl3945_rfkill_set_hw_state(priv);
}

static void iwl3945_rfkill_poll(struct work_struct *data)
{
struct iwl_priv *priv =
container_of(data, struct iwl_priv, rfkill_poll.work);
unsigned long status = priv->status;

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);

if (test_bit(STATUS_RF_KILL_HW, &status) != test_bit(STATUS_RF_KILL_HW, &priv->status))
queue_work(priv->workqueue, &priv->rf_kill);

queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
round_jiffies_relative(2 * HZ));

}

#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)

static void iwl3945_bg_scan_check(struct work_struct *data)
Expand Down Expand Up @@ -5898,20 +5918,6 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)

IWL_DEBUG_MAC80211("enter\n");

if (pci_enable_device(priv->pci_dev)) {
IWL_ERR(priv, "Fail to pci_enable_device\n");
return -ENODEV;
}
pci_restore_state(priv->pci_dev);
pci_enable_msi(priv->pci_dev);

ret = request_irq(priv->pci_dev->irq, iwl3945_isr, IRQF_SHARED,
DRV_NAME, priv);
if (ret) {
IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
goto out_disable_msi;
}

/* we should be verifying the device is ready to be opened */
mutex_lock(&priv->mutex);

Expand Down Expand Up @@ -5957,15 +5963,15 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
}
}

/* ucode is running and will send rfkill notifications,
* no need to poll the killswitch state anymore */
cancel_delayed_work(&priv->rfkill_poll);

priv->is_open = 1;
IWL_DEBUG_MAC80211("leave\n");
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\n");
return ret;
Expand Down Expand Up @@ -5996,10 +6002,10 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw)
iwl3945_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);

/* start polling the killswitch state again */
queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
round_jiffies_relative(2 * HZ));

IWL_DEBUG_MAC80211("leave\n");
}
Expand Down Expand Up @@ -7207,6 +7213,7 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check);
INIT_DELAYED_WORK(&priv->rfkill_poll, iwl3945_rfkill_poll);

iwl3945_hw_setup_deferred_work(priv);

Expand Down Expand Up @@ -7497,6 +7504,15 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
iwl3945_disable_interrupts(priv);
spin_unlock_irqrestore(&priv->lock, flags);

pci_enable_msi(priv->pci_dev);

err = request_irq(priv->pci_dev->irq, iwl3945_isr, IRQF_SHARED,
DRV_NAME, priv);
if (err) {
IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
goto out_disable_msi;
}

err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
if (err) {
IWL_ERR(priv, "failed to create sysfs device attributes\n");
Expand All @@ -7507,14 +7523,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
iwl3945_setup_deferred_work(priv);
iwl3945_setup_rx_handlers(priv);

/***********************
* 9. Conclude
* ********************/
pci_save_state(pdev);
pci_disable_device(pdev);

/*********************************
* 10. Setup and Register mac80211
* 9. Setup and Register mac80211
* *******************************/

err = ieee80211_register_hw(priv->hw);
Expand All @@ -7531,6 +7541,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
IWL_ERR(priv, "Unable to initialize RFKILL system. "
"Ignoring error: %d\n", err);

/* Start monitoring the killswitch */
queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
2 * HZ);

return 0;

out_remove_sysfs:
Expand All @@ -7539,10 +7553,12 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
iwl3945_free_geos(priv);

out_release_irq:
free_irq(priv->pci_dev->irq, priv);
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
iwl3945_unset_hw_params(priv);

out_disable_msi:
pci_disable_msi(priv->pci_dev);
out_iounmap:
pci_iounmap(pdev, priv->hw_base);
out_pci_release_regions:
Expand Down Expand Up @@ -7587,6 +7603,8 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);

iwl3945_rfkill_unregister(priv);
cancel_delayed_work(&priv->rfkill_poll);

iwl3945_dealloc_ucode_pci(priv);

if (priv->rxq.bd)
Expand All @@ -7605,6 +7623,9 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;

free_irq(pdev->irq, priv);
pci_disable_msi(pdev);

pci_iounmap(pdev, priv->hw_base);
pci_release_regions(pdev);
pci_disable_device(pdev);
Expand All @@ -7630,7 +7651,8 @@ static int iwl3945_pci_suspend(struct pci_dev *pdev, pm_message_t state)
iwl3945_mac_stop(priv->hw);
priv->is_open = 1;
}

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

return 0;
Expand All @@ -7641,6 +7663,8 @@ static int iwl3945_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);

if (priv->is_open)
iwl3945_mac_start(priv->hw);
Expand Down

0 comments on commit 2663516

Please sign in to comment.