]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/iwlwifi/iwl3945-base.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireles...
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / iwlwifi / iwl3945-base.c
index ce8a31103eeec900c2231f99da565cc07addbbf0..13925b627e3b5569f5ebaf1399f121dea3d489d2 100644 (file)
@@ -70,7 +70,7 @@ static int iwl3945_param_disable;  /* def: 0 = enable radio */
 static int iwl3945_param_antenna;  /* def: 0 = both antennas (use diversity) */
 int iwl3945_param_hwcrypto;        /* def: 0 = use software encryption */
 static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */
-int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 8 Tx queues */
+int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */
 
 /*
  * module name, copyright, version, etc.
@@ -733,17 +733,17 @@ static int iwl3945_send_cmd_sync(struct iwl3945_priv *priv, struct iwl3945_host_
 {
        int cmd_idx;
        int ret;
-       static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */
 
        BUG_ON(cmd->meta.flags & CMD_ASYNC);
 
         /* A synchronous command can not have a callback set. */
        BUG_ON(cmd->meta.u.callback != NULL);
 
-       if (atomic_xchg(&entry, 1)) {
+       if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
                IWL_ERROR("Error sending %s: Already sending a host command\n",
                          get_cmd_string(cmd->id));
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out;
        }
 
        set_bit(STATUS_HCMD_ACTIVE, &priv->status);
@@ -813,7 +813,7 @@ fail:
                cmd->meta.u.skb = NULL;
        }
 out:
-       atomic_set(&entry, 0);
+       clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
        return ret;
 }
 
@@ -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;
 }
@@ -4951,15 +4965,7 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
        passive_dwell = iwl3945_get_passive_dwell_time(priv, band);
 
        for (i = 0, added = 0; i < sband->n_channels; i++) {
-               if (channels[i].hw_value ==
-                   le16_to_cpu(priv->active_rxon.channel)) {
-                       if (iwl3945_is_associated(priv)) {
-                               IWL_DEBUG_SCAN
-                                   ("Skipping current channel %d\n",
-                                    le16_to_cpu(priv->active_rxon.channel));
-                               continue;
-                       }
-               } else if (priv->only_active_channel)
+               if (channels[i].flags & IEEE80211_CHAN_DISABLED)
                        continue;
 
                scan_ch->channel = channels[i].hw_value;
@@ -5857,18 +5863,19 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
 
        /* At this point, the NIC is initialized and operational */
        priv->notif_missed_beacons = 0;
-       set_bit(STATUS_READY, &priv->status);
 
        iwl3945_reg_txpower_periodic(priv);
 
+       iwl3945_led_register(priv);
+
        IWL_DEBUG_INFO("ALIVE processing complete.\n");
+       set_bit(STATUS_READY, &priv->status);
        wake_up_interruptible(&priv->wait_command_queue);
 
-       iwl3945_led_register(priv);
-
        if (priv->error_recovering)
                iwl3945_error_recovery(priv);
 
+       ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC);
        return;
 
  restart:
@@ -5905,7 +5912,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);
@@ -6282,12 +6292,17 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
                       priv->direct_ssid, priv->direct_ssid_len);
                direct_mask = 1;
        } else if (!iwl3945_is_associated(priv) && priv->essid_len) {
+               IWL_DEBUG_SCAN
+                 ("Kicking off one direct scan for '%s' when not associated\n",
+                  iwl3945_escape_essid(priv->essid, priv->essid_len));
                scan->direct_scan[0].id = WLAN_EID_SSID;
                scan->direct_scan[0].len = priv->essid_len;
                memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
                direct_mask = 1;
-       } else
+       } else {
+               IWL_DEBUG_SCAN("Kicking off one indirect scan.\n");
                direct_mask = 0;
+       }
 
        /* We don't build a direct scan probe request; the uCode will do
         * that based on the direct_mask added to each channel entry */
@@ -6325,23 +6340,18 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
        if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
                scan->filter_flags = RXON_FILTER_PROMISC_MSK;
 
-       if (direct_mask) {
-               IWL_DEBUG_SCAN
-                   ("Initiating direct scan for %s.\n",
-                    iwl3945_escape_essid(priv->essid, priv->essid_len));
+       if (direct_mask)
                scan->channel_count =
                        iwl3945_get_channels_for_scan(
                                priv, band, 1, /* active */
                                direct_mask,
                                (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
-       } else {
-               IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+       else
                scan->channel_count =
                        iwl3945_get_channels_for_scan(
                                priv, band, 0, /* passive */
                                direct_mask,
                                (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
-       }
 
        cmd.len += le16_to_cpu(scan->tx_cmd.len) +
            scan->channel_count * sizeof(struct iwl3945_scan_channel);
@@ -6886,7 +6896,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
 
        if (priv->vif != vif) {
                IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
-               mutex_unlock(&priv->mutex);
                return 0;
        }
 
@@ -7294,8 +7303,6 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
                return;
        }
 
-       priv->only_active_channel = 0;
-
        iwl3945_set_rate(priv);
 
        mutex_unlock(&priv->mutex);
@@ -7943,6 +7950,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
@@ -7952,10 +7960,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
                iwl3945_hw_ops.hw_scan = NULL;
        }
 
-       if ((iwl3945_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+       if ((iwl3945_param_queues_num > IWL39_MAX_NUM_QUEUES) ||
            (iwl3945_param_queues_num < IWL_MIN_NUM_QUEUES)) {
                IWL_ERROR("invalid queues_num, should be between %d and %d\n",
-                         IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
+                         IWL_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
                err = -EINVAL;
                goto out;
        }
@@ -8093,7 +8101,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 +8146,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);
@@ -8175,11 +8184,12 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        return err;
 }
 
-static void iwl3945_pci_remove(struct pci_dev *pdev)
+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 +8200,15 @@ static void 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 +8230,6 @@ static void 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 +8310,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 +8347,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);