Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-core.c
index e93ddb7..6ab0716 100644 (file)
@@ -36,7 +36,6 @@
 #include "iwl-debug.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
-#include "iwl-rfkill.h"
 #include "iwl-power.h"
 #include "iwl-sta.h"
 #include "iwl-helpers.h"
@@ -630,13 +629,9 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
                if (!sta_ht_inf->ht_supported)
                        return 0;
        }
-
-       if (iwl_ht_conf->ht_protection & IEEE80211_HT_OP_MODE_PROTECTION_20MHZ)
-               return 1;
-       else
-               return iwl_is_channel_extension(priv, priv->band,
-                               le16_to_cpu(priv->staging_rxon.channel),
-                               iwl_ht_conf->extension_chan_offset);
+       return iwl_is_channel_extension(priv, priv->band,
+                       le16_to_cpu(priv->staging_rxon.channel),
+                       iwl_ht_conf->extension_chan_offset);
 }
 EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
 
@@ -827,9 +822,18 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
                         RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
        if (iwl_is_fat_tx_allowed(priv, NULL)) {
                /* pure 40 fat */
-               if (rxon->flags & RXON_FLG_FAT_PROT_MSK)
+               if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
                        rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
-               else {
+                       /* Note: control channel is opposite of extension channel */
+                       switch (ht_info->extension_chan_offset) {
+                       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+                               rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+                               break;
+                       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+                               rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+                               break;
+                       }
+               } else {
                        /* Note: control channel is opposite of extension channel */
                        switch (ht_info->extension_chan_offset) {
                        case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
@@ -1389,7 +1393,7 @@ int iwl_init_drv(struct iwl_priv *priv)
        mutex_init(&priv->mutex);
 
        /* Clear the driver's (not device's) station table */
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
 
        priv->data_retry_limit = -1;
        priv->ieee_channels = NULL;
@@ -1704,8 +1708,9 @@ static irqreturn_t iwl_isr(int irq, void *data)
 {
        struct iwl_priv *priv = data;
        u32 inta, inta_mask;
+#ifdef CONFIG_IWLWIFI_DEBUG
        u32 inta_fh;
-
+#endif
        if (!priv)
                return IRQ_NONE;
 
@@ -2210,126 +2215,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
 }
 EXPORT_SYMBOL(iwl_send_card_state);
 
-void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv)
-{
-       unsigned long flags;
-
-       if (test_bit(STATUS_RF_KILL_SW, &priv->status))
-               return;
-
-       IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO OFF\n");
-
-       iwl_scan_cancel(priv);
-       /* FIXME: This is a workaround for AP */
-       if (priv->iw_mode != NL80211_IFTYPE_AP) {
-               spin_lock_irqsave(&priv->lock, flags);
-               iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
-                           CSR_UCODE_SW_BIT_RFKILL);
-               spin_unlock_irqrestore(&priv->lock, flags);
-               /* call the host command only if no hw rf-kill set */
-               if (!test_bit(STATUS_RF_KILL_HW, &priv->status) &&
-                   iwl_is_ready(priv))
-                       iwl_send_card_state(priv,
-                               CARD_STATE_CMD_DISABLE, 0);
-               set_bit(STATUS_RF_KILL_SW, &priv->status);
-                       /* make sure mac80211 stop sending Tx frame */
-               if (priv->mac80211_registered)
-                       ieee80211_stop_queues(priv->hw);
-       }
-}
-EXPORT_SYMBOL(iwl_radio_kill_sw_disable_radio);
-
-int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv)
-{
-       unsigned long flags;
-
-       if (!test_bit(STATUS_RF_KILL_SW, &priv->status))
-               return 0;
-
-       IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO ON\n");
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-       /* If the driver is up it will receive CARD_STATE_NOTIFICATION
-        * notification where it will clear SW rfkill status.
-        * Setting it here would break the handler. Only if the
-        * interface is down we can set here since we don't
-        * receive any further notification.
-        */
-       if (!priv->is_open)
-               clear_bit(STATUS_RF_KILL_SW, &priv->status);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* wake up ucode */
-       msleep(10);
-
-       iwl_read32(priv, CSR_UCODE_DRV_GP1);
-       spin_lock_irqsave(&priv->reg_lock, flags);
-       if (!iwl_grab_nic_access(priv))
-               iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->reg_lock, flags);
-
-       if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
-               IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - "
-                                 "disabled by HW switch\n");
-               return 0;
-       }
-
-       /* when driver is up while rfkill is on, it wont receive
-        * any CARD_STATE_NOTIFICATION notifications so we have to
-        * restart it in here
-        */
-       if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) {
-               clear_bit(STATUS_RF_KILL_SW, &priv->status);
-               if (!iwl_is_rfkill(priv))
-                       queue_work(priv->workqueue, &priv->up);
-       }
-
-       /* If the driver is already loaded, it will receive
-        * CARD_STATE_NOTIFICATION notifications and the handler will
-        * call restart to reload the driver.
-        */
-       return 1;
-}
-EXPORT_SYMBOL(iwl_radio_kill_sw_enable_radio);
-
-void iwl_bg_rf_kill(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
-
-       wake_up_interruptible(&priv->wait_command_queue);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       mutex_lock(&priv->mutex);
-
-       if (!iwl_is_rfkill(priv)) {
-               IWL_DEBUG_RF_KILL(priv,
-                         "HW and/or SW RF Kill no longer active, restarting "
-                         "device\n");
-               if (!test_bit(STATUS_EXIT_PENDING, &priv->status) &&
-                   priv->is_open)
-                       queue_work(priv->workqueue, &priv->restart);
-       } else {
-               /* make sure mac80211 stop sending Tx frame */
-               if (priv->mac80211_registered)
-                       ieee80211_stop_queues(priv->hw);
-
-               if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
-                       IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - "
-                                         "disabled by SW switch\n");
-               else
-                       IWL_WARN(priv, "Radio Frequency Kill Switch is On:\n"
-                                   "Kill switch must be turned off for "
-                                   "wireless networking to work.\n");
-       }
-       mutex_unlock(&priv->mutex);
-       iwl_rfkill_set_hw_state(priv);
-}
-EXPORT_SYMBOL(iwl_bg_rf_kill);
-
 void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
                           struct iwl_rx_mem_buffer *rxb)
 {
@@ -2510,39 +2395,46 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
        }
 
-       if ((changes & BSS_CHANGED_BSSID) && !iwl_is_rfkill(priv)) {
-               /* If there is currently a HW scan going on in the background
-                * then we need to cancel it else the RXON below will fail. */
+       if (changes & BSS_CHANGED_BEACON_INT) {
+               priv->beacon_int = bss_conf->beacon_int;
+               /* TODO: in AP mode, do something to make this take effect */
+       }
+
+       if (changes & BSS_CHANGED_BSSID) {
+               IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid);
+
+               /*
+                * If there is currently a HW scan going on in the
+                * background then we need to cancel it else the RXON
+                * below/in post_associate will fail.
+                */
                if (iwl_scan_cancel_timeout(priv, 100)) {
-                       IWL_WARN(priv, "Aborted scan still in progress "
-                                   "after 100ms\n");
+                       IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
                        IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
                        mutex_unlock(&priv->mutex);
                        return;
                }
-               memcpy(priv->staging_rxon.bssid_addr,
-                      bss_conf->bssid, ETH_ALEN);
-
-               /* TODO: Audit driver for usage of these members and see
-                * if mac80211 deprecates them (priv->bssid looks like it
-                * shouldn't be there, but I haven't scanned the IBSS code
-                * to verify) - jpk */
-               memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
-
-               if (priv->iw_mode == NL80211_IFTYPE_AP)
-                       iwlcore_config_ap(priv);
-               else {
-                       int rc = iwlcore_commit_rxon(priv);
-                       if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc)
-                               iwl_rxon_add_station(
-                                       priv, priv->active_rxon.bssid_addr, 1);
+
+               /* mac80211 only sets assoc when in STATION mode */
+               if (priv->iw_mode == NL80211_IFTYPE_ADHOC ||
+                   bss_conf->assoc) {
+                       memcpy(priv->staging_rxon.bssid_addr,
+                              bss_conf->bssid, ETH_ALEN);
+
+                       /* currently needed in a few places */
+                       memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
+               } else {
+                       priv->staging_rxon.filter_flags &=
+                               ~RXON_FILTER_ASSOC_MSK;
                }
-       } else if (!iwl_is_rfkill(priv)) {
-               iwl_scan_cancel_timeout(priv, 100);
-               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
+
        }
 
+       /*
+        * This needs to be after setting the BSSID in case
+        * mac80211 decides to do both changes at once because
+        * it will invoke post_associate.
+        */
        if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
            changes & BSS_CHANGED_BEACON) {
                struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
@@ -2551,8 +2443,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                        iwl_mac_beacon_update(hw, beacon);
        }
 
-       mutex_unlock(&priv->mutex);
-
        if (changes & BSS_CHANGED_ERP_PREAMBLE) {
                IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
                                   bss_conf->use_short_preamble);
@@ -2570,6 +2460,23 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                        priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
        }
 
+       if (changes & BSS_CHANGED_BASIC_RATES) {
+               /* XXX use this information
+                *
+                * To do that, remove code from iwl_set_rate() and put something
+                * like this here:
+                *
+               if (A-band)
+                       priv->staging_rxon.ofdm_basic_rates =
+                               bss_conf->basic_rates;
+               else
+                       priv->staging_rxon.ofdm_basic_rates =
+                               bss_conf->basic_rates >> 4;
+                       priv->staging_rxon.cck_basic_rates =
+                               bss_conf->basic_rates & 0xF;
+                */
+       }
+
        if (changes & BSS_CHANGED_HT) {
                iwl_ht_conf(priv, bss_conf);
 
@@ -2579,10 +2486,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
 
        if (changes & BSS_CHANGED_ASSOC) {
                IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc);
-               /* This should never happen as this function should
-                * never be called from interrupt context. */
-               if (WARN_ON_ONCE(in_interrupt()))
-                       return;
                if (bss_conf->assoc) {
                        priv->assoc_id = bss_conf->aid;
                        priv->beacon_int = bss_conf->beacon_int;
@@ -2590,27 +2493,35 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                        priv->timestamp = bss_conf->timestamp;
                        priv->assoc_capability = bss_conf->assoc_capability;
 
-                       /* we have just associated, don't start scan too early
-                        * leave time for EAPOL exchange to complete
+                       /*
+                        * We have just associated, don't start scan too early
+                        * leave time for EAPOL exchange to complete.
+                        *
+                        * XXX: do this in mac80211
                         */
                        priv->next_scan_jiffies = jiffies +
                                        IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
-                       mutex_lock(&priv->mutex);
-                       priv->cfg->ops->lib->post_associate(priv);
-                       mutex_unlock(&priv->mutex);
-               } else {
+                       if (!iwl_is_rfkill(priv))
+                               priv->cfg->ops->lib->post_associate(priv);
+               } else
                        priv->assoc_id = 0;
-                       IWL_DEBUG_MAC80211(priv, "DISASSOC %d\n", bss_conf->assoc);
+
+       }
+
+       if (changes && iwl_is_associated(priv) && priv->assoc_id) {
+               IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n",
+                                  changes);
+               ret = iwl_send_rxon_assoc(priv);
+               if (!ret) {
+                       /* Sync active_rxon with latest change. */
+                       memcpy((void *)&priv->active_rxon,
+                               &priv->staging_rxon,
+                               sizeof(struct iwl_rxon_cmd));
                }
-       } else if (changes && iwl_is_associated(priv) && priv->assoc_id) {
-                       IWL_DEBUG_MAC80211(priv, "Associated Changes %d\n", changes);
-                       ret = iwl_send_rxon_assoc(priv);
-                       if (!ret)
-                               /* Sync active_rxon with latest change. */
-                               memcpy((void *)&priv->active_rxon,
-                                       &priv->staging_rxon,
-                                       sizeof(struct iwl_rxon_cmd));
        }
+
+       mutex_unlock(&priv->mutex);
+
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 EXPORT_SYMBOL(iwl_bss_info_changed);
@@ -2679,19 +2590,12 @@ int iwl_set_mode(struct iwl_priv *priv, int mode)
 
        memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
 
        /* dont commit rxon if rf-kill is on*/
        if (!iwl_is_ready_rf(priv))
                return -EAGAIN;
 
-       cancel_delayed_work(&priv->scan_check);
-       if (iwl_scan_cancel_timeout(priv, 100)) {
-               IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
-               IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
-               return -EAGAIN;
-       }
-
        iwlcore_commit_rxon(priv);
 
        return 0;
@@ -2855,23 +2759,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
        if (priv->cfg->ops->hcmd->set_rxon_chain)
                priv->cfg->ops->hcmd->set_rxon_chain(priv);
 
-       if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
-               if (conf->radio_enabled &&
-                       iwl_radio_kill_sw_enable_radio(priv)) {
-                       IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - "
-                                               "waiting for uCode\n");
-                       goto out;
-               }
-
-               if (!conf->radio_enabled)
-                       iwl_radio_kill_sw_disable_radio(priv);
-       }
-
-       if (!conf->radio_enabled) {
-               IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n");
-               goto out;
-       }
-
        if (!iwl_is_ready(priv)) {
                IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
                goto out;