aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
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
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')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c34
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c32
2 files changed, 62 insertions, 4 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]) {
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]) {