iwlwifi: introduce post_scan hook
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / net / wireless / iwlwifi / iwl3945-base.c
index de6d592..db148d0 100644 (file)
@@ -144,7 +144,7 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
        key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
        key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
 
-       if (sta_id == priv->hw_params.bcast_sta_id)
+       if (sta_id == priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id)
                key_flags |= STA_KEY_MULTICAST_MSK;
 
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
@@ -152,7 +152,7 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
        key_flags &= ~STA_KEY_FLG_INVALID;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
-       priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+       priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
        priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
        memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
               keyconf->keylen);
@@ -223,23 +223,25 @@ static int iwl3945_set_dynamic_key(struct iwl_priv *priv,
 
        keyconf->hw_key_idx = HW_KEY_DYNAMIC;
 
-       switch (keyconf->alg) {
-       case ALG_CCMP:
+       switch (keyconf->cipher) {
+       case WLAN_CIPHER_SUITE_CCMP:
                ret = iwl3945_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                ret = iwl3945_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
                break;
-       case ALG_WEP:
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                ret = iwl3945_set_wep_dynamic_key_info(priv, keyconf, sta_id);
                break;
        default:
-               IWL_ERR(priv, "Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
+               IWL_ERR(priv, "Unknown alg: %s alg=%x\n", __func__,
+                       keyconf->cipher);
                ret = -EINVAL;
        }
 
-       IWL_DEBUG_WEP(priv, "Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n",
-                     keyconf->alg, keyconf->keylen, keyconf->keyidx,
+       IWL_DEBUG_WEP(priv, "Set dynamic key: alg=%x len=%d idx=%d sta=%d ret=%d\n",
+                     keyconf->cipher, keyconf->keylen, keyconf->keyidx,
                      sta_id, ret);
 
        return ret;
@@ -255,10 +257,11 @@ static int iwl3945_remove_static_key(struct iwl_priv *priv)
 static int iwl3945_set_static_key(struct iwl_priv *priv,
                                struct ieee80211_key_conf *key)
 {
-       if (key->alg == ALG_WEP)
+       if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+           key->cipher == WLAN_CIPHER_SUITE_WEP104)
                return -EOPNOTSUPP;
 
-       IWL_ERR(priv, "Static key invalid: alg %d\n", key->alg);
+       IWL_ERR(priv, "Static key invalid: cipher %x\n", key->cipher);
        return -EINVAL;
 }
 
@@ -314,7 +317,7 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
                                int left)
 {
 
-       if (!iwl_is_associated(priv) || !priv->ibss_beacon)
+       if (!iwl_is_associated(priv, IWL_RXON_CTX_BSS) || !priv->ibss_beacon)
                return 0;
 
        if (priv->ibss_beacon->len > left)
@@ -340,7 +343,8 @@ static int iwl3945_send_beacon_cmd(struct iwl_priv *priv)
                return -ENOMEM;
        }
 
-       rate = iwl_rate_get_lowest_plcp(priv);
+       rate = iwl_rate_get_lowest_plcp(priv,
+                               &priv->contexts[IWL_RXON_CTX_BSS]);
 
        frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate);
 
@@ -370,23 +374,25 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
        struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
        struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
 
-       switch (keyinfo->alg) {
-       case ALG_CCMP:
+       tx_cmd->sec_ctl = 0;
+
+       switch (keyinfo->cipher) {
+       case WLAN_CIPHER_SUITE_CCMP:
                tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
                memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen);
                IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
                break;
 
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                break;
 
-       case ALG_WEP:
-               tx_cmd->sec_ctl = TX_CMD_SEC_WEP |
+       case WLAN_CIPHER_SUITE_WEP104:
+               tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+               /* fall through */
+       case WLAN_CIPHER_SUITE_WEP40:
+               tx_cmd->sec_ctl |= TX_CMD_SEC_WEP |
                    (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
 
-               if (keyinfo->keylen == 13)
-                       tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
-
                memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen);
 
                IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
@@ -394,7 +400,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
                break;
 
        default:
-               IWL_ERR(priv, "Unknown encode alg %d\n", keyinfo->alg);
+               IWL_ERR(priv, "Unknown encode cipher %x\n", keyinfo->cipher);
                break;
        }
 }
@@ -507,7 +513,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        hdr_len = ieee80211_hdrlen(fc);
 
        /* Find index into station table for destination station */
-       sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
+       sta_id = iwl_sta_id_or_broadcast(
+                       priv, &priv->contexts[IWL_RXON_CTX_BSS],
+                       info->control.sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                               hdr->addr1);
@@ -537,6 +545,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
        txq->txb[q->write_ptr].skb = skb;
+       txq->txb[q->write_ptr].ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        /* Init first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = txq->cmd[idx];
@@ -678,11 +687,12 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
        int rc;
        int spectrum_resp_status;
        int duration = le16_to_cpu(params->duration);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
-       if (iwl_is_associated(priv))
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS))
                add_time = iwl_usecs_to_beacons(priv,
                        le64_to_cpu(params->start_time) - priv->_3945.last_tsf,
-                       le16_to_cpu(priv->rxon_timing.beacon_interval));
+                       le16_to_cpu(ctx->timing.beacon_interval));
 
        memset(&spectrum, 0, sizeof(spectrum));
 
@@ -693,18 +703,18 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
        cmd.len = sizeof(spectrum);
        spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
 
-       if (iwl_is_associated(priv))
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS))
                spectrum.start_time =
                        iwl_add_beacon_time(priv,
                                priv->_3945.last_beacon_time, add_time,
-                               le16_to_cpu(priv->rxon_timing.beacon_interval));
+                               le16_to_cpu(ctx->timing.beacon_interval));
        else
                spectrum.start_time = 0;
 
        spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
        spectrum.channels[0].channel = params->channel;
        spectrum.channels[0].type = type;
-       if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+       if (ctx->active.flags & RXON_FLG_BAND_24G_MSK)
                spectrum.flags |= RXON_FLG_BAND_24G_MSK |
                    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
 
@@ -793,7 +803,8 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
        struct sk_buff *beacon;
 
        /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-       beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+       beacon = ieee80211_beacon_get(priv->hw,
+                       priv->contexts[IWL_RXON_CTX_BSS].vif);
 
        if (!beacon) {
                IWL_ERR(priv, "update beacon failed\n");
@@ -814,9 +825,9 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
 static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
                                struct iwl_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status);
+#ifdef CONFIG_IWLWIFI_DEBUG
        u8 rate = beacon->beacon_notify_hdr.rate;
 
        IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d "
@@ -828,6 +839,8 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
                le32_to_cpu(beacon->low_tsf), rate);
 #endif
 
+       priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
+
        if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
            (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
                queue_work(priv->workqueue, &priv->beacon_update);
@@ -1568,16 +1581,16 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
        num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
        next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
 
-       if (capacity > priv->cfg->max_event_log_size) {
+       if (capacity > priv->cfg->base_params->max_event_log_size) {
                IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
-                       capacity, priv->cfg->max_event_log_size);
-               capacity = priv->cfg->max_event_log_size;
+                       capacity, priv->cfg->base_params->max_event_log_size);
+               capacity = priv->cfg->base_params->max_event_log_size;
        }
 
-       if (next_entry > priv->cfg->max_event_log_size) {
+       if (next_entry > priv->cfg->base_params->max_event_log_size) {
                IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
-                       next_entry, priv->cfg->max_event_log_size);
-               next_entry = priv->cfg->max_event_log_size;
+                       next_entry, priv->cfg->base_params->max_event_log_size);
+               next_entry = priv->cfg->base_params->max_event_log_size;
        }
 
        size = num_wraps ? capacity : next_entry;
@@ -1717,7 +1730,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
                IWL_ERR(priv, "Microcode SW error detected. "
                        "Restarting 0x%X.\n", inta);
                priv->isr_stats.sw++;
-               priv->isr_stats.sw_err = inta;
                iwl_irq_handle_error(priv);
                handled |= CSR_INT_BIT_SW_ERR;
        }
@@ -2461,6 +2473,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
 {
        int thermal_spin = 0;
        u32 rfkill;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
 
@@ -2506,7 +2519,8 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
                /* Enable timer to monitor the driver queues */
                mod_timer(&priv->monitor_recover,
                        jiffies +
-                       msecs_to_jiffies(priv->cfg->monitor_recover_period));
+                       msecs_to_jiffies(
+                         priv->cfg->base_params->monitor_recover_period));
        }
 
        if (iwl_is_rfkill(priv))
@@ -2518,22 +2532,22 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
 
        iwl_power_update_mode(priv, true);
 
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
                struct iwl3945_rxon_cmd *active_rxon =
-                               (struct iwl3945_rxon_cmd *)(&priv->active_rxon);
+                               (struct iwl3945_rxon_cmd *)(&ctx->active);
 
-               priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        } else {
                /* Initialize our rx_config data */
-               iwl_connection_init_rx_config(priv, NULL);
+               iwl_connection_init_rx_config(priv, ctx);
        }
 
        /* Configure Bluetooth device coexistence support */
        priv->cfg->ops->hcmd->send_bt_config(priv);
 
        /* Configure the adapter for unassociated operation */
-       iwlcore_commit_rxon(priv);
+       iwlcore_commit_rxon(priv, ctx);
 
        iwl3945_reg_txpower_periodic(priv);
 
@@ -2554,19 +2568,22 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv);
 static void __iwl3945_down(struct iwl_priv *priv)
 {
        unsigned long flags;
-       int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
-       struct ieee80211_conf *conf = NULL;
+       int exit_pending;
 
        IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
 
-       conf = ieee80211_get_hw_conf(priv->hw);
+       iwl_scan_cancel_timeout(priv, 200);
 
-       if (!exit_pending)
-               set_bit(STATUS_EXIT_PENDING, &priv->status);
+       exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+       /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
+        * to prevent rearm timer */
+       if (priv->cfg->ops->lib->recover_from_tx_stall)
+               del_timer_sync(&priv->monitor_recover);
 
        /* Station information will now be cleared in device */
-       iwl_clear_ucode_stations(priv);
-       iwl_dealloc_bcast_station(priv);
+       iwl_clear_ucode_stations(priv, NULL);
+       iwl_dealloc_bcast_stations(priv);
        iwl_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
@@ -2648,7 +2665,8 @@ static int __iwl3945_up(struct iwl_priv *priv)
 {
        int rc, i;
 
-       rc = iwl_alloc_bcast_station(priv, false);
+       rc = iwl_alloc_bcast_station(priv, &priv->contexts[IWL_RXON_CTX_BSS],
+                                    false);
        if (rc)
                return rc;
 
@@ -2800,7 +2818,7 @@ static void iwl3945_rfkill_poll(struct work_struct *data)
 
 }
 
-void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
+int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        struct iwl_host_cmd cmd = {
                .id = REPLY_SCAN_CMD,
@@ -2808,61 +2826,19 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                .flags = CMD_SIZE_HUGE,
        };
        struct iwl3945_scan_cmd *scan;
-       struct ieee80211_conf *conf = NULL;
        u8 n_probes = 0;
        enum ieee80211_band band;
        bool is_active = false;
+       int ret;
 
-       conf = ieee80211_get_hw_conf(priv->hw);
-
-       cancel_delayed_work(&priv->scan_check);
-
-       if (!iwl_is_ready(priv)) {
-               IWL_WARN(priv, "request scan called when driver not ready.\n");
-               goto done;
-       }
-
-       /* Make sure the scan wasn't canceled before this queued work
-        * was given the chance to run... */
-       if (!test_bit(STATUS_SCANNING, &priv->status))
-               goto done;
-
-       /* This should never be called or scheduled if there is currently
-        * a scan active in the hardware. */
-       if (test_bit(STATUS_SCAN_HW, &priv->status)) {
-               IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests  "
-                               "Ignoring second request.\n");
-               goto done;
-       }
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-               IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n");
-               goto done;
-       }
-
-       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-               IWL_DEBUG_HC(priv,
-                       "Scan request while abort pending. Queuing.\n");
-               goto done;
-       }
-
-       if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n");
-               goto done;
-       }
-
-       if (!test_bit(STATUS_READY, &priv->status)) {
-               IWL_DEBUG_HC(priv,
-                       "Scan request while uninitialized. Queuing.\n");
-               goto done;
-       }
+       lockdep_assert_held(&priv->mutex);
 
        if (!priv->scan_cmd) {
                priv->scan_cmd = kmalloc(sizeof(struct iwl3945_scan_cmd) +
                                         IWL_MAX_SCAN_SIZE, GFP_KERNEL);
                if (!priv->scan_cmd) {
                        IWL_DEBUG_SCAN(priv, "Fail to allocate scan memory\n");
-                       goto done;
+                       return -ENOMEM;
                }
        }
        scan = priv->scan_cmd;
@@ -2871,7 +2847,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
        scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
 
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
                u16 interval = 0;
                u32 extra;
                u32 suspend_time = 100;
@@ -2932,7 +2908,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        /* We don't build a direct scan probe request; the uCode will do
         * that based on the direct_mask added to each channel entry */
        scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-       scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
+       scan->tx_cmd.sta_id = priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id;
        scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
        /* flags + rate selection */
@@ -2957,7 +2933,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                break;
        default:
                IWL_WARN(priv, "Invalid scan band\n");
-               goto done;
+               return -EIO;
        }
 
        if (!priv->is_internal_short_scan) {
@@ -2992,7 +2968,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 
        if (scan->channel_count == 0) {
                IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
-               goto done;
+               return -EIO;
        }
 
        cmd.len += le16_to_cpu(scan->tx_cmd.len) +
@@ -3001,25 +2977,22 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        scan->len = cpu_to_le16(cmd.len);
 
        set_bit(STATUS_SCAN_HW, &priv->status);
-       if (iwl_send_cmd_sync(priv, &cmd))
-               goto done;
-
-       queue_delayed_work(priv->workqueue, &priv->scan_check,
-                          IWL_SCAN_CHECK_WATCHDOG);
+       ret = iwl_send_cmd_sync(priv, &cmd);
+       if (ret)
+               clear_bit(STATUS_SCAN_HW, &priv->status);
+       return ret;
+}
 
-       return;
+void iwl3945_post_scan(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
- done:
-       /* can not perform scan make sure we clear scanning
-        * bits from status so next scan request can be performed.
-        * if we dont clear scanning status bit here all next scan
-        * will fail
-       */
-       clear_bit(STATUS_SCAN_HW, &priv->status);
-       clear_bit(STATUS_SCANNING, &priv->status);
-
-       /* inform mac80211 scan aborted */
-       queue_work(priv->workqueue, &priv->scan_completed);
+       /*
+        * Since setting the RXON may have been deferred while
+        * performing the scan, fire one off if needed
+        */
+       if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+               iwlcore_commit_rxon(priv, ctx);
 }
 
 static void iwl3945_bg_restart(struct work_struct *data)
@@ -3030,8 +3003,10 @@ static void iwl3945_bg_restart(struct work_struct *data)
                return;
 
        if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
+               struct iwl_rxon_context *ctx;
                mutex_lock(&priv->mutex);
-               priv->vif = NULL;
+               for_each_context(priv, ctx)
+                       ctx->vif = NULL;
                priv->is_open = 0;
                mutex_unlock(&priv->mutex);
                iwl3945_down(priv);
@@ -3065,6 +3040,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        int rc = 0;
        struct ieee80211_conf *conf = NULL;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        if (!vif || !priv->is_open)
                return;
@@ -3075,7 +3051,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
        }
 
        IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
-                       vif->bss_conf.aid, priv->active_rxon.bssid_addr);
+                       vif->bss_conf.aid, ctx->active.bssid_addr);
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
@@ -3084,37 +3060,34 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 
        conf = ieee80211_get_hw_conf(priv->hw);
 
-       priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwlcore_commit_rxon(priv);
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       iwlcore_commit_rxon(priv, ctx);
 
-       memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-       iwl_setup_rxon_timing(priv, vif);
-       rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
-                             sizeof(priv->rxon_timing), &priv->rxon_timing);
+       rc = iwl_send_rxon_timing(priv, ctx);
        if (rc)
                IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
                            "Attempting to continue.\n");
 
-       priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+       ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
 
-       priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+       ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
 
        IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
                        vif->bss_conf.aid, vif->bss_conf.beacon_int);
 
        if (vif->bss_conf.use_short_preamble)
-               priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
        else
-               priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
-       if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+       if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
                if (vif->bss_conf.use_short_slot)
-                       priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
        }
 
-       iwlcore_commit_rxon(priv);
+       iwlcore_commit_rxon(priv, ctx);
 
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
@@ -3213,15 +3186,6 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw)
 
        priv->is_open = 0;
 
-       if (iwl_is_ready_rf(priv)) {
-               /* stop mac, cancel any scan request and clear
-                * RXON_FILTER_ASSOC_MSK BIT
-                */
-               mutex_lock(&priv->mutex);
-               iwl_scan_cancel_timeout(priv, 100);
-               mutex_unlock(&priv->mutex);
-       }
-
        iwl3945_down(priv);
 
        flush_workqueue(priv->workqueue);
@@ -3251,48 +3215,45 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        int rc = 0;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* The following should be done only at AP bring up */
-       if (!(iwl_is_associated(priv))) {
+       if (!(iwl_is_associated(priv, IWL_RXON_CTX_BSS))) {
 
                /* RXON - unassoc (to set timing command) */
-               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
+               ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv, ctx);
 
                /* RXON Timing */
-               memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-               iwl_setup_rxon_timing(priv, vif);
-               rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
-                                     sizeof(priv->rxon_timing),
-                                     &priv->rxon_timing);
+               rc = iwl_send_rxon_timing(priv, ctx);
                if (rc)
                        IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
                                        "Attempting to continue.\n");
 
-               priv->staging_rxon.assoc_id = 0;
+               ctx->staging.assoc_id = 0;
 
                if (vif->bss_conf.use_short_preamble)
-                       priv->staging_rxon.flags |=
+                       ctx->staging.flags |=
                                RXON_FLG_SHORT_PREAMBLE_MSK;
                else
-                       priv->staging_rxon.flags &=
+                       ctx->staging.flags &=
                                ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
-               if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+               if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
                        if (vif->bss_conf.use_short_slot)
-                               priv->staging_rxon.flags |=
+                               ctx->staging.flags |=
                                        RXON_FLG_SHORT_SLOT_MSK;
                        else
-                               priv->staging_rxon.flags &=
+                               ctx->staging.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
                }
                /* restore RXON assoc */
-               priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv, ctx);
        }
        iwl3945_send_beacon_cmd(priv);
 
@@ -3318,10 +3279,11 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                return -EOPNOTSUPP;
        }
 
-       static_key = !iwl_is_associated(priv);
+       static_key = !iwl_is_associated(priv, IWL_RXON_CTX_BSS);
 
        if (!static_key) {
-               sta_id = iwl_sta_id_or_broadcast(priv, sta);
+               sta_id = iwl_sta_id_or_broadcast(
+                               priv, &priv->contexts[IWL_RXON_CTX_BSS], sta);
                if (sta_id == IWL_INVALID_STATION)
                        return -EINVAL;
        }
@@ -3372,8 +3334,8 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw,
        sta_priv->common.sta_id = IWL_INVALID_STATION;
 
 
-       ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap,
-                                    &sta_id);
+       ret = iwl_add_station_common(priv, &priv->contexts[IWL_RXON_CTX_BSS],
+                                    sta->addr, is_ap, sta, &sta_id);
        if (ret) {
                IWL_ERR(priv, "Unable to add station %pM (%d)\n",
                        sta->addr, ret);
@@ -3392,6 +3354,56 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw,
 
        return 0;
 }
+
+static void iwl3945_configure_filter(struct ieee80211_hw *hw,
+                                    unsigned int changed_flags,
+                                    unsigned int *total_flags,
+                                    u64 multicast)
+{
+       struct iwl_priv *priv = hw->priv;
+       __le32 filter_or = 0, filter_nand = 0;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
+#define CHK(test, flag)        do { \
+       if (*total_flags & (test))              \
+               filter_or |= (flag);            \
+       else                                    \
+               filter_nand |= (flag);          \
+       } while (0)
+
+       IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
+                       changed_flags, *total_flags);
+
+       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+       CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);
+       CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
+
+#undef CHK
+
+       mutex_lock(&priv->mutex);
+
+       ctx->staging.filter_flags &= ~filter_nand;
+       ctx->staging.filter_flags |= filter_or;
+
+       /*
+        * Committing directly here breaks for some reason,
+        * but we'll eventually commit the filter flags
+        * change anyway.
+        */
+
+       mutex_unlock(&priv->mutex);
+
+       /*
+        * Receiving all multicast frames is always enabled by the
+        * default flags setup in iwl_connection_init_rx_config()
+        * since we currently do not support programming multicast
+        * filters into the device.
+        */
+       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+                       FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
+}
+
+
 /*****************************************************************************
  *
  * sysfs attributes
@@ -3485,8 +3497,9 @@ static ssize_t show_flags(struct device *d,
                          struct device_attribute *attr, char *buf)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
-       return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+       return sprintf(buf, "0x%04X\n", ctx->active.flags);
 }
 
 static ssize_t store_flags(struct device *d,
@@ -3495,17 +3508,18 @@ static ssize_t store_flags(struct device *d,
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
        u32 flags = simple_strtoul(buf, NULL, 0);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        mutex_lock(&priv->mutex);
-       if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+       if (le32_to_cpu(ctx->staging.flags) != flags) {
                /* Cancel any currently running scans... */
                if (iwl_scan_cancel_timeout(priv, 100))
                        IWL_WARN(priv, "Could not cancel scan.\n");
                else {
                        IWL_DEBUG_INFO(priv, "Committing rxon.flags = 0x%04X\n",
                                       flags);
-                       priv->staging_rxon.flags = cpu_to_le32(flags);
-                       iwlcore_commit_rxon(priv);
+                       ctx->staging.flags = cpu_to_le32(flags);
+                       iwlcore_commit_rxon(priv, ctx);
                }
        }
        mutex_unlock(&priv->mutex);
@@ -3519,9 +3533,10 @@ static ssize_t show_filter_flags(struct device *d,
                                 struct device_attribute *attr, char *buf)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        return sprintf(buf, "0x%04X\n",
-               le32_to_cpu(priv->active_rxon.filter_flags));
+               le32_to_cpu(ctx->active.filter_flags));
 }
 
 static ssize_t store_filter_flags(struct device *d,
@@ -3529,19 +3544,20 @@ static ssize_t store_filter_flags(struct device *d,
                                  const char *buf, size_t count)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        u32 filter_flags = simple_strtoul(buf, NULL, 0);
 
        mutex_lock(&priv->mutex);
-       if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+       if (le32_to_cpu(ctx->staging.filter_flags) != filter_flags) {
                /* Cancel any currently running scans... */
                if (iwl_scan_cancel_timeout(priv, 100))
                        IWL_WARN(priv, "Could not cancel scan.\n");
                else {
                        IWL_DEBUG_INFO(priv, "Committing rxon.filter_flags = "
                                       "0x%04X\n", filter_flags);
-                       priv->staging_rxon.filter_flags =
+                       ctx->staging.filter_flags =
                                cpu_to_le32(filter_flags);
-                       iwlcore_commit_rxon(priv);
+                       iwlcore_commit_rxon(priv, ctx);
                }
        }
        mutex_unlock(&priv->mutex);
@@ -3589,8 +3605,9 @@ static ssize_t store_measurement(struct device *d,
                                 const char *buf, size_t count)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct ieee80211_measurement_params params = {
-               .channel = le16_to_cpu(priv->active_rxon.channel),
+               .channel = le16_to_cpu(ctx->active.channel),
                .start_time = cpu_to_le64(priv->_3945.last_tsf),
                .duration = cpu_to_le16(1),
        };
@@ -3758,12 +3775,10 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv)
        iwl3945_hw_cancel_deferred_work(priv);
 
        cancel_delayed_work_sync(&priv->init_alive_start);
-       cancel_delayed_work(&priv->scan_check);
        cancel_delayed_work(&priv->alive_start);
-       cancel_work_sync(&priv->start_internal_scan);
        cancel_work_sync(&priv->beacon_update);
-       if (priv->cfg->ops->lib->recover_from_tx_stall)
-               del_timer_sync(&priv->monitor_recover);
+
+       iwl_cancel_scan_deferred_work(priv);
 }
 
 static struct attribute *iwl3945_sysfs_entries[] = {
@@ -3795,7 +3810,7 @@ static struct ieee80211_ops iwl3945_hw_ops = {
        .add_interface = iwl_mac_add_interface,
        .remove_interface = iwl_mac_remove_interface,
        .config = iwl_mac_config,
-       .configure_filter = iwl_configure_filter,
+       .configure_filter = iwl3945_configure_filter,
        .set_key = iwl3945_mac_set_key,
        .conf_tx = iwl_mac_conf_tx,
        .reset_tsf = iwl_mac_reset_tsf,
@@ -3803,6 +3818,7 @@ static struct ieee80211_ops iwl3945_hw_ops = {
        .hw_scan = iwl_mac_hw_scan,
        .sta_add = iwl3945_mac_sta_add,
        .sta_remove = iwl_mac_sta_remove,
+       .tx_last_beacon = iwl_mac_tx_last_beacon,
 };
 
 static int iwl3945_init_drv(struct iwl_priv *priv)
@@ -3878,13 +3894,12 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_SPECTRUM_MGMT;
 
-       if (!priv->cfg->broken_powersave)
+       if (!priv->cfg->base_params->broken_powersave)
                hw->flags |= IEEE80211_HW_SUPPORTS_PS |
                             IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
        hw->wiphy->interface_modes =
-               BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_ADHOC);
+               priv->contexts[IWL_RXON_CTX_BSS].interface_modes;
 
        hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
                            WIPHY_FLAG_DISABLE_BEACON_HINTS;
@@ -3916,7 +3931,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
 
 static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       int err = 0;
+       int err = 0, i;
        struct iwl_priv *priv;
        struct ieee80211_hw *hw;
        struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
@@ -3938,12 +3953,33 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        priv = hw->priv;
        SET_IEEE80211_DEV(hw, &pdev->dev);
 
+       priv->cmd_queue = IWL39_CMD_QUEUE_NUM;
+
+       /* 3945 has only one valid context */
+       priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
+
+       for (i = 0; i < NUM_IWL_RXON_CTX; i++)
+               priv->contexts[i].ctxid = i;
+
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
+       priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
+       priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
+       priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC);
+       priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
+       priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
+       priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
+
        /*
         * Disabling hardware scan means that mac80211 will perform scans
         * "the hard way", rather than using device's scan.
         */
        if (iwl3945_mod_params.disable_hw_scan) {
-               IWL_DEBUG_INFO(priv, "Disabling hw_scan\n");
+               IWL_ERR(priv, "sw scan support is deprecated\n");
                iwl3945_hw_ops.hw_scan = NULL;
        }
 
@@ -4073,7 +4109,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        }
 
        iwl_set_rxon_channel(priv,
-                            &priv->bands[IEEE80211_BAND_2GHZ].channels[5]);
+                            &priv->bands[IEEE80211_BAND_2GHZ].channels[5],
+                            &priv->contexts[IWL_RXON_CTX_BSS]);
        iwl3945_setup_deferred_work(priv);
        iwl3945_setup_rx_handlers(priv);
        iwl_power_initialize(priv);
@@ -4267,7 +4304,8 @@ MODULE_PARM_DESC(debug, "debug output mask");
 #endif
 module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan,
                   int, S_IRUGO);
-MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+MODULE_PARM_DESC(disable_hw_scan,
+                "disable hardware scanning (default 0) (deprecated)");
 module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, S_IRUGO);
 MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");