aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl4965-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/iwl4965-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/iwl4965-base.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 7f56565b4002..29e843108e9f 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -4285,6 +4285,14 @@ static void iwl4965_enable_interrupts(struct iwl_priv *priv)
4285 iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); 4285 iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
4286} 4286}
4287 4287
4288/* call this function to flush any scheduled tasklet */
4289static inline void iwl_synchronize_irq(struct iwl_priv *priv)
4290{
4291 /* wait to make sure we flush pedding tasklet*/
4292 synchronize_irq(priv->pci_dev->irq);
4293 tasklet_kill(&priv->irq_tasklet);
4294}
4295
4288static inline void iwl4965_disable_interrupts(struct iwl_priv *priv) 4296static inline void iwl4965_disable_interrupts(struct iwl_priv *priv)
4289{ 4297{
4290 clear_bit(STATUS_INT_ENABLED, &priv->status); 4298 clear_bit(STATUS_INT_ENABLED, &priv->status);
@@ -4668,7 +4676,9 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
4668 } 4676 }
4669 4677
4670 /* Re-enable all interrupts */ 4678 /* Re-enable all interrupts */
4671 iwl4965_enable_interrupts(priv); 4679 /* only Re-enable if diabled by irq */
4680 if (test_bit(STATUS_INT_ENABLED, &priv->status))
4681 iwl4965_enable_interrupts(priv);
4672 4682
4673#ifdef CONFIG_IWLWIFI_DEBUG 4683#ifdef CONFIG_IWLWIFI_DEBUG
4674 if (iwl_debug_level & (IWL_DL_ISR)) { 4684 if (iwl_debug_level & (IWL_DL_ISR)) {
@@ -4733,7 +4743,9 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
4733 4743
4734 none: 4744 none:
4735 /* re-enable interrupts here since we don't have anything to service. */ 4745 /* re-enable interrupts here since we don't have anything to service. */
4736 iwl4965_enable_interrupts(priv); 4746 /* only Re-enable if diabled by irq */
4747 if (test_bit(STATUS_INT_ENABLED, &priv->status))
4748 iwl4965_enable_interrupts(priv);
4737 spin_unlock(&priv->lock); 4749 spin_unlock(&priv->lock);
4738 return IRQ_NONE; 4750 return IRQ_NONE;
4739} 4751}
@@ -5772,7 +5784,10 @@ static void __iwl4965_down(struct iwl_priv *priv)
5772 iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); 5784 iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
5773 5785
5774 /* tell the device to stop sending interrupts */ 5786 /* tell the device to stop sending interrupts */
5787 spin_lock_irqsave(&priv->lock, flags);
5775 iwl4965_disable_interrupts(priv); 5788 iwl4965_disable_interrupts(priv);
5789 spin_unlock_irqrestore(&priv->lock, flags);
5790 iwl_synchronize_irq(priv);
5776 5791
5777 if (priv->mac80211_registered) 5792 if (priv->mac80211_registered)
5778 ieee80211_stop_queues(priv->hw); 5793 ieee80211_stop_queues(priv->hw);
@@ -7996,6 +8011,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
7996 struct iwl_priv *priv; 8011 struct iwl_priv *priv;
7997 struct ieee80211_hw *hw; 8012 struct ieee80211_hw *hw;
7998 struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); 8013 struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
8014 unsigned long flags;
7999 DECLARE_MAC_BUF(mac); 8015 DECLARE_MAC_BUF(mac);
8000 8016
8001 /************************ 8017 /************************
@@ -8133,7 +8149,9 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
8133 /******************** 8149 /********************
8134 * 8. Setup services 8150 * 8. Setup services
8135 ********************/ 8151 ********************/
8152 spin_lock_irqsave(&priv->lock, flags);
8136 iwl4965_disable_interrupts(priv); 8153 iwl4965_disable_interrupts(priv);
8154 spin_unlock_irqrestore(&priv->lock, flags);
8137 8155
8138 err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); 8156 err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
8139 if (err) { 8157 if (err) {
@@ -8182,6 +8200,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
8182 struct iwl_priv *priv = pci_get_drvdata(pdev); 8200 struct iwl_priv *priv = pci_get_drvdata(pdev);
8183 struct list_head *p, *q; 8201 struct list_head *p, *q;
8184 int i; 8202 int i;
8203 unsigned long flags;
8185 8204
8186 if (!priv) 8205 if (!priv)
8187 return; 8206 return;
@@ -8192,6 +8211,15 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
8192 8211
8193 iwl4965_down(priv); 8212 iwl4965_down(priv);
8194 8213
8214 /* make sure we flush any pending irq or
8215 * tasklet for the driver
8216 */
8217 spin_lock_irqsave(&priv->lock, flags);
8218 iwl4965_disable_interrupts(priv);
8219 spin_unlock_irqrestore(&priv->lock, flags);
8220
8221 iwl_synchronize_irq(priv);
8222
8195 /* Free MAC hash list for ADHOC */ 8223 /* Free MAC hash list for ADHOC */
8196 for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { 8224 for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
8197 list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { 8225 list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {