Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
John W. Linville [Fri, 26 Feb 2010 21:54:45 +0000 (16:54 -0500)]
Conflicts:
drivers/net/wireless/iwlwifi/iwl-core.h
net/mac80211/rate.c

1  2 
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwmc3200wifi/rx.c
drivers/net/wireless/rtl818x/rtl8187_dev.c
net/mac80211/rate.c

@@@ -1498,6 -1498,26 +1498,6 @@@ static void ath_buf_set_rate(struct ath
        if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
                ctsrate |= rate->hw_value_short;
  
 -      /*
 -       * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive.
 -       * Check the first rate in the series to decide whether RTS/CTS
 -       * or CTS-to-self has to be used.
 -       */
 -      if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
 -              flags = ATH9K_TXDESC_CTSENA;
 -      else if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
 -              flags = ATH9K_TXDESC_RTSENA;
 -
 -      /* FIXME: Handle aggregation protection */
 -      if (sc->config.ath_aggr_prot &&
 -          (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
 -              flags = ATH9K_TXDESC_RTSENA;
 -      }
 -
 -      /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
 -      if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
 -              flags &= ~(ATH9K_TXDESC_RTSENA);
 -
        for (i = 0; i < 4; i++) {
                bool is_40, is_sgi, is_sp;
                int phy;
                series[i].Tries = rates[i].count;
                series[i].ChSel = common->tx_chainmask;
  
 -              if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)
 +              if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
 +                  (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
 +                      series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
 +                      flags |= ATH9K_TXDESC_RTSENA;
 +              } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
                        series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
 +                      flags |= ATH9K_TXDESC_CTSENA;
 +              }
 +
                if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
                        series[i].RateFlags |= ATH9K_RATESERIES_2040;
                if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
                        phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
        }
  
 +      /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
 +      if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
 +              flags &= ~ATH9K_TXDESC_RTSENA;
 +
 +      /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
 +      if (flags & ATH9K_TXDESC_RTSENA)
 +              flags &= ~ATH9K_TXDESC_CTSENA;
 +
        /* set dur_update_en for l-sig computation except for PS-Poll frames */
        ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
                                     bf->bf_lastbf->bf_desc,
@@@ -1610,7 -1615,7 +1610,7 @@@ static int ath_tx_setup_buffer(struct i
                bf->bf_frmlen -= padsize;
        }
  
-       if (conf_is_ht(&hw->conf) && !is_pae(skb))
+       if (conf_is_ht(&hw->conf))
                bf->bf_state.bf_type |= BUF_HT;
  
        bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
        /* tag if this is a nullfunc frame to enable PS when AP acks it */
        if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
                bf->bf_isnullfunc = true;
 -              sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
 +              sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
        } else
                bf->bf_isnullfunc = false;
  
@@@ -1696,7 -1701,7 +1696,7 @@@ static void ath_tx_start_dma(struct ath
                        goto tx_done;
                }
  
-               if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+               if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && !is_pae(skb)) {
                        /*
                         * Try aggregation if it's a unicast data frame
                         * and the destination is HT capable.
@@@ -1853,15 -1858,15 +1853,15 @@@ static void ath_tx_complete(struct ath_
                skb_pull(skb, padsize);
        }
  
 -      if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) {
 -              sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK;
 +      if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
 +              sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
                ath_print(common, ATH_DBG_PS,
                          "Going back to sleep after having "
 -                        "received TX status (0x%x)\n",
 -                      sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
 -                                      SC_OP_WAIT_FOR_CAB |
 -                                      SC_OP_WAIT_FOR_PSPOLL_DATA |
 -                                      SC_OP_WAIT_FOR_TX_ACK));
 +                        "received TX status (0x%lx)\n",
 +                      sc->ps_flags & (PS_WAIT_FOR_BEACON |
 +                                      PS_WAIT_FOR_CAB |
 +                                      PS_WAIT_FOR_PSPOLL_DATA |
 +                                      PS_WAIT_FOR_TX_ACK));
        }
  
        if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
@@@ -2048,10 -2053,11 +2048,10 @@@ static void ath_tx_processq(struct ath_
                 */
                if (bf->bf_isnullfunc &&
                    (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) {
 -                      if ((sc->sc_flags & SC_OP_PS_ENABLED)) {
 -                              sc->ps_enabled = true;
 -                              ath9k_hw_setrxabort(sc->sc_ah, 1);
 -                      } else
 -                              sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED;
 +                      if ((sc->ps_flags & PS_ENABLED))
 +                              ath9k_enable_ps(sc);
 +                      else
 +                              sc->ps_flags |= PS_NULLFUNC_COMPLETED;
                }
  
                /*
@@@ -1,6 -1,6 +1,6 @@@
  /******************************************************************************
   *
 - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
 + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of version 2 of the GNU General Public License as
@@@ -581,13 -581,6 +581,13 @@@ static int iwl4965_alive_notify(struct 
  
        iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
  
 +      /* make sure all queue are not stopped */
 +      memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
 +      for (i = 0; i < 4; i++)
 +              atomic_set(&priv->queue_stop_count[i], 0);
 +
 +      /* reset to 0 to enable all the queue first */
 +      priv->txq_ctx_active_msk = 0;
        /* Map each Tx/cmd queue to its corresponding fifo */
        for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
                int ac = default_queue_to_tx_fifo[i];
@@@ -2015,7 -2008,7 +2015,7 @@@ static void iwl4965_rx_reply_tx(struct 
                        IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim scd_ssn "
                                           "%d index %d\n", scd_ssn , index);
                        freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+                       iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
  
                        if (priv->mac80211_registered &&
                            (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
@@@ -2213,10 -2206,9 +2213,10 @@@ static struct iwl_lib_ops iwl4965_lib 
                .temperature = iwl4965_temperature_calib,
                .set_ct_kill = iwl4965_set_ct_threshold,
        },
 +      .add_bcast_station = iwl_add_bcast_station,
  };
  
 -static struct iwl_ops iwl4965_ops = {
 +static const struct iwl_ops iwl4965_ops = {
        .ucode = &iwl4965_ucode,
        .lib = &iwl4965_lib,
        .hcmd = &iwl4965_hcmd,
@@@ -2247,7 -2239,7 +2247,7 @@@ struct iwl_cfg iwl4965_agn_cfg = 
        .broken_powersave = true,
        .led_compensation = 61,
        .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
 -      .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 +      .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
  };
  
  /* Module firmware */
@@@ -1,6 -1,6 +1,6 @@@
  /******************************************************************************
   *
 - * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
 + * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of version 2 of the GNU General Public License as
@@@ -179,24 -179,14 +179,24 @@@ static void iwl5000_gain_computation(st
                        data->delta_gain_code[i] = 0;
                        continue;
                }
 -              delta_g = (1000 * ((s32)average_noise[default_chain] -
 +
 +              delta_g = (priv->cfg->chain_noise_scale *
 +                      ((s32)average_noise[default_chain] -
                        (s32)average_noise[i])) / 1500;
 +
                /* bound gain by 2 bits value max, 3rd bit is sign */
                data->delta_gain_code[i] =
                        min(abs(delta_g), (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
  
                if (delta_g < 0)
 -                      /* set negative sign */
 +                      /*
 +                       * set negative sign ...
 +                       * note to Intel developers:  This is uCode API format,
 +                       *   not the format of any internal device registers.
 +                       *   Do not change this format for e.g. 6050 or similar
 +                       *   devices.  Change format only if more resolution
 +                       *   (i.e. more than 2 bits magnitude) is needed.
 +                       */
                        data->delta_gain_code[i] |= (1 << 2);
        }
  
@@@ -273,8 -263,8 +273,8 @@@ static struct iwl_sensitivity_ranges iw
  
        .auto_corr_max_ofdm = 120,
        .auto_corr_max_ofdm_mrc = 210,
 -      .auto_corr_max_ofdm_x1 = 155,
 -      .auto_corr_max_ofdm_mrc_x1 = 290,
 +      .auto_corr_max_ofdm_x1 = 120,
 +      .auto_corr_max_ofdm_mrc_x1 = 240,
  
        .auto_corr_min_cck = 125,
        .auto_corr_max_cck = 200,
@@@ -422,14 -412,12 +422,14 @@@ static void iwl5000_rx_calib_complete(s
  /*
   * ucode
   */
 -static int iwl5000_load_section(struct iwl_priv *priv,
 -                              struct fw_desc *image,
 -                              u32 dst_addr)
 +static int iwl5000_load_section(struct iwl_priv *priv, const char *name,
 +                              struct fw_desc *image, u32 dst_addr)
  {
        dma_addr_t phy_addr = image->p_addr;
        u32 byte_cnt = image->len;
 +      int ret;
 +
 +      priv->ucode_write_complete = 0;
  
        iwl_write_direct32(priv,
                FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
                FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
  
 -      return 0;
 -}
 -
 -static int iwl5000_load_given_ucode(struct iwl_priv *priv,
 -              struct fw_desc *inst_image,
 -              struct fw_desc *data_image)
 -{
 -      int ret = 0;
 -
 -      ret = iwl5000_load_section(priv, inst_image,
 -                                 IWL50_RTC_INST_LOWER_BOUND);
 -      if (ret)
 -              return ret;
 -
 -      IWL_DEBUG_INFO(priv, "INST uCode section being loaded...\n");
 +      IWL_DEBUG_INFO(priv, "%s uCode section being loaded...\n", name);
        ret = wait_event_interruptible_timeout(priv->wait_command_queue,
                                        priv->ucode_write_complete, 5 * HZ);
        if (ret == -ERESTARTSYS) {
 -              IWL_ERR(priv, "Could not load the INST uCode section due "
 -                      "to interrupt\n");
 +              IWL_ERR(priv, "Could not load the %s uCode section due "
 +                      "to interrupt\n", name);
                return ret;
        }
        if (!ret) {
 -              IWL_ERR(priv, "Could not load the INST uCode section\n");
 +              IWL_ERR(priv, "Could not load the %s uCode section\n",
 +                      name);
                return -ETIMEDOUT;
        }
  
 -      priv->ucode_write_complete = 0;
 -
 -      ret = iwl5000_load_section(
 -              priv, data_image, IWL50_RTC_DATA_LOWER_BOUND);
 -      if (ret)
 -              return ret;
 +      return 0;
 +}
  
 -      IWL_DEBUG_INFO(priv, "DATA uCode section being loaded...\n");
 +static int iwl5000_load_given_ucode(struct iwl_priv *priv,
 +              struct fw_desc *inst_image,
 +              struct fw_desc *data_image)
 +{
 +      int ret = 0;
  
 -      ret = wait_event_interruptible_timeout(priv->wait_command_queue,
 -                              priv->ucode_write_complete, 5 * HZ);
 -      if (ret == -ERESTARTSYS) {
 -              IWL_ERR(priv, "Could not load the INST uCode section due "
 -                      "to interrupt\n");
 +      ret = iwl5000_load_section(priv, "INST", inst_image,
 +                                 IWL50_RTC_INST_LOWER_BOUND);
 +      if (ret)
                return ret;
 -      } else if (!ret) {
 -              IWL_ERR(priv, "Could not load the DATA uCode section\n");
 -              return -ETIMEDOUT;
 -      } else
 -              ret = 0;
  
 -      priv->ucode_write_complete = 0;
 -
 -      return ret;
 +      return iwl5000_load_section(priv, "DATA", data_image,
 +                                  IWL50_RTC_DATA_LOWER_BOUND);
  }
  
  int iwl5000_load_ucode(struct iwl_priv *priv)
@@@ -648,13 -657,6 +648,13 @@@ int iwl5000_alive_notify(struct iwl_pri
  
        iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
  
 +      /* make sure all queue are not stopped */
 +      memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
 +      for (i = 0; i < 4; i++)
 +              atomic_set(&priv->queue_stop_count[i], 0);
 +
 +      /* reset to 0 to enable all the queue first */
 +      priv->txq_ctx_active_msk = 0;
        /* map qos queues to fifos one-to-one */
        for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
                int ac = iwl5000_default_queue_to_tx_fifo[i];
@@@ -779,7 -781,7 +779,7 @@@ void iwl5000_txq_update_byte_cnt_tbl(st
  
        scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
  
 -      if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
 +      if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
                scd_bc_tbl[txq_id].
                        tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
  }
@@@ -798,12 -800,12 +798,12 @@@ void iwl5000_txq_inval_byte_cnt_tbl(str
        if (txq_id != IWL_CMD_QUEUE_NUM)
                sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
  
 -      bc_ent =  cpu_to_le16(1 | (sta_id << 12));
 +      bc_ent = cpu_to_le16(1 | (sta_id << 12));
        scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
  
 -      if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
 +      if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
                scd_bc_tbl[txq_id].
 -                      tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] =  bc_ent;
 +                      tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
  }
  
  static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
@@@ -1123,7 -1125,7 +1123,7 @@@ static void iwl5000_rx_reply_tx(struct 
                                        scd_ssn , index, txq_id, txq->swq_id);
  
                        freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+                       iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
  
                        if (priv->mac80211_registered &&
                            (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
                                   tx_resp->failure_frame);
  
                freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-               if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
-                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
  
                if (priv->mac80211_registered &&
                    (iwl_queue_space(&txq->q) > txq->q.low_mark))
                        iwl_wake_queue(priv, txq_id);
        }
  
-       if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
-               iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+       iwl_txq_check_empty(priv, sta_id, tid, txq_id);
  
        if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
                IWL_ERR(priv, "TODO:  Implement Tx ABORT REQUIRED!!!\n");
@@@ -1464,8 -1464,6 +1462,8 @@@ struct iwl_lib_ops iwl5000_lib = 
        .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
 +      .dump_csr = iwl_dump_csr,
 +      .dump_fh = iwl_dump_fh,
        .load_ucode = iwl5000_load_ucode,
        .init_alive_start = iwl5000_init_alive_start,
        .alive_notify = iwl5000_alive_notify,
                .temperature = iwl5000_temperature,
                .set_ct_kill = iwl5000_set_ct_threshold,
         },
 +      .add_bcast_station = iwl_add_bcast_station,
  };
  
  static struct iwl_lib_ops iwl5150_lib = {
        .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
 +      .dump_csr = iwl_dump_csr,
        .load_ucode = iwl5000_load_ucode,
        .init_alive_start = iwl5000_init_alive_start,
        .alive_notify = iwl5000_alive_notify,
                .temperature = iwl5150_temperature,
                .set_ct_kill = iwl5150_set_ct_threshold,
         },
 +      .add_bcast_station = iwl_add_bcast_station,
  };
  
 -static struct iwl_ops iwl5000_ops = {
 +static const struct iwl_ops iwl5000_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl5000_lib,
        .hcmd = &iwl5000_hcmd,
        .led = &iwlagn_led_ops,
  };
  
 -static struct iwl_ops iwl5150_ops = {
 +static const struct iwl_ops iwl5150_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl5150_lib,
        .hcmd = &iwl5000_hcmd,
@@@ -1603,8 -1598,7 +1601,8 @@@ struct iwl_cfg iwl5300_agn_cfg = 
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 -      .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 +      .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 +      .chain_noise_scale = 1000,
  };
  
  struct iwl_cfg iwl5100_bgn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 +      .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 +      .chain_noise_scale = 1000,
  };
  
  struct iwl_cfg iwl5100_abg_cfg = {
        .use_bsm = false,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 +      .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 +      .chain_noise_scale = 1000,
  };
  
  struct iwl_cfg iwl5100_agn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 -      .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 +      .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 +      .chain_noise_scale = 1000,
  };
  
  struct iwl_cfg iwl5350_agn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 -      .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 +      .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 +      .chain_noise_scale = 1000,
  };
  
  struct iwl_cfg iwl5150_agn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 -      .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 +      .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 +      .chain_noise_scale = 1000,
  };
  
  struct iwl_cfg iwl5150_abg_cfg = {
        .use_bsm = false,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 +      .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 +      .chain_noise_scale = 1000,
  };
  
  MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
@@@ -2,7 -2,7 +2,7 @@@
   *
   * GPL LICENSE SUMMARY
   *
 - * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
 + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of version 2 of the GNU General Public License as
@@@ -47,26 -47,6 +47,26 @@@ MODULE_VERSION(IWLWIFI_VERSION)
  MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
  MODULE_LICENSE("GPL");
  
 +/*
 + * set bt_coex_active to true, uCode will do kill/defer
 + * every time the priority line is asserted (BT is sending signals on the
 + * priority line in the PCIx).
 + * set bt_coex_active to false, uCode will ignore the BT activity and
 + * perform the normal operation
 + *
 + * User might experience transmit issue on some platform due to WiFi/BT
 + * co-exist problem. The possible behaviors are:
 + *   Able to scan and finding all the available AP
 + *   Not able to associate with any AP
 + * On those platforms, WiFi communication can be restored by set
 + * "bt_coex_active" module parameter to "false"
 + *
 + * default: bt_coex_active = true (BT_COEX_ENABLE)
 + */
 +static bool bt_coex_active = true;
 +module_param(bt_coex_active, bool, S_IRUGO);
 +MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist\n");
 +
  static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
        {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
         0, COEX_UNASSOC_IDLE_FLAGS},
@@@ -277,8 -257,8 +277,8 @@@ int iwl_hw_nic_init(struct iwl_priv *pr
        spin_lock_irqsave(&priv->lock, flags);
        priv->cfg->ops->lib->apm_ops.init(priv);
  
 -      /* Set interrupt coalescing timer to 512 usecs */
 -      iwl_write8(priv, CSR_INT_COALESCING, 512 / 32);
 +      /* Set interrupt coalescing calibration timer to default (512 usecs) */
 +      iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
  
        spin_unlock_irqrestore(&priv->lock, flags);
  
@@@ -470,6 -450,8 +470,6 @@@ static void iwlcore_init_ht_hw_capab(co
        if (priv->cfg->ht_greenfield_support)
                ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
        ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
 -      ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
 -                           (priv->cfg->sm_ps_mode << 2));
        max_bit_rate = MAX_BIT_RATE_20_MHZ;
        if (priv->hw_params.ht40_channel & BIT(band)) {
                ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
@@@ -654,7 -636,7 +654,7 @@@ EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag)
  
  static bool is_single_rx_stream(struct iwl_priv *priv)
  {
 -      return !priv->current_ht_config.is_ht ||
 +      return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
               priv->current_ht_config.single_chain_sufficient;
  }
  
@@@ -1021,18 -1003,28 +1021,18 @@@ static int iwl_get_active_rx_chain_coun
   */
  static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
  {
 -      int idle_cnt = active_cnt;
 -      bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
 -
 -      /* # Rx chains when idling and maybe trying to save power */
 -      switch (priv->cfg->sm_ps_mode) {
 -      case WLAN_HT_CAP_SM_PS_STATIC:
 -              idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
 -              break;
 -      case WLAN_HT_CAP_SM_PS_DYNAMIC:
 -              idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
 -                      IWL_NUM_IDLE_CHAINS_SINGLE;
 -              break;
 -      case WLAN_HT_CAP_SM_PS_DISABLED:
 -              break;
 -      case WLAN_HT_CAP_SM_PS_INVALID:
 +      /* # Rx chains when idling, depending on SMPS mode */
 +      switch (priv->current_ht_config.smps) {
 +      case IEEE80211_SMPS_STATIC:
 +      case IEEE80211_SMPS_DYNAMIC:
 +              return IWL_NUM_IDLE_CHAINS_SINGLE;
 +      case IEEE80211_SMPS_OFF:
 +              return active_cnt;
        default:
 -              IWL_ERR(priv, "invalid sm_ps mode %u\n",
 -                      priv->cfg->sm_ps_mode);
 -              WARN_ON(1);
 -              break;
 +              WARN(1, "invalid SMPS mode %d",
 +                   priv->current_ht_config.smps);
 +              return active_cnt;
        }
 -      return idle_cnt;
  }
  
  /* up to 4 chains */
@@@ -1371,11 -1363,7 +1371,11 @@@ void iwl_irq_handle_error(struct iwl_pr
        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
  
        priv->cfg->ops->lib->dump_nic_error_log(priv);
 -      priv->cfg->ops->lib->dump_nic_event_log(priv, false);
 +      if (priv->cfg->ops->lib->dump_csr)
 +              priv->cfg->ops->lib->dump_csr(priv);
 +      if (priv->cfg->ops->lib->dump_fh)
 +              priv->cfg->ops->lib->dump_fh(priv, NULL, false);
 +      priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);
  #ifdef CONFIG_IWLWIFI_DEBUG
        if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
                iwl_print_rx_config_cmd(priv);
@@@ -1670,9 -1658,9 +1670,9 @@@ EXPORT_SYMBOL(iwl_set_tx_power)
  void iwl_free_isr_ict(struct iwl_priv *priv)
  {
        if (priv->ict_tbl_vir) {
 -              pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) +
 -                                      PAGE_SIZE, priv->ict_tbl_vir,
 -                                      priv->ict_tbl_dma);
 +              dma_free_coherent(&priv->pci_dev->dev,
 +                                (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
 +                                priv->ict_tbl_vir, priv->ict_tbl_dma);
                priv->ict_tbl_vir = NULL;
        }
  }
@@@ -1688,9 -1676,9 +1688,9 @@@ int iwl_alloc_isr_ict(struct iwl_priv *
        if (priv->cfg->use_isr_legacy)
                return 0;
        /* allocate shrared data table */
 -      priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) *
 -                                                ICT_COUNT) + PAGE_SIZE,
 -                                                &priv->ict_tbl_dma);
 +      priv->ict_tbl_vir = dma_alloc_coherent(&priv->pci_dev->dev,
 +                                      (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
 +                                      &priv->ict_tbl_dma, GFP_KERNEL);
        if (!priv->ict_tbl_vir)
                return -ENOMEM;
  
@@@ -1825,16 -1813,6 +1825,16 @@@ irqreturn_t iwl_isr_ict(int irq, void *
        if (val == 0xffffffff)
                val = 0;
  
 +      /*
 +       * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
 +       * (bit 15 before shifting it to 31) to clear when using interrupt
 +       * coalescing. fortunately, bits 18 and 19 stay set when this happens
 +       * so we use them to decide on the real state of the Rx bit.
 +       * In order words, bit 15 is set if bit 18 or bit 19 are set.
 +       */
 +      if (val & 0xC0000)
 +              val |= 0x8000;
 +
        inta = (0xff & val) | ((0xff00 & val) << 16);
        IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
                        inta, inta_mask, val);
@@@ -1997,20 -1975,13 +1997,20 @@@ EXPORT_SYMBOL(iwl_isr_legacy)
  int iwl_send_bt_config(struct iwl_priv *priv)
  {
        struct iwl_bt_cmd bt_cmd = {
 -              .flags = BT_COEX_MODE_4W,
                .lead_time = BT_LEAD_TIME_DEF,
                .max_kill = BT_MAX_KILL_DEF,
                .kill_ack_mask = 0,
                .kill_cts_mask = 0,
        };
  
 +      if (!bt_coex_active)
 +              bt_cmd.flags = BT_COEX_DISABLE;
 +      else
 +              bt_cmd.flags = BT_COEX_ENABLE;
 +
 +      IWL_DEBUG_INFO(priv, "BT coex %s\n",
 +              (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
 +
        return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
                                sizeof(struct iwl_bt_cmd), &bt_cmd);
  }
@@@ -2628,43 -2599,44 +2628,43 @@@ int iwl_set_mode(struct iwl_priv *priv
  EXPORT_SYMBOL(iwl_set_mode);
  
  int iwl_mac_add_interface(struct ieee80211_hw *hw,
 -                               struct ieee80211_if_init_conf *conf)
 +                               struct ieee80211_vif *vif)
  {
        struct iwl_priv *priv = hw->priv;
 -      unsigned long flags;
 +      int err = 0;
  
 -      IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type);
 +      IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type);
 +
 +      mutex_lock(&priv->mutex);
  
        if (priv->vif) {
                IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
 -              return -EOPNOTSUPP;
 +              err = -EOPNOTSUPP;
 +              goto out;
        }
  
 -      spin_lock_irqsave(&priv->lock, flags);
 -      priv->vif = conf->vif;
 -      priv->iw_mode = conf->type;
 -
 -      spin_unlock_irqrestore(&priv->lock, flags);
 -
 -      mutex_lock(&priv->mutex);
 +      priv->vif = vif;
 +      priv->iw_mode = vif->type;
  
 -      if (conf->mac_addr) {
 -              IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr);
 -              memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
 +      if (vif->addr) {
 +              IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr);
 +              memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
        }
  
 -      if (iwl_set_mode(priv, conf->type) == -EAGAIN)
 +      if (iwl_set_mode(priv, vif->type) == -EAGAIN)
                /* we are not ready, will run again when ready */
                set_bit(STATUS_MODE_PENDING, &priv->status);
  
 + out:
        mutex_unlock(&priv->mutex);
  
        IWL_DEBUG_MAC80211(priv, "leave\n");
 -      return 0;
 +      return err;
  }
  EXPORT_SYMBOL(iwl_mac_add_interface);
  
  void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 -                                   struct ieee80211_if_init_conf *conf)
 +                                   struct ieee80211_vif *vif)
  {
        struct iwl_priv *priv = hw->priv;
  
                priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
                iwlcore_commit_rxon(priv);
        }
 -      if (priv->vif == conf->vif) {
 +      if (priv->vif == vif) {
                priv->vif = NULL;
                memset(priv->bssid, 0, ETH_ALEN);
        }
@@@ -2717,21 -2689,6 +2717,21 @@@ int iwl_mac_config(struct ieee80211_hw 
                IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
        }
  
 +      if (changed & (IEEE80211_CONF_CHANGE_SMPS |
 +                     IEEE80211_CONF_CHANGE_CHANNEL)) {
 +              /* mac80211 uses static for non-HT which is what we want */
 +              priv->current_ht_config.smps = conf->smps_mode;
 +
 +              /*
 +               * Recalculate chain counts.
 +               *
 +               * If monitor mode is enabled then mac80211 will
 +               * set up the SM PS mode to OFF if an HT channel is
 +               * configured.
 +               */
 +              if (priv->cfg->ops->hcmd->set_rxon_chain)
 +                      priv->cfg->ops->hcmd->set_rxon_chain(priv);
 +      }
  
        /* during scanning mac80211 will delay channel setting until
         * scan finish with changed = 0
                if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
                        priv->staging_rxon.flags = 0;
  
-               iwl_set_rxon_ht(priv, ht_conf);
                iwl_set_rxon_channel(priv, conf->channel);
+               iwl_set_rxon_ht(priv, ht_conf);
  
                iwl_set_flags_for_band(priv, conf->channel->band);
                spin_unlock_irqrestore(&priv->lock, flags);
                iwl_set_tx_power(priv, conf->power_level, false);
        }
  
 -      /* call to ensure that 4965 rx_chain is set properly in monitor mode */
 -      if (priv->cfg->ops->hcmd->set_rxon_chain)
 -              priv->cfg->ops->hcmd->set_rxon_chain(priv);
 -
        if (!iwl_is_ready(priv)) {
                IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
                goto out;
@@@ -2851,6 -2812,42 +2851,6 @@@ out
  }
  EXPORT_SYMBOL(iwl_mac_config);
  
 -int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
 -                       struct ieee80211_tx_queue_stats *stats)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      int i, avail;
 -      struct iwl_tx_queue *txq;
 -      struct iwl_queue *q;
 -      unsigned long flags;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -
 -      if (!iwl_is_ready_rf(priv)) {
 -              IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
 -              return -EIO;
 -      }
 -
 -      spin_lock_irqsave(&priv->lock, flags);
 -
 -      for (i = 0; i < AC_NUM; i++) {
 -              txq = &priv->txq[i];
 -              q = &txq->q;
 -              avail = iwl_queue_space(q);
 -
 -              stats[i].len = q->n_window - avail;
 -              stats[i].limit = q->n_window - q->high_mark;
 -              stats[i].count = q->n_window;
 -
 -      }
 -      spin_unlock_irqrestore(&priv->lock, flags);
 -
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -
 -      return 0;
 -}
 -EXPORT_SYMBOL(iwl_mac_get_tx_stats);
 -
  void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
  {
        struct iwl_priv *priv = hw->priv;
@@@ -3200,207 -3197,6 +3200,207 @@@ void iwl_update_stats(struct iwl_priv *
  EXPORT_SYMBOL(iwl_update_stats);
  #endif
  
 +const static char *get_csr_string(int cmd)
 +{
 +      switch (cmd) {
 +              IWL_CMD(CSR_HW_IF_CONFIG_REG);
 +              IWL_CMD(CSR_INT_COALESCING);
 +              IWL_CMD(CSR_INT);
 +              IWL_CMD(CSR_INT_MASK);
 +              IWL_CMD(CSR_FH_INT_STATUS);
 +              IWL_CMD(CSR_GPIO_IN);
 +              IWL_CMD(CSR_RESET);
 +              IWL_CMD(CSR_GP_CNTRL);
 +              IWL_CMD(CSR_HW_REV);
 +              IWL_CMD(CSR_EEPROM_REG);
 +              IWL_CMD(CSR_EEPROM_GP);
 +              IWL_CMD(CSR_OTP_GP_REG);
 +              IWL_CMD(CSR_GIO_REG);
 +              IWL_CMD(CSR_GP_UCODE_REG);
 +              IWL_CMD(CSR_GP_DRIVER_REG);
 +              IWL_CMD(CSR_UCODE_DRV_GP1);
 +              IWL_CMD(CSR_UCODE_DRV_GP2);
 +              IWL_CMD(CSR_LED_REG);
 +              IWL_CMD(CSR_DRAM_INT_TBL_REG);
 +              IWL_CMD(CSR_GIO_CHICKEN_BITS);
 +              IWL_CMD(CSR_ANA_PLL_CFG);
 +              IWL_CMD(CSR_HW_REV_WA_REG);
 +              IWL_CMD(CSR_DBG_HPET_MEM_REG);
 +      default:
 +              return "UNKNOWN";
 +
 +      }
 +}
 +
 +void iwl_dump_csr(struct iwl_priv *priv)
 +{
 +      int i;
 +      u32 csr_tbl[] = {
 +              CSR_HW_IF_CONFIG_REG,
 +              CSR_INT_COALESCING,
 +              CSR_INT,
 +              CSR_INT_MASK,
 +              CSR_FH_INT_STATUS,
 +              CSR_GPIO_IN,
 +              CSR_RESET,
 +              CSR_GP_CNTRL,
 +              CSR_HW_REV,
 +              CSR_EEPROM_REG,
 +              CSR_EEPROM_GP,
 +              CSR_OTP_GP_REG,
 +              CSR_GIO_REG,
 +              CSR_GP_UCODE_REG,
 +              CSR_GP_DRIVER_REG,
 +              CSR_UCODE_DRV_GP1,
 +              CSR_UCODE_DRV_GP2,
 +              CSR_LED_REG,
 +              CSR_DRAM_INT_TBL_REG,
 +              CSR_GIO_CHICKEN_BITS,
 +              CSR_ANA_PLL_CFG,
 +              CSR_HW_REV_WA_REG,
 +              CSR_DBG_HPET_MEM_REG
 +      };
 +      IWL_ERR(priv, "CSR values:\n");
 +      IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is "
 +              "CSR_INT_PERIODIC_REG)\n");
 +      for (i = 0; i <  ARRAY_SIZE(csr_tbl); i++) {
 +              IWL_ERR(priv, "  %25s: 0X%08x\n",
 +                      get_csr_string(csr_tbl[i]),
 +                      iwl_read32(priv, csr_tbl[i]));
 +      }
 +}
 +EXPORT_SYMBOL(iwl_dump_csr);
 +
 +const static char *get_fh_string(int cmd)
 +{
 +      switch (cmd) {
 +              IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
 +              IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
 +              IWL_CMD(FH_RSCSR_CHNL0_WPTR);
 +              IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
 +              IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
 +              IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
 +              IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
 +              IWL_CMD(FH_TSSR_TX_STATUS_REG);
 +              IWL_CMD(FH_TSSR_TX_ERROR_REG);
 +      default:
 +              return "UNKNOWN";
 +
 +      }
 +}
 +
 +int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
 +{
 +      int i;
 +#ifdef CONFIG_IWLWIFI_DEBUG
 +      int pos = 0;
 +      size_t bufsz = 0;
 +#endif
 +      u32 fh_tbl[] = {
 +              FH_RSCSR_CHNL0_STTS_WPTR_REG,
 +              FH_RSCSR_CHNL0_RBDCB_BASE_REG,
 +              FH_RSCSR_CHNL0_WPTR,
 +              FH_MEM_RCSR_CHNL0_CONFIG_REG,
 +              FH_MEM_RSSR_SHARED_CTRL_REG,
 +              FH_MEM_RSSR_RX_STATUS_REG,
 +              FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
 +              FH_TSSR_TX_STATUS_REG,
 +              FH_TSSR_TX_ERROR_REG
 +      };
 +#ifdef CONFIG_IWLWIFI_DEBUG
 +      if (display) {
 +              bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
 +              *buf = kmalloc(bufsz, GFP_KERNEL);
 +              if (!*buf)
 +                      return -ENOMEM;
 +              pos += scnprintf(*buf + pos, bufsz - pos,
 +                              "FH register values:\n");
 +              for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
 +                      pos += scnprintf(*buf + pos, bufsz - pos,
 +                              "  %34s: 0X%08x\n",
 +                              get_fh_string(fh_tbl[i]),
 +                              iwl_read_direct32(priv, fh_tbl[i]));
 +              }
 +              return pos;
 +      }
 +#endif
 +      IWL_ERR(priv, "FH register values:\n");
 +      for (i = 0; i <  ARRAY_SIZE(fh_tbl); i++) {
 +              IWL_ERR(priv, "  %34s: 0X%08x\n",
 +                      get_fh_string(fh_tbl[i]),
 +                      iwl_read_direct32(priv, fh_tbl[i]));
 +      }
 +      return 0;
 +}
 +EXPORT_SYMBOL(iwl_dump_fh);
 +
 +static void iwl_force_rf_reset(struct iwl_priv *priv)
 +{
 +      if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 +              return;
 +
 +      if (!iwl_is_associated(priv)) {
 +              IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
 +              return;
 +      }
 +      /*
 +       * There is no easy and better way to force reset the radio,
 +       * the only known method is switching channel which will force to
 +       * reset and tune the radio.
 +       * Use internal short scan (single channel) operation to should
 +       * achieve this objective.
 +       * Driver should reset the radio when number of consecutive missed
 +       * beacon, or any other uCode error condition detected.
 +       */
 +      IWL_DEBUG_INFO(priv, "perform radio reset.\n");
 +      iwl_internal_short_hw_scan(priv);
 +      return;
 +}
 +
 +
 +int iwl_force_reset(struct iwl_priv *priv, int mode)
 +{
 +      struct iwl_force_reset *force_reset;
 +
 +      if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 +              return -EINVAL;
 +
 +      if (mode >= IWL_MAX_FORCE_RESET) {
 +              IWL_DEBUG_INFO(priv, "invalid reset request.\n");
 +              return -EINVAL;
 +      }
 +      force_reset = &priv->force_reset[mode];
 +      force_reset->reset_request_count++;
 +      if (force_reset->last_force_reset_jiffies &&
 +          time_after(force_reset->last_force_reset_jiffies +
 +          force_reset->reset_duration, jiffies)) {
 +              IWL_DEBUG_INFO(priv, "force reset rejected\n");
 +              force_reset->reset_reject_count++;
 +              return -EAGAIN;
 +      }
 +      force_reset->reset_success_count++;
 +      force_reset->last_force_reset_jiffies = jiffies;
 +      IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode);
 +      switch (mode) {
 +      case IWL_RF_RESET:
 +              iwl_force_rf_reset(priv);
 +              break;
 +      case IWL_FW_RESET:
 +              IWL_ERR(priv, "On demand firmware reload\n");
 +              /* Set the FW error flag -- cleared on iwl_down */
 +              set_bit(STATUS_FW_ERROR, &priv->status);
 +              wake_up_interruptible(&priv->wait_command_queue);
 +              /*
 +               * Keep the restart process from trying to send host
 +               * commands by clearing the INIT status bit
 +               */
 +              clear_bit(STATUS_READY, &priv->status);
 +              queue_work(priv->workqueue, &priv->restart);
 +              break;
 +      }
 +      return 0;
 +}
 +
  #ifdef CONFIG_PM
  
  int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
@@@ -5,7 -5,7 +5,7 @@@
   *
   * GPL LICENSE SUMMARY
   *
 - * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
 + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of version 2 of the GNU General Public License as
@@@ -30,7 -30,7 +30,7 @@@
   *
   * BSD LICENSE
   *
 - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
 + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
@@@ -63,6 -63,8 +63,6 @@@
  #ifndef __iwl_core_h__
  #define __iwl_core_h__
  
 -#include <linux/utsrelease.h>
 -
  /************************
   * forward declarations *
   ************************/
@@@ -70,8 -72,8 +70,8 @@@ struct iwl_host_cmd
  struct iwl_cmd;
  
  
 -#define IWLWIFI_VERSION UTS_RELEASE "-k"
 -#define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation"
 +#define IWLWIFI_VERSION "in-tree:"
 +#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation"
  #define DRV_AUTHOR     "<ilw@linux.intel.com>"
  
  #define IWL_PCI_DEVICE(dev, subdev, cfg) \
@@@ -117,7 -119,6 +117,7 @@@ struct iwl_apm_ops 
  struct iwl_temp_ops {
        void (*temperature)(struct iwl_priv *priv);
        void (*set_ct_kill)(struct iwl_priv *priv);
 +      void (*set_calib_version)(struct iwl_priv *priv);
  };
  
  struct iwl_ucode_ops {
@@@ -168,11 -169,8 +168,11 @@@ struct iwl_lib_ops 
        int (*is_valid_rtc_data_addr)(u32 addr);
        /* 1st ucode load */
        int (*load_ucode)(struct iwl_priv *priv);
 -      void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log);
 +      int (*dump_nic_event_log)(struct iwl_priv *priv,
 +                                bool full_log, char **buf, bool display);
        void (*dump_nic_error_log)(struct iwl_priv *priv);
 +      void (*dump_csr)(struct iwl_priv *priv);
 +      int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display);
        int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
        /* power management */
        struct iwl_apm_ops apm_ops;
  
        /* temperature */
        struct iwl_temp_ops temp_ops;
 +      /* station management */
 +      void (*add_bcast_station)(struct iwl_priv *priv);
  };
  
  struct iwl_led_ops {
@@@ -234,9 -230,8 +234,9 @@@ struct iwl_mod_params 
   * @chain_noise_num_beacons: number of beacons used to compute chain noise
   * @adv_thermal_throttle: support advance thermal throttle
   * @support_ct_kill_exit: support ct kill exit condition
 - * @sm_ps_mode: spatial multiplexing power save mode
   * @support_wimax_coexist: support wimax/wifi co-exist
 + * @plcp_delta_threshold: plcp error rate threshold used to trigger
 + *    radio tuning when there is a high receiving plcp error rate
   *
   * We enable the driver to be backward compatible wrt API version. The
   * driver specifies which APIs it supports (with @ucode_api_max being the
@@@ -292,9 -287,8 +292,9 @@@ struct iwl_cfg 
        const bool supports_idle;
        bool adv_thermal_throttle;
        bool support_ct_kill_exit;
 -      u8 sm_ps_mode;
        const bool support_wimax_coexist;
 +      u8 plcp_delta_threshold;
 +      s32 chain_noise_scale;
  };
  
  /***************************
@@@ -338,11 -332,13 +338,11 @@@ int iwl_mac_beacon_update(struct ieee80
  int iwl_commit_rxon(struct iwl_priv *priv);
  int iwl_set_mode(struct iwl_priv *priv, int mode);
  int iwl_mac_add_interface(struct ieee80211_hw *hw,
 -                               struct ieee80211_if_init_conf *conf);
 +                        struct ieee80211_vif *vif);
  void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 -                               struct ieee80211_if_init_conf *conf);
 +                            struct ieee80211_vif *vif);
  int iwl_mac_config(struct ieee80211_hw *hw, u32 changed);
  void iwl_config_ap(struct iwl_priv *priv);
 -int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
 -                       struct ieee80211_tx_queue_stats *stats);
  void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
  int iwl_alloc_txq_mem(struct iwl_priv *priv);
  void iwl_free_txq_mem(struct iwl_priv *priv);
@@@ -415,13 -411,13 +415,13 @@@ void iwl_rx_queue_free(struct iwl_priv 
  void iwl_cmd_queue_free(struct iwl_priv *priv);
  int iwl_rx_queue_alloc(struct iwl_priv *priv);
  void iwl_rx_handle(struct iwl_priv *priv);
 -int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
 +void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
                                  struct iwl_rx_queue *q);
  void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
  void iwl_rx_replenish(struct iwl_priv *priv);
  void iwl_rx_replenish_now(struct iwl_priv *priv);
  int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 -int iwl_rx_queue_restock(struct iwl_priv *priv);
 +void iwl_rx_queue_restock(struct iwl_priv *priv);
  int iwl_rx_queue_space(const struct iwl_rx_queue *q);
  void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority);
  void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
@@@ -429,8 -425,6 +429,8 @@@ int iwl_tx_queue_reclaim(struct iwl_pri
  /* Handlers */
  void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
                               struct iwl_rx_mem_buffer *rxb);
 +void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
 +                                        struct iwl_rx_mem_buffer *rxb);
  void iwl_rx_statistics(struct iwl_priv *priv,
                              struct iwl_rx_mem_buffer *rxb);
  void iwl_reply_statistics(struct iwl_priv *priv,
@@@ -451,7 -445,9 +451,9 @@@ int iwl_tx_skb(struct iwl_priv *priv, s
  void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
  int iwl_hw_tx_queue_init(struct iwl_priv *priv,
                         struct iwl_tx_queue *txq);
 -int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+ void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+                           int sta_id, int tid, int freed);
 +void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
  int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
                      int slots_num, u32 txq_id);
  void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
@@@ -501,8 -497,6 +503,8 @@@ void iwl_init_scan_params(struct iwl_pr
  int iwl_scan_cancel(struct iwl_priv *priv);
  int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
  int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
 +int iwl_internal_short_hw_scan(struct iwl_priv *priv);
 +int iwl_force_reset(struct iwl_priv *priv, int mode);
  u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
                       const u8 *ie, int ie_len, int left);
  void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
@@@ -533,6 -527,14 +535,6 @@@ int iwl_send_calib_results(struct iwl_p
  int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
  void iwl_calib_free_results(struct iwl_priv *priv);
  
 -/*******************************************************************************
 - * Spectrum Measureemtns in  iwl-spectrum.c
 - ******************************************************************************/
 -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
 -void iwl_setup_spectrum_handlers(struct iwl_priv *priv);
 -#else
 -static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {}
 -#endif
  /*****************************************************
   *   S e n d i n g     H o s t     C o m m a n d s   *
   *****************************************************/
@@@ -581,10 -583,7 +583,10 @@@ int iwl_pci_resume(struct pci_dev *pdev
  *  Error Handling Debugging
  ******************************************************/
  void iwl_dump_nic_error_log(struct iwl_priv *priv);
 -void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
 +int iwl_dump_nic_event_log(struct iwl_priv *priv,
 +                         bool full_log, char **buf, bool display);
 +void iwl_dump_csr(struct iwl_priv *priv);
 +int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
  #ifdef CONFIG_IWLWIFI_DEBUG
  void iwl_print_rx_config_cmd(struct iwl_priv *priv);
  #else
@@@ -604,7 -603,7 +606,7 @@@ void iwlcore_free_geos(struct iwl_priv 
  /*************** DRIVER STATUS FUNCTIONS   *****/
  
  #define STATUS_HCMD_ACTIVE    0       /* host command in progress */
 -#define STATUS_HCMD_SYNC_ACTIVE       1       /* sync host command in progress */
 +/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */
  #define STATUS_INT_ENABLED    2
  #define STATUS_RF_KILL_HW     3
  #define STATUS_CT_KILL                4
@@@ -1,6 -1,6 +1,6 @@@
  /******************************************************************************
   *
 - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
 + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
   *
   * Portions of this file are derived from the ipw3945 project, as well
   * as portions of the ieee80211 subsystem header files.
@@@ -123,11 -123,12 +123,11 @@@ EXPORT_SYMBOL(iwl_rx_queue_space)
  /**
   * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
   */
 -int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
 +void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
  {
        unsigned long flags;
        u32 rx_wrt_ptr_reg = priv->hw_params.rx_wrt_ptr_reg;
        u32 reg;
 -      int ret = 0;
  
        spin_lock_irqsave(&q->lock, flags);
  
  
   exit_unlock:
        spin_unlock_irqrestore(&q->lock, flags);
 -      return ret;
  }
  EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr);
  /**
@@@ -182,13 -184,14 +182,13 @@@ static inline __le32 iwl_dma_addr2rbd_p
   * also updates the memory address in the firmware to reference the new
   * target buffer.
   */
 -int iwl_rx_queue_restock(struct iwl_priv *priv)
 +void iwl_rx_queue_restock(struct iwl_priv *priv)
  {
        struct iwl_rx_queue *rxq = &priv->rxq;
        struct list_head *element;
        struct iwl_rx_mem_buffer *rxb;
        unsigned long flags;
        int write;
 -      int ret = 0;
  
        spin_lock_irqsave(&rxq->lock, flags);
        write = rxq->write & ~0x7;
                spin_lock_irqsave(&rxq->lock, flags);
                rxq->need_update = 1;
                spin_unlock_irqrestore(&rxq->lock, flags);
 -              ret = iwl_rx_queue_update_write_ptr(priv, rxq);
 +              iwl_rx_queue_update_write_ptr(priv, rxq);
        }
 -
 -      return ret;
  }
  EXPORT_SYMBOL(iwl_rx_queue_restock);
  
@@@ -345,10 -350,10 +345,10 @@@ void iwl_rx_queue_free(struct iwl_priv 
                }
        }
  
 -      pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
 -                          rxq->dma_addr);
 -      pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status),
 -                          rxq->rb_stts, rxq->rb_stts_dma);
 +      dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
 +                        rxq->dma_addr);
 +      dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
 +                        rxq->rb_stts, rxq->rb_stts_dma);
        rxq->bd = NULL;
        rxq->rb_stts  = NULL;
  }
@@@ -357,7 -362,7 +357,7 @@@ EXPORT_SYMBOL(iwl_rx_queue_free)
  int iwl_rx_queue_alloc(struct iwl_priv *priv)
  {
        struct iwl_rx_queue *rxq = &priv->rxq;
 -      struct pci_dev *dev = priv->pci_dev;
 +      struct device *dev = &priv->pci_dev->dev;
        int i;
  
        spin_lock_init(&rxq->lock);
        INIT_LIST_HEAD(&rxq->rx_used);
  
        /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
 -      rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
 +      rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr,
 +                                   GFP_KERNEL);
        if (!rxq->bd)
                goto err_bd;
  
 -      rxq->rb_stts = pci_alloc_consistent(dev, sizeof(struct iwl_rb_status),
 -                                      &rxq->rb_stts_dma);
 +      rxq->rb_stts = dma_alloc_coherent(dev, sizeof(struct iwl_rb_status),
 +                                        &rxq->rb_stts_dma, GFP_KERNEL);
        if (!rxq->rb_stts)
                goto err_rb;
  
        return 0;
  
  err_rb:
 -      pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
 -                          rxq->dma_addr);
 +      dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
 +                        rxq->dma_addr);
  err_bd:
        return -ENOMEM;
  }
@@@ -469,8 -473,8 +469,8 @@@ int iwl_rx_init(struct iwl_priv *priv, 
                           (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
                           (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
  
 -      /* Set interrupt coalescing timer to 64 x 32 = 2048 usecs */
 -      iwl_write8(priv, CSR_INT_COALESCING, 0x40);
 +      /* Set interrupt coalescing timer to default (2048 usecs) */
 +      iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
  
        return 0;
  }
@@@ -495,10 -499,9 +495,10 @@@ void iwl_rx_missed_beacon_notif(struct 
        struct iwl_missed_beacon_notif *missed_beacon;
  
        missed_beacon = &pkt->u.missed_beacon;
 -      if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
 +      if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
 +          priv->missed_beacon_threshold) {
                IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
 -                  le32_to_cpu(missed_beacon->consequtive_missed_beacons),
 +                  le32_to_cpu(missed_beacon->consecutive_missed_beacons),
                    le32_to_cpu(missed_beacon->total_missed_becons),
                    le32_to_cpu(missed_beacon->num_recvd_beacons),
                    le32_to_cpu(missed_beacon->num_expected_beacons));
  }
  EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
  
 +void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
 +                                        struct iwl_rx_mem_buffer *rxb)
 +{
 +      struct iwl_rx_packet *pkt = rxb_addr(rxb);
 +      struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
 +
 +      if (!report->state) {
 +              IWL_DEBUG_11H(priv,
 +                      "Spectrum Measure Notification: Start\n");
 +              return;
 +      }
 +
 +      memcpy(&priv->measure_report, report, sizeof(*report));
 +      priv->measurement_status |= MEASUREMENT_READY;
 +}
 +EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif);
 +
 +
  
  /* Calculate noise level, based on measurements during network silence just
   *   before arriving beacon.  This measurement can be done only if we know
@@@ -579,24 -564,15 +579,24 @@@ static void iwl_accumulative_statistics
        int i;
        __le32 *prev_stats;
        u32 *accum_stats;
 +      u32 *delta, *max_delta;
  
        prev_stats = (__le32 *)&priv->statistics;
        accum_stats = (u32 *)&priv->accum_statistics;
 +      delta = (u32 *)&priv->delta_statistics;
 +      max_delta = (u32 *)&priv->max_delta;
  
        for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);
 -           i += sizeof(__le32), stats++, prev_stats++, accum_stats++)
 -              if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats))
 -                      *accum_stats += (le32_to_cpu(*stats) -
 +           i += sizeof(__le32), stats++, prev_stats++, delta++,
 +           max_delta++, accum_stats++) {
 +              if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
 +                      *delta = (le32_to_cpu(*stats) -
                                le32_to_cpu(*prev_stats));
 +                      *accum_stats += *delta;
 +                      if (*delta > *max_delta)
 +                              *max_delta = *delta;
 +              }
 +      }
  
        /* reset accumulative statistics for "no-counter" type statistics */
        priv->accum_statistics.general.temperature =
  
  #define REG_RECALIB_PERIOD (60)
  
 +/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
 +#define ACK_CNT_RATIO (50)
 +#define BA_TIMEOUT_CNT (5)
 +#define BA_TIMEOUT_MAX (16)
 +
 +#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n"
  void iwl_rx_statistics(struct iwl_priv *priv,
                              struct iwl_rx_mem_buffer *rxb)
  {
        int change;
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 +      int combined_plcp_delta;
 +      unsigned int plcp_msec;
 +      unsigned long plcp_received_jiffies;
 +      int actual_ack_cnt_delta;
 +      int expected_ack_cnt_delta;
 +      int ba_timeout_delta;
  
        IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
                     (int)sizeof(priv->statistics),
  #ifdef CONFIG_IWLWIFI_DEBUG
        iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
  #endif
 +      actual_ack_cnt_delta = le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
 +              le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
 +      expected_ack_cnt_delta = le32_to_cpu(
 +                      pkt->u.stats.tx.expected_ack_cnt) -
 +              le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
 +      ba_timeout_delta = le32_to_cpu(
 +                      pkt->u.stats.tx.agg.ba_timeout) -
 +              le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
 +      if ((priv->agg_tids_count > 0) &&
 +              (expected_ack_cnt_delta > 0) &&
 +              (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta) <
 +                      ACK_CNT_RATIO) &&
 +              (ba_timeout_delta > BA_TIMEOUT_CNT)) {
 +              IWL_DEBUG_RADIO(priv,
 +                      "actual_ack_cnt delta = %d, expected_ack_cnt = %d\n",
 +                      actual_ack_cnt_delta, expected_ack_cnt_delta);
 +
 +#ifdef CONFIG_IWLWIFI_DEBUG
 +              IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
 +                      priv->delta_statistics.tx.rx_detected_cnt);
 +              IWL_DEBUG_RADIO(priv,
 +                      "ack_or_ba_timeout_collision delta = %d\n",
 +                      priv->delta_statistics.tx.ack_or_ba_timeout_collision);
 +#endif
 +              IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
 +                      ba_timeout_delta);
 +              if ((actual_ack_cnt_delta == 0) &&
 +                      (ba_timeout_delta >=
 +                              BA_TIMEOUT_MAX)) {
 +                      IWL_DEBUG_RADIO(priv,
 +                              "call iwl_force_reset(IWL_FW_RESET)\n");
 +                      iwl_force_reset(priv, IWL_FW_RESET);
 +              } else {
 +                      IWL_DEBUG_RADIO(priv,
 +                              "call iwl_force_reset(IWL_RF_RESET)\n");
 +                      iwl_force_reset(priv, IWL_RF_RESET);
 +              }
 +      }
 +      /*
 +       * check for plcp_err and trigger radio reset if it exceeds
 +       * the plcp error threshold plcp_delta.
 +       */
 +      plcp_received_jiffies = jiffies;
 +      plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
 +                                      (long) priv->plcp_jiffies);
 +      priv->plcp_jiffies = plcp_received_jiffies;
 +      /*
 +       * check to make sure plcp_msec is not 0 to prevent division
 +       * by zero.
 +       */
 +      if (plcp_msec) {
 +              combined_plcp_delta =
 +                      (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) -
 +                      le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) +
 +                      (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) -
 +                      le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));
 +
 +              if ((combined_plcp_delta > 0) &&
 +                      ((combined_plcp_delta * 100) / plcp_msec) >
 +                      priv->cfg->plcp_delta_threshold) {
 +                      /*
 +                       * if plcp_err exceed the threshold, the following
 +                       * data is printed in csv format:
 +                       *    Text: plcp_err exceeded %d,
 +                       *    Received ofdm.plcp_err,
 +                       *    Current ofdm.plcp_err,
 +                       *    Received ofdm_ht.plcp_err,
 +                       *    Current ofdm_ht.plcp_err,
 +                       *    combined_plcp_delta,
 +                       *    plcp_msec
 +                       */
 +                      IWL_DEBUG_RADIO(priv, PLCP_MSG,
 +                              priv->cfg->plcp_delta_threshold,
 +                              le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
 +                              le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),
 +                              le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),
 +                              le32_to_cpu(
 +                                      priv->statistics.rx.ofdm_ht.plcp_err),
 +                              combined_plcp_delta, plcp_msec);
 +
 +                      /*
 +                       * Reset the RF radio due to the high plcp
 +                       * error rate
 +                       */
 +                      iwl_force_reset(priv, IWL_RF_RESET);
 +              }
 +      }
 +
        memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
  
        set_bit(STATUS_STATISTICS, &priv->status);
@@@ -762,13 -638,11 +762,13 @@@ void iwl_reply_statistics(struct iwl_pr
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
  
        if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
  #ifdef CONFIG_IWLWIFI_DEBUG
                memset(&priv->accum_statistics, 0,
                        sizeof(struct iwl_notif_statistics));
 +              memset(&priv->delta_statistics, 0,
 +                      sizeof(struct iwl_notif_statistics));
 +              memset(&priv->max_delta, 0,
 +                      sizeof(struct iwl_notif_statistics));
  #endif
                IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
        }
@@@ -1054,7 -928,10 +1054,10 @@@ static void iwl_pass_packet_to_mac80211
        if (ieee80211_is_mgmt(fc) ||
            ieee80211_has_protected(fc) ||
            ieee80211_has_morefrags(fc) ||
-           le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
+           le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG ||
+           (ieee80211_is_data_qos(fc) &&
+            *ieee80211_get_qos_ctl(hdr) &
+            IEEE80211_QOS_CONTROL_A_MSDU_PRESENT))
                ret = skb_linearize(skb);
        else
                ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
@@@ -1,6 -1,6 +1,6 @@@
  /******************************************************************************
   *
 - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
 + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
   *
   * Portions of this file are derived from the ipw3945 project, as well
   * as portions of the ieee80211 subsystem header files.
@@@ -60,8 -60,7 +60,8 @@@ static const u16 default_tid_to_tx_fifo
  static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv,
                                    struct iwl_dma_ptr *ptr, size_t size)
  {
 -      ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma);
 +      ptr->addr = dma_alloc_coherent(&priv->pci_dev->dev, size, &ptr->dma,
 +                                     GFP_KERNEL);
        if (!ptr->addr)
                return -ENOMEM;
        ptr->size = size;
@@@ -74,20 -73,21 +74,20 @@@ static inline void iwl_free_dma_ptr(str
        if (unlikely(!ptr->addr))
                return;
  
 -      pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma);
 +      dma_free_coherent(&priv->pci_dev->dev, ptr->size, ptr->addr, ptr->dma);
        memset(ptr, 0, sizeof(*ptr));
  }
  
  /**
   * iwl_txq_update_write_ptr - Send new write index to hardware
   */
 -int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 +void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
  {
        u32 reg = 0;
        int txq_id = txq->q.id;
  
        if (txq->need_update == 0)
 -              return ret;
 +              return;
  
        /* if we're trying to save power */
        if (test_bit(STATUS_POWER_PMI, &priv->status)) {
                                      txq_id, reg);
                        iwl_set_bit(priv, CSR_GP_CNTRL,
                                    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 -                      return ret;
 +                      return;
                }
  
                iwl_write_direct32(priv, HBUS_TARG_WRPTR,
                            txq->q.write_ptr | (txq_id << 8));
  
        txq->need_update = 0;
 -
 -      return ret;
  }
  EXPORT_SYMBOL(iwl_txq_update_write_ptr);
  
  
+ void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+                           int sta_id, int tid, int freed)
+ {
+       if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
+               priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+       else {
+               IWL_ERR(priv, "free more than tfds_in_queue (%u:%d)\n",
+                       priv->stations[sta_id].tid[tid].tfds_in_queue,
+                       freed);
+               priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
+       }
+ }
+ EXPORT_SYMBOL(iwl_free_tfds_in_queue);
  /**
   * iwl_tx_queue_free - Deallocate DMA queue.
   * @txq: Transmit queue to deallocate.
@@@ -130,7 -146,7 +144,7 @@@ void iwl_tx_queue_free(struct iwl_priv 
  {
        struct iwl_tx_queue *txq = &priv->txq[txq_id];
        struct iwl_queue *q = &txq->q;
 -      struct pci_dev *dev = priv->pci_dev;
 +      struct device *dev = &priv->pci_dev->dev;
        int i;
  
        if (q->n_bd == 0)
  
        /* De-alloc circular buffer of TFDs */
        if (txq->q.n_bd)
 -              pci_free_consistent(dev, priv->hw_params.tfd_size *
 -                                  txq->q.n_bd, txq->tfds, txq->q.dma_addr);
 +              dma_free_coherent(dev, priv->hw_params.tfd_size *
 +                                txq->q.n_bd, txq->tfds, txq->q.dma_addr);
  
        /* De-alloc array of per-TFD driver data */
        kfree(txq->txb);
@@@ -177,7 -193,7 +191,7 @@@ void iwl_cmd_queue_free(struct iwl_pri
  {
        struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
        struct iwl_queue *q = &txq->q;
 -      struct pci_dev *dev = priv->pci_dev;
 +      struct device *dev = &priv->pci_dev->dev;
        int i;
  
        if (q->n_bd == 0)
  
        /* De-alloc circular buffer of TFDs */
        if (txq->q.n_bd)
 -              pci_free_consistent(dev, priv->hw_params.tfd_size *
 -                                  txq->q.n_bd, txq->tfds, txq->q.dma_addr);
 +              dma_free_coherent(dev, priv->hw_params.tfd_size * txq->q.n_bd,
 +                                txq->tfds, txq->q.dma_addr);
  
        /* deallocate arrays */
        kfree(txq->cmd);
@@@ -281,7 -297,7 +295,7 @@@ static int iwl_queue_init(struct iwl_pr
  static int iwl_tx_queue_alloc(struct iwl_priv *priv,
                              struct iwl_tx_queue *txq, u32 id)
  {
 -      struct pci_dev *dev = priv->pci_dev;
 +      struct device *dev = &priv->pci_dev->dev;
        size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX;
  
        /* Driver private data, only for Tx (not command) queues,
  
        /* Circular buffer of transmit frame descriptors (TFDs),
         * shared with device */
 -      txq->tfds = pci_alloc_consistent(dev, tfd_sz, &txq->q.dma_addr);
 -
 +      txq->tfds = dma_alloc_coherent(dev, tfd_sz, &txq->q.dma_addr,
 +                                     GFP_KERNEL);
        if (!txq->tfds) {
                IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n", tfd_sz);
                goto error;
@@@ -729,6 -745,7 +743,6 @@@ int iwl_tx_skb(struct iwl_priv *priv, s
        u8 tid = 0;
        u8 *qc = NULL;
        unsigned long flags;
 -      int ret;
  
        spin_lock_irqsave(&priv->lock, flags);
        if (iwl_is_rfkill(priv)) {
                hdr->seq_ctrl |= cpu_to_le16(seq_number);
                seq_number += 0x10;
                /* aggregation is on for this <sta,tid> */
 -              if (info->flags & IEEE80211_TX_CTL_AMPDU)
 +              if (info->flags & IEEE80211_TX_CTL_AMPDU &&
 +                  priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) {
                        txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
 +              }
        }
  
        txq = &priv->txq[txq_id];
  
        /* Tell device the write index *just past* this latest filled TFD */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
 -      ret = iwl_txq_update_write_ptr(priv, txq);
 +      iwl_txq_update_write_ptr(priv, txq);
        spin_unlock_irqrestore(&priv->lock, flags);
  
        /*
        if (sta_priv && sta_priv->client)
                atomic_inc(&sta_priv->pending_frames);
  
 -      if (ret)
 -              return ret;
 -
        if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
                if (wait_write_ptr) {
                        spin_lock_irqsave(&priv->lock, flags);
@@@ -1000,7 -1018,7 +1014,7 @@@ int iwl_enqueue_hcmd(struct iwl_priv *p
        struct iwl_cmd_meta *out_meta;
        dma_addr_t phys_addr;
        unsigned long flags;
 -      int len, ret;
 +      int len;
        u32 idx;
        u16 fix_size;
  
  
        /* Increment and update queue's write index */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
 -      ret = iwl_txq_update_write_ptr(priv, txq);
 +      iwl_txq_update_write_ptr(priv, txq);
  
        spin_unlock_irqrestore(&priv->hcmd_lock, flags);
 -      return ret ? ret : idx;
 +      return idx;
  }
  
  static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
@@@ -1127,6 -1145,7 +1141,7 @@@ int iwl_tx_queue_reclaim(struct iwl_pri
        struct iwl_queue *q = &txq->q;
        struct iwl_tx_info *tx_info;
        int nfreed = 0;
+       struct ieee80211_hdr *hdr;
  
        if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
                IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, "
  
                tx_info = &txq->txb[txq->q.read_ptr];
                iwl_tx_status(priv, tx_info->skb[0]);
+               hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
+               if (hdr && ieee80211_is_data_qos(hdr->frame_control))
+                       nfreed++;
                tx_info->skb[0] = NULL;
  
                if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
                        priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
  
                priv->cfg->ops->lib->txq_free_tfd(priv, txq);
-               nfreed++;
        }
        return nfreed;
  }
@@@ -1238,8 -1260,6 +1256,8 @@@ void iwl_tx_cmd_complete(struct iwl_pri
  
        if (!(meta->flags & CMD_ASYNC)) {
                clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 +              IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
 +                             get_cmd_string(cmd->hdr.cmd));
                wake_up_interruptible(&priv->wait_command_queue);
        }
  }
@@@ -1326,7 -1346,7 +1344,7 @@@ int iwl_tx_agg_stop(struct iwl_priv *pr
  {
        int tx_fifo_id, txq_id, sta_id, ssn = -1;
        struct iwl_tid_data *tid_data;
 -      int ret, write_ptr, read_ptr;
 +      int write_ptr, read_ptr;
        unsigned long flags;
  
        if (!ra) {
        priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
  
        spin_lock_irqsave(&priv->lock, flags);
 -      ret = priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
 +      /*
 +       * the only reason this call can fail is queue number out of range,
 +       * which can happen if uCode is reloaded and all the station
 +       * information are lost. if it is outside the range, there is no need
 +       * to deactivate the uCode queue, just return "success" to allow
 +       *  mac80211 to clean up it own data.
 +       */
 +      priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
                                                   tx_fifo_id);
        spin_unlock_irqrestore(&priv->lock, flags);
  
 -      if (ret)
 -              return ret;
 -
        ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
  
        return 0;
@@@ -1561,7 -1577,7 +1579,7 @@@ void iwl_rx_reply_compressed_ba(struct 
        if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
                /* calculate mac80211 ampdu sw queue to wake */
                int freed = iwl_tx_queue_reclaim(priv, scd_flow, index);
-               priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
  
                if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
                    priv->mac80211_registered &&
@@@ -794,7 -794,7 +794,7 @@@ static int iwm_mlme_update_bss_table(st
        }
  
        bss->bss = kzalloc(bss_len, GFP_KERNEL);
-       if (!bss) {
+       if (!bss->bss) {
                kfree(bss);
                IWM_ERR(iwm, "Couldn't allocate bss\n");
                return -ENOMEM;
@@@ -868,35 -868,36 +868,35 @@@ static int iwm_mlme_mgt_frame(struct iw
        struct iwm_umac_notif_mgt_frame *mgt_frame =
                        (struct iwm_umac_notif_mgt_frame *)buf;
        struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
 -      u8 *ie;
  
        IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
                    le16_to_cpu(mgt_frame->len));
  
        if (ieee80211_is_assoc_req(mgt->frame_control)) {
 -              ie = mgt->u.assoc_req.variable;;
 -              iwm->req_ie_len =
 -                              le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
 +              iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
 +                                - offsetof(struct ieee80211_mgmt,
 +                                           u.assoc_req.variable);
                kfree(iwm->req_ie);
                iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
                                      iwm->req_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
 -              ie = mgt->u.reassoc_req.variable;;
 -              iwm->req_ie_len =
 -                              le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
 +              iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
 +                                - offsetof(struct ieee80211_mgmt,
 +                                           u.reassoc_req.variable);
                kfree(iwm->req_ie);
                iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
                                      iwm->req_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
 -              ie = mgt->u.assoc_resp.variable;;
 -              iwm->resp_ie_len =
 -                              le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
 +              iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
 +                                 - offsetof(struct ieee80211_mgmt,
 +                                            u.assoc_resp.variable);
                kfree(iwm->resp_ie);
                iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
                                       iwm->resp_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
 -              ie = mgt->u.reassoc_resp.variable;;
 -              iwm->resp_ie_len =
 -                              le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
 +              iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
 +                                 - offsetof(struct ieee80211_mgmt,
 +                                            u.reassoc_resp.variable);
                kfree(iwm->resp_ie);
                iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
                                       iwm->resp_ie_len, GFP_KERNEL);
@@@ -1533,33 -1534,6 +1533,33 @@@ static void classify8023(struct sk_buf
        }
  }
  
 +static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb)
 +{
 +      struct wireless_dev *wdev = iwm_to_wdev(iwm);
 +      struct net_device *ndev = iwm_to_ndev(iwm);
 +      struct sk_buff_head list;
 +      struct sk_buff *frame;
 +
 +      IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len);
 +
 +      __skb_queue_head_init(&list);
 +      ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0);
 +
 +      while ((frame = __skb_dequeue(&list))) {
 +              ndev->stats.rx_packets++;
 +              ndev->stats.rx_bytes += frame->len;
 +
 +              frame->protocol = eth_type_trans(frame, ndev);
 +              frame->ip_summed = CHECKSUM_NONE;
 +              memset(frame->cb, 0, sizeof(frame->cb));
 +
 +              if (netif_rx_ni(frame) == NET_RX_DROP) {
 +                      IWM_ERR(iwm, "Packet dropped\n");
 +                      ndev->stats.rx_dropped++;
 +              }
 +      }
 +}
 +
  static void iwm_rx_process_packet(struct iwm_priv *iwm,
                                  struct iwm_rx_packet *packet,
                                  struct iwm_rx_ticket_node *ticket_node)
        switch (le16_to_cpu(ticket_node->ticket->action)) {
        case IWM_RX_TICKET_RELEASE:
                IWM_DBG_RX(iwm, DBG, "RELEASE packet\n");
 -              classify8023(skb);
 +
                iwm_rx_adjust_packet(iwm, packet, ticket_node);
 +              skb->dev = iwm_to_ndev(iwm);
 +              classify8023(skb);
 +
 +              if (le16_to_cpu(ticket_node->ticket->flags) &
 +                  IWM_RX_TICKET_AMSDU_MSK) {
 +                      iwm_rx_process_amsdu(iwm, skb);
 +                      break;
 +              }
 +
                ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype);
                if (ret < 0) {
                        IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - "
                                   "%d\n", ret);
 +                      kfree_skb(packet->skb);
                        break;
                }
  
                IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len);
  
 -              skb->dev = iwm_to_ndev(iwm);
 +              ndev->stats.rx_packets++;
 +              ndev->stats.rx_bytes += skb->len;
 +
                skb->protocol = eth_type_trans(skb, ndev);
                skb->ip_summed = CHECKSUM_NONE;
                memset(skb->cb, 0, sizeof(skb->cb));
  
 -              ndev->stats.rx_packets++;
 -              ndev->stats.rx_bytes += skb->len;
 -
                if (netif_rx_ni(skb) == NET_RX_DROP) {
                        IWM_ERR(iwm, "Packet dropped\n");
                        ndev->stats.rx_dropped++;
@@@ -65,6 -65,7 +65,7 @@@ static struct usb_device_id rtl8187_tab
        /* Sitecom */
        {USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187},
        {USB_DEVICE(0x0df6, 0x0028), .driver_info = DEVICE_RTL8187B},
+       {USB_DEVICE(0x0df6, 0x0029), .driver_info = DEVICE_RTL8187B},
        /* Sphairon Access Systems GmbH */
        {USB_DEVICE(0x114B, 0x0150), .driver_info = DEVICE_RTL8187},
        /* Dick Smith Electronics */
@@@ -1018,30 -1019,31 +1019,30 @@@ static void rtl8187_stop(struct ieee802
  }
  
  static int rtl8187_add_interface(struct ieee80211_hw *dev,
 -                               struct ieee80211_if_init_conf *conf)
 +                               struct ieee80211_vif *vif)
  {
        struct rtl8187_priv *priv = dev->priv;
        int i;
        int ret = -EOPNOTSUPP;
  
        mutex_lock(&priv->conf_mutex);
 -      if (priv->mode != NL80211_IFTYPE_MONITOR)
 +      if (priv->vif)
                goto exit;
  
 -      switch (conf->type) {
 +      switch (vif->type) {
        case NL80211_IFTYPE_STATION:
 -              priv->mode = conf->type;
                break;
        default:
                goto exit;
        }
  
        ret = 0;
 -      priv->vif = conf->vif;
 +      priv->vif = vif;
  
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
        for (i = 0; i < ETH_ALEN; i++)
                rtl818x_iowrite8(priv, &priv->map->MAC[i],
 -                               ((u8 *)conf->mac_addr)[i]);
 +                               ((u8 *)vif->addr)[i]);
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
  
  exit:
  }
  
  static void rtl8187_remove_interface(struct ieee80211_hw *dev,
 -                                   struct ieee80211_if_init_conf *conf)
 +                                   struct ieee80211_vif *vif)
  {
        struct rtl8187_priv *priv = dev->priv;
        mutex_lock(&priv->conf_mutex);
 -      priv->mode = NL80211_IFTYPE_MONITOR;
        priv->vif = NULL;
        mutex_unlock(&priv->conf_mutex);
  }
@@@ -1265,14 -1268,6 +1266,14 @@@ static int rtl8187_conf_tx(struct ieee8
        return 0;
  }
  
 +static u64 rtl8187_get_tsf(struct ieee80211_hw *dev)
 +{
 +      struct rtl8187_priv *priv = dev->priv;
 +
 +      return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
 +             (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
 +}
 +
  static const struct ieee80211_ops rtl8187_ops = {
        .tx                     = rtl8187_tx,
        .start                  = rtl8187_start,
        .prepare_multicast      = rtl8187_prepare_multicast,
        .configure_filter       = rtl8187_configure_filter,
        .conf_tx                = rtl8187_conf_tx,
 -      .rfkill_poll            = rtl8187_rfkill_poll
 +      .rfkill_poll            = rtl8187_rfkill_poll,
 +      .get_tsf                = rtl8187_get_tsf,
  };
  
  static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@@ -1372,6 -1366,7 +1373,6 @@@ static int __devinit rtl8187_probe(stru
        dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
  
  
 -      priv->mode = NL80211_IFTYPE_MONITOR;
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                     IEEE80211_HW_SIGNAL_DBM |
                     IEEE80211_HW_RX_INCLUDES_FCS;
diff --combined net/mac80211/rate.c
@@@ -145,7 -145,7 +145,7 @@@ static const struct file_operations rcn
  };
  #endif
  
 -struct rate_control_ref *rate_control_alloc(const char *name,
 +static struct rate_control_ref *rate_control_alloc(const char *name,
                                            struct ieee80211_local *local)
  {
        struct dentry *debugfsdir = NULL;
@@@ -207,27 -207,6 +207,27 @@@ static bool rc_no_data_or_no_ack(struc
        return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc));
  }
  
 +static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx)
 +{
 +      u8 i;
 +
 +      if (basic_rates == 0)
 +              return; /* assume basic rates unknown and accept rate */
 +      if (*idx < 0)
 +              return;
 +      if (basic_rates & (1 << *idx))
 +              return; /* selected rate is a basic rate */
 +
 +      for (i = *idx + 1; i <= max_rate_idx; i++) {
 +              if (basic_rates & (1 << i)) {
 +                      *idx = i;
 +                      return;
 +              }
 +      }
 +
 +      /* could not find a basic rate; use original selection */
 +}
 +
  bool rate_control_send_low(struct ieee80211_sta *sta,
                           void *priv_sta,
                           struct ieee80211_tx_rate_control *txrc)
                info->control.rates[0].count =
                        (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
                        1 : txrc->hw->max_rate_tries;
 +              if (!sta && txrc->ap)
 +                      rc_send_low_broadcast(&info->control.rates[0].idx,
 +                                            txrc->bss_conf->basic_rates,
 +                                            txrc->sband->n_bitrates);
                return true;
        }
        return false;
  }
  EXPORT_SYMBOL(rate_control_send_low);
  
 +static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
 +                              int n_bitrates, u32 mask)
 +{
 +      int j;
 +
 +      /* See whether the selected rate or anything below it is allowed. */
 +      for (j = rate->idx; j >= 0; j--) {
 +              if (mask & (1 << j)) {
 +                      /* Okay, found a suitable rate. Use it. */
 +                      rate->idx = j;
 +                      return;
 +              }
 +      }
 +
 +      /* Try to find a higher rate that would be allowed */
 +      for (j = rate->idx + 1; j < n_bitrates; j++) {
 +              if (mask & (1 << j)) {
 +                      /* Okay, found a suitable rate. Use it. */
 +                      rate->idx = j;
 +                      return;
 +              }
 +      }
 +
 +      /*
 +       * Uh.. No suitable rate exists. This should not really happen with
 +       * sane TX rate mask configurations. However, should someone manage to
 +       * configure supported rates and TX rate mask in incompatible way,
 +       * allow the frame to be transmitted with whatever the rate control
 +       * selected.
 +       */
 +}
 +
  void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
                           struct sta_info *sta,
                           struct ieee80211_tx_rate_control *txrc)
        struct ieee80211_sta *ista = NULL;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
        int i;
 +      u32 mask;
  
        if (sta) {
                ista = &sta->sta;
                info->control.rates[i].count = 1;
        }
  
+       if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
+               return;
 -      if (sta && sdata->force_unicast_rateidx > -1) {
 -              info->control.rates[0].idx = sdata->force_unicast_rateidx;
 -      } else {
 -              ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
 -              info->flags |= IEEE80211_TX_INTFL_RCALGO;
 -      }
 +      ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
  
        /*
 -       * try to enforce the maximum rate the user wanted
 +       * Try to enforce the rateidx mask the user wanted. skip this if the
 +       * default mask (allow all rates) is used to save some processing for
 +       * the common case.
         */
 -      if (sdata->max_ratectrl_rateidx > -1)
 +      mask = sdata->rc_rateidx_mask[info->band];
 +      if (mask != (1 << txrc->sband->n_bitrates) - 1) {
 +              if (sta) {
 +                      /* Filter out rates that the STA does not support */
 +                      mask &= sta->sta.supp_rates[info->band];
 +              }
 +              /*
 +               * Make sure the rate index selected for each TX rate is
 +               * included in the configured mask and change the rate indexes
 +               * if needed.
 +               */
                for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
 +                      /* Rate masking supports only legacy rates for now */
                        if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
                                continue;
 -                      info->control.rates[i].idx =
 -                              min_t(s8, info->control.rates[i].idx,
 -                                    sdata->max_ratectrl_rateidx);
 +                      rate_idx_match_mask(&info->control.rates[i],
 +                                          txrc->sband->n_bitrates, mask);
 +              }
        }
  
        BUG_ON(info->control.rates[0].idx < 0);