aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl3945-base.c
diff options
context:
space:
mode:
authorMohamed Abbas <mabbas@linux.intel.com>2008-03-28 19:21:08 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-04-01 17:13:18 -0400
commit0359facc7b7a37fd1223ac60649c80cd8daeaf73 (patch)
treefcf6d571afa5a30dc893f853e20e6d81a3871b92 /drivers/net/wireless/iwlwifi/iwl3945-base.c
parentad97edd2f524940d524c26ae273a4eb23067a7c0 (diff)
iwlwifi: fix race condition during driver unload
This patch fixed the OOPS when load the driver while rf-kill is on then unload the driver right after load. a race condition caused the interupt handler to schedule the tasklet which will run right after the driver pci_remove causing invalid poiter OOPS. Signed-off-by: Mohamed Abbas <mabbas@linux.intel.com> Signed-off-by: Joonwoo Park <joonwpark81@gmail.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl3945-base.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c34
1 files changed, 32 insertions, 2 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index ab635dcfd5d1..2a5245b63e32 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -4153,6 +4153,16 @@ static void iwl3945_enable_interrupts(struct iwl3945_priv *priv)
4153 iwl3945_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); 4153 iwl3945_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
4154} 4154}
4155 4155
4156
4157/* call this function to flush any scheduled tasklet */
4158static inline void iwl_synchronize_irq(struct iwl3945_priv *priv)
4159{
4160 /* wait to make sure we flush pedding tasklet*/
4161 synchronize_irq(priv->pci_dev->irq);
4162 tasklet_kill(&priv->irq_tasklet);
4163}
4164
4165
4156static inline void iwl3945_disable_interrupts(struct iwl3945_priv *priv) 4166static inline void iwl3945_disable_interrupts(struct iwl3945_priv *priv)
4157{ 4167{
4158 clear_bit(STATUS_INT_ENABLED, &priv->status); 4168 clear_bit(STATUS_INT_ENABLED, &priv->status);
@@ -4552,7 +4562,9 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
4552 } 4562 }
4553 4563
4554 /* Re-enable all interrupts */ 4564 /* Re-enable all interrupts */
4555 iwl3945_enable_interrupts(priv); 4565 /* only Re-enable if disabled by irq */
4566 if (test_bit(STATUS_INT_ENABLED, &priv->status))
4567 iwl3945_enable_interrupts(priv);
4556 4568
4557#ifdef CONFIG_IWL3945_DEBUG 4569#ifdef CONFIG_IWL3945_DEBUG
4558 if (iwl3945_debug_level & (IWL_DL_ISR)) { 4570 if (iwl3945_debug_level & (IWL_DL_ISR)) {
@@ -4616,7 +4628,9 @@ unplugged:
4616 4628
4617 none: 4629 none:
4618 /* re-enable interrupts here since we don't have anything to service. */ 4630 /* re-enable interrupts here since we don't have anything to service. */
4619 iwl3945_enable_interrupts(priv); 4631 /* only Re-enable if disabled by irq */
4632 if (test_bit(STATUS_INT_ENABLED, &priv->status))
4633 iwl3945_enable_interrupts(priv);
4620 spin_unlock(&priv->lock); 4634 spin_unlock(&priv->lock);
4621 return IRQ_NONE; 4635 return IRQ_NONE;
4622} 4636}
@@ -5905,7 +5919,10 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
5905 iwl3945_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); 5919 iwl3945_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
5906 5920
5907 /* tell the device to stop sending interrupts */ 5921 /* tell the device to stop sending interrupts */
5922 spin_lock_irqsave(&priv->lock, flags);
5908 iwl3945_disable_interrupts(priv); 5923 iwl3945_disable_interrupts(priv);
5924 spin_unlock_irqrestore(&priv->lock, flags);
5925 iwl_synchronize_irq(priv);
5909 5926
5910 if (priv->mac80211_registered) 5927 if (priv->mac80211_registered)
5911 ieee80211_stop_queues(priv->hw); 5928 ieee80211_stop_queues(priv->hw);
@@ -7943,6 +7960,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
7943 struct ieee80211_hw *hw; 7960 struct ieee80211_hw *hw;
7944 struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data); 7961 struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
7945 int i; 7962 int i;
7963 unsigned long flags;
7946 DECLARE_MAC_BUF(mac); 7964 DECLARE_MAC_BUF(mac);
7947 7965
7948 /* Disabling hardware scan means that mac80211 will perform scans 7966 /* Disabling hardware scan means that mac80211 will perform scans
@@ -8093,7 +8111,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
8093 priv->power_mode = IWL_POWER_AC; 8111 priv->power_mode = IWL_POWER_AC;
8094 priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; 8112 priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
8095 8113
8114 spin_lock_irqsave(&priv->lock, flags);
8096 iwl3945_disable_interrupts(priv); 8115 iwl3945_disable_interrupts(priv);
8116 spin_unlock_irqrestore(&priv->lock, flags);
8097 8117
8098 err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); 8118 err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
8099 if (err) { 8119 if (err) {
@@ -8180,6 +8200,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
8180 struct iwl3945_priv *priv = pci_get_drvdata(pdev); 8200 struct iwl3945_priv *priv = pci_get_drvdata(pdev);
8181 struct list_head *p, *q; 8201 struct list_head *p, *q;
8182 int i; 8202 int i;
8203 unsigned long flags;
8183 8204
8184 if (!priv) 8205 if (!priv)
8185 return; 8206 return;
@@ -8190,6 +8211,15 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
8190 8211
8191 iwl3945_down(priv); 8212 iwl3945_down(priv);
8192 8213
8214 /* make sure we flush any pending irq or
8215 * tasklet for the driver
8216 */
8217 spin_lock_irqsave(&priv->lock, flags);
8218 iwl3945_disable_interrupts(priv);
8219 spin_unlock_irqrestore(&priv->lock, flags);
8220
8221 iwl_synchronize_irq(priv);
8222
8193 /* Free MAC hash list for ADHOC */ 8223 /* Free MAC hash list for ADHOC */
8194 for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { 8224 for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
8195 list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { 8225 list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {