Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Wed, 5 Jan 2011 19:35:41 +0000 (14:35 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 5 Jan 2011 19:35:41 +0000 (14:35 -0500)
1  2 
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-helpers.h
net/mac80211/key.c
net/mac80211/rx.c

@@@ -90,6 -90,170 +90,6 @@@ MODULE_ALIAS("iwl4965")
  static int iwlagn_ant_coupling;
  static bool iwlagn_bt_ch_announce = 1;
  
 -/**
 - * iwlagn_commit_rxon - commit staging_rxon to hardware
 - *
 - * The RXON command in staging_rxon is committed to the hardware and
 - * the active_rxon structure is updated with the new data.  This
 - * function correctly transitions out of the RXON_ASSOC_MSK state if
 - * a HW tune is required based on the RXON structure changes.
 - */
 -int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 -{
 -      /* cast away the const for active_rxon in this function */
 -      struct iwl_rxon_cmd *active_rxon = (void *)&ctx->active;
 -      int ret;
 -      bool new_assoc =
 -              !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
 -      bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK);
 -
 -      if (!iwl_is_alive(priv))
 -              return -EBUSY;
 -
 -      if (!ctx->is_active)
 -              return 0;
 -
 -      /* always get timestamp with Rx frame */
 -      ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
 -
 -      ret = iwl_check_rxon_cmd(priv, ctx);
 -      if (ret) {
 -              IWL_ERR(priv, "Invalid RXON configuration.  Not committing.\n");
 -              return -EINVAL;
 -      }
 -
 -      /*
 -       * receive commit_rxon request
 -       * abort any previous channel switch if still in process
 -       */
 -      if (priv->switch_rxon.switch_in_progress &&
 -          (priv->switch_rxon.channel != ctx->staging.channel)) {
 -              IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
 -                    le16_to_cpu(priv->switch_rxon.channel));
 -              iwl_chswitch_done(priv, false);
 -      }
 -
 -      /* If we don't need to send a full RXON, we can use
 -       * iwl_rxon_assoc_cmd which is used to reconfigure filter
 -       * and other flags for the current radio configuration. */
 -      if (!iwl_full_rxon_required(priv, ctx)) {
 -              ret = iwl_send_rxon_assoc(priv, ctx);
 -              if (ret) {
 -                      IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
 -                      return ret;
 -              }
 -
 -              memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
 -              iwl_print_rx_config_cmd(priv, ctx);
 -              return 0;
 -      }
 -
 -      /* If we are currently associated and the new config requires
 -       * an RXON_ASSOC and the new config wants the associated mask enabled,
 -       * we must clear the associated from the active configuration
 -       * before we apply the new config */
 -      if (iwl_is_associated_ctx(ctx) && new_assoc) {
 -              IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
 -              active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 -
 -              ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
 -                                     sizeof(struct iwl_rxon_cmd),
 -                                     active_rxon);
 -
 -              /* If the mask clearing failed then we set
 -               * active_rxon back to what it was previously */
 -              if (ret) {
 -                      active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
 -                      IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret);
 -                      return ret;
 -              }
 -              iwl_clear_ucode_stations(priv, ctx);
 -              iwl_restore_stations(priv, ctx);
 -              ret = iwl_restore_default_wep_keys(priv, ctx);
 -              if (ret) {
 -                      IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
 -                      return ret;
 -              }
 -      }
 -
 -      IWL_DEBUG_INFO(priv, "Sending RXON\n"
 -                     "* with%s RXON_FILTER_ASSOC_MSK\n"
 -                     "* channel = %d\n"
 -                     "* bssid = %pM\n",
 -                     (new_assoc ? "" : "out"),
 -                     le16_to_cpu(ctx->staging.channel),
 -                     ctx->staging.bssid_addr);
 -
 -      iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto);
 -
 -      if (!old_assoc) {
 -              /*
 -               * First of all, before setting associated, we need to
 -               * send RXON timing so the device knows about the DTIM
 -               * period and other timing values
 -               */
 -              ret = iwl_send_rxon_timing(priv, ctx);
 -              if (ret) {
 -                      IWL_ERR(priv, "Error setting RXON timing!\n");
 -                      return ret;
 -              }
 -      }
 -
 -      if (priv->cfg->ops->hcmd->set_pan_params) {
 -              ret = priv->cfg->ops->hcmd->set_pan_params(priv);
 -              if (ret)
 -                      return ret;
 -      }
 -
 -      /* Apply the new configuration
 -       * RXON unassoc clears the station table in uCode so restoration of
 -       * stations is needed after it (the RXON command) completes
 -       */
 -      if (!new_assoc) {
 -              ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
 -                            sizeof(struct iwl_rxon_cmd), &ctx->staging);
 -              if (ret) {
 -                      IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
 -                      return ret;
 -              }
 -              IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n");
 -              memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
 -              iwl_clear_ucode_stations(priv, ctx);
 -              iwl_restore_stations(priv, ctx);
 -              ret = iwl_restore_default_wep_keys(priv, ctx);
 -              if (ret) {
 -                      IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
 -                      return ret;
 -              }
 -      }
 -      if (new_assoc) {
 -              priv->start_calib = 0;
 -              /* Apply the new configuration
 -               * RXON assoc doesn't clear the station table in uCode,
 -               */
 -              ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
 -                            sizeof(struct iwl_rxon_cmd), &ctx->staging);
 -              if (ret) {
 -                      IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
 -                      return ret;
 -              }
 -              memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
 -      }
 -      iwl_print_rx_config_cmd(priv, ctx);
 -
 -      iwl_init_sensitivity(priv);
 -
 -      /* If we issue a new RXON command which required a tune then we must
 -       * send a new TXPOWER command or we won't be able to Tx any frames */
 -      ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
 -      if (ret) {
 -              IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
 -              return ret;
 -      }
 -
 -      return 0;
 -}
 -
  void iwl_update_chain_flags(struct iwl_priv *priv)
  {
        struct iwl_rxon_context *ctx;
        if (priv->cfg->ops->hcmd->set_rxon_chain) {
                for_each_context(priv, ctx) {
                        priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 -                      iwlcore_commit_rxon(priv, ctx);
 +                      if (ctx->active.rx_chain != ctx->staging.rx_chain)
 +                              iwlcore_commit_rxon(priv, ctx);
                }
        }
  }
@@@ -248,8 -411,7 +248,8 @@@ static unsigned int iwl_hw_get_beacon_c
  
        return sizeof(*tx_beacon_cmd) + frame_size;
  }
 -static int iwl_send_beacon_cmd(struct iwl_priv *priv)
 +
 +int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
  {
        struct iwl_frame *frame;
        unsigned int frame_size;
@@@ -499,7 -661,7 +499,7 @@@ static void iwl_bg_beacon_update(struc
  
        priv->beacon_skb = beacon;
  
 -      iwl_send_beacon_cmd(priv);
 +      iwlagn_send_beacon_cmd(priv);
   out:
        mutex_unlock(&priv->mutex);
  }
@@@ -2502,7 -2664,7 +2502,7 @@@ int iwl_dump_nic_event_log(struct iwl_p
                return pos;
        }
  
 -      /* enable/disable bt channel announcement */
 +      /* enable/disable bt channel inhibition */
        priv->bt_ch_announce = iwlagn_bt_ch_announce;
  
  #ifdef CONFIG_IWLWIFI_DEBUG
@@@ -2654,8 -2816,13 +2654,8 @@@ static void iwl_alive_start(struct iwl_
        /* After the ALIVE response, we can send host commands to the uCode */
        set_bit(STATUS_ALIVE, &priv->status);
  
 -      if (priv->cfg->ops->lib->recover_from_tx_stall) {
 -              /* Enable timer to monitor the driver queues */
 -              mod_timer(&priv->monitor_recover,
 -                      jiffies +
 -                      msecs_to_jiffies(
 -                        priv->cfg->base_params->monitor_recover_period));
 -      }
 +      /* Enable watchdog to monitor the driver tx queues */
 +      iwl_setup_watchdog(priv);
  
        if (iwl_is_rfkill(priv))
                return;
  
        iwl_reset_run_time_calib(priv);
  
 +      set_bit(STATUS_READY, &priv->status);
 +
        /* Configure the adapter for unassociated operation */
        iwlcore_commit_rxon(priv, ctx);
  
        iwl_leds_init(priv);
  
        IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
 -      set_bit(STATUS_READY, &priv->status);
        wake_up_interruptible(&priv->wait_command_queue);
  
        iwl_power_update_mode(priv, true);
@@@ -2750,7 -2916,8 +2750,7 @@@ static void __iwl_down(struct iwl_priv 
  
        /* 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);
 +      del_timer_sync(&priv->watchdog);
  
        iwl_clear_ucode_stations(priv, NULL);
        iwl_dealloc_bcast_stations(priv);
                                STATUS_EXIT_PENDING;
  
        /* device going down, Stop using ICT table */
 -      iwl_disable_ict(priv);
 +      if (priv->cfg->ops->lib->isr_ops.disable)
 +              priv->cfg->ops->lib->isr_ops.disable(priv);
  
        iwlagn_txq_ctx_stop(priv);
        iwlagn_rxq_stop(priv);
@@@ -3035,8 -3201,7 +3035,8 @@@ static void iwl_bg_alive_start(struct w
                return;
  
        /* enable dram interrupt */
 -      iwl_reset_ict(priv);
 +      if (priv->cfg->ops->lib->isr_ops.reset)
 +              priv->cfg->ops->lib->isr_ops.reset(priv);
  
        mutex_lock(&priv->mutex);
        iwl_alive_start(priv);
@@@ -3144,6 -3309,92 +3144,6 @@@ static void iwl_bg_rx_replenish(struct 
        mutex_unlock(&priv->mutex);
  }
  
 -#define IWL_DELAY_NEXT_SCAN (HZ*2)
 -
 -void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 -{
 -      struct iwl_rxon_context *ctx;
 -      struct ieee80211_conf *conf = NULL;
 -      int ret = 0;
 -
 -      if (!vif || !priv->is_open)
 -              return;
 -
 -      ctx = iwl_rxon_ctx_from_vif(vif);
 -
 -      if (vif->type == NL80211_IFTYPE_AP) {
 -              IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
 -              return;
 -      }
 -
 -      if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 -              return;
 -
 -      iwl_scan_cancel_timeout(priv, 200);
 -
 -      conf = ieee80211_get_hw_conf(priv->hw);
 -
 -      ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 -      iwlcore_commit_rxon(priv, ctx);
 -
 -      ret = iwl_send_rxon_timing(priv, ctx);
 -      if (ret)
 -              IWL_WARN(priv, "RXON timing - "
 -                          "Attempting to continue.\n");
 -
 -      ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
 -
 -      iwl_set_rxon_ht(priv, &priv->current_ht_config);
 -
 -      if (priv->cfg->ops->hcmd->set_rxon_chain)
 -              priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 -
 -      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)
 -              ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
 -      else
 -              ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 -
 -      if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
 -              if (vif->bss_conf.use_short_slot)
 -                      ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
 -              else
 -                      ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 -      }
 -
 -      iwlcore_commit_rxon(priv, ctx);
 -
 -      IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
 -                      vif->bss_conf.aid, ctx->active.bssid_addr);
 -
 -      switch (vif->type) {
 -      case NL80211_IFTYPE_STATION:
 -              break;
 -      case NL80211_IFTYPE_ADHOC:
 -              iwl_send_beacon_cmd(priv);
 -              break;
 -      default:
 -              IWL_ERR(priv, "%s Should not be called in %d mode\n",
 -                        __func__, vif->type);
 -              break;
 -      }
 -
 -      /* the chain noise calibration will enabled PM upon completion
 -       * If chain noise has already been run, then we need to enable
 -       * power management here */
 -      if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
 -              iwl_power_update_mode(priv, false);
 -
 -      /* Enable Rx differential gain and sensitivity calibrations */
 -      iwl_chain_noise_reset(priv);
 -      priv->start_calib = 1;
 -
 -}
 -
  /*****************************************************************************
   *
   * mac80211 entry point functions
@@@ -3169,8 -3420,7 +3169,8 @@@ static int iwl_mac_setup_register(struc
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_AMPDU_AGGREGATION |
                    IEEE80211_HW_NEED_DTIM_PERIOD |
 -                  IEEE80211_HW_SPECTRUM_MGMT;
 +                  IEEE80211_HW_SPECTRUM_MGMT |
 +                  IEEE80211_HW_REPORTS_TX_ACK_STATUS;
  
        if (!priv->cfg->base_params->broken_powersave)
                hw->flags |= IEEE80211_HW_SUPPORTS_PS |
  }
  
  
 -static int iwl_mac_start(struct ieee80211_hw *hw)
 +int iwlagn_mac_start(struct ieee80211_hw *hw)
  {
        struct iwl_priv *priv = hw->priv;
        int ret;
@@@ -3265,7 -3515,7 +3265,7 @@@ out
        return 0;
  }
  
 -static void iwl_mac_stop(struct ieee80211_hw *hw)
 +void iwlagn_mac_stop(struct ieee80211_hw *hw)
  {
        struct iwl_priv *priv = hw->priv;
  
  
        flush_workqueue(priv->workqueue);
  
-       /* enable interrupts again in order to receive rfkill changes */
+       /* User space software may expect getting rfkill changes
+        * even if interface is down */
        iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-       iwl_enable_interrupts(priv);
+       iwl_enable_rfkill_int(priv);
  
        IWL_DEBUG_MAC80211(priv, "leave\n");
  }
  
 -static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 +int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
  {
        struct iwl_priv *priv = hw->priv;
  
        return NETDEV_TX_OK;
  }
  
 -void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
 -{
 -      struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
 -      int ret = 0;
 -
 -      lockdep_assert_held(&priv->mutex);
 -
 -      if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 -              return;
 -
 -      /* The following should be done only at AP bring up */
 -      if (!iwl_is_associated_ctx(ctx)) {
 -
 -              /* RXON - unassoc (to set timing command) */
 -              ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 -              iwlcore_commit_rxon(priv, ctx);
 -
 -              /* RXON Timing */
 -              ret = iwl_send_rxon_timing(priv, ctx);
 -              if (ret)
 -                      IWL_WARN(priv, "RXON timing failed - "
 -                                      "Attempting to continue.\n");
 -
 -              /* AP has all antennas */
 -              priv->chain_noise_data.active_chains =
 -                      priv->hw_params.valid_rx_ant;
 -              iwl_set_rxon_ht(priv, &priv->current_ht_config);
 -              if (priv->cfg->ops->hcmd->set_rxon_chain)
 -                      priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 -
 -              ctx->staging.assoc_id = 0;
 -
 -              if (vif->bss_conf.use_short_preamble)
 -                      ctx->staging.flags |=
 -                              RXON_FLG_SHORT_PREAMBLE_MSK;
 -              else
 -                      ctx->staging.flags &=
 -                              ~RXON_FLG_SHORT_PREAMBLE_MSK;
 -
 -              if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
 -                      if (vif->bss_conf.use_short_slot)
 -                              ctx->staging.flags |=
 -                                      RXON_FLG_SHORT_SLOT_MSK;
 -                      else
 -                              ctx->staging.flags &=
 -                                      ~RXON_FLG_SHORT_SLOT_MSK;
 -              }
 -              /* need to send beacon cmd before committing assoc RXON! */
 -              iwl_send_beacon_cmd(priv);
 -              /* restore RXON assoc */
 -              ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
 -              iwlcore_commit_rxon(priv, ctx);
 -      }
 -      iwl_send_beacon_cmd(priv);
 -
 -      /* FIXME - we need to add code here to detect a totally new
 -       * configuration, reset the AP, unassoc, rxon timing, assoc,
 -       * clear sta table, add BCAST sta... */
 -}
 -
 -static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
 -                                  struct ieee80211_vif *vif,
 -                                  struct ieee80211_key_conf *keyconf,
 -                                  struct ieee80211_sta *sta,
 -                                  u32 iv32, u16 *phase1key)
 +void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
 +                              struct ieee80211_vif *vif,
 +                              struct ieee80211_key_conf *keyconf,
 +                              struct ieee80211_sta *sta,
 +                              u32 iv32, u16 *phase1key)
  {
 -
        struct iwl_priv *priv = hw->priv;
        struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
  
        IWL_DEBUG_MAC80211(priv, "leave\n");
  }
  
 -static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 -                         struct ieee80211_vif *vif,
 -                         struct ieee80211_sta *sta,
 -                         struct ieee80211_key_conf *key)
 +int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 +                     struct ieee80211_vif *vif, struct ieee80211_sta *sta,
 +                     struct ieee80211_key_conf *key)
  {
        struct iwl_priv *priv = hw->priv;
        struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
        return ret;
  }
  
 -static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
 -                              struct ieee80211_vif *vif,
 -                              enum ieee80211_ampdu_mlme_action action,
 -                              struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 +int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
 +                          struct ieee80211_vif *vif,
 +                          enum ieee80211_ampdu_mlme_action action,
 +                          struct ieee80211_sta *sta, u16 tid, u16 *ssn)
  {
        struct iwl_priv *priv = hw->priv;
        int ret = -EINVAL;
        return ret;
  }
  
 -static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
 -                             struct ieee80211_vif *vif,
 -                             enum sta_notify_cmd cmd,
 -                             struct ieee80211_sta *sta)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
 -      int sta_id;
 -
 -      switch (cmd) {
 -      case STA_NOTIFY_SLEEP:
 -              WARN_ON(!sta_priv->client);
 -              sta_priv->asleep = true;
 -              if (atomic_read(&sta_priv->pending_frames) > 0)
 -                      ieee80211_sta_block_awake(hw, sta, true);
 -              break;
 -      case STA_NOTIFY_AWAKE:
 -              WARN_ON(!sta_priv->client);
 -              if (!sta_priv->asleep)
 -                      break;
 -              sta_priv->asleep = false;
 -              sta_id = iwl_sta_id(sta);
 -              if (sta_id != IWL_INVALID_STATION)
 -                      iwl_sta_modify_ps_wake(priv, sta_id);
 -              break;
 -      default:
 -              break;
 -      }
 -}
 -
 -static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
 -                            struct ieee80211_vif *vif,
 -                            struct ieee80211_sta *sta)
 +int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
 +                     struct ieee80211_vif *vif,
 +                     struct ieee80211_sta *sta)
  {
        struct iwl_priv *priv = hw->priv;
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
        return 0;
  }
  
 -static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
 -                                 struct ieee80211_channel_switch *ch_switch)
 +void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
 +                             struct ieee80211_channel_switch *ch_switch)
  {
        struct iwl_priv *priv = hw->priv;
        const struct iwl_channel_info *ch_info;
@@@ -3614,10 -3957,10 +3615,10 @@@ out_exit
        IWL_DEBUG_MAC80211(priv, "leave\n");
  }
  
 -static void iwlagn_configure_filter(struct ieee80211_hw *hw,
 -                                  unsigned int changed_flags,
 -                                  unsigned int *total_flags,
 -                                  u64 multicast)
 +void iwlagn_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;
                        changed_flags, *total_flags);
  
        CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
 -      CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);
 +      /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
 +      CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
        CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
  
  #undef CHK
        for_each_context(priv, ctx) {
                ctx->staging.filter_flags &= ~filter_nand;
                ctx->staging.filter_flags |= filter_or;
 -              iwlcore_commit_rxon(priv, ctx);
 +
 +              /*
 +               * Not committing directly because hardware can perform a scan,
 +               * but we'll eventually commit the filter flags change anyway.
 +               */
        }
  
        mutex_unlock(&priv->mutex);
                        FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
  }
  
 -static void iwl_mac_flush(struct ieee80211_hw *hw, bool drop)
 +void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
  {
        struct iwl_priv *priv = hw->priv;
  
@@@ -3737,9 -4075,12 +3738,9 @@@ static void iwl_setup_deferred_work(str
        priv->ucode_trace.data = (unsigned long)priv;
        priv->ucode_trace.function = iwl_bg_ucode_trace;
  
 -      if (priv->cfg->ops->lib->recover_from_tx_stall) {
 -              init_timer(&priv->monitor_recover);
 -              priv->monitor_recover.data = (unsigned long)priv;
 -              priv->monitor_recover.function =
 -                      priv->cfg->ops->lib->recover_from_tx_stall;
 -      }
 +      init_timer(&priv->watchdog);
 +      priv->watchdog.data = (unsigned long)priv;
 +      priv->watchdog.function = iwl_bg_watchdog;
  
        if (!priv->cfg->base_params->use_isr_legacy)
                tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
@@@ -3832,13 -4173,13 +3833,13 @@@ static int iwl_init_drv(struct iwl_pri
                priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
                priv->bt_duration = BT_DURATION_LIMIT_DEF;
                priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
 -              priv->dynamic_agg_thresh = BT_AGG_THRESHOLD_DEF;
        }
  
        /* Set the tx_power_user_lmt to the lowest power level
         * this value will get overwritten by channel max power avg
         * from eeprom */
        priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN;
 +      priv->tx_power_next = IWLAGN_TX_POWER_TARGET_POWER_MIN;
  
        ret = iwl_init_channel_map(priv);
        if (ret) {
@@@ -3869,30 -4210,28 +3870,30 @@@ static void iwl_uninit_drv(struct iwl_p
        kfree(priv->scan_cmd);
  }
  
 -static struct ieee80211_ops iwl_hw_ops = {
 -      .tx = iwl_mac_tx,
 -      .start = iwl_mac_start,
 -      .stop = iwl_mac_stop,
 +#ifdef CONFIG_IWL5000
 +struct ieee80211_ops iwlagn_hw_ops = {
 +      .tx = iwlagn_mac_tx,
 +      .start = iwlagn_mac_start,
 +      .stop = iwlagn_mac_stop,
        .add_interface = iwl_mac_add_interface,
        .remove_interface = iwl_mac_remove_interface,
 -      .config = iwl_mac_config,
 +      .change_interface = iwl_mac_change_interface,
 +      .config = iwlagn_mac_config,
        .configure_filter = iwlagn_configure_filter,
 -      .set_key = iwl_mac_set_key,
 -      .update_tkip_key = iwl_mac_update_tkip_key,
 +      .set_key = iwlagn_mac_set_key,
 +      .update_tkip_key = iwlagn_mac_update_tkip_key,
        .conf_tx = iwl_mac_conf_tx,
 -      .reset_tsf = iwl_mac_reset_tsf,
 -      .bss_info_changed = iwl_bss_info_changed,
 -      .ampdu_action = iwl_mac_ampdu_action,
 +      .bss_info_changed = iwlagn_bss_info_changed,
 +      .ampdu_action = iwlagn_mac_ampdu_action,
        .hw_scan = iwl_mac_hw_scan,
 -      .sta_notify = iwl_mac_sta_notify,
 +      .sta_notify = iwlagn_mac_sta_notify,
        .sta_add = iwlagn_mac_sta_add,
        .sta_remove = iwl_mac_sta_remove,
 -      .channel_switch = iwl_mac_channel_switch,
 -      .flush = iwl_mac_flush,
 +      .channel_switch = iwlagn_mac_channel_switch,
 +      .flush = iwlagn_mac_flush,
        .tx_last_beacon = iwl_mac_tx_last_beacon,
  };
 +#endif
  
  static void iwl_hw_detect(struct iwl_priv *priv)
  {
@@@ -3960,15 -4299,10 +3961,15 @@@ static int iwl_pci_probe(struct pci_de
        if (cfg->mod_params->disable_hw_scan) {
                dev_printk(KERN_DEBUG, &(pdev->dev),
                        "sw scan support is deprecated\n");
 -              iwl_hw_ops.hw_scan = NULL;
 +#ifdef CONFIG_IWL5000
 +              iwlagn_hw_ops.hw_scan = NULL;
 +#endif
 +#ifdef CONFIG_IWL4965
 +              iwl4965_hw_ops.hw_scan = NULL;
 +#endif
        }
  
 -      hw = iwl_alloc_all(cfg, &iwl_hw_ops);
 +      hw = iwl_alloc_all(cfg);
        if (!hw) {
                err = -ENOMEM;
                goto out;
                BIT(NL80211_IFTYPE_ADHOC);
        priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
                BIT(NL80211_IFTYPE_STATION);
 +      priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
        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;
                (iwlagn_ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
                true : false;
  
 -      /* enable/disable bt channel announcement */
 +      /* enable/disable bt channel inhibition */
        priv->bt_ch_announce = iwlagn_bt_ch_announce;
 +      IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n",
 +                     (priv->bt_ch_announce) ? "On" : "Off");
  
        if (iwl_alloc_traffic_mem(priv))
                IWL_ERR(priv, "Not enough memory to generate traffic log\n");
        if (err)
                goto out_free_eeprom;
  
 +      err = iwl_eeprom_check_sku(priv);
 +      if (err)
 +              goto out_free_eeprom;
 +
        /* extract MAC Address */
        iwl_eeprom_get_mac(priv, priv->addresses[0].addr);
        IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr);
  
        pci_enable_msi(priv->pci_dev);
  
 -      iwl_alloc_isr_ict(priv);
 -      err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr,
 +      if (priv->cfg->ops->lib->isr_ops.alloc)
 +              priv->cfg->ops->lib->isr_ops.alloc(priv);
 +
 +      err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr,
                          IRQF_SHARED, DRV_NAME, priv);
        if (err) {
                IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
         * 8. Enable interrupts and read RFKILL state
         *********************************************/
  
-       /* enable interrupts if needed: hw bug w/a */
+       /* enable rfkill interrupt: hw bug w/a */
        pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd);
        if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
                pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
                pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
        }
  
-       iwl_enable_interrupts(priv);
+       iwl_enable_rfkill_int(priv);
  
        /* If platform's RF_KILL switch is NOT set to KILL */
        if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
        destroy_workqueue(priv->workqueue);
        priv->workqueue = NULL;
        free_irq(priv->pci_dev->irq, priv);
 -      iwl_free_isr_ict(priv);
 +      if (priv->cfg->ops->lib->isr_ops.free)
 +              priv->cfg->ops->lib->isr_ops.free(priv);
   out_disable_msi:
        pci_disable_msi(priv->pci_dev);
        iwl_uninit_drv(priv);
@@@ -4320,8 -4644,7 +4321,8 @@@ static void __devexit iwl_pci_remove(st
  
        iwl_uninit_drv(priv);
  
 -      iwl_free_isr_ict(priv);
 +      if (priv->cfg->ops->lib->isr_ops.free)
 +              priv->cfg->ops->lib->isr_ops.free(priv);
  
        dev_kfree_skb(priv->beacon_skb);
  
@@@ -4412,32 -4735,51 +4413,32 @@@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_c
        {IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
        {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
  
 -/* 6x00 Series Gen2a */
 -      {IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2a_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x0085, 0x1211, iwl6000g2a_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x0082, 0x1221, iwl6000g2a_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x0082, 0x1206, iwl6000g2a_2abg_cfg)},
 -      {IWL_PCI_DEVICE(0x0085, 0x1216, iwl6000g2a_2abg_cfg)},
 -      {IWL_PCI_DEVICE(0x0082, 0x1226, iwl6000g2a_2abg_cfg)},
 -      {IWL_PCI_DEVICE(0x0082, 0x1207, iwl6000g2a_2bg_cfg)},
 -      {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6000g2a_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x0082, 0x1306, iwl6000g2a_2abg_cfg)},
 -      {IWL_PCI_DEVICE(0x0082, 0x1307, iwl6000g2a_2bg_cfg)},
 -      {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6000g2a_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x0082, 0x1326, iwl6000g2a_2abg_cfg)},
 -      {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6000g2a_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6000g2a_2abg_cfg)},
 -
 -/* 6x00 Series Gen2b */
 -      {IWL_PCI_DEVICE(0x008F, 0x5105, iwl6000g2b_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x0090, 0x5115, iwl6000g2b_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x008F, 0x5125, iwl6000g2b_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x008F, 0x5107, iwl6000g2b_bg_cfg)},
 -      {IWL_PCI_DEVICE(0x008F, 0x5201, iwl6000g2b_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x008F, 0x5221, iwl6000g2b_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x008F, 0x5206, iwl6000g2b_2abg_cfg)},
 -      {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
 -      {IWL_PCI_DEVICE(0x008F, 0x5226, iwl6000g2b_2abg_cfg)},
 -      {IWL_PCI_DEVICE(0x008F, 0x5207, iwl6000g2b_2bg_cfg)},
 -      {IWL_PCI_DEVICE(0x008A, 0x5301, iwl6000g2b_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x008A, 0x5305, iwl6000g2b_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x008A, 0x5307, iwl6000g2b_bg_cfg)},
 -      {IWL_PCI_DEVICE(0x008A, 0x5321, iwl6000g2b_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x008A, 0x5325, iwl6000g2b_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x008B, 0x5311, iwl6000g2b_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x008B, 0x5315, iwl6000g2b_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6000g2b_2bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
 -      {IWL_PCI_DEVICE(0x0091, 0x5201, iwl6000g2b_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x0091, 0x5205, iwl6000g2b_2bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x0091, 0x5206, iwl6000g2b_2abg_cfg)},
 -      {IWL_PCI_DEVICE(0x0091, 0x5207, iwl6000g2b_2bg_cfg)},
 -      {IWL_PCI_DEVICE(0x0091, 0x5221, iwl6000g2b_2agn_cfg)},
 -      {IWL_PCI_DEVICE(0x0091, 0x5225, iwl6000g2b_2bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x0091, 0x5226, iwl6000g2b_2abg_cfg)},
 +/* 6x05 Series */
 +      {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6005_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1306, iwl6005_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1307, iwl6005_2bg_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6005_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1326, iwl6005_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
 +
 +/* 6x30 Series */
 +      {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x008A, 0x5307, iwl1030_bg_cfg)},
 +      {IWL_PCI_DEVICE(0x008A, 0x5325, iwl1030_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x008A, 0x5327, iwl1030_bg_cfg)},
 +      {IWL_PCI_DEVICE(0x008B, 0x5315, iwl1030_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x008B, 0x5317, iwl1030_bg_cfg)},
 +      {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6030_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6030_2bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6030_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5201, iwl6030_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5205, iwl6030_2bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5206, iwl6030_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5207, iwl6030_2bg_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5221, iwl6030_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5225, iwl6030_2bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5226, iwl6030_2abg_cfg)},
  
  /* 6x50 WiFi/WiMax Series */
        {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
  
 -/* 6x50 WiFi/WiMax Series Gen2 */
 -      {IWL_PCI_DEVICE(0x0885, 0x1305, iwl6050g2_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x0885, 0x1306, iwl6050g2_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x0885, 0x1325, iwl6050g2_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x0885, 0x1326, iwl6050g2_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x0886, 0x1315, iwl6050g2_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x0886, 0x1316, iwl6050g2_bgn_cfg)},
 +/* 6150 WiFi/WiMax Series */
 +      {IWL_PCI_DEVICE(0x0885, 0x1305, iwl6150_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0885, 0x1306, iwl6150_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0885, 0x1325, iwl6150_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0885, 0x1326, iwl6150_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0886, 0x1315, iwl6150_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0886, 0x1316, iwl6150_bgn_cfg)},
  
  /* 1000 Series WiFi */
        {IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)},
  
  /* 100 Series WiFi */
        {IWL_PCI_DEVICE(0x08AE, 0x1005, iwl100_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)},
        {IWL_PCI_DEVICE(0x08AF, 0x1015, iwl100_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x08AF, 0x1017, iwl100_bg_cfg)},
        {IWL_PCI_DEVICE(0x08AE, 0x1025, iwl100_bgn_cfg)},
 -      {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)},
 -      {IWL_PCI_DEVICE(0x08AE, 0x1017, iwl100_bg_cfg)},
 +      {IWL_PCI_DEVICE(0x08AE, 0x1027, iwl100_bg_cfg)},
  
  /* 130 Series WiFi */
        {IWL_PCI_DEVICE(0x0896, 0x5005, iwl130_bgn_cfg)},
@@@ -4496,7 -4837,10 +4497,7 @@@ static struct pci_driver iwl_driver = 
        .id_table = iwl_hw_card_ids,
        .probe = iwl_pci_probe,
        .remove = __devexit_p(iwl_pci_remove),
 -#ifdef CONFIG_PM
 -      .suspend = iwl_pci_suspend,
 -      .resume = iwl_pci_resume,
 -#endif
 +      .driver.pm = IWL_PM_OPS,
  };
  
  static int __init iwl_init(void)
@@@ -4582,6 -4926,6 +4583,6 @@@ module_param_named(antenna_coupling, iw
  MODULE_PARM_DESC(antenna_coupling,
                 "specify antenna coupling in dB (defualt: 0 dB)");
  
 -module_param_named(bt_ch_announce, iwlagn_bt_ch_announce, bool, S_IRUGO);
 -MODULE_PARM_DESC(bt_ch_announce,
 -               "Enable BT channel announcement mode (default: enable)");
 +module_param_named(bt_ch_inhibition, iwlagn_bt_ch_announce, bool, S_IRUGO);
 +MODULE_PARM_DESC(bt_ch_inhibition,
 +               "Disable BT channel inhibition (default: enable)");
@@@ -44,6 -44,15 +44,6 @@@ static inline struct ieee80211_conf *ie
        return &hw->conf;
  }
  
 -static inline unsigned long elapsed_jiffies(unsigned long start,
 -                                          unsigned long end)
 -{
 -      if (end >= start)
 -              return end - start;
 -
 -      return end + (MAX_JIFFY_OFFSET - start) + 1;
 -}
 -
  /**
   * iwl_queue_inc_wrap - increment queue index, wrap back to beginning
   * @index -- current index
@@@ -95,36 -104,42 +95,36 @@@ static inline int iwl_alloc_fw_desc(str
   * | | | | | | | |
   * | | | | | | +-+-------- AC queue (0-3)
   * | | | | | |
 - * | +-+-+-+-+------------ HW A-MPDU queue
 + * | +-+-+-+-+------------ HW queue ID
   * |
 - * +---------------------- indicates agg queue
 + * +---------------------- unused
   */
 -static inline u8 iwl_virtual_agg_queue_num(u8 ac, u8 hwq)
 +static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq)
  {
        BUG_ON(ac > 3);   /* only have 2 bits */
 -      BUG_ON(hwq > 31); /* only have 5 bits */
 +      BUG_ON(hwq > 31); /* only use 5 bits */
  
 -      return 0x80 | (hwq << 2) | ac;
 +      txq->swq_id = (hwq << 2) | ac;
  }
  
 -static inline void iwl_wake_queue(struct iwl_priv *priv, u8 queue)
 +static inline void iwl_wake_queue(struct iwl_priv *priv,
 +                                struct iwl_tx_queue *txq)
  {
 -      u8 ac = queue;
 -      u8 hwq = queue;
 -
 -      if (queue & 0x80) {
 -              ac = queue & 3;
 -              hwq = (queue >> 2) & 0x1f;
 -      }
 +      u8 queue = txq->swq_id;
 +      u8 ac = queue & 3;
 +      u8 hwq = (queue >> 2) & 0x1f;
  
        if (test_and_clear_bit(hwq, priv->queue_stopped))
                if (atomic_dec_return(&priv->queue_stop_count[ac]) <= 0)
                        ieee80211_wake_queue(priv->hw, ac);
  }
  
 -static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue)
 +static inline void iwl_stop_queue(struct iwl_priv *priv,
 +                                struct iwl_tx_queue *txq)
  {
 -      u8 ac = queue;
 -      u8 hwq = queue;
 -
 -      if (queue & 0x80) {
 -              ac = queue & 3;
 -              hwq = (queue >> 2) & 0x1f;
 -      }
 +      u8 queue = txq->swq_id;
 +      u8 ac = queue & 3;
 +      u8 hwq = (queue >> 2) & 0x1f;
  
        if (!test_and_set_bit(hwq, priv->queue_stopped))
                if (atomic_inc_return(&priv->queue_stop_count[ac]) > 0)
@@@ -148,6 -163,12 +148,12 @@@ static inline void iwl_disable_interrup
        IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
  }
  
+ static inline void iwl_enable_rfkill_int(struct iwl_priv *priv)
+ {
+       IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n");
+       iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
+ }
  static inline void iwl_enable_interrupts(struct iwl_priv *priv)
  {
        IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
diff --combined net/mac80211/key.c
   * keys and per-station keys. Since each station belongs to an interface,
   * each station key also belongs to that interface.
   *
 - * Hardware acceleration is done on a best-effort basis, for each key
 - * that is eligible the hardware is asked to enable that key but if
 - * it cannot do that they key is simply kept for software encryption.
 - * There is currently no way of knowing this except by looking into
 - * debugfs.
 + * Hardware acceleration is done on a best-effort basis for algorithms
 + * that are implemented in software,  for each key the hardware is asked
 + * to enable that key for offloading but if it cannot do that the key is
 + * simply kept for software encryption (unless it is for an algorithm
 + * that isn't implemented in software).
 + * There is currently no way of knowing whether a key is handled in SW
 + * or HW except by looking into debugfs.
   *
 - * All key operations are protected internally.
 - *
 - * Within mac80211, key references are, just as STA structure references,
 - * protected by RCU. Note, however, that some things are unprotected,
 - * namely the key->sta dereferences within the hardware acceleration
 - * functions. This means that sta_info_destroy() must remove the key
 - * which waits for an RCU grace period.
 + * All key management is internally protected by a mutex. Within all
 + * other parts of mac80211, key references are, just as STA structure
 + * references, protected by RCU. Note, however, that some things are
 + * unprotected, namely the key->sta dereferences within the hardware
 + * acceleration functions. This means that sta_info_destroy() must
 + * remove the key which waits for an RCU grace period.
   */
  
  static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
@@@ -85,17 -84,10 +85,17 @@@ static int ieee80211_key_enable_hw_acce
                goto out_unsupported;
  
        sdata = key->sdata;
 -      if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 +      if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
 +              /*
 +               * The driver doesn't know anything about VLAN interfaces.
 +               * Hence, don't send GTKs for VLAN interfaces to the driver.
 +               */
 +              if (!(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE))
 +                      goto out_unsupported;
                sdata = container_of(sdata->bss,
                                     struct ieee80211_sub_if_data,
                                     u.ap);
 +      }
  
        ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
  
@@@ -179,7 -171,7 +179,7 @@@ void ieee80211_key_removed(struct ieee8
  EXPORT_SYMBOL_GPL(ieee80211_key_removed);
  
  static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
 -                                      int idx)
 +                                      int idx, bool uni, bool multi)
  {
        struct ieee80211_key *key = NULL;
  
        if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
                key = sdata->keys[idx];
  
 -      rcu_assign_pointer(sdata->default_key, key);
 +      if (uni)
 +              rcu_assign_pointer(sdata->default_unicast_key, key);
 +      if (multi)
 +              rcu_assign_pointer(sdata->default_multicast_key, key);
  
 -      if (key) {
 -              ieee80211_debugfs_key_remove_default(key->sdata);
 -              ieee80211_debugfs_key_add_default(key->sdata);
 -      }
 +      ieee80211_debugfs_key_update_default(sdata);
  }
  
 -void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
 +void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
 +                             bool uni, bool multi)
  {
        mutex_lock(&sdata->local->key_mtx);
 -      __ieee80211_set_default_key(sdata, idx);
 +      __ieee80211_set_default_key(sdata, idx, uni, multi);
        mutex_unlock(&sdata->local->key_mtx);
  }
  
@@@ -217,7 -208,10 +217,7 @@@ __ieee80211_set_default_mgmt_key(struc
  
        rcu_assign_pointer(sdata->default_mgmt_key, key);
  
 -      if (key) {
 -              ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
 -              ieee80211_debugfs_key_add_mgmt_default(key->sdata);
 -      }
 +      ieee80211_debugfs_key_update_default(sdata);
  }
  
  void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
@@@ -235,8 -229,7 +235,8 @@@ static void __ieee80211_key_replace(str
                                    struct ieee80211_key *old,
                                    struct ieee80211_key *new)
  {
 -      int idx, defkey, defmgmtkey;
 +      int idx;
 +      bool defunikey, defmultikey, defmgmtkey;
  
        if (new)
                list_add(&new->list, &sdata->key_list);
                else
                        idx = new->conf.keyidx;
  
 -              defkey = old && sdata->default_key == old;
 +              defunikey = old && sdata->default_unicast_key == old;
 +              defmultikey = old && sdata->default_multicast_key == old;
                defmgmtkey = old && sdata->default_mgmt_key == old;
  
 -              if (defkey && !new)
 -                      __ieee80211_set_default_key(sdata, -1);
 +              if (defunikey && !new)
 +                      __ieee80211_set_default_key(sdata, -1, true, false);
 +              if (defmultikey && !new)
 +                      __ieee80211_set_default_key(sdata, -1, false, true);
                if (defmgmtkey && !new)
                        __ieee80211_set_default_mgmt_key(sdata, -1);
  
                rcu_assign_pointer(sdata->keys[idx], new);
 -              if (defkey && new)
 -                      __ieee80211_set_default_key(sdata, new->conf.keyidx);
 +              if (defunikey && new)
 +                      __ieee80211_set_default_key(sdata, new->conf.keyidx,
 +                                                  true, false);
 +              if (defmultikey && new)
 +                      __ieee80211_set_default_key(sdata, new->conf.keyidx,
 +                                                  false, true);
                if (defmgmtkey && new)
                        __ieee80211_set_default_mgmt_key(sdata,
                                                         new->conf.keyidx);
        }
  
 -      if (old) {
 -              /*
 -               * We'll use an empty list to indicate that the key
 -               * has already been removed.
 -               */
 -              list_del_init(&old->list);
 -      }
 +      if (old)
 +              list_del(&old->list);
  }
  
  struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
@@@ -375,6 -366,12 +375,12 @@@ static void __ieee80211_key_destroy(str
        if (!key)
                return;
  
+       /*
+        * Synchronize so the TX path can no longer be using
+        * this key before we free/remove it.
+        */
+       synchronize_rcu();
        if (key->local)
                ieee80211_key_disable_hw_accel(key);
  
@@@ -416,8 -413,8 +422,8 @@@ int ieee80211_key_link(struct ieee80211
                        struct sta_info *ap;
  
                        /*
 -                       * We're getting a sta pointer in,
 -                       * so must be under RCU read lock.
 +                       * We're getting a sta pointer in, so must be under
 +                       * appropriate locking for sta_info_get().
                         */
  
                        /* same here, the AP could be using QoS */
@@@ -511,12 -508,11 +517,12 @@@ void ieee80211_free_keys(struct ieee802
  
        mutex_lock(&sdata->local->key_mtx);
  
 -      ieee80211_debugfs_key_remove_default(sdata);
        ieee80211_debugfs_key_remove_mgmt_default(sdata);
  
        list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
                __ieee80211_key_free(key);
  
 +      ieee80211_debugfs_key_update_default(sdata);
 +
        mutex_unlock(&sdata->local->key_mtx);
  }
diff --combined net/mac80211/rx.c
@@@ -533,13 -533,10 +533,13 @@@ static inline u16 seq_sub(u16 sq1, u16 
  
  static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
                                            struct tid_ampdu_rx *tid_agg_rx,
 -                                          int index,
 -                                          struct sk_buff_head *frames)
 +                                          int index)
  {
 +      struct ieee80211_local *local = hw_to_local(hw);
        struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
 +      struct ieee80211_rx_status *status;
 +
 +      lockdep_assert_held(&tid_agg_rx->reorder_lock);
  
        if (!skb)
                goto no_frame;
        /* release the frame from the reorder ring buffer */
        tid_agg_rx->stored_mpdu_num--;
        tid_agg_rx->reorder_buf[index] = NULL;
 -      __skb_queue_tail(frames, skb);
 +      status = IEEE80211_SKB_RXCB(skb);
 +      status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE;
 +      skb_queue_tail(&local->rx_skb_queue, skb);
  
  no_frame:
        tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
  
  static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
                                             struct tid_ampdu_rx *tid_agg_rx,
 -                                           u16 head_seq_num,
 -                                           struct sk_buff_head *frames)
 +                                           u16 head_seq_num)
  {
        int index;
  
 +      lockdep_assert_held(&tid_agg_rx->reorder_lock);
 +
        while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
                index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
                                                        tid_agg_rx->buf_size;
 -              ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
 +              ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
        }
  }
  
  #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
  
  static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
 -                                        struct tid_ampdu_rx *tid_agg_rx,
 -                                        struct sk_buff_head *frames)
 +                                        struct tid_ampdu_rx *tid_agg_rx)
  {
        int index, j;
  
 +      lockdep_assert_held(&tid_agg_rx->reorder_lock);
 +
        /* release the buffer until next missing frame */
        index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
                                                tid_agg_rx->buf_size;
                                wiphy_debug(hw->wiphy,
                                            "release an RX reorder frame due to timeout on earlier frames\n");
  #endif
 -                      ieee80211_release_reorder_frame(hw, tid_agg_rx,
 -                                                      j, frames);
 +                      ieee80211_release_reorder_frame(hw, tid_agg_rx, j);
  
                        /*
                         * Increment the head seq# also for the skipped slots.
                        skipped = 0;
                }
        } else while (tid_agg_rx->reorder_buf[index]) {
 -              ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
 +              ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
                index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
                                                        tid_agg_rx->buf_size;
        }
  
 -      /*
 -       * Disable the reorder release timer for now.
 -       *
 -       * The current implementation lacks a proper locking scheme
 -       * which would protect vital statistic and debug counters
 -       * from being updated by two different but concurrent BHs.
 -       *
 -       * More information about the topic is available from:
 -       * - thread: http://marc.info/?t=128635927000001
 -       *
 -       * What was wrong:
 -       * =>  http://marc.info/?l=linux-wireless&m=128636170811964
 -       * "Basically the thing is that until your patch, the data
 -       *  in the struct didn't actually need locking because it
 -       *  was accessed by the RX path only which is not concurrent."
 -       *
 -       * List of what needs to be fixed:
 -       * => http://marc.info/?l=linux-wireless&m=128656352920957
 -       *
 -
        if (tid_agg_rx->stored_mpdu_num) {
                j = index = seq_sub(tid_agg_rx->head_seq_num,
                                    tid_agg_rx->ssn) % tid_agg_rx->buf_size;
        } else {
                del_timer(&tid_agg_rx->reorder_timer);
        }
 -      */
 -
 -set_release_timer:
 -      return;
  }
  
  /*
   */
  static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                                             struct tid_ampdu_rx *tid_agg_rx,
 -                                           struct sk_buff *skb,
 -                                           struct sk_buff_head *frames)
 +                                           struct sk_buff *skb)
  {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        u16 sc = le16_to_cpu(hdr->seq_ctrl);
        int index;
        bool ret = true;
  
 +      spin_lock(&tid_agg_rx->reorder_lock);
 +
        buf_size = tid_agg_rx->buf_size;
        head_seq_num = tid_agg_rx->head_seq_num;
  
 -      spin_lock(&tid_agg_rx->reorder_lock);
        /* frame with out of date sequence number */
        if (seq_less(mpdu_seq_num, head_seq_num)) {
                dev_kfree_skb(skb);
        if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
                head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
                /* release stored frames up to new head to stack */
 -              ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num,
 -                                               frames);
 +              ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num);
        }
  
        /* Now the new frame is always in the range of the reordering buffer */
        tid_agg_rx->reorder_buf[index] = skb;
        tid_agg_rx->reorder_time[index] = jiffies;
        tid_agg_rx->stored_mpdu_num++;
 -      ieee80211_sta_reorder_release(hw, tid_agg_rx, frames);
 +      ieee80211_sta_reorder_release(hw, tid_agg_rx);
  
   out:
        spin_unlock(&tid_agg_rx->reorder_lock);
   * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
   * true if the MPDU was buffered, false if it should be processed.
   */
 -static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
 -                                     struct sk_buff_head *frames)
 +static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
  {
        struct sk_buff *skb = rx->skb;
        struct ieee80211_local *local = rx->local;
         * sure that we cannot get to it any more before doing
         * anything with it.
         */
 -      if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
 +      if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb))
                return;
  
   dont_reorder:
 -      __skb_queue_tail(frames, skb);
 +      skb_queue_tail(&local->rx_skb_queue, skb);
  }
  
  static ieee80211_rx_result debug_noinline
@@@ -928,31 -948,12 +928,31 @@@ ieee80211_rx_h_decrypt(struct ieee80211
                 * have been expected.
                 */
                struct ieee80211_key *key = NULL;
 +              struct ieee80211_sub_if_data *sdata = rx->sdata;
 +              int i;
 +
                if (ieee80211_is_mgmt(fc) &&
                    is_multicast_ether_addr(hdr->addr1) &&
                    (key = rcu_dereference(rx->sdata->default_mgmt_key)))
                        rx->key = key;
 -              else if ((key = rcu_dereference(rx->sdata->default_key)))
 -                      rx->key = key;
 +              else {
 +                      if (rx->sta) {
 +                              for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
 +                                      key = rcu_dereference(rx->sta->gtk[i]);
 +                                      if (key)
 +                                              break;
 +                              }
 +                      }
 +                      if (!key) {
 +                              for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
 +                                      key = rcu_dereference(sdata->keys[i]);
 +                                      if (key)
 +                                              break;
 +                              }
 +                      }
 +                      if (key)
 +                              rx->key = key;
 +              }
                return RX_CONTINUE;
        } else {
                u8 keyid;
@@@ -1101,6 -1102,8 +1101,6 @@@ static void ap_sta_ps_end(struct sta_in
  
        atomic_dec(&sdata->bss->num_sta_ps);
  
 -      clear_sta_flags(sta, WLAN_STA_PS_STA);
 -
  #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
               sdata->name, sta->sta.addr, sta->sta.aid);
@@@ -1155,14 -1158,12 +1155,14 @@@ ieee80211_rx_h_sta_process(struct ieee8
        sta->rx_fragments++;
        sta->rx_bytes += rx->skb->len;
        sta->last_signal = status->signal;
 +      ewma_add(&sta->avg_signal, -status->signal);
  
        /*
         * Change STA power saving mode only at the end of a frame
         * exchange sequence.
         */
        if (!ieee80211_has_morefrags(hdr->frame_control) &&
 +          !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
            (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
             rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
                if (test_sta_flags(sta, WLAN_STA_PS_STA)) {
@@@ -1514,30 -1515,12 +1514,30 @@@ ieee80211_drop_unencrypted_mgmt(struct 
        if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
                if (unlikely(!ieee80211_has_protected(fc) &&
                             ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
 -                           rx->key))
 +                           rx->key)) {
 +                      if (ieee80211_is_deauth(fc))
 +                              cfg80211_send_unprot_deauth(rx->sdata->dev,
 +                                                          rx->skb->data,
 +                                                          rx->skb->len);
 +                      else if (ieee80211_is_disassoc(fc))
 +                              cfg80211_send_unprot_disassoc(rx->sdata->dev,
 +                                                            rx->skb->data,
 +                                                            rx->skb->len);
                        return -EACCES;
 +              }
                /* BIP does not use Protected field, so need to check MMIE */
                if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
 -                           ieee80211_get_mmie_keyidx(rx->skb) < 0))
 +                           ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
 +                      if (ieee80211_is_deauth(fc))
 +                              cfg80211_send_unprot_deauth(rx->sdata->dev,
 +                                                          rx->skb->data,
 +                                                          rx->skb->len);
 +                      else if (ieee80211_is_disassoc(fc))
 +                              cfg80211_send_unprot_disassoc(rx->sdata->dev,
 +                                                            rx->skb->data,
 +                                                            rx->skb->len);
                        return -EACCES;
 +              }
                /*
                 * When using MFP, Action frames are not allowed prior to
                 * having configured keys.
@@@ -1808,6 -1791,8 +1808,8 @@@ ieee80211_rx_h_mesh_fwding(struct ieee8
                        if (!fwd_skb && net_ratelimit())
                                printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
                                                   sdata->name);
+                       if (!fwd_skb)
+                               goto out;
  
                        fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
                        memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
                }
        }
  
+  out:
        if (is_multicast_ether_addr(hdr->addr1) ||
            sdata->dev->flags & IFF_PROMISC)
                return RX_CONTINUE;
@@@ -1889,8 -1875,9 +1892,8 @@@ ieee80211_rx_h_data(struct ieee80211_rx
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += rx->skb->len;
  
 -      if (ieee80211_is_data(hdr->frame_control) &&
 -          !is_multicast_ether_addr(hdr->addr1) &&
 -          local->hw.conf.dynamic_ps_timeout > 0 && local->ps_sdata) {
 +      if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
 +          !is_multicast_ether_addr(((struct ethhdr *)rx->skb->data)->h_dest)) {
                        mod_timer(&local->dynamic_ps_timer, jiffies +
                         msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
        }
  }
  
  static ieee80211_rx_result debug_noinline
 -ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
 +ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
  {
        struct ieee80211_local *local = rx->local;
        struct ieee80211_hw *hw = &local->hw;
                        mod_timer(&tid_agg_rx->session_timer,
                                  TU_TO_EXP_TIME(tid_agg_rx->timeout));
  
 +              spin_lock(&tid_agg_rx->reorder_lock);
                /* release stored frames up to start of BAR */
 -              ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
 -                                               frames);
 +              ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num);
 +              spin_unlock(&tid_agg_rx->reorder_lock);
 +
                kfree_skb(skb);
                return RX_QUEUED;
        }
@@@ -2134,13 -2119,10 +2137,13 @@@ ieee80211_rx_h_action(struct ieee80211_
                }
                break;
        case WLAN_CATEGORY_MESH_PLINK:
 -      case WLAN_CATEGORY_MESH_PATH_SEL:
                if (!ieee80211_vif_is_mesh(&sdata->vif))
                        break;
                goto queue;
 +      case WLAN_CATEGORY_MESH_PATH_SEL:
 +              if (!mesh_path_sel_is_hwmp(sdata))
 +                      break;
 +              goto queue;
        }
  
        return RX_CONTINUE;
@@@ -2458,7 -2440,8 +2461,7 @@@ static void ieee80211_rx_handlers_resul
        }
  }
  
 -static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
 -                                struct sk_buff_head *frames)
 +static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)
  {
        ieee80211_rx_result res = RX_DROP_MONITOR;
        struct sk_buff *skb;
                        goto rxh_next;  \
        } while (0);
  
 -      while ((skb = __skb_dequeue(frames))) {
 +      spin_lock(&rx->local->rx_skb_queue.lock);
 +      if (rx->local->running_rx_handler)
 +              goto unlock;
 +
 +      rx->local->running_rx_handler = true;
 +
 +      while ((skb = __skb_dequeue(&rx->local->rx_skb_queue))) {
 +              spin_unlock(&rx->local->rx_skb_queue.lock);
 +
                /*
                 * all the other fields are valid across frames
                 * that belong to an aMPDU since they are on the
                        CALL_RXH(ieee80211_rx_h_mesh_fwding);
  #endif
                CALL_RXH(ieee80211_rx_h_data)
 -
 -              /* special treatment -- needs the queue */
 -              res = ieee80211_rx_h_ctrl(rx, frames);
 -              if (res != RX_CONTINUE)
 -                      goto rxh_next;
 -
 +              CALL_RXH(ieee80211_rx_h_ctrl);
                CALL_RXH(ieee80211_rx_h_mgmt_check)
                CALL_RXH(ieee80211_rx_h_action)
                CALL_RXH(ieee80211_rx_h_userspace_mgmt)
  
   rxh_next:
                ieee80211_rx_handlers_result(rx, res);
 -
 +              spin_lock(&rx->local->rx_skb_queue.lock);
  #undef CALL_RXH
        }
 +
 +      rx->local->running_rx_handler = false;
 +
 + unlock:
 +      spin_unlock(&rx->local->rx_skb_queue.lock);
  }
  
  static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
  {
 -      struct sk_buff_head reorder_release;
        ieee80211_rx_result res = RX_DROP_MONITOR;
  
 -      __skb_queue_head_init(&reorder_release);
 -
  #define CALL_RXH(rxh)                 \
        do {                            \
                res = rxh(rx);          \
        CALL_RXH(ieee80211_rx_h_passive_scan)
        CALL_RXH(ieee80211_rx_h_check)
  
 -      ieee80211_rx_reorder_ampdu(rx, &reorder_release);
 +      ieee80211_rx_reorder_ampdu(rx);
  
 -      ieee80211_rx_handlers(rx, &reorder_release);
 +      ieee80211_rx_handlers(rx);
        return;
  
   rxh_next:
  }
  
  /*
 - * This function makes calls into the RX path. Therefore the
 - * caller must hold the sta_info->lock and everything has to
 - * be under rcu_read_lock protection as well.
 + * This function makes calls into the RX path, therefore
 + * it has to be invoked under RCU read lock.
   */
  void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
  {
 -      struct sk_buff_head frames;
        struct ieee80211_rx_data rx = {
                .sta = sta,
                .sdata = sta->sdata,
        if (!tid_agg_rx)
                return;
  
 -      __skb_queue_head_init(&frames);
 -
        spin_lock(&tid_agg_rx->reorder_lock);
 -      ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx, &frames);
 +      ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx);
        spin_unlock(&tid_agg_rx->reorder_lock);
  
 -      ieee80211_rx_handlers(&rx, &frames);
 +      ieee80211_rx_handlers(&rx);
  }
  
  /* main receive path */