]> err.no Git - linux-2.6/blobdiff - drivers/net/wireless/iwlwifi/iwl3945-base.c
iwlwifi: move rate registration to module load
[linux-2.6] / drivers / net / wireless / iwlwifi / iwl3945-base.c
index ab635dcfd5d116b625f86df98466b01a503a0980..8c2036850c89ee93e18bd0548134d7762c0620a4 100644 (file)
@@ -4153,6 +4153,16 @@ static void iwl3945_enable_interrupts(struct iwl3945_priv *priv)
        iwl3945_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
 }
 
+
+/* call this function to flush any scheduled tasklet */
+static inline void iwl_synchronize_irq(struct iwl3945_priv *priv)
+{
+       /* wait to make sure we flush pedding tasklet*/
+       synchronize_irq(priv->pci_dev->irq);
+       tasklet_kill(&priv->irq_tasklet);
+}
+
+
 static inline void iwl3945_disable_interrupts(struct iwl3945_priv *priv)
 {
        clear_bit(STATUS_INT_ENABLED, &priv->status);
@@ -4552,7 +4562,9 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
        }
 
        /* Re-enable all interrupts */
-       iwl3945_enable_interrupts(priv);
+       /* only Re-enable if disabled by irq */
+       if (test_bit(STATUS_INT_ENABLED, &priv->status))
+               iwl3945_enable_interrupts(priv);
 
 #ifdef CONFIG_IWL3945_DEBUG
        if (iwl3945_debug_level & (IWL_DL_ISR)) {
@@ -4616,7 +4628,9 @@ unplugged:
 
  none:
        /* re-enable interrupts here since we don't have anything to service. */
-       iwl3945_enable_interrupts(priv);
+       /* only Re-enable if disabled by irq */
+       if (test_bit(STATUS_INT_ENABLED, &priv->status))
+               iwl3945_enable_interrupts(priv);
        spin_unlock(&priv->lock);
        return IRQ_NONE;
 }
@@ -5905,7 +5919,10 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
        iwl3945_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 
        /* tell the device to stop sending interrupts */
+       spin_lock_irqsave(&priv->lock, flags);
        iwl3945_disable_interrupts(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       iwl_synchronize_irq(priv);
 
        if (priv->mac80211_registered)
                ieee80211_stop_queues(priv->hw);
@@ -7943,6 +7960,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        struct ieee80211_hw *hw;
        struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
        int i;
+       unsigned long flags;
        DECLARE_MAC_BUF(mac);
 
        /* 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
        priv->power_mode = IWL_POWER_AC;
        priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
 
+       spin_lock_irqsave(&priv->lock, flags);
        iwl3945_disable_interrupts(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
        if (err) {
@@ -8136,7 +8156,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
                goto out_free_channel_map;
        }
 
-       iwl3945_rate_control_register(priv->hw);
        err = ieee80211_register_hw(priv->hw);
        if (err) {
                IWL_ERROR("Failed to register network device (error %d)\n", err);
@@ -8180,6 +8199,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
        struct iwl3945_priv *priv = pci_get_drvdata(pdev);
        struct list_head *p, *q;
        int i;
+       unsigned long flags;
 
        if (!priv)
                return;
@@ -8190,6 +8210,15 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
 
        iwl3945_down(priv);
 
+       /* make sure we flush any pending irq or
+        * tasklet for the driver
+        */
+       spin_lock_irqsave(&priv->lock, flags);
+       iwl3945_disable_interrupts(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       iwl_synchronize_irq(priv);
+
        /* Free MAC hash list for ADHOC */
        for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
                list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
@@ -8211,7 +8240,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
 
        if (priv->mac80211_registered) {
                ieee80211_unregister_hw(priv->hw);
-               iwl3945_rate_control_unregister(priv->hw);
        }
 
        /*netif_stop_queue(dev); */
@@ -8292,21 +8320,35 @@ static int __init iwl3945_init(void)
        int ret;
        printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
        printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+
+       ret = iwl3945_rate_control_register();
+       if (ret) {
+               IWL_ERROR("Unable to register rate control algorithm: %d\n", ret);
+               return ret;
+       }
+
        ret = pci_register_driver(&iwl3945_driver);
        if (ret) {
                IWL_ERROR("Unable to initialize PCI module\n");
-               return ret;
+               goto error_register;
        }
 #ifdef CONFIG_IWL3945_DEBUG
        ret = driver_create_file(&iwl3945_driver.driver, &driver_attr_debug_level);
        if (ret) {
                IWL_ERROR("Unable to create driver sysfs file\n");
-               pci_unregister_driver(&iwl3945_driver);
-               return ret;
+               goto error_debug;
        }
 #endif
 
        return ret;
+
+#ifdef CONFIG_IWL3945_DEBUG
+error_debug:
+       pci_unregister_driver(&iwl3945_driver);
+#endif
+error_register:
+       iwl3945_rate_control_unregister();
+       return ret;
 }
 
 static void __exit iwl3945_exit(void)
@@ -8315,6 +8357,7 @@ static void __exit iwl3945_exit(void)
        driver_remove_file(&iwl3945_driver.driver, &driver_attr_debug_level);
 #endif
        pci_unregister_driver(&iwl3945_driver);
+       iwl3945_rate_control_unregister();
 }
 
 module_param_named(antenna, iwl3945_param_antenna, int, 0444);