Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 28 Jan 2013 18:54:03 +0000 (13:54 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 28 Jan 2013 18:54:03 +0000 (13:54 -0500)
Conflicts:
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/iwlwifi/dvm/tx.c

29 files changed:
1  2 
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/carl9170/fw.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/rtlwifi/rtl8192de/trx.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
drivers/ssb/Kconfig
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/mesh_hwmp.c
net/mac80211/offchannel.c
net/mac80211/scan.c
net/mac80211/tx.c

@@@ -32,6 -32,7 +32,6 @@@ struct coeff 
  
  enum ar9003_cal_types {
        IQ_MISMATCH_CAL = BIT(0),
 -      TEMP_COMP_CAL = BIT(1),
  };
  
  static void ar9003_hw_setup_calibration(struct ath_hw *ah,
@@@ -48,7 -49,7 +48,7 @@@
                 */
                REG_RMW_FIELD(ah, AR_PHY_TIMING4,
                              AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
 -              currCal->calData->calCountMax);
 +                            currCal->calData->calCountMax);
                REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
  
                ath_dbg(common, CALIBRATE,
                /* Kick-off cal */
                REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
                break;
 -      case TEMP_COMP_CAL:
 -              REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
 -                            AR_PHY_65NM_CH0_THERM_LOCAL, 1);
 -              REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
 -                            AR_PHY_65NM_CH0_THERM_START, 1);
 -
 -              ath_dbg(common, CALIBRATE,
 -                      "starting Temperature Compensation Calibration\n");
 +      default:
 +              ath_err(common, "Invalid calibration type\n");
                break;
        }
  }
@@@ -316,14 -323,6 +316,14 @@@ static const struct ath9k_percal_data i
  static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
  {
        ah->iq_caldata.calData = &iq_cal_single_sample;
 +
 +      if (AR_SREV_9300_20_OR_LATER(ah)) {
 +              ah->enabled_cals |= TX_IQ_CAL;
 +              if (AR_SREV_9485_OR_LATER(ah) && !AR_SREV_9340(ah))
 +                      ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
 +      }
 +
 +      ah->supp_cals = IQ_MISMATCH_CAL;
  }
  
  /*
@@@ -960,69 -959,25 +960,71 @@@ static void ar9003_hw_manual_peak_cal(s
                      AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);
  }
  
 +static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah,
 +                                       struct ath9k_channel *chan)
 +{
 +      int i;
 +
 +      if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah))
 +              return;
 +
 +      for (i = 0; i < AR9300_MAX_CHAINS; i++) {
 +              if (!(ah->rxchainmask & (1 << i)))
 +                      continue;
 +              ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan));
 +      }
 +}
 +
 +static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
 +{
 +      u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
 +                                        AR_PHY_CL_TAB_1,
 +                                        AR_PHY_CL_TAB_2 };
 +      struct ath9k_hw_cal_data *caldata = ah->caldata;
 +      bool txclcal_done = false;
 +      int i, j;
 +
 +      if (!caldata || !(ah->enabled_cals & TX_CL_CAL))
 +              return;
 +
 +      txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
 +                        AR_PHY_AGC_CONTROL_CLC_SUCCESS);
 +
 +      if (caldata->done_txclcal_once) {
 +              for (i = 0; i < AR9300_MAX_CHAINS; i++) {
 +                      if (!(ah->txchainmask & (1 << i)))
 +                              continue;
 +                      for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
 +                              REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
 +                                        caldata->tx_clcal[i][j]);
 +              }
 +      } else if (is_reusable && txclcal_done) {
 +              for (i = 0; i < AR9300_MAX_CHAINS; i++) {
 +                      if (!(ah->txchainmask & (1 << i)))
 +                              continue;
 +                      for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
 +                              caldata->tx_clcal[i][j] =
 +                                      REG_READ(ah, CL_TAB_ENTRY(cl_idx[i]));
 +              }
 +              caldata->done_txclcal_once = true;
 +      }
 +}
 +
  static bool ar9003_hw_init_cal(struct ath_hw *ah,
                               struct ath9k_channel *chan)
  {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_cal_data *caldata = ah->caldata;
 -      bool txiqcal_done = false, txclcal_done = false;
 +      bool txiqcal_done = false;
        bool is_reusable = true, status = true;
 -      bool run_rtt_cal = false, run_agc_cal;
 +      bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false;
        bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
        u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
                                          AR_PHY_AGC_CONTROL_FLTR_CAL   |
                                          AR_PHY_AGC_CONTROL_PKDET_CAL;
 -      int i, j;
 -      u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
 -                                        AR_PHY_CL_TAB_1,
 -                                        AR_PHY_CL_TAB_2 };
  
+       ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
        if (rtt) {
                if (!ar9003_hw_rtt_restore(ah, chan))
                        run_rtt_cal = true;
                }
        }
  
 -      if (!(ah->enabled_cals & TX_IQ_CAL))
 +      if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) ||
 +          !(ah->enabled_cals & TX_IQ_CAL))
                goto skip_tx_iqcal;
  
        /* Do Tx IQ Calibration */
                        REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
                                    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
                txiqcal_done = run_agc_cal = true;
 -              goto skip_tx_iqcal;
 -      } else if (caldata && !caldata->done_txiqcal_once)
 +      } else if (caldata && !caldata->done_txiqcal_once) {
                run_agc_cal = true;
 +              sep_iq_cal = true;
 +      }
  
 +skip_tx_iqcal:
        if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
                ar9003_mci_init_cal_req(ah, &is_reusable);
  
 -      if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
 +      if (sep_iq_cal) {
                txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
                REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
                udelay(5);
                REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
        }
  
 -skip_tx_iqcal:
        if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
                /* Calibrate the AGC */
                REG_WRITE(ah, AR_PHY_AGC_CONTROL,
                status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
                                       AR_PHY_AGC_CONTROL_CAL,
                                       0, AH_WAIT_TIMEOUT);
 -              if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
 -                      for (i = 0; i < AR9300_MAX_CHAINS; i++) {
 -                              if (!(ah->rxchainmask & (1 << i)))
 -                                      continue;
 -                              ar9003_hw_manual_peak_cal(ah, i,
 -                                                        IS_CHAN_2GHZ(chan));
 -                      }
 -              }
 +
 +              ar9003_hw_do_manual_peak_cal(ah, chan);
        }
  
        if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
        else if (caldata && caldata->done_txiqcal_once)
                ar9003_hw_tx_iq_cal_reload(ah);
  
 -#define CL_TAB_ENTRY(reg_base)        (reg_base + (4 * j))
 -      if (caldata && (ah->enabled_cals & TX_CL_CAL)) {
 -              txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
 -                                         AR_PHY_AGC_CONTROL_CLC_SUCCESS);
 -              if (caldata->done_txclcal_once) {
 -                      for (i = 0; i < AR9300_MAX_CHAINS; i++) {
 -                              if (!(ah->txchainmask & (1 << i)))
 -                                      continue;
 -                              for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
 -                                      REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
 -                                                caldata->tx_clcal[i][j]);
 -                      }
 -              } else if (is_reusable && txclcal_done) {
 -                      for (i = 0; i < AR9300_MAX_CHAINS; i++) {
 -                              if (!(ah->txchainmask & (1 << i)))
 -                                      continue;
 -                              for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
 -                                      caldata->tx_clcal[i][j] =
 -                                              REG_READ(ah,
 -                                                CL_TAB_ENTRY(cl_idx[i]));
 -                      }
 -                      caldata->done_txclcal_once = true;
 -              }
 -      }
 -#undef CL_TAB_ENTRY
 +      ar9003_hw_cl_cal_post_proc(ah, is_reusable);
  
        if (run_rtt_cal && caldata) {
                if (is_reusable) {
  
        /* Initialize list pointers */
        ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
 -      ah->supp_cals = IQ_MISMATCH_CAL;
 -
 -      if (ah->supp_cals & IQ_MISMATCH_CAL) {
 -              INIT_CAL(&ah->iq_caldata);
 -              INSERT_CAL(ah, &ah->iq_caldata);
 -              ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
 -      }
  
 -      if (ah->supp_cals & TEMP_COMP_CAL) {
 -              INIT_CAL(&ah->tempCompCalData);
 -              INSERT_CAL(ah, &ah->tempCompCalData);
 -              ath_dbg(common, CALIBRATE,
 -                      "enabling Temperature Compensation Calibration\n");
 -      }
 +      INIT_CAL(&ah->iq_caldata);
 +      INSERT_CAL(ah, &ah->iq_caldata);
 +      ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
  
        /* Initialize current pointer to first element in list */
        ah->cal_list_curr = ah->cal_list;
@@@ -507,59 -507,28 +507,59 @@@ static void ar9003_tx_gain_table_mode4(
        else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9580_1p0_mixed_ob_db_tx_gain_table);
 +      else
 +              INIT_INI_ARRAY(&ah->iniModesTxGain,
 +                      ar9300Modes_mixed_ob_db_tx_gain_table_2p2);
 +}
 +
 +static void ar9003_tx_gain_table_mode5(struct ath_hw *ah)
 +{
 +      if (AR_SREV_9485_11(ah))
 +              INIT_INI_ARRAY(&ah->iniModesTxGain,
 +                      ar9485Modes_green_ob_db_tx_gain_1_1);
 +      else if (AR_SREV_9340(ah))
 +              INIT_INI_ARRAY(&ah->iniModesTxGain,
 +                      ar9340Modes_ub124_tx_gain_table_1p0);
 +      else if (AR_SREV_9580(ah))
 +              INIT_INI_ARRAY(&ah->iniModesTxGain,
 +                      ar9580_1p0_type5_tx_gain_table);
 +      else if (AR_SREV_9300_22(ah))
 +              INIT_INI_ARRAY(&ah->iniModesTxGain,
 +                      ar9300Modes_type5_tx_gain_table_2p2);
  }
  
 +static void ar9003_tx_gain_table_mode6(struct ath_hw *ah)
 +{
 +      if (AR_SREV_9340(ah))
 +              INIT_INI_ARRAY(&ah->iniModesTxGain,
 +                      ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0);
 +      else if (AR_SREV_9485_11(ah))
 +              INIT_INI_ARRAY(&ah->iniModesTxGain,
 +                      ar9485Modes_green_spur_ob_db_tx_gain_1_1);
 +      else if (AR_SREV_9580(ah))
 +              INIT_INI_ARRAY(&ah->iniModesTxGain,
 +                      ar9580_1p0_type6_tx_gain_table);
 +}
 +
 +typedef void (*ath_txgain_tab)(struct ath_hw *ah);
 +
  static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
  {
 -      switch (ar9003_hw_get_tx_gain_idx(ah)) {
 -      case 0:
 -      default:
 -              ar9003_tx_gain_table_mode0(ah);
 -              break;
 -      case 1:
 -              ar9003_tx_gain_table_mode1(ah);
 -              break;
 -      case 2:
 -              ar9003_tx_gain_table_mode2(ah);
 -              break;
 -      case 3:
 -              ar9003_tx_gain_table_mode3(ah);
 -              break;
 -      case 4:
 -              ar9003_tx_gain_table_mode4(ah);
 -              break;
 -      }
 +      static const ath_txgain_tab modes[] = {
 +              ar9003_tx_gain_table_mode0,
 +              ar9003_tx_gain_table_mode1,
 +              ar9003_tx_gain_table_mode2,
 +              ar9003_tx_gain_table_mode3,
 +              ar9003_tx_gain_table_mode4,
 +              ar9003_tx_gain_table_mode5,
 +              ar9003_tx_gain_table_mode6,
 +      };
 +      int idx = ar9003_hw_get_tx_gain_idx(ah);
 +
 +      if (idx >= ARRAY_SIZE(modes))
 +              idx = 0;
 +
 +      modes[idx](ah);
  }
  
  static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
                                ar9340Common_rx_gain_table_1p0);
        else if (AR_SREV_9485_11(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
-                               ar9485Common_wo_xlna_rx_gain_1_1);
+                              ar9485_common_rx_gain_1_1);
        else if (AR_SREV_9550(ah)) {
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                                ar955x_1p0_common_rx_gain_table);
@@@ -704,7 -673,7 +704,7 @@@ void ar9003_hw_attach_ops(struct ath_h
        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
        struct ath_hw_ops *ops = ath9k_hw_ops(ah);
  
 -      priv_ops->init_mode_regs = ar9003_hw_init_mode_regs;
 +      ar9003_hw_init_mode_regs(ah);
        priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
  
        ops->config_pci_powersave = ar9003_hw_configpcipowersave;
@@@ -68,7 -68,7 +68,7 @@@ static const int m2ThreshExt_off = 127
  static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
  {
        u16 bMode, fracMode = 0, aModeRefSel = 0;
 -      u32 freq, channelSel = 0, reg32 = 0;
 +      u32 freq, chan_frac, div, channelSel = 0, reg32 = 0;
        struct chan_centers centers;
        int loadSynthChannel;
  
@@@ -77,6 -77,9 +77,6 @@@
  
        if (freq < 4800) {     /* 2 GHz, fractional mode */
                if (AR_SREV_9330(ah)) {
 -                      u32 chan_frac;
 -                      u32 div;
 -
                        if (ah->is_clk_25mhz)
                                div = 75;
                        else
                        chan_frac = (((freq * 4) % div) * 0x20000) / div;
                        channelSel = (channelSel << 17) | chan_frac;
                } else if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) {
 -                      u32 chan_frac;
 -
                        /*
 -                       * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0
 +                       * freq_ref = 40 / (refdiva >> amoderefsel);
 +                       * where refdiva=1 and amoderefsel=0
                         * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
                         * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000
                         */
                        channelSel = (freq * 4) / 120;
                        chan_frac = (((freq * 4) % 120) * 0x20000) / 120;
                        channelSel = (channelSel << 17) | chan_frac;
 -              } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) {
 +              } else if (AR_SREV_9340(ah)) {
                        if (ah->is_clk_25mhz) {
 -                              u32 chan_frac;
 -
                                channelSel = (freq * 2) / 75;
                                chan_frac = (((freq * 2) % 75) * 0x20000) / 75;
                                channelSel = (channelSel << 17) | chan_frac;
 -                      } else
 +                      } else {
                                channelSel = CHANSEL_2G(freq) >> 1;
 -              } else
 +                      }
 +              } else if (AR_SREV_9550(ah)) {
 +                      if (ah->is_clk_25mhz)
 +                              div = 75;
 +                      else
 +                              div = 120;
 +
 +                      channelSel = (freq * 4) / div;
 +                      chan_frac = (((freq * 4) % div) * 0x20000) / div;
 +                      channelSel = (channelSel << 17) | chan_frac;
 +              } else {
                        channelSel = CHANSEL_2G(freq);
 +              }
                /* Set to 2G mode */
                bMode = 1;
        } else {
                if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) &&
                    ah->is_clk_25mhz) {
 -                      u32 chan_frac;
 -
                        channelSel = freq / 75;
                        chan_frac = ((freq % 75) * 0x20000) / 75;
                        channelSel = (channelSel << 17) | chan_frac;
@@@ -589,32 -586,19 +589,19 @@@ static void ar9003_hw_init_bb(struct at
        ath9k_hw_synth_delay(ah, chan, synthDelay);
  }
  
static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
+ void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
  {
-       switch (rx) {
-       case 0x5:
+       if (ah->caps.tx_chainmask == 5 || ah->caps.rx_chainmask == 5)
                REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
                            AR_PHY_SWAP_ALT_CHAIN);
-       case 0x3:
-       case 0x1:
-       case 0x2:
-       case 0x7:
-               REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
-               REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
-               break;
-       default:
-               break;
-       }
+       REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
+       REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
  
        if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7))
-               REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
-       else
-               REG_WRITE(ah, AR_SELFGEN_MASK, tx);
+               tx = 3;
  
-       if (tx == 0x5) {
-               REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
-                           AR_PHY_SWAP_ALT_CHAIN);
-       }
+       REG_WRITE(ah, AR_SELFGEN_MASK, tx);
  }
  
  /*
@@@ -1453,67 -1437,6 +1440,67 @@@ set_rfmode
        return 0;
  }
  
 +static void ar9003_hw_spectral_scan_config(struct ath_hw *ah,
 +                                         struct ath_spec_scan *param)
 +{
 +      u8 count;
 +
 +      if (!param->enabled) {
 +              REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
 +                          AR_PHY_SPECTRAL_SCAN_ENABLE);
 +              return;
 +      }
 +
 +      REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
 +      REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
 +
 +      /* on AR93xx and newer, count = 0 will make the the chip send
 +       * spectral samples endlessly. Check if this really was intended,
 +       * and fix otherwise.
 +       */
 +      count = param->count;
 +      if (param->endless)
 +              count = 0;
 +      else if (param->count == 0)
 +              count = 1;
 +
 +      if (param->short_repeat)
 +              REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
 +                          AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
 +      else
 +              REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
 +                          AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
 +
 +      REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
 +                    AR_PHY_SPECTRAL_SCAN_COUNT, count);
 +      REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
 +                    AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
 +      REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
 +                    AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period);
 +
 +      return;
 +}
 +
 +static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah)
 +{
 +      /* Activate spectral scan */
 +      REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
 +                  AR_PHY_SPECTRAL_SCAN_ACTIVE);
 +}
 +
 +static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah)
 +{
 +      struct ath_common *common = ath9k_hw_common(ah);
 +
 +      /* Poll for spectral scan complete */
 +      if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN,
 +                         AR_PHY_SPECTRAL_SCAN_ACTIVE,
 +                         0, AH_WAIT_TIMEOUT)) {
 +              ath_err(common, "spectral scan wait failed\n");
 +              return;
 +      }
 +}
 +
  void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
  {
        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
        ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
        ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
        ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv;
 +      ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
 +      ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger;
 +      ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait;
  
        ar9003_hw_set_nf_limits(ah);
        ar9003_hw_set_radar_conf(ah);
@@@ -109,11 -109,14 +109,11 @@@ struct ath_descdma 
        void *dd_desc;
        dma_addr_t dd_desc_paddr;
        u32 dd_desc_len;
 -      struct ath_buf *dd_bufptr;
  };
  
  int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
                      struct list_head *head, const char *name,
                      int nbuf, int ndesc, bool is_tx);
 -void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
 -                       struct list_head *head);
  
  /***********/
  /* RX / TX */
@@@ -314,9 -317,9 +314,8 @@@ struct ath_rx 
        u32 *rxlink;
        u32 num_pkts;
        unsigned int rxfilter;
-       spinlock_t rxbuflock;
        struct list_head rxbuf;
        struct ath_descdma rxdma;
 -      struct ath_buf *rx_bufptr;
        struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
  
        struct sk_buff *frag;
  
  int ath_startrecv(struct ath_softc *sc);
  bool ath_stoprecv(struct ath_softc *sc);
- void ath_flushrecv(struct ath_softc *sc);
  u32 ath_calcrxfilter(struct ath_softc *sc);
  int ath_rx_init(struct ath_softc *sc, int nbufs);
  void ath_rx_cleanup(struct ath_softc *sc);
@@@ -334,12 -336,14 +332,12 @@@ void ath_txq_lock(struct ath_softc *sc
  void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq);
  void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq);
  void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
 -bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
 -void ath_draintxq(struct ath_softc *sc,
 -                   struct ath_txq *txq, bool retry_tx);
 +bool ath_drain_all_txq(struct ath_softc *sc);
 +void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq);
  void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
  void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
  void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
  int ath_tx_init(struct ath_softc *sc, int nbufs);
 -void ath_tx_cleanup(struct ath_softc *sc);
  int ath_txq_update(struct ath_softc *sc, int qnum,
                   struct ath9k_tx_queue_info *q);
  void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop);
@@@ -640,7 -644,6 +638,6 @@@ void ath_ant_comb_update(struct ath_sof
  enum sc_op_flags {
        SC_OP_INVALID,
        SC_OP_BEACONS,
-       SC_OP_RXFLUSH,
        SC_OP_ANI_RUN,
        SC_OP_PRIM_STA_VIF,
        SC_OP_HW_RESET,
@@@ -669,23 -672,6 +666,23 @@@ struct ath9k_vif_iter_data 
        int nadhocs;   /* number of adhoc vifs */
  };
  
 +/* enum spectral_mode:
 + *
 + * @SPECTRAL_DISABLED: spectral mode is disabled
 + * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
 + *    something else.
 + * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
 + *    is performed manually.
 + * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels
 + *    during a channel scan.
 + */
 +enum spectral_mode {
 +      SPECTRAL_DISABLED = 0,
 +      SPECTRAL_BACKGROUND,
 +      SPECTRAL_MANUAL,
 +      SPECTRAL_CHANSCAN,
 +};
 +
  struct ath_softc {
        struct ieee80211_hw *hw;
        struct device *dev;
        u8 ant_tx, ant_rx;
        struct dfs_pattern_detector *dfs_detector;
        u32 wow_enabled;
 +      /* relay(fs) channel for spectral scan */
 +      struct rchan *rfs_chan_spec_scan;
 +      enum spectral_mode spectral_mode;
 +      int scanning;
  
  #ifdef CONFIG_PM_SLEEP
        atomic_t wow_got_bmiss_intr;
  #endif
  };
  
 +#define SPECTRAL_SCAN_BITMASK         0x10
 +/* Radar info packet format, used for DFS and spectral formats. */
 +struct ath_radar_info {
 +      u8 pulse_length_pri;
 +      u8 pulse_length_ext;
 +      u8 pulse_bw_info;
 +} __packed;
 +
 +/* The HT20 spectral data has 4 bytes of additional information at it's end.
 + *
 + * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
 + * [7:0]: all bins  max_magnitude[9:2]
 + * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
 + * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
 + */
 +struct ath_ht20_mag_info {
 +      u8 all_bins[3];
 +      u8 max_exp;
 +} __packed;
 +
 +#define SPECTRAL_HT20_NUM_BINS                56
 +
 +/* WARNING: don't actually use this struct! MAC may vary the amount of
 + * data by -1/+2. This struct is for reference only.
 + */
 +struct ath_ht20_fft_packet {
 +      u8 data[SPECTRAL_HT20_NUM_BINS];
 +      struct ath_ht20_mag_info mag_info;
 +      struct ath_radar_info radar_info;
 +} __packed;
 +
 +#define SPECTRAL_HT20_TOTAL_DATA_LEN  (sizeof(struct ath_ht20_fft_packet))
 +
 +/* Dynamic 20/40 mode:
 + *
 + * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
 + * [7:0]: lower bins  max_magnitude[9:2]
 + * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
 + * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
 + * [7:0]: upper bins  max_magnitude[9:2]
 + * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
 + * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
 + */
 +struct ath_ht20_40_mag_info {
 +      u8 lower_bins[3];
 +      u8 upper_bins[3];
 +      u8 max_exp;
 +} __packed;
 +
 +#define SPECTRAL_HT20_40_NUM_BINS             128
 +
 +/* WARNING: don't actually use this struct! MAC may vary the amount of
 + * data. This struct is for reference only.
 + */
 +struct ath_ht20_40_fft_packet {
 +      u8 data[SPECTRAL_HT20_40_NUM_BINS];
 +      struct ath_ht20_40_mag_info mag_info;
 +      struct ath_radar_info radar_info;
 +} __packed;
 +
 +
 +#define SPECTRAL_HT20_40_TOTAL_DATA_LEN       (sizeof(struct ath_ht20_40_fft_packet))
 +
 +/* grabs the max magnitude from the all/upper/lower bins */
 +static inline u16 spectral_max_magnitude(u8 *bins)
 +{
 +      return (bins[0] & 0xc0) >> 6 |
 +             (bins[1] & 0xff) << 2 |
 +             (bins[2] & 0x03) << 10;
 +}
 +
 +/* return the max magnitude from the all/upper/lower bins */
 +static inline u8 spectral_max_index(u8 *bins)
 +{
 +      s8 m = (bins[2] & 0xfc) >> 2;
 +
 +      /* TODO: this still doesn't always report the right values ... */
 +      if (m > 32)
 +              m |= 0xe0;
 +      else
 +              m &= ~0xe0;
 +
 +      return m + 29;
 +}
 +
 +/* return the bitmap weight from the all/upper/lower bins */
 +static inline u8 spectral_bitmap_weight(u8 *bins)
 +{
 +      return bins[0] & 0x3f;
 +}
 +
 +/* FFT sample format given to userspace via debugfs.
 + *
 + * Please keep the type/length at the front position and change
 + * other fields after adding another sample type
 + *
 + * TODO: this might need rework when switching to nl80211-based
 + * interface.
 + */
 +enum ath_fft_sample_type {
 +      ATH_FFT_SAMPLE_HT20 = 0,
 +};
 +
 +struct fft_sample_tlv {
 +      u8 type;        /* see ath_fft_sample */
 +      u16 length;
 +      /* type dependent data follows */
 +} __packed;
 +
 +struct fft_sample_ht20 {
 +      struct fft_sample_tlv tlv;
 +
 +      u8 __alignment;
 +
 +      u16 freq;
 +      s8 rssi;
 +      s8 noise;
 +
 +      u16 max_magnitude;
 +      u8 max_index;
 +      u8 bitmap_weight;
 +
 +      u64 tsf;
 +
 +      u16 data[SPECTRAL_HT20_NUM_BINS];
 +} __packed;
 +
  void ath9k_tasklet(unsigned long data);
  int ath_cabq_update(struct ath_softc *);
  
@@@ -915,10 -770,6 +912,10 @@@ void ath9k_set_hw_capab(struct ath_soft
  void ath9k_reload_chainmask_settings(struct ath_softc *sc);
  
  bool ath9k_uses_beacons(int type);
 +void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
 +int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
 +                             enum spectral_mode spectral_mode);
 +
  
  #ifdef CONFIG_ATH9K_PCI
  int ath_pci_init(void);
@@@ -147,6 -147,7 +147,7 @@@ static struct ath_buf *ath9k_beacon_gen
                                 skb->len, DMA_TO_DEVICE);
                dev_kfree_skb_any(skb);
                bf->bf_buf_addr = 0;
+               bf->bf_mpdu = NULL;
        }
  
        skb = ieee80211_beacon_get(hw, vif);
                if (sc->nvifs > 1) {
                        ath_dbg(common, BEACON,
                                "Flushing previous cabq traffic\n");
 -                      ath_draintxq(sc, cabq, false);
 +                      ath_draintxq(sc, cabq);
                }
        }
  
@@@ -359,7 -360,6 +360,6 @@@ void ath9k_beacon_tasklet(unsigned lon
                return;
  
        bf = ath9k_beacon_generate(sc->hw, vif);
-       WARN_ON(!bf);
  
        if (sc->beacon.bmisscnt != 0) {
                ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n",
@@@ -17,7 -17,6 +17,7 @@@
  #include <linux/slab.h>
  #include <linux/vmalloc.h>
  #include <linux/export.h>
 +#include <linux/relay.h>
  #include <asm/unaligned.h>
  
  #include "ath9k.h"
@@@ -862,7 -861,6 +862,6 @@@ static ssize_t read_file_recv(struct fi
        RXS_ERR("RX-LENGTH-ERR", rx_len_err);
        RXS_ERR("RX-OOM-ERR", rx_oom_err);
        RXS_ERR("RX-RATE-ERR", rx_rate_err);
-       RXS_ERR("RX-DROP-RXFLUSH", rx_drop_rxflush);
        RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err);
  
        PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
@@@ -967,112 -965,6 +966,112 @@@ static const struct file_operations fop
        .llseek = default_llseek,
  };
  
 +static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
 +                                     size_t count, loff_t *ppos)
 +{
 +      struct ath_softc *sc = file->private_data;
 +      char *mode = "";
 +      unsigned int len;
 +
 +      switch (sc->spectral_mode) {
 +      case SPECTRAL_DISABLED:
 +              mode = "disable";
 +              break;
 +      case SPECTRAL_BACKGROUND:
 +              mode = "background";
 +              break;
 +      case SPECTRAL_CHANSCAN:
 +              mode = "chanscan";
 +              break;
 +      case SPECTRAL_MANUAL:
 +              mode = "manual";
 +              break;
 +      }
 +      len = strlen(mode);
 +      return simple_read_from_buffer(user_buf, count, ppos, mode, len);
 +}
 +
 +static ssize_t write_file_spec_scan_ctl(struct file *file,
 +                                      const char __user *user_buf,
 +                                      size_t count, loff_t *ppos)
 +{
 +      struct ath_softc *sc = file->private_data;
 +      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 +      char buf[32];
 +      ssize_t len;
 +
 +      len = min(count, sizeof(buf) - 1);
 +      if (copy_from_user(buf, user_buf, len))
 +              return -EFAULT;
 +
 +      buf[len] = '\0';
 +
 +      if (strncmp("trigger", buf, 7) == 0) {
 +              ath9k_spectral_scan_trigger(sc->hw);
 +      } else if (strncmp("background", buf, 9) == 0) {
 +              ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
 +              ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
 +      } else if (strncmp("chanscan", buf, 8) == 0) {
 +              ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN);
 +              ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
 +      } else if (strncmp("manual", buf, 6) == 0) {
 +              ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL);
 +              ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
 +      } else if (strncmp("disable", buf, 7) == 0) {
 +              ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED);
 +              ath_dbg(common, CONFIG, "spectral scan: disabled\n");
 +      } else {
 +              return -EINVAL;
 +      }
 +
 +      return count;
 +}
 +
 +static const struct file_operations fops_spec_scan_ctl = {
 +      .read = read_file_spec_scan_ctl,
 +      .write = write_file_spec_scan_ctl,
 +      .open = simple_open,
 +      .owner = THIS_MODULE,
 +      .llseek = default_llseek,
 +};
 +
 +static struct dentry *create_buf_file_handler(const char *filename,
 +                                            struct dentry *parent,
 +                                            umode_t mode,
 +                                            struct rchan_buf *buf,
 +                                            int *is_global)
 +{
 +      struct dentry *buf_file;
 +
 +      buf_file = debugfs_create_file(filename, mode, parent, buf,
 +                                     &relay_file_operations);
 +      *is_global = 1;
 +      return buf_file;
 +}
 +
 +static int remove_buf_file_handler(struct dentry *dentry)
 +{
 +      debugfs_remove(dentry);
 +
 +      return 0;
 +}
 +
 +void ath_debug_send_fft_sample(struct ath_softc *sc,
 +                             struct fft_sample_tlv *fft_sample_tlv)
 +{
 +      if (!sc->rfs_chan_spec_scan)
 +              return;
 +
 +      relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv,
 +                  fft_sample_tlv->length + sizeof(*fft_sample_tlv));
 +}
 +
 +static struct rchan_callbacks rfs_spec_scan_cb = {
 +      .create_buf_file = create_buf_file_handler,
 +      .remove_buf_file = remove_buf_file_handler,
 +};
 +
 +
  static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
                                  size_t count, loff_t *ppos)
  {
@@@ -1887,14 -1779,6 +1886,14 @@@ int ath9k_init_debug(struct ath_hw *ah
                            &fops_base_eeprom);
        debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_modal_eeprom);
 +      sc->rfs_chan_spec_scan = relay_open("spectral_scan",
 +                                          sc->debug.debugfs_phy,
 +                                          262144, 4, &rfs_spec_scan_cb,
 +                                          NULL);
 +      debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR,
 +                          sc->debug.debugfs_phy, sc,
 +                          &fops_spec_scan_ctl);
 +
  #ifdef CONFIG_ATH9K_MAC_DEBUG
        debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_samps);
@@@ -23,7 -23,6 +23,7 @@@
  
  struct ath_txq;
  struct ath_buf;
 +struct fft_sample_tlv;
  
  #ifdef CONFIG_ATH9K_DEBUGFS
  #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
@@@ -217,7 -216,6 +217,6 @@@ struct ath_tx_stats 
   * @rx_oom_err:  No. of frames dropped due to OOM issues.
   * @rx_rate_err:  No. of frames dropped due to rate errors.
   * @rx_too_many_frags_err:  Frames dropped due to too-many-frags received.
-  * @rx_drop_rxflush: No. of frames dropped due to RX-FLUSH.
   * @rx_beacons:  No. of beacons received.
   * @rx_frags:  No. of rx-fragements received.
   */
@@@ -236,7 -234,6 +235,6 @@@ struct ath_rx_stats 
        u32 rx_oom_err;
        u32 rx_rate_err;
        u32 rx_too_many_frags_err;
-       u32 rx_drop_rxflush;
        u32 rx_beacons;
        u32 rx_frags;
  };
@@@ -324,10 -321,6 +322,10 @@@ void ath9k_sta_remove_debugfs(struct ie
                              struct ieee80211_vif *vif,
                              struct ieee80211_sta *sta,
                              struct dentry *dir);
 +
 +void ath_debug_send_fft_sample(struct ath_softc *sc,
 +                             struct fft_sample_tlv *fft_sample);
 +
  #else
  
  #define RX_STAT_INC(c) /* NOP */
@@@ -397,7 -397,6 +397,7 @@@ enum ath9k_int 
  #define MAX_RTT_TABLE_ENTRY     6
  #define MAX_IQCAL_MEASUREMENT 8
  #define MAX_CL_TAB_ENTRY      16
 +#define CL_TAB_ENTRY(reg_base)        (reg_base + (4 * j))
  
  struct ath9k_hw_cal_data {
        u16 channel;
@@@ -600,10 -599,13 +600,10 @@@ struct ath_hw_radar_conf 
   * @init_cal_settings: setup types of calibrations supported
   * @init_cal: starts actual calibration
   *
 - * @init_mode_regs: Initializes mode registers
   * @init_mode_gain_regs: Initialize TX/RX gain registers
   *
   * @rf_set_freq: change frequency
   * @spur_mitigate_freq: spur mitigation
 - * @rf_alloc_ext_banks:
 - * @rf_free_ext_banks:
   * @set_rf_regs:
   * @compute_pll_control: compute the PLL control value to use for
   *    AR_RTC_PLL_CONTROL for a given channel
@@@ -618,6 -620,7 +618,6 @@@ struct ath_hw_private_ops 
        void (*init_cal_settings)(struct ath_hw *ah);
        bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan);
  
 -      void (*init_mode_regs)(struct ath_hw *ah);
        void (*init_mode_gain_regs)(struct ath_hw *ah);
        void (*setup_calibration)(struct ath_hw *ah,
                                  struct ath9k_cal_list *currCal);
                           struct ath9k_channel *chan);
        void (*spur_mitigate_freq)(struct ath_hw *ah,
                                   struct ath9k_channel *chan);
 -      int (*rf_alloc_ext_banks)(struct ath_hw *ah);
 -      void (*rf_free_ext_banks)(struct ath_hw *ah);
        bool (*set_rf_regs)(struct ath_hw *ah,
                            struct ath9k_channel *chan,
                            u16 modesIndex);
        void (*ani_cache_ini_regs)(struct ath_hw *ah);
  };
  
 +/**
 + * struct ath_spec_scan - parameters for Atheros spectral scan
 + *
 + * @enabled: enable/disable spectral scan
 + * @short_repeat: controls whether the chip is in spectral scan mode
 + *              for 4 usec (enabled) or 204 usec (disabled)
 + * @count: number of scan results requested. There are special meanings
 + *       in some chip revisions:
 + *       AR92xx: highest bit set (>=128) for endless mode
 + *               (spectral scan won't stopped until explicitly disabled)
 + *       AR9300 and newer: 0 for endless mode
 + * @endless: true if endless mode is intended. Otherwise, count value is
 + *           corrected to the next possible value.
 + * @period: time duration between successive spectral scan entry points
 + *        (period*256*Tclk). Tclk = ath_common->clockrate
 + * @fft_period: PHY passes FFT frames to MAC every (fft_period+1)*4uS
 + *
 + * Note: Tclk = 40MHz or 44MHz depending upon operating mode.
 + *     Typically it's 44MHz in 2/5GHz on later chips, but there's
 + *     a "fast clock" check for this in 5GHz.
 + *
 + */
 +struct ath_spec_scan {
 +      bool enabled;
 +      bool short_repeat;
 +      bool endless;
 +      u8 count;
 +      u8 period;
 +      u8 fft_period;
 +};
 +
  /**
   * struct ath_hw_ops - callbacks used by hardware code and driver code
   *
   *
   * @config_pci_powersave:
   * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
 + *
 + * @spectral_scan_config: set parameters for spectral scan and enable/disable it
 + * @spectral_scan_trigger: trigger a spectral scan run
 + * @spectral_scan_wait: wait for a spectral scan run to finish
   */
  struct ath_hw_ops {
        void (*config_pci_powersave)(struct ath_hw *ah,
        void (*antdiv_comb_conf_set)(struct ath_hw *ah,
                        struct ath_hw_antcomb_conf *antconf);
        void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable);
 +      void (*spectral_scan_config)(struct ath_hw *ah,
 +                                   struct ath_spec_scan *param);
 +      void (*spectral_scan_trigger)(struct ath_hw *ah);
 +      void (*spectral_scan_wait)(struct ath_hw *ah);
  };
  
  struct ath_nf_limits {
@@@ -744,7 -710,6 +744,7 @@@ enum ath_cal_list 
  struct ath_hw {
        struct ath_ops reg_ops;
  
 +      struct device *dev;
        struct ieee80211_hw *hw;
        struct ath_common common;
        struct ath9k_hw_version hw_version;
        struct ath9k_cal_list iq_caldata;
        struct ath9k_cal_list adcgain_caldata;
        struct ath9k_cal_list adcdc_caldata;
 -      struct ath9k_cal_list tempCompCalData;
        struct ath9k_cal_list *cal_list;
        struct ath9k_cal_list *cal_list_last;
        struct ath9k_cal_list *cal_list_curr;
        /* ANI */
        u32 proc_phyerr;
        u32 aniperiod;
 -      int totalSizeDesired[5];
 -      int coarse_high[5];
 -      int coarse_low[5];
 -      int firpwr[5];
        enum ath9k_ani_cmd ani_function;
        u32 ani_skip_count;
  
@@@ -1009,7 -979,7 +1009,7 @@@ void ath9k_hw_setantenna(struct ath_hw 
  void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
                          int hw_delay);
  bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
 -void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
 +void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
                          int column, unsigned int *writecnt);
  u32 ath9k_hw_reverse_bits(u32 val, u32 n);
  u16 ath9k_hw_computetxtime(struct ath_hw *ah,
@@@ -1096,16 -1066,17 +1096,17 @@@ void ar9003_paprd_setup_gain_table(stru
  int ar9003_paprd_init_table(struct ath_hw *ah);
  bool ar9003_paprd_is_done(struct ath_hw *ah);
  bool ar9003_is_paprd_enabled(struct ath_hw *ah);
+ void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
  
  /* Hardware family op attach helpers */
 -void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
 +int ar5008_hw_attach_phy_ops(struct ath_hw *ah);
  void ar9002_hw_attach_phy_ops(struct ath_hw *ah);
  void ar9003_hw_attach_phy_ops(struct ath_hw *ah);
  
  void ar9002_hw_attach_calib_ops(struct ath_hw *ah);
  void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
  
 -void ar9002_hw_attach_ops(struct ath_hw *ah);
 +int ar9002_hw_attach_ops(struct ath_hw *ah);
  void ar9003_hw_attach_ops(struct ath_hw *ah);
  
  void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
@@@ -182,7 -182,7 +182,7 @@@ static void ath_restart_work(struct ath
        ath_start_ani(sc);
  }
  
- static bool ath_prepare_reset(struct ath_softc *sc, bool flush)
 -static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx)
++static bool ath_prepare_reset(struct ath_softc *sc)
  {
        struct ath_hw *ah = sc->sc_ah;
        bool ret = true;
        ath9k_debug_samp_bb_mac(sc);
        ath9k_hw_disable_interrupts(ah);
  
 -      if (!ath_stoprecv(sc))
 +      if (!ath_drain_all_txq(sc))
                ret = false;
  
 -      if (!ath_drain_all_txq(sc, retry_tx))
 +      if (!ath_stoprecv(sc))
                ret = false;
  
-       if (!flush) {
-               if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
-                       ath_rx_tasklet(sc, 1, true);
-               ath_rx_tasklet(sc, 1, false);
-       } else {
-               ath_flushrecv(sc);
-       }
        return ret;
  }
  
@@@ -255,17 -247,18 +247,17 @@@ static bool ath_complete_reset(struct a
        return true;
  }
  
 -static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
 -                            bool retry_tx)
 +static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
  {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_cal_data *caldata = NULL;
        bool fastcc = true;
-       bool flush = false;
        int r;
  
        __ath_cancel_work(sc);
  
+       tasklet_disable(&sc->intr_tq);
        spin_lock_bh(&sc->sc_pcu_lock);
  
        if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) {
  
        if (!hchan) {
                fastcc = false;
-               flush = true;
                hchan = ah->curchan;
        }
  
-       if (!ath_prepare_reset(sc, flush))
 -      if (!ath_prepare_reset(sc, retry_tx))
++      if (!ath_prepare_reset(sc))
                fastcc = false;
  
        ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
  
  out:
        spin_unlock_bh(&sc->sc_pcu_lock);
+       tasklet_enable(&sc->intr_tq);
        return r;
  }
  
@@@ -318,7 -312,7 +311,7 @@@ static int ath_set_channel(struct ath_s
        if (test_bit(SC_OP_INVALID, &sc->sc_flags))
                return -EIO;
  
 -      r = ath_reset_internal(sc, hchan, false);
 +      r = ath_reset_internal(sc, hchan);
  
        return r;
  }
@@@ -548,21 -542,23 +541,21 @@@ chip_reset
  #undef SCHED_INTR
  }
  
 -static int ath_reset(struct ath_softc *sc, bool retry_tx)
 +static int ath_reset(struct ath_softc *sc)
  {
 -      int r;
 +      int i, r;
  
        ath9k_ps_wakeup(sc);
  
 -      r = ath_reset_internal(sc, NULL, retry_tx);
 +      r = ath_reset_internal(sc, NULL);
  
 -      if (retry_tx) {
 -              int i;
 -              for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
 -                      if (ATH_TXQ_SETUP(sc, i)) {
 -                              spin_lock_bh(&sc->tx.txq[i].axq_lock);
 -                              ath_txq_schedule(sc, &sc->tx.txq[i]);
 -                              spin_unlock_bh(&sc->tx.txq[i].axq_lock);
 -                      }
 -              }
 +      for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
 +              if (!ATH_TXQ_SETUP(sc, i))
 +                      continue;
 +
 +              spin_lock_bh(&sc->tx.txq[i].axq_lock);
 +              ath_txq_schedule(sc, &sc->tx.txq[i]);
 +              spin_unlock_bh(&sc->tx.txq[i].axq_lock);
        }
  
        ath9k_ps_restore(sc);
@@@ -583,7 -579,7 +576,7 @@@ void ath_reset_work(struct work_struct 
  {
        struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
  
 -      ath_reset(sc, true);
 +      ath_reset(sc);
  }
  
  /**********************/
@@@ -801,7 -797,7 +794,7 @@@ static void ath9k_stop(struct ieee80211
                ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
        }
  
-       ath_prepare_reset(sc, true);
 -      ath_prepare_reset(sc, false);
++      ath_prepare_reset(sc);
  
        if (sc->rx.frag) {
                dev_kfree_skb_any(sc->rx.frag);
@@@ -1072,86 -1068,6 +1065,86 @@@ static void ath9k_disable_ps(struct ath
        ath_dbg(common, PS, "PowerSave disabled\n");
  }
  
 +void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw)
 +{
 +      struct ath_softc *sc = hw->priv;
 +      struct ath_hw *ah = sc->sc_ah;
 +      struct ath_common *common = ath9k_hw_common(ah);
 +      u32 rxfilter;
 +
 +      if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
 +              ath_err(common, "spectrum analyzer not implemented on this hardware\n");
 +              return;
 +      }
 +
 +      ath9k_ps_wakeup(sc);
 +      rxfilter = ath9k_hw_getrxfilter(ah);
 +      ath9k_hw_setrxfilter(ah, rxfilter |
 +                               ATH9K_RX_FILTER_PHYRADAR |
 +                               ATH9K_RX_FILTER_PHYERR);
 +
 +      /* TODO: usually this should not be neccesary, but for some reason
 +       * (or in some mode?) the trigger must be called after the
 +       * configuration, otherwise the register will have its values reset
 +       * (on my ar9220 to value 0x01002310)
 +       */
 +      ath9k_spectral_scan_config(hw, sc->spectral_mode);
 +      ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
 +      ath9k_ps_restore(sc);
 +}
 +
 +int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
 +                             enum spectral_mode spectral_mode)
 +{
 +      struct ath_softc *sc = hw->priv;
 +      struct ath_hw *ah = sc->sc_ah;
 +      struct ath_common *common = ath9k_hw_common(ah);
 +      struct ath_spec_scan param;
 +
 +      if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
 +              ath_err(common, "spectrum analyzer not implemented on this hardware\n");
 +              return -1;
 +      }
 +
 +      /* NOTE: this will generate a few samples ...
 +       *
 +       * TODO: review default parameters, and/or define an interface to set
 +       * them.
 +       */
 +      param.enabled = 1;
 +      param.short_repeat = true;
 +      param.count = 8;
 +      param.endless = false;
 +      param.period = 0xFF;
 +      param.fft_period = 0xF;
 +
 +      switch (spectral_mode) {
 +      case SPECTRAL_DISABLED:
 +              param.enabled = 0;
 +              break;
 +      case SPECTRAL_BACKGROUND:
 +              /* send endless samples.
 +               * TODO: is this really useful for "background"?
 +               */
 +              param.endless = 1;
 +              break;
 +      case SPECTRAL_CHANSCAN:
 +              break;
 +      case SPECTRAL_MANUAL:
 +              break;
 +      default:
 +              return -1;
 +      }
 +
 +      ath9k_ps_wakeup(sc);
 +      ath9k_hw_ops(ah)->spectral_scan_config(ah, &param);
 +      ath9k_ps_restore(sc);
 +
 +      sc->spectral_mode = spectral_mode;
 +
 +      return 0;
 +}
 +
  static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
  {
        struct ath_softc *sc = hw->priv;
                 */
                if (old_pos >= 0)
                        ath_update_survey_nf(sc, old_pos);
 +
 +              /* perform spectral scan if requested. */
 +              if (sc->scanning && sc->spectral_mode == SPECTRAL_CHANSCAN)
 +                      ath9k_spectral_scan_trigger(hw);
 +
        }
  
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@@ -1692,9 -1603,7 +1685,9 @@@ static int ath9k_ampdu_action(struct ie
                        ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                ath9k_ps_restore(sc);
                break;
 -      case IEEE80211_AMPDU_TX_STOP:
 +      case IEEE80211_AMPDU_TX_STOP_CONT:
 +      case IEEE80211_AMPDU_TX_STOP_FLUSH:
 +      case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                ath9k_ps_wakeup(sc);
                ath_tx_aggr_stop(sc, sta, tid);
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@@ -1813,11 -1722,11 +1806,11 @@@ static void ath9k_flush(struct ieee8021
        if (drop) {
                ath9k_ps_wakeup(sc);
                spin_lock_bh(&sc->sc_pcu_lock);
 -              drain_txq = ath_drain_all_txq(sc, false);
 +              drain_txq = ath_drain_all_txq(sc);
                spin_unlock_bh(&sc->sc_pcu_lock);
  
                if (!drain_txq)
 -                      ath_reset(sc, false);
 +                      ath_reset(sc);
  
                ath9k_ps_restore(sc);
                ieee80211_wake_queues(hw);
@@@ -1917,6 -1826,9 +1910,9 @@@ static u32 fill_chainmask(u32 cap, u32 
  
  static bool validate_antenna_mask(struct ath_hw *ah, u32 val)
  {
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               return true;
        switch (val & 0x7) {
        case 0x1:
        case 0x3:
@@@ -2322,19 -2234,6 +2318,19 @@@ static void ath9k_set_wakeup(struct iee
  }
  
  #endif
 +static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 +{
 +      struct ath_softc *sc = hw->priv;
 +
 +      sc->scanning = 1;
 +}
 +
 +static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
 +{
 +      struct ath_softc *sc = hw->priv;
 +
 +      sc->scanning = 0;
 +}
  
  struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
        .sta_add_debugfs    = ath9k_sta_add_debugfs,
        .sta_remove_debugfs = ath9k_sta_remove_debugfs,
  #endif
 +      .sw_scan_start      = ath9k_sw_scan_start,
 +      .sw_scan_complete   = ath9k_sw_scan_complete,
  };
@@@ -15,7 -15,6 +15,7 @@@
   */
  
  #include <linux/dma-mapping.h>
 +#include <linux/relay.h>
  #include "ath9k.h"
  #include "ar9003_mac.h"
  
@@@ -181,6 -180,11 +181,6 @@@ static void ath_rx_edma_cleanup(struct 
                        bf->bf_mpdu = NULL;
                }
        }
 -
 -      INIT_LIST_HEAD(&sc->rx.rxbuf);
 -
 -      kfree(sc->rx.rx_bufptr);
 -      sc->rx.rx_bufptr = NULL;
  }
  
  static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size)
@@@ -207,11 -211,12 +207,11 @@@ static int ath_rx_edma_init(struct ath_
                               ah->caps.rx_hp_qdepth);
  
        size = sizeof(struct ath_buf) * nbufs;
 -      bf = kzalloc(size, GFP_KERNEL);
 +      bf = devm_kzalloc(sc->dev, size, GFP_KERNEL);
        if (!bf)
                return -ENOMEM;
  
        INIT_LIST_HEAD(&sc->rx.rxbuf);
 -      sc->rx.rx_bufptr = bf;
  
        for (i = 0; i < nbufs; i++, bf++) {
                skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL);
@@@ -249,8 -254,6 +249,6 @@@ rx_init_fail
  
  static void ath_edma_start_recv(struct ath_softc *sc)
  {
-       spin_lock_bh(&sc->rx.rxbuflock);
        ath9k_hw_rxena(sc->sc_ah);
  
        ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP,
        ath_opmode_init(sc);
  
        ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
-       spin_unlock_bh(&sc->rx.rxbuflock);
  }
  
  static void ath_edma_stop_recv(struct ath_softc *sc)
@@@ -280,8 -281,6 +276,6 @@@ int ath_rx_init(struct ath_softc *sc, i
        int error = 0;
  
        spin_lock_init(&sc->sc_pcu_lock);
-       spin_lock_init(&sc->rx.rxbuflock);
-       clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
  
        common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
                             sc->sc_ah->caps.rx_status_len;
@@@ -358,6 -357,9 +352,6 @@@ void ath_rx_cleanup(struct ath_softc *s
                                bf->bf_mpdu = NULL;
                        }
                }
 -
 -              if (sc->rx.rxdma.dd_desc_len != 0)
 -                      ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf);
        }
  }
  
@@@ -439,7 -441,6 +433,6 @@@ int ath_startrecv(struct ath_softc *sc
                return 0;
        }
  
-       spin_lock_bh(&sc->rx.rxbuflock);
        if (list_empty(&sc->rx.rxbuf))
                goto start_recv;
  
@@@ -460,26 -461,31 +453,31 @@@ start_recv
        ath_opmode_init(sc);
        ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
  
-       spin_unlock_bh(&sc->rx.rxbuflock);
        return 0;
  }
  
+ static void ath_flushrecv(struct ath_softc *sc)
+ {
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+               ath_rx_tasklet(sc, 1, true);
+       ath_rx_tasklet(sc, 1, false);
+ }
  bool ath_stoprecv(struct ath_softc *sc)
  {
        struct ath_hw *ah = sc->sc_ah;
        bool stopped, reset = false;
  
-       spin_lock_bh(&sc->rx.rxbuflock);
        ath9k_hw_abortpcurecv(ah);
        ath9k_hw_setrxfilter(ah, 0);
        stopped = ath9k_hw_stopdmarecv(ah, &reset);
  
+       ath_flushrecv(sc);
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                ath_edma_stop_recv(sc);
        else
                sc->rx.rxlink = NULL;
-       spin_unlock_bh(&sc->rx.rxbuflock);
  
        if (!(ah->ah_flags & AH_UNPLUGGED) &&
            unlikely(!stopped)) {
        return stopped && !reset;
  }
  
- void ath_flushrecv(struct ath_softc *sc)
- {
-       set_bit(SC_OP_RXFLUSH, &sc->sc_flags);
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
-               ath_rx_tasklet(sc, 1, true);
-       ath_rx_tasklet(sc, 1, false);
-       clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
- }
  static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
  {
        /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */
@@@ -736,6 -733,7 +725,7 @@@ static struct ath_buf *ath_get_next_rx_
                        return NULL;
        }
  
+       list_del(&bf->list);
        if (!bf->bf_mpdu)
                return bf;
  
@@@ -1026,108 -1024,6 +1016,108 @@@ static void ath9k_rx_skb_postprocess(st
                rxs->flag &= ~RX_FLAG_DECRYPTED;
  }
  
 +static s8 fix_rssi_inv_only(u8 rssi_val)
 +{
 +      if (rssi_val == 128)
 +              rssi_val = 0;
 +      return (s8) rssi_val;
 +}
 +
 +
 +static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
 +                          struct ath_rx_status *rs, u64 tsf)
 +{
 +#ifdef CONFIG_ATH_DEBUG
 +      struct ath_hw *ah = sc->sc_ah;
 +      u8 bins[SPECTRAL_HT20_NUM_BINS];
 +      u8 *vdata = (u8 *)hdr;
 +      struct fft_sample_ht20 fft_sample;
 +      struct ath_radar_info *radar_info;
 +      struct ath_ht20_mag_info *mag_info;
 +      int len = rs->rs_datalen;
 +      int i, dc_pos;
 +
 +      /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
 +       * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
 +       * yet, but this is supposed to be possible as well.
 +       */
 +      if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
 +          rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
 +          rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
 +              return;
 +
 +      /* Variation in the data length is possible and will be fixed later.
 +       * Note that we only support HT20 for now.
 +       *
 +       * TODO: add HT20_40 support as well.
 +       */
 +      if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) ||
 +          (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1))
 +              return;
 +
 +      /* check if spectral scan bit is set. This does not have to be checked
 +       * if received through a SPECTRAL phy error, but shouldn't hurt.
 +       */
 +      radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
 +      if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
 +              return;
 +
 +      fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20;
 +      fft_sample.tlv.length = sizeof(fft_sample) - sizeof(fft_sample.tlv);
 +
 +      fft_sample.freq = ah->curchan->chan->center_freq;
 +      fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
 +      fft_sample.noise = ah->noise;
 +
 +      switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) {
 +      case 0:
 +              /* length correct, nothing to do. */
 +              memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS);
 +              break;
 +      case -1:
 +              /* first byte missing, duplicate it. */
 +              memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1);
 +              bins[0] = vdata[0];
 +              break;
 +      case 2:
 +              /* MAC added 2 extra bytes at bin 30 and 32, remove them. */
 +              memcpy(bins, vdata, 30);
 +              bins[30] = vdata[31];
 +              memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31);
 +              break;
 +      case 1:
 +              /* MAC added 2 extra bytes AND first byte is missing. */
 +              bins[0] = vdata[0];
 +              memcpy(&bins[0], vdata, 30);
 +              bins[31] = vdata[31];
 +              memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32);
 +              break;
 +      default:
 +              return;
 +      }
 +
 +      /* DC value (value in the middle) is the blind spot of the spectral
 +       * sample and invalid, interpolate it.
 +       */
 +      dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
 +      bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
 +
 +      /* mag data is at the end of the frame, in front of radar_info */
 +      mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
 +
 +      /* Apply exponent and grab further auxiliary information. */
 +      for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++)
 +              fft_sample.data[i] = bins[i] << mag_info->max_exp;
 +
 +      fft_sample.max_magnitude = spectral_max_magnitude(mag_info->all_bins);
 +      fft_sample.max_index = spectral_max_index(mag_info->all_bins);
 +      fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins);
 +      fft_sample.tsf = tsf;
 +
 +      ath_debug_send_fft_sample(sc, &fft_sample.tlv);
 +#endif
 +}
 +
  int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
  {
        struct ath_buf *bf;
                dma_type = DMA_FROM_DEVICE;
  
        qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP;
-       spin_lock_bh(&sc->rx.rxbuflock);
  
        tsf = ath9k_hw_gettsf64(ah);
        tsf_lower = tsf & 0xffffffff;
  
        do {
                bool decrypt_error = false;
-               /* If handling rx interrupt and flush is in progress => exit */
-               if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0))
-                       break;
  
                memset(&rs, 0, sizeof(rs));
                if (edma)
  
                ath_debug_stat_rx(sc, &rs);
  
-               /*
-                * If we're asked to flush receive queue, directly
-                * chain it back at the queue without processing it.
-                */
-               if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) {
-                       RX_STAT_INC(rx_drop_rxflush);
-                       goto requeue_drop_frag;
-               }
                memset(rxs, 0, sizeof(struct ieee80211_rx_status));
  
                rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
                    unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
                        rxs->mactime += 0x100000000ULL;
  
 +              if ((rs.rs_status & ATH9K_RXERR_PHY))
 +                      ath_process_fft(sc, hdr, &rs, rxs->mactime);
 +
                retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
                                                 rxs, &decrypt_error);
                if (retval)
@@@ -1351,19 -1231,18 +1328,18 @@@ requeue_drop_frag
                        sc->rx.frag = NULL;
                }
  requeue:
+               list_add_tail(&bf->list, &sc->rx.rxbuf);
+               if (flush)
+                       continue;
                if (edma) {
-                       list_add_tail(&bf->list, &sc->rx.rxbuf);
                        ath_rx_edma_buf_link(sc, qtype);
                } else {
-                       list_move_tail(&bf->list, &sc->rx.rxbuf);
                        ath_rx_buf_link(sc, bf);
-                       if (!flush)
-                               ath9k_hw_rxena(ah);
+                       ath9k_hw_rxena(ah);
                }
        } while (1);
  
-       spin_unlock_bh(&sc->rx.rxbuflock);
        if (!(ah->imask & ATH9K_INT_RXEOL)) {
                ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
                ath9k_hw_set_interrupts(ah);
@@@ -215,24 -215,6 +215,24 @@@ static int carl9170_fw_tx_sequence(stru
        return 0;
  }
  
 +static void carl9170_fw_set_if_combinations(struct ar9170 *ar,
 +                                          u16 if_comb_types)
 +{
 +      if (ar->fw.vif_num < 2)
 +              return;
 +
 +      ar->if_comb_limits[0].max = ar->fw.vif_num;
 +      ar->if_comb_limits[0].types = if_comb_types;
 +
 +      ar->if_combs[0].num_different_channels = 1;
 +      ar->if_combs[0].max_interfaces = ar->fw.vif_num;
 +      ar->if_combs[0].limits = ar->if_comb_limits;
 +      ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
 +
 +      ar->hw->wiphy->iface_combinations = ar->if_combs;
 +      ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
 +}
 +
  static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
  {
        const struct carl9170fw_otus_desc *otus_desc;
        if (!SUPP(CARL9170FW_COMMAND_CAM)) {
                dev_info(&ar->udev->dev, "crypto offloading is disabled "
                         "by firmware.\n");
 -              ar->disable_offload = true;
 +              ar->fw.disable_offload_fw = true;
        }
  
        if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM))
                if (SUPP(CARL9170FW_WLANTX_CAB)) {
                        if_comb_types |=
                                BIT(NL80211_IFTYPE_AP) |
-                               BIT(NL80211_IFTYPE_MESH_POINT) |
                                BIT(NL80211_IFTYPE_P2P_GO);
+ #ifdef CONFIG_MAC80211_MESH
+                       if_comb_types |=
+                               BIT(NL80211_IFTYPE_MESH_POINT);
+ #endif /* CONFIG_MAC80211_MESH */
                }
        }
  
 -      ar->if_comb_limits[0].max = ar->fw.vif_num;
 -      ar->if_comb_limits[0].types = if_comb_types;
 -
 -      ar->if_combs[0].num_different_channels = 1;
 -      ar->if_combs[0].max_interfaces = ar->fw.vif_num;
 -      ar->if_combs[0].limits = ar->if_comb_limits;
 -      ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
 -
 -      ar->hw->wiphy->iface_combinations = ar->if_combs;
 -      ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
 +      carl9170_fw_set_if_combinations(ar, if_comb_types);
  
        ar->hw->wiphy->interface_modes |= if_comb_types;
  
 -      ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 +      ar->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 +
 +      /* As IBSS Encryption is software-based, IBSS RSN is supported. */
 +      ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
 +               WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_SUPPORTS_TDLS;
  
  #undef SUPPORTED
        return carl9170_fw_tx_sequence(ar);
@@@ -16,6 -16,8 +16,6 @@@
  
  /* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
  
 -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 -
  #include <linux/kernel.h>
  #include <linux/etherdevice.h>
  #include <net/cfg80211.h>
@@@ -2009,6 -2011,67 +2009,6 @@@ done
        return err;
  }
  
 -static s32
 -brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
 -                           const u8 *addr,
 -                           const struct cfg80211_bitrate_mask *mask)
 -{
 -      struct brcmf_if *ifp = netdev_priv(ndev);
 -      struct brcm_rateset_le rateset_le;
 -      s32 rate;
 -      s32 val;
 -      s32 err_bg;
 -      s32 err_a;
 -      u32 legacy;
 -      s32 err = 0;
 -
 -      brcmf_dbg(TRACE, "Enter\n");
 -      if (!check_vif_up(ifp->vif))
 -              return -EIO;
 -
 -      /* addr param is always NULL. ignore it */
 -      /* Get current rateset */
 -      err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CURR_RATESET,
 -                                   &rateset_le, sizeof(rateset_le));
 -      if (err) {
 -              brcmf_err("could not get current rateset (%d)\n", err);
 -              goto done;
 -      }
 -
 -      legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF);
 -      if (!legacy)
 -              legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy &
 -                           0xFFFF);
 -
 -      val = wl_g_rates[legacy - 1].bitrate * 100000;
 -
 -      if (val < le32_to_cpu(rateset_le.count))
 -              /* Select rate by rateset index */
 -              rate = rateset_le.rates[val] & 0x7f;
 -      else
 -              /* Specified rate in bps */
 -              rate = val / 500000;
 -
 -      brcmf_dbg(CONN, "rate %d mbps\n", rate / 2);
 -
 -      /*
 -       *
 -       *      Set rate override,
 -       *      Since the is a/b/g-blind, both a/bg_rate are enforced.
 -       */
 -      err_bg = brcmf_fil_iovar_int_set(ifp, "bg_rate", rate);
 -      err_a = brcmf_fil_iovar_int_set(ifp, "a_rate", rate);
 -      if (err_bg && err_a) {
 -              brcmf_err("could not set fixed rate (%d) (%d)\n", err_bg,
 -                        err_a);
 -              err = err_bg | err_a;
 -      }
 -
 -done:
 -      brcmf_dbg(TRACE, "Exit\n");
 -      return err;
 -}
 -
  static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
                                   struct brcmf_bss_info_le *bi)
  {
@@@ -3028,10 -3091,11 +3028,11 @@@ brcmf_configure_wpaie(struct net_devic
  
        len = wpa_ie->len + TLV_HDR_LEN;
        data = (u8 *)wpa_ie;
-       offset = 0;
+       offset = TLV_HDR_LEN;
        if (!is_rsn_ie)
                offset += VS_IE_FIXED_HDR_LEN;
-       offset += WPA_IE_VERSION_LEN;
+       else
+               offset += WPA_IE_VERSION_LEN;
  
        /* check for multicast cipher suite */
        if (offset + WPA_IE_MIN_OUI_LEN > len) {
@@@ -3640,6 -3704,7 +3641,6 @@@ static struct cfg80211_ops wl_cfg80211_
        .set_default_key = brcmf_cfg80211_config_default_key,
        .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
        .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
 -      .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask,
        .connect = brcmf_cfg80211_connect,
        .disconnect = brcmf_cfg80211_disconnect,
        .suspend = brcmf_cfg80211_suspend,
@@@ -4265,8 -4330,9 +4266,8 @@@ void brcmf_cfg80211_detach(struct brcmf
  }
  
  static s32
 -brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
 +brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
  {
 -      struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err = 0;
        __le32 roamtrigger[2];
        __le32 roam_delta[2];
@@@ -4317,9 -4383,10 +4318,9 @@@ dongle_rom_out
  }
  
  static s32
 -brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
 +brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
                      s32 scan_unassoc_time, s32 scan_passive_time)
  {
 -      struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err = 0;
  
        err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
@@@ -4389,7 -4456,6 +4390,7 @@@ static s32 brcmf_config_dongle(struct b
  {
        struct net_device *ndev;
        struct wireless_dev *wdev;
 +      struct brcmf_if *ifp;
        s32 power_mode;
        s32 err = 0;
  
  
        ndev = cfg_to_ndev(cfg);
        wdev = ndev->ieee80211_ptr;
 +      ifp = netdev_priv(ndev);
  
 -      brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
 -                      WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
 +      /* make sure RF is ready for work */
 +      brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
 +
 +      brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
 +                            WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
  
        power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
 -      err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
 -                                  power_mode);
 +      err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
        if (err)
                goto default_conf_out;
        brcmf_dbg(INFO, "power save set to %s\n",
                  (power_mode ? "enabled" : "disabled"));
  
 -      err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1),
 -                              WL_BEACON_TIMEOUT);
 +      err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
        if (err)
                goto default_conf_out;
        err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
                                          NULL, NULL);
 -      if (err && err != -EINPROGRESS)
 +      if (err)
                goto default_conf_out;
        err = brcmf_dongle_probecap(cfg);
        if (err)
                goto default_conf_out;
  
 -      /* -EINPROGRESS: Call commit handler */
 -
 -default_conf_out:
 -
        cfg->dongle_up = true;
 +default_conf_out:
  
        return err;
  
  static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
  {
        set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
 -      if (ifp->idx)
 -              return 0;
  
        return brcmf_config_dongle(ifp->drvr->config);
  }
@@@ -3273,7 -3273,7 +3273,7 @@@ il3945_store_measurement(struct device 
  
        if (count) {
                char *p = buffer;
-               strncpy(buffer, buf, min(sizeof(buffer), count));
+               strlcpy(buffer, buf, sizeof(buffer));
                channel = simple_strtoul(p, NULL, 0);
                if (channel)
                        params.channel = channel;
@@@ -3474,7 -3474,6 +3474,7 @@@ struct ieee80211_ops il3945_mac_ops = 
        .sta_add = il3945_mac_sta_add,
        .sta_remove = il_mac_sta_remove,
        .tx_last_beacon = il_mac_tx_last_beacon,
 +      .flush = il_mac_flush,
  };
  
  static int
@@@ -3549,8 -3548,7 +3549,8 @@@ il3945_setup_mac(struct il_priv *il
        hw->vif_data_size = sizeof(struct il_vif_priv);
  
        /* Tell mac80211 our characteristics */
 -      hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT;
 +      hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT |
 +                  IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
  
        hw->wiphy->interface_modes =
            BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
            WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
            WIPHY_FLAG_IBSS_RSN;
  
 +      hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 +
        hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
        /* we create the 802.11 header and a zero-length SSID element */
        hw->wiphy->max_scan_ie_len = IL3945_MAX_PROBE_REQUEST - 24 - 2;
@@@ -3958,17 -3958,21 +3958,21 @@@ il_connection_init_rx_config(struct il_
  
        memset(&il->staging, 0, sizeof(il->staging));
  
-       if (!il->vif) {
+       switch (il->iw_mode) {
+       case NL80211_IFTYPE_UNSPECIFIED:
                il->staging.dev_type = RXON_DEV_TYPE_ESS;
-       } else if (il->vif->type == NL80211_IFTYPE_STATION) {
+               break;
+       case NL80211_IFTYPE_STATION:
                il->staging.dev_type = RXON_DEV_TYPE_ESS;
                il->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
-       } else if (il->vif->type == NL80211_IFTYPE_ADHOC) {
+               break;
+       case NL80211_IFTYPE_ADHOC:
                il->staging.dev_type = RXON_DEV_TYPE_IBSS;
                il->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
                il->staging.filter_flags =
                    RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
-       } else {
+               break;
+       default:
                IL_ERR("Unsupported interface type %d\n", il->vif->type);
                return;
        }
@@@ -4550,8 -4554,7 +4554,7 @@@ out
  EXPORT_SYMBOL(il_mac_add_interface);
  
  static void
- il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif,
-                     bool mode_change)
+ il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif)
  {
        lockdep_assert_held(&il->mutex);
  
                il_force_scan_end(il);
        }
  
-       if (!mode_change)
-               il_set_mode(il);
+       il_set_mode(il);
  }
  
  void
@@@ -4575,8 -4576,8 +4576,8 @@@ il_mac_remove_interface(struct ieee8021
  
        WARN_ON(il->vif != vif);
        il->vif = NULL;
-       il_teardown_interface(il, vif, false);
+       il->iw_mode = NL80211_IFTYPE_UNSPECIFIED;
+       il_teardown_interface(il, vif);
        memset(il->bssid, 0, ETH_ALEN);
  
        D_MAC80211("leave\n");
@@@ -4685,18 -4686,10 +4686,10 @@@ il_mac_change_interface(struct ieee8021
        }
  
        /* success */
-       il_teardown_interface(il, vif, true);
        vif->type = newtype;
        vif->p2p = false;
-       err = il_set_mode(il);
-       WARN_ON(err);
-       /*
-        * We've switched internally, but submitting to the
-        * device may have failed for some reason. Mask this
-        * error, because otherwise mac80211 will not switch
-        * (and set the interface type back) and we'll be
-        * out of sync with it.
-        */
+       il->iw_mode = newtype;
+       il_teardown_interface(il, vif);
        err = 0;
  
  out:
  }
  EXPORT_SYMBOL(il_mac_change_interface);
  
 +void
 +il_mac_flush(struct ieee80211_hw *hw, bool drop)
 +{
 +      struct il_priv *il = hw->priv;
 +      unsigned long timeout = jiffies + msecs_to_jiffies(500);
 +      int i;
 +
 +      mutex_lock(&il->mutex);
 +      D_MAC80211("enter\n");
 +
 +      if (il->txq == NULL)
 +              goto out;
 +
 +      for (i = 0; i < il->hw_params.max_txq_num; i++) {
 +              struct il_queue *q;
 +
 +              if (i == il->cmd_queue)
 +                      continue;
 +
 +              q = &il->txq[i].q;
 +              if (q->read_ptr == q->write_ptr)
 +                      continue;
 +
 +              if (time_after(jiffies, timeout)) {
 +                      IL_ERR("Failed to flush queue %d\n", q->id);
 +                      break;
 +              }
 +
 +              msleep(20);
 +      }
 +out:
 +      D_MAC80211("leave\n");
 +      mutex_unlock(&il->mutex);
 +}
 +EXPORT_SYMBOL(il_mac_flush);
 +
  /*
   * On every watchdog tick we check (latest) time stamp. If it does not
   * change during timeout period and queue is not empty we reset firmware.
@@@ -231,11 -231,13 +231,11 @@@ static void iwlagn_tx_cmd_build_hwcrypt
                memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
                if (info->flags & IEEE80211_TX_CTL_AMPDU)
                        tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
 -              IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
                break;
  
        case WLAN_CIPHER_SUITE_TKIP:
                tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
                ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
 -              IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
                break;
  
        case WLAN_CIPHER_SUITE_WEP104:
@@@ -353,6 -355,8 +353,6 @@@ int iwlagn_tx_skb(struct iwl_priv *priv
                }
        }
  
 -      IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
 -
        if (sta)
                sta_priv = (void *)sta->drv_priv;
  
        WARN_ON_ONCE(is_agg &&
                     priv->queue_to_mac80211[txq_id] != info->hw_queue);
  
 +      IWL_DEBUG_TX(priv, "TX to [%d|%d] Q:%d - seq: 0x%x\n", sta_id, tid,
 +                   txq_id, seq_number);
 +
        if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id))
                goto drop_unlock_sta;
  
@@@ -540,9 -541,9 +540,9 @@@ int iwlagn_tx_agg_stop(struct iwl_priv 
        spin_lock_bh(&priv->sta_lock);
  
        tid_data = &priv->tid_data[sta_id][tid];
 -      txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
 +      txq_id = tid_data->agg.txq_id;
  
 -      switch (priv->tid_data[sta_id][tid].agg.state) {
 +      switch (tid_data->agg.state) {
        case IWL_EMPTYING_HW_QUEUE_ADDBA:
                /*
                * This can happen if the peer stops aggregation
        case IWL_AGG_ON:
                break;
        default:
 -              IWL_WARN(priv, "Stopping AGG while state not ON "
 -                       "or starting for %d on %d (%d)\n", sta_id, tid,
 -                       priv->tid_data[sta_id][tid].agg.state);
 +              IWL_WARN(priv,
 +                       "Stopping AGG while state not ON or starting for %d on %d (%d)\n",
 +                       sta_id, tid, tid_data->agg.state);
                spin_unlock_bh(&priv->sta_lock);
                return 0;
        }
                        "stopping AGG on STA/TID %d/%d but hwq %d not used\n",
                        sta_id, tid, txq_id);
        } else if (tid_data->agg.ssn != tid_data->next_reclaimed) {
 -              IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
 -                                  "next_recl = %d\n",
 +              IWL_DEBUG_TX_QUEUES(priv,
 +                                  "Can't proceed: ssn %d, next_recl = %d\n",
                                    tid_data->agg.ssn,
                                    tid_data->next_reclaimed);
 -              priv->tid_data[sta_id][tid].agg.state =
 -                      IWL_EMPTYING_HW_QUEUE_DELBA;
 +              tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_DELBA;
                spin_unlock_bh(&priv->sta_lock);
                return 0;
        }
        IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
                            tid_data->agg.ssn);
  turn_off:
 -      agg_state = priv->tid_data[sta_id][tid].agg.state;
 -      priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
 +      agg_state = tid_data->agg.state;
 +      tid_data->agg.state = IWL_AGG_OFF;
  
        spin_unlock_bh(&priv->sta_lock);
  
@@@ -952,6 -954,12 +952,6 @@@ static void iwl_rx_reply_tx_agg(struct 
                if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
                              AGG_TX_STATE_ABORT_MSK))
                        continue;
 -
 -              IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
 -                                 "try-count (0x%08x)\n",
 -                                 iwl_get_agg_tx_fail_reason(fstatus),
 -                                 fstatus & AGG_TX_STATUS_MSK,
 -                                 fstatus & AGG_TX_TRY_MSK);
        }
  }
  
@@@ -1071,6 -1079,8 +1071,8 @@@ static void iwlagn_set_tx_status(struc
  {
        u16 status = le16_to_cpu(tx_resp->status.status);
  
+       info->flags &= ~IEEE80211_TX_CTL_AMPDU;
        info->status.rates[0].count = tx_resp->failure_frame + 1;
        info->flags |= iwl_tx_status_to_mac80211(status);
        iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
@@@ -1143,13 -1153,6 +1145,6 @@@ int iwlagn_rx_reply_tx(struct iwl_priv 
                        next_reclaimed = ssn;
                }
  
-               if (tid != IWL_TID_NON_QOS) {
-                       priv->tid_data[sta_id][tid].next_reclaimed =
-                               next_reclaimed;
-                       IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n",
-                                                 next_reclaimed);
-               }
                iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs);
  
                iwlagn_check_ratid_empty(priv, sta_id, tid);
                        if (!is_agg)
                                iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1);
  
+                       /*
+                        * W/A for FW bug - the seq_ctl isn't updated when the
+                        * queues are flushed. Fetch it from the packet itself
+                        */
+                       if (!is_agg && status == TX_STATUS_FAIL_FIFO_FLUSHED) {
+                               next_reclaimed = le16_to_cpu(hdr->seq_ctrl);
+                               next_reclaimed =
+                                       SEQ_TO_SN(next_reclaimed + 0x10);
+                       }
                        is_offchannel_skb =
                                (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN);
                        freed++;
                }
  
 -              WARN_ON(!is_agg && freed != 1);
+               if (tid != IWL_TID_NON_QOS) {
+                       priv->tid_data[sta_id][tid].next_reclaimed =
+                               next_reclaimed;
+                       IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n",
+                                          next_reclaimed);
+               }
 +              if (!is_agg && freed != 1)
 +                      IWL_ERR(priv, "Q: %d, freed %d\n", txq_id, freed);
  
                /*
                 * An offchannel frame can be send only on the AUX queue, where
                 * there is no aggregation (and reordering) so it only is single
                 * skb is expected to be processed.
                 */
 -              WARN_ON(is_offchannel_skb && freed != 1);
 +              if (is_offchannel_skb && freed != 1)
 +                      IWL_ERR(priv, "OFFCHANNEL SKB freed %d\n", freed);
        }
  
 +      IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x)\n", txq_id,
 +                         iwl_get_tx_fail_reason(status), status);
 +
 +      IWL_DEBUG_TX_REPLY(priv,
 +                         "\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d seq_ctl=0x%x\n",
 +                         le32_to_cpu(tx_resp->rate_n_flags),
 +                         tx_resp->failure_frame, SEQ_TO_INDEX(sequence), ssn,
 +                         le16_to_cpu(tx_resp->seq_ctl));
 +
        iwl_check_abort_status(priv, tx_resp->frame_count, status);
        spin_unlock(&priv->sta_lock);
  
@@@ -436,7 -436,7 +436,7 @@@ static int iwl_pcie_rx_alloc(struct iwl
  err_rb_stts:
        dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
                          rxq->bd, rxq->bd_dma);
 -      memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
 +      rxq->bd_dma = 0;
        rxq->bd = NULL;
  err_bd:
        return -ENOMEM;
@@@ -455,10 -455,6 +455,10 @@@ static void iwl_pcie_rx_hw_init(struct 
  
        /* Stop Rx DMA */
        iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
 +      /* reset and flush pointers */
 +      iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0);
 +      iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0);
 +      iwl_write_direct32(trans, FH_RSCSR_CHNL0_RDPTR, 0);
  
        /* Reset driver's Rx queue write index */
        iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
@@@ -495,6 -491,7 +495,6 @@@ int iwl_pcie_rx_init(struct iwl_trans *
  {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
 -
        int i, err;
        unsigned long flags;
  
        rxq->read = rxq->write = 0;
        rxq->write_actual = 0;
        rxq->free_count = 0;
 +      memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
        spin_unlock_irqrestore(&rxq->lock, flags);
  
        iwl_pcie_rx_replenish(trans);
@@@ -549,15 -545,13 +549,15 @@@ void iwl_pcie_rx_free(struct iwl_trans 
                return;
        }
  
 +      cancel_work_sync(&trans_pcie->rx_replenish);
 +
        spin_lock_irqsave(&rxq->lock, flags);
        iwl_pcie_rxq_free_rbs(trans);
        spin_unlock_irqrestore(&rxq->lock, flags);
  
        dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
                          rxq->bd, rxq->bd_dma);
 -      memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
 +      rxq->bd_dma = 0;
        rxq->bd = NULL;
  
        if (rxq->rb_stts)
                                  rxq->rb_stts, rxq->rb_stts_dma);
        else
                IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
 -      memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
 +      rxq->rb_stts_dma = 0;
        rxq->rb_stts = NULL;
  }
  
@@@ -1172,6 -1166,7 +1172,7 @@@ static irqreturn_t iwl_pcie_isr(int irq
        else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
                 !trans_pcie->inta)
                iwl_enable_interrupts(trans);
+       return IRQ_HANDLED;
  
  none:
        /* re-enable interrupts here since we don't have anything to service. */
@@@ -519,8 -519,8 +519,8 @@@ static int mwifiex_send_domain_info_cmd
   *      - Set by user
   *      - Set bt Country IE
   */
 -static int mwifiex_reg_notifier(struct wiphy *wiphy,
 -                              struct regulatory_request *request)
 +static void mwifiex_reg_notifier(struct wiphy *wiphy,
 +                               struct regulatory_request *request)
  {
        struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
  
                break;
        }
        mwifiex_send_domain_info_cmd_fw(wiphy);
 -
 -      return 0;
  }
  
  /*
@@@ -1325,7 -1327,6 +1325,7 @@@ static int mwifiex_cfg80211_start_ap(st
        }
  
        mwifiex_set_ht_params(priv, bss_cfg, params);
 +      mwifiex_set_wmm_params(priv, bss_cfg, params);
  
        if (params->inactivity_timeout > 0) {
                /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */
@@@ -1458,7 -1459,7 +1458,7 @@@ mwifiex_cfg80211_assoc(struct mwifiex_p
        struct cfg80211_ssid req_ssid;
        int ret, auth_type = 0;
        struct cfg80211_bss *bss = NULL;
-       u8 is_scanning_required = 0, config_bands = 0;
+       u8 is_scanning_required = 0;
  
        memset(&req_ssid, 0, sizeof(struct cfg80211_ssid));
  
        /* disconnect before try to associate */
        mwifiex_deauthenticate(priv, NULL);
  
-       if (channel) {
-               if (mode == NL80211_IFTYPE_STATION) {
-                       if (channel->band == IEEE80211_BAND_2GHZ)
-                               config_bands = BAND_B | BAND_G | BAND_GN;
-                       else
-                               config_bands = BAND_A | BAND_AN;
-                       if (!((config_bands | priv->adapter->fw_bands) &
-                             ~priv->adapter->fw_bands))
-                               priv->adapter->config_bands = config_bands;
-               }
-       }
        /* As this is new association, clear locally stored
         * keys and security related flags */
        priv->sec_info.wpa_enabled = false;
@@@ -1706,9 -1694,9 +1693,9 @@@ static int mwifiex_set_ibss_params(stru
  
                if (cfg80211_get_chandef_type(&params->chandef) !=
                                                NL80211_CHAN_NO_HT)
-                       config_bands |= BAND_GN;
+                       config_bands |= BAND_G | BAND_GN;
        } else {
-               if (cfg80211_get_chandef_type(&params->chandef) !=
+               if (cfg80211_get_chandef_type(&params->chandef) ==
                                                NL80211_CHAN_NO_HT)
                        config_bands = BAND_A;
                else
@@@ -2260,7 -2248,6 +2247,7 @@@ int mwifiex_register_cfg80211(struct mw
        wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
        wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
                        WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
 +                      WIPHY_FLAG_AP_UAPSD |
                        WIPHY_FLAG_CUSTOM_REGULATORY |
                        WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
  
@@@ -39,20 -39,17 +39,20 @@@ static struct semaphore add_remove_card
  static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter);
  static int mwifiex_pcie_resume(struct pci_dev *pdev);
  
 -/*
 - * This function is called after skb allocation to update
 - * "skb->cb" with physical address of data pointer.
 - */
 -static phys_addr_t *mwifiex_update_sk_buff_pa(struct sk_buff *skb)
 +static int
 +mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
 +                     int size, int flags)
  {
 -      phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
 -
 -      *buf_pa = (phys_addr_t)virt_to_phys(skb->data);
 +      struct pcie_service_card *card = adapter->card;
 +      dma_addr_t buf_pa;
  
 -      return buf_pa;
 +      buf_pa = pci_map_single(card->dev, skb->data, size, flags);
 +      if (pci_dma_mapping_error(card->dev, buf_pa)) {
 +              dev_err(adapter->dev, "failed to map pci memory!\n");
 +              return -1;
 +      }
 +      memcpy(skb->cb, &buf_pa, sizeof(dma_addr_t));
 +      return 0;
  }
  
  /*
@@@ -63,8 -60,8 +63,8 @@@ static bool mwifiex_pcie_ok_to_access_h
        u32 *cookie_addr;
        struct pcie_service_card *card = adapter->card;
  
 -      if (card->sleep_cookie) {
 -              cookie_addr = (u32 *)card->sleep_cookie->data;
 +      if (card->sleep_cookie_vbase) {
 +              cookie_addr = (u32 *)card->sleep_cookie_vbase;
                dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n",
                        *cookie_addr);
                if (*cookie_addr == FW_AWAKE_COOKIE)
@@@ -164,7 -161,7 +164,7 @@@ static int mwifiex_pcie_suspend(struct 
  
        if (pdev) {
                card = (struct pcie_service_card *) pci_get_drvdata(pdev);
-               if (!card || card->adapter) {
+               if (!card || !card->adapter) {
                        pr_err("Card or adapter structure is not valid\n");
                        return 0;
                }
@@@ -369,7 -366,9 +369,7 @@@ static int mwifiex_pcie_enable_host_int
  static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
  {
        struct pcie_service_card *card = adapter->card;
 -      struct sk_buff *skb;
        int i;
 -      phys_addr_t *buf_pa;
  
        /*
         * driver maintaines the write pointer and firmware maintaines the read
                                                        MWIFIEX_MAX_TXRX_BD;
        dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n",
                card->txbd_ring_size);
 -      card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL);
 +      card->txbd_ring_vbase = pci_alloc_consistent(card->dev,
 +                                                   card->txbd_ring_size,
 +                                                   &card->txbd_ring_pbase);
        if (!card->txbd_ring_vbase) {
 -              dev_err(adapter->dev, "Unable to alloc buffer for txbd ring\n");
 +              dev_err(adapter->dev,
 +                      "allocate consistent memory (%d bytes) failed!\n",
 +                      card->txbd_ring_size);
                return -ENOMEM;
        }
 -      card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase);
 -
        dev_dbg(adapter->dev,
                "info: txbd_ring - base: %p, pbase: %#x:%x, len: %x\n",
 -              card->txbd_ring_vbase, (u32)card->txbd_ring_pbase,
 +              card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase,
                (u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size);
  
        for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
                                      (sizeof(struct mwifiex_pcie_buf_desc)
                                       * i));
  
 -              /* Allocate buffer here so that firmware can DMA data from it */
 -              skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
 -              if (!skb) {
 -                      dev_err(adapter->dev, "Unable to allocate skb for TX ring.\n");
 -                      kfree(card->txbd_ring_vbase);
 -                      return -ENOMEM;
 -              }
 -              buf_pa = mwifiex_update_sk_buff_pa(skb);
 -
 -              skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
 -              dev_dbg(adapter->dev, "info: TX ring: add new skb base: %p, "
 -                      "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
 -                      skb, skb->data, (u32)*buf_pa,
 -                      (u32)(((u64)*buf_pa >> 32)), skb->len);
 -
 -              card->tx_buf_list[i] = skb;
 -              card->txbd_ring[i]->paddr = *buf_pa;
 -              card->txbd_ring[i]->len = (u16)skb->len;
 +              card->tx_buf_list[i] = NULL;
 +              card->txbd_ring[i]->paddr = 0;
 +              card->txbd_ring[i]->len = 0;
                card->txbd_ring[i]->flags = 0;
        }
  
  static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
  {
        struct pcie_service_card *card = adapter->card;
 +      struct sk_buff *skb;
        int i;
  
        for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
 -              if (card->tx_buf_list[i])
 -                      dev_kfree_skb_any(card->tx_buf_list[i]);
 +              if (card->tx_buf_list[i]) {
 +                      skb = card->tx_buf_list[i];
 +                      pci_unmap_single(card->dev, card->txbd_ring[i]->paddr,
 +                                       skb->len, PCI_DMA_TODEVICE);
 +                      dev_kfree_skb_any(skb);
 +              }
                card->tx_buf_list[i] = NULL;
                card->txbd_ring[i]->paddr = 0;
                card->txbd_ring[i]->len = 0;
                card->txbd_ring[i] = NULL;
        }
  
 -      kfree(card->txbd_ring_vbase);
 +      if (card->txbd_ring_vbase)
 +              pci_free_consistent(card->dev, card->txbd_ring_size,
 +                                  card->txbd_ring_vbase,
 +                                  card->txbd_ring_pbase);
        card->txbd_ring_size = 0;
        card->txbd_wrptr = 0;
        card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
        card->txbd_ring_vbase = NULL;
 +      card->txbd_ring_pbase = 0;
  
        return 0;
  }
@@@ -455,7 -458,7 +455,7 @@@ static int mwifiex_pcie_create_rxbd_rin
        struct pcie_service_card *card = adapter->card;
        struct sk_buff *skb;
        int i;
 -      phys_addr_t *buf_pa;
 +      dma_addr_t buf_pa;
  
        /*
         * driver maintaines the read pointer and firmware maintaines the write
                                                        MWIFIEX_MAX_TXRX_BD;
        dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n",
                card->rxbd_ring_size);
 -      card->rxbd_ring_vbase = kzalloc(card->rxbd_ring_size, GFP_KERNEL);
 +      card->rxbd_ring_vbase = pci_alloc_consistent(card->dev,
 +                                                   card->rxbd_ring_size,
 +                                                   &card->rxbd_ring_pbase);
        if (!card->rxbd_ring_vbase) {
 -              dev_err(adapter->dev, "Unable to allocate buffer for "
 -                              "rxbd_ring.\n");
 +              dev_err(adapter->dev,
 +                      "allocate consistent memory (%d bytes) failed!\n",
 +                      card->rxbd_ring_size);
                return -ENOMEM;
        }
 -      card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase);
  
        dev_dbg(adapter->dev,
                "info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
                        kfree(card->rxbd_ring_vbase);
                        return -ENOMEM;
                }
 -              buf_pa = mwifiex_update_sk_buff_pa(skb);
 -              skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
 +              if (mwifiex_map_pci_memory(adapter, skb,
 +                                         MWIFIEX_RX_DATA_BUF_SIZE,
 +                                         PCI_DMA_FROMDEVICE))
 +                      return -1;
 +
 +              MWIFIEX_SKB_PACB(skb, &buf_pa);
  
                dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, "
                        "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
 -                      skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
 +                      skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32),
                        skb->len);
  
                card->rx_buf_list[i] = skb;
 -              card->rxbd_ring[i]->paddr = *buf_pa;
 +              card->rxbd_ring[i]->paddr = buf_pa;
                card->rxbd_ring[i]->len = (u16)skb->len;
                card->rxbd_ring[i]->flags = 0;
        }
  static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
  {
        struct pcie_service_card *card = adapter->card;
 +      struct sk_buff *skb;
        int i;
  
        for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
 -              if (card->rx_buf_list[i])
 -                      dev_kfree_skb_any(card->rx_buf_list[i]);
 +              if (card->rx_buf_list[i]) {
 +                      skb = card->rx_buf_list[i];
 +                      pci_unmap_single(card->dev, card->rxbd_ring[i]->paddr ,
 +                                       MWIFIEX_RX_DATA_BUF_SIZE,
 +                                       PCI_DMA_FROMDEVICE);
 +                      dev_kfree_skb_any(skb);
 +              }
                card->rx_buf_list[i] = NULL;
                card->rxbd_ring[i]->paddr = 0;
                card->rxbd_ring[i]->len = 0;
                card->rxbd_ring[i] = NULL;
        }
  
 -      kfree(card->rxbd_ring_vbase);
 +      if (card->rxbd_ring_vbase)
 +              pci_free_consistent(card->dev, card->rxbd_ring_size,
 +                                  card->rxbd_ring_vbase,
 +                                  card->rxbd_ring_pbase);
        card->rxbd_ring_size = 0;
        card->rxbd_wrptr = 0;
        card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
        card->rxbd_ring_vbase = NULL;
 +      card->rxbd_ring_pbase = 0;
  
        return 0;
  }
@@@ -565,7 -552,7 +565,7 @@@ static int mwifiex_pcie_create_evtbd_ri
        struct pcie_service_card *card = adapter->card;
        struct sk_buff *skb;
        int i;
 -      phys_addr_t *buf_pa;
 +      dma_addr_t buf_pa;
  
        /*
         * driver maintaines the read pointer and firmware maintaines the write
                                                        MWIFIEX_MAX_EVT_BD;
        dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n",
                card->evtbd_ring_size);
 -      card->evtbd_ring_vbase = kzalloc(card->evtbd_ring_size, GFP_KERNEL);
 +      card->evtbd_ring_vbase = pci_alloc_consistent(card->dev,
 +                                                    card->evtbd_ring_size,
 +                                                    &card->evtbd_ring_pbase);
        if (!card->evtbd_ring_vbase) {
                dev_err(adapter->dev,
 -                      "Unable to allocate buffer. Terminating download\n");
 +                      "allocate consistent memory (%d bytes) failed!\n",
 +                      card->evtbd_ring_size);
                return -ENOMEM;
        }
 -      card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase);
  
        dev_dbg(adapter->dev,
                "info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n",
                        kfree(card->evtbd_ring_vbase);
                        return -ENOMEM;
                }
 -              buf_pa = mwifiex_update_sk_buff_pa(skb);
                skb_put(skb, MAX_EVENT_SIZE);
  
 +              if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE,
 +                                         PCI_DMA_FROMDEVICE))
 +                      return -1;
 +
 +              MWIFIEX_SKB_PACB(skb, &buf_pa);
                dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, "
                        "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
 -                      skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
 +                      skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32),
                        skb->len);
  
                card->evt_buf_list[i] = skb;
 -              card->evtbd_ring[i]->paddr = *buf_pa;
 +              card->evtbd_ring[i]->paddr = buf_pa;
                card->evtbd_ring[i]->len = (u16)skb->len;
                card->evtbd_ring[i]->flags = 0;
        }
  static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
  {
        struct pcie_service_card *card = adapter->card;
 +      struct sk_buff *skb;
        int i;
  
        for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
 -              if (card->evt_buf_list[i])
 -                      dev_kfree_skb_any(card->evt_buf_list[i]);
 +              if (card->evt_buf_list[i]) {
 +                      skb = card->evt_buf_list[i];
 +                      pci_unmap_single(card->dev, card->evtbd_ring[i]->paddr,
 +                                       MAX_EVENT_SIZE, PCI_DMA_FROMDEVICE);
 +                      dev_kfree_skb_any(skb);
 +              }
                card->evt_buf_list[i] = NULL;
                card->evtbd_ring[i]->paddr = 0;
                card->evtbd_ring[i]->len = 0;
                card->evtbd_ring[i] = NULL;
        }
  
 -      kfree(card->evtbd_ring_vbase);
 +      if (card->evtbd_ring_vbase)
 +              pci_free_consistent(card->dev, card->evtbd_ring_size,
 +                                  card->evtbd_ring_vbase,
 +                                  card->evtbd_ring_pbase);
        card->evtbd_wrptr = 0;
        card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
        card->evtbd_ring_size = 0;
        card->evtbd_ring_vbase = NULL;
 +      card->evtbd_ring_pbase = 0;
  
        return 0;
  }
@@@ -681,12 -653,21 +681,12 @@@ static int mwifiex_pcie_alloc_cmdrsp_bu
                        "Unable to allocate skb for command response data.\n");
                return -ENOMEM;
        }
 -      mwifiex_update_sk_buff_pa(skb);
        skb_put(skb, MWIFIEX_UPLD_SIZE);
 -      card->cmdrsp_buf = skb;
 +      if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
 +                                 PCI_DMA_FROMDEVICE))
 +              return -1;
  
 -      skb = NULL;
 -      /* Allocate memory for sending command to firmware */
 -      skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
 -      if (!skb) {
 -              dev_err(adapter->dev,
 -                      "Unable to allocate skb for command data.\n");
 -              return -ENOMEM;
 -      }
 -      mwifiex_update_sk_buff_pa(skb);
 -      skb_put(skb, MWIFIEX_SIZE_OF_CMD_BUFFER);
 -      card->cmd_buf = skb;
 +      card->cmdrsp_buf = skb;
  
        return 0;
  }
  static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
  {
        struct pcie_service_card *card;
 +      dma_addr_t buf_pa;
  
        if (!adapter)
                return 0;
  
        card = adapter->card;
  
 -      if (card && card->cmdrsp_buf)
 +      if (card && card->cmdrsp_buf) {
 +              MWIFIEX_SKB_PACB(card->cmdrsp_buf, &buf_pa);
 +              pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
 +                               PCI_DMA_FROMDEVICE);
                dev_kfree_skb_any(card->cmdrsp_buf);
 +      }
  
 -      if (card && card->cmd_buf)
 +      if (card && card->cmd_buf) {
 +              MWIFIEX_SKB_PACB(card->cmd_buf, &buf_pa);
 +              pci_unmap_single(card->dev, buf_pa, MWIFIEX_SIZE_OF_CMD_BUFFER,
 +                               PCI_DMA_TODEVICE);
                dev_kfree_skb_any(card->cmd_buf);
 -
 +      }
        return 0;
  }
  
   */
  static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
  {
 -      struct sk_buff *skb;
        struct pcie_service_card *card = adapter->card;
  
 -      /* Allocate memory for sleep cookie */
 -      skb = dev_alloc_skb(sizeof(u32));
 -      if (!skb) {
 -              dev_err(adapter->dev,
 -                      "Unable to allocate skb for sleep cookie!\n");
 +      card->sleep_cookie_vbase = pci_alloc_consistent(card->dev, sizeof(u32),
 +                                                   &card->sleep_cookie_pbase);
 +      if (!card->sleep_cookie_vbase) {
 +              dev_err(adapter->dev, "pci_alloc_consistent failed!\n");
                return -ENOMEM;
        }
 -      mwifiex_update_sk_buff_pa(skb);
 -      skb_put(skb, sizeof(u32));
 -
        /* Init val of Sleep Cookie */
 -      *(u32 *)skb->data = FW_AWAKE_COOKIE;
 +      *(u32 *)card->sleep_cookie_vbase = FW_AWAKE_COOKIE;
  
        dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n",
 -              *((u32 *)skb->data));
 -
 -      /* Save the sleep cookie */
 -      card->sleep_cookie = skb;
 +              *((u32 *)card->sleep_cookie_vbase));
  
        return 0;
  }
@@@ -754,57 -735,24 +754,57 @@@ static int mwifiex_pcie_delete_sleep_co
  
        card = adapter->card;
  
 -      if (card && card->sleep_cookie) {
 -              dev_kfree_skb_any(card->sleep_cookie);
 -              card->sleep_cookie = NULL;
 +      if (card && card->sleep_cookie_vbase) {
 +              pci_free_consistent(card->dev, sizeof(u32),
 +                                  card->sleep_cookie_vbase,
 +                                  card->sleep_cookie_pbase);
 +              card->sleep_cookie_vbase = NULL;
        }
  
        return 0;
  }
  
 +/* This function flushes the TX buffer descriptor ring
 + * This function defined as handler is also called while cleaning TXRX
 + * during disconnect/ bss stop.
 + */
 +static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
 +{
 +      struct pcie_service_card *card = adapter->card;
 +      u32 rdptr;
 +
 +      /* Read the TX ring read pointer set by firmware */
 +      if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
 +              dev_err(adapter->dev,
 +                      "Flush TXBD: failed to read REG_TXBD_RDPTR\n");
 +              return -1;
 +      }
 +
 +      if (!mwifiex_pcie_txbd_empty(card, rdptr)) {
 +              card->txbd_flush = 1;
 +              /* write pointer already set at last send
 +               * send dnld-rdy intr again, wait for completion.
 +               */
 +              if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
 +                                    CPU_INTR_DNLD_RDY)) {
 +                      dev_err(adapter->dev,
 +                              "failed to assert dnld-rdy interrupt.\n");
 +                      return -1;
 +              }
 +      }
 +      return 0;
 +}
 +
  /*
 - * This function sends data buffer to device
 + * This function unmaps and frees downloaded data buffer
   */
 -static int
 -mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 +static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
  {
 +      const u32 num_tx_buffs = MWIFIEX_MAX_TXRX_BD;
 +      struct sk_buff *skb;
 +      dma_addr_t buf_pa;
 +      u32 wrdoneidx, rdptr, unmap_count = 0;
        struct pcie_service_card *card = adapter->card;
 -      u32 wrindx, rdptr;
 -      phys_addr_t *buf_pa;
 -      __le16 *tmp;
  
        if (!mwifiex_pcie_ok_to_access_hw(adapter))
                mwifiex_pm_wakeup_card(adapter);
        /* Read the TX ring read pointer set by firmware */
        if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
                dev_err(adapter->dev,
 -                      "SEND DATA: failed to read REG_TXBD_RDPTR\n");
 +                      "SEND COMP: failed to read REG_TXBD_RDPTR\n");
                return -1;
        }
  
 -      wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
 +      dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
 +              card->txbd_rdptr, rdptr);
  
 -      dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr,
 -              card->txbd_wrptr);
 -      if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) !=
 -                      (rdptr & MWIFIEX_TXBD_MASK)) ||
 -          ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
 -                      (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
 -              struct sk_buff *skb_data;
 +      /* free from previous txbd_rdptr to current txbd_rdptr */
 +      while (((card->txbd_rdptr & MWIFIEX_TXBD_MASK) !=
 +              (rdptr & MWIFIEX_TXBD_MASK)) ||
 +             ((card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
 +              (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
 +              wrdoneidx = card->txbd_rdptr & MWIFIEX_TXBD_MASK;
 +
 +              skb = card->tx_buf_list[wrdoneidx];
 +              if (skb) {
 +                      dev_dbg(adapter->dev,
 +                              "SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
 +                              skb, wrdoneidx);
 +                      MWIFIEX_SKB_PACB(skb, &buf_pa);
 +                      pci_unmap_single(card->dev, buf_pa, skb->len,
 +                                       PCI_DMA_TODEVICE);
 +
 +                      unmap_count++;
 +
 +                      if (card->txbd_flush)
 +                              mwifiex_write_data_complete(adapter, skb, 0,
 +                                                          -1);
 +                      else
 +                              mwifiex_write_data_complete(adapter, skb, 0, 0);
 +              }
 +
 +              card->tx_buf_list[wrdoneidx] = NULL;
 +              card->txbd_ring[wrdoneidx]->paddr = 0;
 +              card->rxbd_ring[wrdoneidx]->len = 0;
 +              card->rxbd_ring[wrdoneidx]->flags = 0;
 +              card->txbd_rdptr++;
 +
 +              if ((card->txbd_rdptr & MWIFIEX_TXBD_MASK) == num_tx_buffs)
 +                      card->txbd_rdptr = ((card->txbd_rdptr &
 +                                          MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
 +                                          MWIFIEX_BD_FLAG_ROLLOVER_IND);
 +      }
 +
 +      if (unmap_count)
 +              adapter->data_sent = false;
 +
 +      if (card->txbd_flush) {
 +              if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
 +                   (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) &&
 +                  ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
 +                   (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND)))
 +                      card->txbd_flush = 0;
 +              else
 +                      mwifiex_clean_pcie_ring_buf(adapter);
 +      }
 +
 +      return 0;
 +}
 +
 +/* This function sends data buffer to device. First 4 bytes of payload
 + * are filled with payload length and payload type. Then this payload
 + * is mapped to PCI device memory. Tx ring pointers are advanced accordingly.
 + * Download ready interrupt to FW is deffered if Tx ring is not full and
 + * additional payload can be accomodated.
 + */
 +static int
 +mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
 +                     struct mwifiex_tx_param *tx_param)
 +{
 +      struct pcie_service_card *card = adapter->card;
 +      u32 wrindx;
 +      int ret;
 +      dma_addr_t buf_pa;
 +      __le16 *tmp;
 +
 +      if (!(skb->data && skb->len)) {
 +              dev_err(adapter->dev, "%s(): invalid parameter <%p, %#x>\n",
 +                      __func__, skb->data, skb->len);
 +              return -1;
 +      }
 +
 +      if (!mwifiex_pcie_ok_to_access_hw(adapter))
 +              mwifiex_pm_wakeup_card(adapter);
 +
 +      dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
 +              card->txbd_rdptr, card->txbd_wrptr);
 +      if (mwifiex_pcie_txbd_not_full(card)) {
                u8 *payload;
  
                adapter->data_sent = true;
 -              skb_data = card->tx_buf_list[wrindx];
 -              memcpy(skb_data->data, skb->data, skb->len);
 -              payload = skb_data->data;
 +              payload = skb->data;
                tmp = (__le16 *)&payload[0];
                *tmp = cpu_to_le16((u16)skb->len);
                tmp = (__le16 *)&payload[2];
                *tmp = cpu_to_le16(MWIFIEX_TYPE_DATA);
 -              skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len);
 -              skb_trim(skb_data, skb->len);
 -              buf_pa = MWIFIEX_SKB_PACB(skb_data);
 -              card->txbd_ring[wrindx]->paddr = *buf_pa;
 -              card->txbd_ring[wrindx]->len = (u16)skb_data->len;
 +
 +              if (mwifiex_map_pci_memory(adapter, skb, skb->len ,
 +                                         PCI_DMA_TODEVICE))
 +                      return -1;
 +
 +              wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
 +              MWIFIEX_SKB_PACB(skb, &buf_pa);
 +              card->tx_buf_list[wrindx] = skb;
 +              card->txbd_ring[wrindx]->paddr = buf_pa;
 +              card->txbd_ring[wrindx]->len = (u16)skb->len;
                card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
                                                MWIFIEX_BD_FLAG_LAST_DESC;
  
                                      card->txbd_wrptr)) {
                        dev_err(adapter->dev,
                                "SEND DATA: failed to write REG_TXBD_WRPTR\n");
 -                      return 0;
 +                      ret = -1;
 +                      goto done_unmap;
                }
 -
 -              /* Send the TX ready interrupt */
 -              if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
 -                                    CPU_INTR_DNLD_RDY)) {
 -                      dev_err(adapter->dev,
 -                              "SEND DATA: failed to assert door-bell intr\n");
 -                      return -1;
 +              if ((mwifiex_pcie_txbd_not_full(card)) &&
 +                  tx_param->next_pkt_len) {
 +                      /* have more packets and TxBD still can hold more */
 +                      dev_dbg(adapter->dev,
 +                              "SEND DATA: delay dnld-rdy interrupt.\n");
 +                      adapter->data_sent = false;
 +              } else {
 +                      /* Send the TX ready interrupt */
 +                      if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
 +                                            CPU_INTR_DNLD_RDY)) {
 +                              dev_err(adapter->dev,
 +                                      "SEND DATA: failed to assert dnld-rdy interrupt.\n");
 +                              ret = -1;
 +                              goto done_unmap;
 +                      }
                }
                dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: "
                        "%#x> and sent packet to firmware successfully\n",
 -                      rdptr, card->txbd_wrptr);
 +                      card->txbd_rdptr, card->txbd_wrptr);
        } else {
                dev_dbg(adapter->dev,
                        "info: TX Ring full, can't send packets to fw\n");
                return -EBUSY;
        }
  
 -      return 0;
 +      return -EINPROGRESS;
 +done_unmap:
 +      MWIFIEX_SKB_PACB(skb, &buf_pa);
 +      pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE);
 +      card->tx_buf_list[wrindx] = NULL;
 +      card->txbd_ring[wrindx]->paddr = 0;
 +      card->txbd_ring[wrindx]->len = 0;
 +      card->txbd_ring[wrindx]->flags = 0;
 +      return ret;
  }
  
  /*
@@@ -985,13 -838,9 +985,13 @@@ static int mwifiex_pcie_process_recv_da
  {
        struct pcie_service_card *card = adapter->card;
        u32 wrptr, rd_index;
 +      dma_addr_t buf_pa;
        int ret = 0;
        struct sk_buff *skb_tmp = NULL;
  
 +      if (!mwifiex_pcie_ok_to_access_hw(adapter))
 +              mwifiex_pm_wakeup_card(adapter);
 +
        /* Read the RX ring Write pointer set by firmware */
        if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
                dev_err(adapter->dev,
                ret = -1;
                goto done;
        }
 +      card->rxbd_wrptr = wrptr;
  
        while (((wrptr & MWIFIEX_RXBD_MASK) !=
                (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) ||
                (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
                struct sk_buff *skb_data;
                u16 rx_len;
 +              __le16 pkt_len;
  
                rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK;
                skb_data = card->rx_buf_list[rd_index];
  
 +              MWIFIEX_SKB_PACB(skb_data, &buf_pa);
 +              pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE,
 +                               PCI_DMA_FROMDEVICE);
 +              card->rx_buf_list[rd_index] = NULL;
 +
                /* Get data length from interface header -
 -                 first byte is len, second byte is type */
 -              rx_len = *((u16 *)skb_data->data);
 +               * first 2 bytes for len, next 2 bytes is for type
 +               */
 +              pkt_len = *((__le16 *)skb_data->data);
 +              rx_len = le16_to_cpu(pkt_len);
 +              skb_put(skb_data, rx_len);
                dev_dbg(adapter->dev,
                        "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
                        card->rxbd_rdptr, wrptr, rx_len);
 -              skb_tmp = dev_alloc_skb(rx_len);
 +              skb_pull(skb_data, INTF_HEADER_LEN);
 +              mwifiex_handle_rx_packet(adapter, skb_data);
 +
 +              skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
                if (!skb_tmp) {
 -                      dev_dbg(adapter->dev,
 -                              "info: Failed to alloc skb for RX\n");
 -                      ret = -EBUSY;
 -                      goto done;
 +                      dev_err(adapter->dev,
 +                              "Unable to allocate skb.\n");
 +                      return -ENOMEM;
                }
  
 -              skb_put(skb_tmp, rx_len);
 +              if (mwifiex_map_pci_memory(adapter, skb_tmp,
 +                                         MWIFIEX_RX_DATA_BUF_SIZE,
 +                                         PCI_DMA_FROMDEVICE))
 +                      return -1;
 +
 +              MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
 +
 +              dev_dbg(adapter->dev,
 +                      "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
 +                      skb_tmp, rd_index);
 +              card->rx_buf_list[rd_index] = skb_tmp;
 +              card->rxbd_ring[rd_index]->paddr = buf_pa;
 +              card->rxbd_ring[rd_index]->len = skb_tmp->len;
 +              card->rxbd_ring[rd_index]->flags = 0;
  
 -              memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len);
                if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) ==
                                                        MWIFIEX_MAX_TXRX_BD) {
                        card->rxbd_rdptr = ((card->rxbd_rdptr &
                }
                dev_dbg(adapter->dev,
                        "info: RECV DATA: Rcvd packet from fw successfully\n");
 -              mwifiex_handle_rx_packet(adapter, skb_tmp);
 +              card->rxbd_wrptr = wrptr;
        }
  
  done:
 -      if (ret && skb_tmp)
 -              dev_kfree_skb_any(skb_tmp);
        return ret;
  }
  
  static int
  mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
  {
 -      phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
 +      dma_addr_t buf_pa;
 +      struct pcie_service_card *card = adapter->card;
  
 -      if (!(skb->data && skb->len && *buf_pa)) {
 +      if (!(skb->data && skb->len)) {
                dev_err(adapter->dev,
 -                      "Invalid parameter in %s <%p, %#x:%x, %x>\n",
 -                      __func__, skb->data, skb->len,
 -                      (u32)*buf_pa, (u32)((u64)*buf_pa >> 32));
 +                      "Invalid parameter in %s <%p. len %d>\n",
 +                      __func__, skb->data, skb->len);
                return -1;
        }
  
 +      if (mwifiex_map_pci_memory(adapter, skb, skb->len , PCI_DMA_TODEVICE))
 +              return -1;
 +
 +      MWIFIEX_SKB_PACB(skb, &buf_pa);
 +
        /* Write the lower 32bits of the physical address to scratch
         * register 0 */
 -      if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)*buf_pa)) {
 +      if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)buf_pa)) {
                dev_err(adapter->dev,
                        "%s: failed to write download command to boot code.\n",
                        __func__);
 +              pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
 +                               PCI_DMA_TODEVICE);
                return -1;
        }
  
        /* Write the upper 32bits of the physical address to scratch
         * register 1 */
        if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG,
 -                            (u32)((u64)*buf_pa >> 32))) {
 +                            (u32)((u64)buf_pa >> 32))) {
                dev_err(adapter->dev,
                        "%s: failed to write download command to boot code.\n",
                        __func__);
 +              pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
 +                               PCI_DMA_TODEVICE);
                return -1;
        }
  
                dev_err(adapter->dev,
                        "%s: failed to write command len to scratch reg 2\n",
                        __func__);
 +              pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
 +                               PCI_DMA_TODEVICE);
                return -1;
        }
  
                              CPU_INTR_DOOR_BELL)) {
                dev_err(adapter->dev,
                        "%s: failed to assert door-bell intr\n", __func__);
 +              pci_unmap_single(card->dev, buf_pa,
 +                               MWIFIEX_UPLD_SIZE, PCI_DMA_TODEVICE);
                return -1;
        }
  
        return 0;
  }
  
 -/*
 - * This function downloads commands to the device
 +/* This function init rx port in firmware which in turn enables to receive data
 + * from device before transmitting any packet.
 + */
 +static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
 +{
 +      struct pcie_service_card *card = adapter->card;
 +
 +      /* Write the RX ring read pointer in to REG_RXBD_RDPTR */
 +      if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, card->rxbd_rdptr | 0)) {
 +              dev_err(adapter->dev,
 +                      "RECV DATA: failed to write REG_RXBD_RDPTR\n");
 +              return -1;
 +      }
 +      return 0;
 +}
 +
 +/* This function downloads commands to the device
   */
  static int
  mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
  {
        struct pcie_service_card *card = adapter->card;
        int ret = 0;
 -      phys_addr_t *cmd_buf_pa;
 -      phys_addr_t *cmdrsp_buf_pa;
 +      dma_addr_t cmd_buf_pa, cmdrsp_buf_pa;
 +      u8 *payload = (u8 *)skb->data;
  
        if (!(skb->data && skb->len)) {
                dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n",
                return -EBUSY;
        }
  
 -      /* Make sure a command buffer is available */
 -      if (!card->cmd_buf) {
 -              dev_err(adapter->dev, "Command buffer not available\n");
 -              return -EBUSY;
 -      }
 +      if (!mwifiex_pcie_ok_to_access_hw(adapter))
 +              mwifiex_pm_wakeup_card(adapter);
  
        adapter->cmd_sent = true;
 -      /* Copy the given skb in to DMA accessable shared buffer */
 -      skb_put(card->cmd_buf, MWIFIEX_SIZE_OF_CMD_BUFFER - card->cmd_buf->len);
 -      skb_trim(card->cmd_buf, skb->len);
 -      memcpy(card->cmd_buf->data, skb->data, skb->len);
 +
 +      *(__le16 *)&payload[0] = cpu_to_le16((u16)skb->len);
 +      *(__le16 *)&payload[2] = cpu_to_le16(MWIFIEX_TYPE_CMD);
 +
 +      if (mwifiex_map_pci_memory(adapter, skb, skb->len, PCI_DMA_TODEVICE))
 +              return -1;
 +
 +      card->cmd_buf = skb;
  
        /* To send a command, the driver will:
                1. Write the 64bit physical address of the data buffer to
        */
  
        if (card->cmdrsp_buf) {
 -              cmdrsp_buf_pa = MWIFIEX_SKB_PACB(card->cmdrsp_buf);
 +              MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa);
                /* Write the lower 32bits of the cmdrsp buffer physical
                   address */
                if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO,
 -                                    (u32)*cmdrsp_buf_pa)) {
 +                                    (u32)cmdrsp_buf_pa)) {
                        dev_err(adapter->dev,
                                "Failed to write download cmd to boot code.\n");
                        ret = -1;
                /* Write the upper 32bits of the cmdrsp buffer physical
                   address */
                if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI,
 -                                    (u32)((u64)*cmdrsp_buf_pa >> 32))) {
 +                                    (u32)((u64)cmdrsp_buf_pa >> 32))) {
                        dev_err(adapter->dev,
                                "Failed to write download cmd to boot code.\n");
                        ret = -1;
                }
        }
  
 -      cmd_buf_pa = MWIFIEX_SKB_PACB(card->cmd_buf);
 +      MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa);
        /* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */
 -      if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)*cmd_buf_pa)) {
 +      if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)cmd_buf_pa)) {
                dev_err(adapter->dev,
                        "Failed to write download cmd to boot code.\n");
                ret = -1;
        }
        /* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */
        if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI,
 -                            (u32)((u64)*cmd_buf_pa >> 32))) {
 +                            (u32)((u64)cmd_buf_pa >> 32))) {
                dev_err(adapter->dev,
                        "Failed to write download cmd to boot code.\n");
                ret = -1;
@@@ -1285,22 -1083,11 +1285,22 @@@ static int mwifiex_pcie_process_cmd_com
        struct pcie_service_card *card = adapter->card;
        struct sk_buff *skb = card->cmdrsp_buf;
        int count = 0;
 +      u16 rx_len;
 +      __le16 pkt_len;
 +      dma_addr_t buf_pa;
  
        dev_dbg(adapter->dev, "info: Rx CMD Response\n");
  
 +      MWIFIEX_SKB_PACB(skb, &buf_pa);
 +      pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
 +                       PCI_DMA_FROMDEVICE);
 +
 +      pkt_len = *((__le16 *)skb->data);
 +      rx_len = le16_to_cpu(pkt_len);
 +      skb_trim(skb, rx_len);
 +      skb_pull(skb, INTF_HEADER_LEN);
 +
        if (!adapter->curr_cmd) {
 -              skb_pull(skb, INTF_HEADER_LEN);
                if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
                        mwifiex_process_sleep_confirm_resp(adapter, skb->data,
                                                           skb->len);
                }
                memcpy(adapter->upld_buf, skb->data,
                       min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
 -              skb_push(skb, INTF_HEADER_LEN);
 +              if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
 +                                         PCI_DMA_FROMDEVICE))
 +                      return -1;
 +
 +              MWIFIEX_SKB_PACB(skb, &buf_pa);
        } else if (mwifiex_pcie_ok_to_access_hw(adapter)) {
 -              skb_pull(skb, INTF_HEADER_LEN);
                adapter->curr_cmd->resp_skb = skb;
                adapter->cmd_resp_received = true;
                /* Take the pointer and set it to CMD node and will
@@@ -1352,23 -1136,10 +1352,23 @@@ static int mwifiex_pcie_cmdrsp_complete
                                        struct sk_buff *skb)
  {
        struct pcie_service_card *card = adapter->card;
 +      dma_addr_t buf_pa;
 +      struct sk_buff *skb_tmp;
  
        if (skb) {
                card->cmdrsp_buf = skb;
                skb_push(card->cmdrsp_buf, INTF_HEADER_LEN);
 +              if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
 +                                         PCI_DMA_FROMDEVICE))
 +                      return -1;
 +      }
 +
 +      skb_tmp = card->cmd_buf;
 +      if (skb_tmp) {
 +              MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
 +              pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
 +                               PCI_DMA_FROMDEVICE);
 +              card->cmd_buf = NULL;
        }
  
        return 0;
@@@ -1382,10 -1153,6 +1382,10 @@@ static int mwifiex_pcie_process_event_r
        struct pcie_service_card *card = adapter->card;
        u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
        u32 wrptr, event;
 +      dma_addr_t buf_pa;
 +
 +      if (!mwifiex_pcie_ok_to_access_hw(adapter))
 +              mwifiex_pm_wakeup_card(adapter);
  
        if (adapter->event_received) {
                dev_dbg(adapter->dev, "info: Event being processed, "
  
                dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr);
                skb_cmd = card->evt_buf_list[rdptr];
 +              MWIFIEX_SKB_PACB(skb_cmd, &buf_pa);
 +              pci_unmap_single(card->dev, buf_pa, MAX_EVENT_SIZE,
 +                               PCI_DMA_FROMDEVICE);
 +
                /* Take the pointer and set it to event pointer in adapter
                   and will return back after event handling callback */
                card->evt_buf_list[rdptr] = NULL;
@@@ -1465,7 -1228,7 +1465,7 @@@ static int mwifiex_pcie_event_complete(
        int ret = 0;
        u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
        u32 wrptr;
 -      phys_addr_t *buf_pa;
 +      dma_addr_t buf_pa;
  
        if (!skb)
                return 0;
  
        if (!card->evt_buf_list[rdptr]) {
                skb_push(skb, INTF_HEADER_LEN);
 +              if (mwifiex_map_pci_memory(adapter, skb,
 +                                         MAX_EVENT_SIZE,
 +                                         PCI_DMA_FROMDEVICE))
 +                      return -1;
 +              MWIFIEX_SKB_PACB(skb, &buf_pa);
                card->evt_buf_list[rdptr] = skb;
 -              buf_pa = MWIFIEX_SKB_PACB(skb);
 -              card->evtbd_ring[rdptr]->paddr = *buf_pa;
 +              MWIFIEX_SKB_PACB(skb, &buf_pa);
 +              card->evtbd_ring[rdptr]->paddr = buf_pa;
                card->evtbd_ring[rdptr]->len = (u16)skb->len;
                card->evtbd_ring[rdptr]->flags = 0;
                skb = NULL;
@@@ -1541,8 -1299,11 +1541,8 @@@ static int mwifiex_prog_fw_w_helper(str
        struct sk_buff *skb;
        u32 txlen, tx_blocks = 0, tries, len;
        u32 block_retry_cnt = 0;
 -
 -      if (!adapter) {
 -              pr_err("adapter structure is not valid\n");
 -              return -1;
 -      }
 +      dma_addr_t buf_pa;
 +      struct pcie_service_card *card = adapter->card;
  
        if (!firmware || !firmware_len) {
                dev_err(adapter->dev,
                ret = -ENOMEM;
                goto done;
        }
 -      mwifiex_update_sk_buff_pa(skb);
  
        /* Perform firmware data transfer */
        do {
                        ret = -1;
                        goto done;
                }
 +
 +              MWIFIEX_SKB_PACB(skb, &buf_pa);
 +
                /* Wait for the command done interrupt */
                do {
                        if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
                                dev_err(adapter->dev, "%s: Failed to read "
                                        "interrupt status during fw dnld.\n",
                                        __func__);
 +                              pci_unmap_single(card->dev, buf_pa, skb->len,
 +                                               PCI_DMA_TODEVICE);
                                ret = -1;
                                goto done;
                        }
                } while ((ireg_intr & CPU_INTR_DOOR_BELL) ==
                         CPU_INTR_DOOR_BELL);
 +
 +              pci_unmap_single(card->dev, buf_pa, skb->len,
 +                               PCI_DMA_TODEVICE);
 +
                offset += txlen;
        } while (true);
  
@@@ -1841,40 -1594,39 +1841,40 @@@ exit
  static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
  {
        int ret;
 -      u32 pcie_ireg = 0;
 +      u32 pcie_ireg;
        unsigned long flags;
  
        spin_lock_irqsave(&adapter->int_lock, flags);
        /* Clear out unused interrupts */
 -      adapter->int_status &= HOST_INTR_MASK;
 +      pcie_ireg = adapter->int_status;
 +      adapter->int_status = 0;
        spin_unlock_irqrestore(&adapter->int_lock, flags);
  
 -      while (adapter->int_status & HOST_INTR_MASK) {
 -              if (adapter->int_status & HOST_INTR_DNLD_DONE) {
 -                      adapter->int_status &= ~HOST_INTR_DNLD_DONE;
 -                      if (adapter->data_sent) {
 -                              dev_dbg(adapter->dev, "info: DATA sent intr\n");
 -                              adapter->data_sent = false;
 -                      }
 +      while (pcie_ireg & HOST_INTR_MASK) {
 +              if (pcie_ireg & HOST_INTR_DNLD_DONE) {
 +                      pcie_ireg &= ~HOST_INTR_DNLD_DONE;
 +                      dev_dbg(adapter->dev, "info: TX DNLD Done\n");
 +                      ret = mwifiex_pcie_send_data_complete(adapter);
 +                      if (ret)
 +                              return ret;
                }
 -              if (adapter->int_status & HOST_INTR_UPLD_RDY) {
 -                      adapter->int_status &= ~HOST_INTR_UPLD_RDY;
 +              if (pcie_ireg & HOST_INTR_UPLD_RDY) {
 +                      pcie_ireg &= ~HOST_INTR_UPLD_RDY;
                        dev_dbg(adapter->dev, "info: Rx DATA\n");
                        ret = mwifiex_pcie_process_recv_data(adapter);
                        if (ret)
                                return ret;
                }
 -              if (adapter->int_status & HOST_INTR_EVENT_RDY) {
 -                      adapter->int_status &= ~HOST_INTR_EVENT_RDY;
 +              if (pcie_ireg & HOST_INTR_EVENT_RDY) {
 +                      pcie_ireg &= ~HOST_INTR_EVENT_RDY;
                        dev_dbg(adapter->dev, "info: Rx EVENT\n");
                        ret = mwifiex_pcie_process_event_ready(adapter);
                        if (ret)
                                return ret;
                }
  
 -              if (adapter->int_status & HOST_INTR_CMD_DONE) {
 -                      adapter->int_status &= ~HOST_INTR_CMD_DONE;
 +              if (pcie_ireg & HOST_INTR_CMD_DONE) {
 +                      pcie_ireg &= ~HOST_INTR_CMD_DONE;
                        if (adapter->cmd_sent) {
                                dev_dbg(adapter->dev,
                                        "info: CMD sent Interrupt\n");
                                                 "Write register failed\n");
                                        return -1;
                                }
 -                              adapter->int_status |= pcie_ireg;
 -                              adapter->int_status &= HOST_INTR_MASK;
                        }
  
                }
@@@ -1933,7 -1687,7 +1933,7 @@@ static int mwifiex_pcie_host_to_card(st
        }
  
        if (type == MWIFIEX_TYPE_DATA)
 -              return mwifiex_pcie_send_data(adapter, skb);
 +              return mwifiex_pcie_send_data(adapter, skb, tx_param);
        else if (type == MWIFIEX_TYPE_CMD)
                return mwifiex_pcie_send_cmd(adapter, skb);
  
@@@ -2060,8 -1814,15 +2060,8 @@@ static void mwifiex_pcie_cleanup(struc
        struct pcie_service_card *card = adapter->card;
        struct pci_dev *pdev = card->dev;
  
 -      mwifiex_pcie_delete_sleep_cookie_buf(adapter);
 -      mwifiex_pcie_delete_cmdrsp_buf(adapter);
 -      mwifiex_pcie_delete_evtbd_ring(adapter);
 -      mwifiex_pcie_delete_rxbd_ring(adapter);
 -      mwifiex_pcie_delete_txbd_ring(adapter);
 -      card->cmdrsp_buf = NULL;
 -
 -      dev_dbg(adapter->dev, "Clearing driver ready signature\n");
        if (user_rmmod) {
 +              dev_dbg(adapter->dev, "Clearing driver ready signature\n");
                if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000))
                        dev_err(adapter->dev,
                                "Failed to write driver not-ready signature\n");
@@@ -2118,13 -1879,6 +2118,13 @@@ static void mwifiex_unregister_dev(stru
        if (card) {
                dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__);
                free_irq(card->dev->irq, card->dev);
 +
 +              mwifiex_pcie_delete_sleep_cookie_buf(adapter);
 +              mwifiex_pcie_delete_cmdrsp_buf(adapter);
 +              mwifiex_pcie_delete_evtbd_ring(adapter);
 +              mwifiex_pcie_delete_rxbd_ring(adapter);
 +              mwifiex_pcie_delete_txbd_ring(adapter);
 +              card->cmdrsp_buf = NULL;
        }
  }
  
@@@ -2146,8 -1900,6 +2146,8 @@@ static struct mwifiex_if_ops pcie_ops 
        .event_complete =               mwifiex_pcie_event_complete,
        .update_mp_end_port =           NULL,
        .cleanup_mpa_buf =              NULL,
 +      .init_fw_port =                 mwifiex_pcie_init_fw_port,
 +      .clean_pcie_ring =              mwifiex_clean_pcie_ring_buf,
  };
  
  /*
@@@ -101,18 -101,6 +101,18 @@@ MODULE_PARM_DESC(ap_mode_default
  #define MWL8K_MAX_TX_QUEUES   (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES)
  #define mwl8k_tx_queues(priv) (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues)
  
 +/* txpriorities are mapped with hw queues.
 + * Each hw queue has a txpriority.
 + */
 +#define TOTAL_HW_TX_QUEUES    8
 +
 +/* Each HW queue can have one AMPDU stream.
 + * But, because one of the hw queue is reserved,
 + * maximum AMPDU queues that can be created are
 + * one short of total tx queues.
 + */
 +#define MWL8K_NUM_AMPDU_STREAMS       (TOTAL_HW_TX_QUEUES - 1)
 +
  struct rxd_ops {
        int rxd_size;
        void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
@@@ -172,6 -160,7 +172,6 @@@ struct mwl8k_ampdu_stream 
        u8 tid;
        u8 state;
        u8 idx;
 -      u8 txq_idx; /* index of this stream in priv->txq */
  };
  
  struct mwl8k_priv {
        int fw_mutex_depth;
        struct completion *hostcmd_wait;
  
 +      atomic_t watchdog_event_pending;
 +
        /* lock held over TX and TX reap */
        spinlock_t tx_lock;
  
@@@ -1529,9 -1516,6 +1529,9 @@@ static int mwl8k_tx_wait_empty(struct i
                        return -EBUSY;
        }
  
 +      if (atomic_read(&priv->watchdog_event_pending))
 +              return 0;
 +
        /*
         * The TX queues are stopped at this point, so this test
         * doesn't need to take ->tx_lock.
                spin_unlock_bh(&priv->tx_lock);
                timeout = wait_for_completion_timeout(&tx_wait,
                            msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS));
 +
 +              if (atomic_read(&priv->watchdog_event_pending)) {
 +                      spin_lock_bh(&priv->tx_lock);
 +                      priv->tx_wait = NULL;
 +                      spin_unlock_bh(&priv->tx_lock);
 +                      return 0;
 +              }
 +
                spin_lock_bh(&priv->tx_lock);
  
                if (timeout) {
  
                rc = -ETIMEDOUT;
        }
 +      priv->tx_wait = NULL;
        spin_unlock_bh(&priv->tx_lock);
  
        return rc;
@@@ -1759,13 -1734,14 +1759,13 @@@ mwl8k_add_stream(struct ieee80211_hw *h
        struct mwl8k_priv *priv = hw->priv;
        int i;
  
 -      for (i = 0; i < priv->num_ampdu_queues; i++) {
 +      for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) {
                stream = &priv->ampdu[i];
                if (stream->state == AMPDU_NO_STREAM) {
                        stream->sta = sta;
                        stream->state = AMPDU_STREAM_NEW;
                        stream->tid = tid;
                        stream->idx = i;
 -                      stream->txq_idx = MWL8K_TX_WMM_QUEUES + i;
                        wiphy_debug(hw->wiphy, "Added a new stream for %pM %d",
                                    sta->addr, tid);
                        return stream;
@@@ -1806,7 -1782,7 +1806,7 @@@ mwl8k_lookup_stream(struct ieee80211_h
        struct mwl8k_priv *priv = hw->priv;
        int i;
  
 -      for (i = 0 ; i < priv->num_ampdu_queues; i++) {
 +      for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) {
                struct mwl8k_ampdu_stream *stream;
                stream = &priv->ampdu[i];
                if (stream->state == AMPDU_NO_STREAM)
@@@ -1853,13 -1829,6 +1853,13 @@@ static inline void mwl8k_tx_count_packe
                tx_stats->pkts++;
  }
  
 +/* The hardware ampdu queues start from 5.
 + * txpriorities for ampdu queues are
 + * 5 6 7 0 1 2 3 4 ie., queue 5 is highest
 + * and queue 3 is lowest (queue 4 is reserved)
 + */
 +#define BA_QUEUE              5
 +
  static void
  mwl8k_txq_xmit(struct ieee80211_hw *hw,
               int index,
                stream = mwl8k_lookup_stream(hw, sta->addr, tid);
                if (stream != NULL) {
                        if (stream->state == AMPDU_STREAM_ACTIVE) {
 -                              txpriority = stream->txq_idx;
 -                              index = stream->txq_idx;
 +                              WARN_ON(!(qos & MWL8K_QOS_ACK_POLICY_BLOCKACK));
 +                              txpriority = (BA_QUEUE + stream->idx) %
 +                                           TOTAL_HW_TX_QUEUES;
 +                              if (stream->idx <= 1)
 +                                      index = stream->idx +
 +                                              MWL8K_TX_WMM_QUEUES;
 +
                        } else if (stream->state == AMPDU_STREAM_NEW) {
                                /* We get here if the driver sends us packets
                                 * after we've initiated a stream, but before
                        }
                }
                spin_unlock(&priv->stream_lock);
 +      } else {
 +              qos &= ~MWL8K_QOS_ACK_POLICY_MASK;
 +              qos |= MWL8K_QOS_ACK_POLICY_NORMAL;
        }
  
        dma = pci_map_single(priv->pdev, skb->data,
@@@ -3617,11 -3578,7 +3617,11 @@@ static int mwl8k_cmd_get_watchdog_bitma
        return rc;
  }
  
 -#define INVALID_BA    0xAA
 +#define MWL8K_WMM_QUEUE_NUMBER        3
 +
 +static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
 +                           u8 idx);
 +
  static void mwl8k_watchdog_ba_events(struct work_struct *work)
  {
        int rc;
        struct mwl8k_ampdu_stream *streams;
        struct mwl8k_priv *priv =
                container_of(work, struct mwl8k_priv, watchdog_ba_handle);
 +      struct ieee80211_hw *hw = priv->hw;
 +      int i;
 +      u32 status = 0;
 +
 +      mwl8k_fw_lock(hw);
  
        rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap);
        if (rc)
 -              return;
 +              goto done;
  
 -      if (bitmap == INVALID_BA)
 -              return;
 +      spin_lock(&priv->stream_lock);
  
        /* the bitmap is the hw queue number.  Map it to the ampdu queue. */
 -      stream_index = bitmap - MWL8K_TX_WMM_QUEUES;
 -
 -      BUG_ON(stream_index >= priv->num_ampdu_queues);
 -
 -      streams = &priv->ampdu[stream_index];
 -
 -      if (streams->state == AMPDU_STREAM_ACTIVE)
 -              ieee80211_stop_tx_ba_session(streams->sta, streams->tid);
 +      for (i = 0; i < TOTAL_HW_TX_QUEUES; i++) {
 +              if (bitmap & (1 << i)) {
 +                      stream_index = (i + MWL8K_WMM_QUEUE_NUMBER) %
 +                                     TOTAL_HW_TX_QUEUES;
 +                      streams = &priv->ampdu[stream_index];
 +                      if (streams->state == AMPDU_STREAM_ACTIVE) {
 +                              ieee80211_stop_tx_ba_session(streams->sta,
 +                                                           streams->tid);
 +                              spin_unlock(&priv->stream_lock);
 +                              mwl8k_destroy_ba(hw, stream_index);
 +                              spin_lock(&priv->stream_lock);
 +                      }
 +              }
 +      }
  
 +      spin_unlock(&priv->stream_lock);
 +done:
 +      atomic_dec(&priv->watchdog_event_pending);
 +      status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
 +      iowrite32((status | MWL8K_A2H_INT_BA_WATCHDOG),
 +                priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
 +      mwl8k_fw_unlock(hw);
        return;
  }
  
@@@ -3823,7 -3763,7 +3823,7 @@@ mwl8k_create_ba(struct ieee80211_hw *hw
  }
  
  static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
 -                           struct mwl8k_ampdu_stream *stream)
 +                           u8 idx)
  {
        struct mwl8k_cmd_bastream *cmd;
  
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
        cmd->action = cpu_to_le32(MWL8K_BA_DESTROY);
  
 -      cmd->destroy_params.ba_context = cpu_to_le32(stream->idx);
 +      cmd->destroy_params.ba_context = cpu_to_le32(idx);
        mwl8k_post_cmd(hw, &cmd->header);
  
 -      wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx);
 +      wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", idx);
  
        kfree(cmd);
  }
@@@ -3935,30 -3875,7 +3935,30 @@@ static int mwl8k_cmd_set_new_stn_del(st
                                     struct ieee80211_vif *vif, u8 *addr)
  {
        struct mwl8k_cmd_set_new_stn *cmd;
 -      int rc;
 +      struct mwl8k_priv *priv = hw->priv;
 +      int rc, i;
 +      u8 idx;
 +
 +      spin_lock(&priv->stream_lock);
 +      /* Destroy any active ampdu streams for this sta */
 +      for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) {
 +              struct mwl8k_ampdu_stream *s;
 +              s = &priv->ampdu[i];
 +              if (s->state != AMPDU_NO_STREAM) {
 +                      if (memcmp(s->sta->addr, addr, ETH_ALEN) == 0) {
 +                              if (s->state == AMPDU_STREAM_ACTIVE) {
 +                                      idx = s->idx;
 +                                      spin_unlock(&priv->stream_lock);
 +                                      mwl8k_destroy_ba(hw, idx);
 +                                      spin_lock(&priv->stream_lock);
 +                              } else if (s->state == AMPDU_STREAM_NEW) {
 +                                      mwl8k_remove_stream(hw, s);
 +                              }
 +                      }
 +              }
 +      }
 +
 +      spin_unlock(&priv->stream_lock);
  
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
@@@ -4333,9 -4250,11 +4333,11 @@@ static int mwl8k_cmd_update_stadb_add(s
        p->amsdu_enabled = 0;
  
        rc = mwl8k_post_cmd(hw, &cmd->header);
+       if (!rc)
+               rc = p->station_id;
        kfree(cmd);
  
-       return rc ? rc : p->station_id;
+       return rc;
  }
  
  static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw,
@@@ -4384,10 -4303,6 +4386,10 @@@ static irqreturn_t mwl8k_interrupt(int 
        }
  
        if (status & MWL8K_A2H_INT_BA_WATCHDOG) {
 +              iowrite32(~MWL8K_A2H_INT_BA_WATCHDOG,
 +                        priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
 +
 +              atomic_inc(&priv->watchdog_event_pending);
                status &= ~MWL8K_A2H_INT_BA_WATCHDOG;
                ieee80211_queue_work(hw, &priv->watchdog_ba_handle);
        }
@@@ -4531,8 -4446,6 +4533,8 @@@ static int mwl8k_start(struct ieee80211
                priv->irq = -1;
                tasklet_disable(&priv->poll_tx_task);
                tasklet_disable(&priv->poll_rx_task);
 +      } else {
 +              ieee80211_wake_queues(hw);
        }
  
        return rc;
@@@ -5181,7 -5094,7 +5183,7 @@@ mwl8k_ampdu_action(struct ieee80211_hw 
        int i, rc = 0;
        struct mwl8k_priv *priv = hw->priv;
        struct mwl8k_ampdu_stream *stream;
 -      u8 *addr = sta->addr;
 +      u8 *addr = sta->addr, idx;
        struct mwl8k_sta *sta_info = MWL8K_STA(sta);
  
        if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
                }
                ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
                break;
 -      case IEEE80211_AMPDU_TX_STOP:
 +      case IEEE80211_AMPDU_TX_STOP_CONT:
 +      case IEEE80211_AMPDU_TX_STOP_FLUSH:
 +      case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                if (stream) {
                        if (stream->state == AMPDU_STREAM_ACTIVE) {
 +                              idx = stream->idx;
                                spin_unlock(&priv->stream_lock);
 -                              mwl8k_destroy_ba(hw, stream);
 +                              mwl8k_destroy_ba(hw, idx);
                                spin_lock(&priv->stream_lock);
                        }
                        mwl8k_remove_stream(hw, stream);
                if (!rc)
                        stream->state = AMPDU_STREAM_ACTIVE;
                else {
 +                      idx = stream->idx;
                        spin_unlock(&priv->stream_lock);
 -                      mwl8k_destroy_ba(hw, stream);
 +                      mwl8k_destroy_ba(hw, idx);
                        spin_lock(&priv->stream_lock);
                        wiphy_debug(hw->wiphy,
                                "Failed adding stream for sta %pM tid %d\n",
@@@ -5347,7 -5256,7 +5349,7 @@@ enum 
        MWL8366,
  };
  
 -#define MWL8K_8366_AP_FW_API 2
 +#define MWL8K_8366_AP_FW_API 3
  #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw"
  #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api)
  
@@@ -5555,7 -5464,6 +5557,7 @@@ static int mwl8k_probe_hw(struct ieee80
                if (priv->rxd_ops == NULL) {
                        wiphy_err(hw->wiphy,
                                  "Driver does not have AP firmware image support for this hardware\n");
 +                      rc = -ENOENT;
                        goto err_stop_firmware;
                }
        } else {
        priv->sniffer_enabled = false;
        priv->wmm_enabled = false;
        priv->pending_tx_pkts = 0;
 +      atomic_set(&priv->watchdog_event_pending, 0);
  
        rc = mwl8k_rxq_init(hw, 0);
        if (rc)
@@@ -5902,7 -5809,6 +5904,7 @@@ static int mwl8k_probe(struct pci_dev *
        priv->sram = pci_iomap(pdev, 0, 0x10000);
        if (priv->sram == NULL) {
                wiphy_err(hw->wiphy, "Cannot map device SRAM\n");
 +              rc = -EIO;
                goto err_iounmap;
        }
  
                priv->regs = pci_iomap(pdev, 2, 0x10000);
                if (priv->regs == NULL) {
                        wiphy_err(hw->wiphy, "Cannot map device registers\n");
 +                      rc = -EIO;
                        goto err_iounmap;
                }
        }
@@@ -452,7 -452,7 +452,7 @@@ static void _rtl92de_translate_rx_signa
        u8 *praddr;
        u16 type, cfc;
        __le16 fc;
 -      bool packet_matchbssid, packet_toself, packet_beacon;
 +      bool packet_matchbssid, packet_toself, packet_beacon = false;
  
        tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
        hdr = (struct ieee80211_hdr *)tmp_buf;
@@@ -587,6 -587,11 +587,11 @@@ void rtl92de_tx_fill_desc(struct ieee80
        buf_len = skb->len;
        mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
                                 PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92d));
        if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
                firstseg = true;
@@@ -740,6 -745,11 +745,11 @@@ void rtl92de_tx_fill_cmddesc(struct iee
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
        __le16 fc = hdr->frame_control;
  
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
        if (firstseg)
                SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
@@@ -480,7 -480,7 +480,7 @@@ static void _rtl92se_translate_rx_signa
        u8 *praddr;
        __le16 fc;
        u16 type, cfc;
 -      bool packet_matchbssid, packet_toself, packet_beacon;
 +      bool packet_matchbssid, packet_toself, packet_beacon = false;
  
        tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
  
@@@ -611,6 -611,11 +611,11 @@@ void rtl92se_tx_fill_desc(struct ieee80
                    PCI_DMA_TODEVICE);
        u8 bw_40 = 0;
  
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        if (mac->opmode == NL80211_IFTYPE_STATION) {
                bw_40 = mac->bw_40;
        } else if (mac->opmode == NL80211_IFTYPE_AP ||
  void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
        bool firstseg, bool lastseg, struct sk_buff *skb)
  {
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
        struct rtl_tcb_desc *tcb_desc = (struct rtl_tcb_desc *)(skb->cb);
        dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
                        PCI_DMA_TODEVICE);
  
-     /* Clear all status       */
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
+       /* Clear all status     */
        CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_CMDDESC_SIZE_RTL8192S);
  
        /* This bit indicate this packet is used for FW download. */
@@@ -247,7 -247,7 +247,7 @@@ static void _rtl8723ae_translate_rx_sig
        u8 *psaddr;
        __le16 fc;
        u16 type;
 -      bool packet_matchbssid, packet_toself, packet_beacon;
 +      bool packet_matchbssid, packet_toself, packet_beacon = false;
  
        tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
  
@@@ -387,6 -387,11 +387,11 @@@ void rtl8723ae_tx_fill_desc(struct ieee
                                            PCI_DMA_TODEVICE);
        u8 bw_40 = 0;
  
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        if (mac->opmode == NL80211_IFTYPE_STATION) {
                bw_40 = mac->bw_40;
        } else if (mac->opmode == NL80211_IFTYPE_AP ||
@@@ -542,6 -547,11 +547,11 @@@ void rtl8723ae_tx_fill_cmddesc(struct i
                                            PCI_DMA_TODEVICE);
        __le16 fc = hdr->frame_control;
  
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
  
        if (firstseg)
diff --combined drivers/ssb/Kconfig
@@@ -136,11 -136,6 +136,11 @@@ config SSB_DRIVER_MIP
  
          If unsure, say N
  
 +config SSB_SFLASH
 +      bool "SSB serial flash support"
 +      depends on SSB_DRIVER_MIPS && BROKEN
 +      default y
 +
  # Assumption: We are on embedded, if we compile the MIPS core.
  config SSB_EMBEDDED
        bool
@@@ -167,8 -162,7 +167,7 @@@ config SSB_DRIVER_GIG
  
  config SSB_DRIVER_GPIO
        bool "SSB GPIO driver"
-       depends on SSB
-       select GPIOLIB
+       depends on SSB && GPIOLIB
        help
          Driver to provide access to the GPIO pins on the bus.
  
diff --combined net/mac80211/cfg.c
@@@ -164,7 -164,17 +164,17 @@@ static int ieee80211_add_key(struct wip
                        sta = sta_info_get(sdata, mac_addr);
                else
                        sta = sta_info_get_bss(sdata, mac_addr);
-               if (!sta) {
+               /*
+                * The ASSOC test makes sure the driver is ready to
+                * receive the key. When wpa_supplicant has roamed
+                * using FT, it attempts to set the key before
+                * association has completed, this rejects that attempt
+                * so it will set the key again after assocation.
+                *
+                * TODO: accept the key if we have a station entry and
+                *       add it to the device after the station.
+                */
+               if (!sta || !test_sta_flag(sta, WLAN_STA_ASSOC)) {
                        ieee80211_key_free(sdata->local, key);
                        err = -ENOENT;
                        goto out_unlock;
@@@ -510,7 -520,6 +520,7 @@@ static void sta_set_sinfo(struct sta_in
                                BIT(NL80211_STA_FLAG_WME) |
                                BIT(NL80211_STA_FLAG_MFP) |
                                BIT(NL80211_STA_FLAG_AUTHENTICATED) |
 +                              BIT(NL80211_STA_FLAG_ASSOCIATED) |
                                BIT(NL80211_STA_FLAG_TDLS_PEER);
        if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
        if (test_sta_flag(sta, WLAN_STA_AUTH))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
 +      if (test_sta_flag(sta, WLAN_STA_ASSOC))
 +              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
        if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
  }
@@@ -933,7 -940,6 +943,7 @@@ static int ieee80211_start_ap(struct wi
  
        sdata->vif.bss_conf.beacon_int = params->beacon_interval;
        sdata->vif.bss_conf.dtim_period = params->dtim_period;
 +      sdata->vif.bss_conf.enable_beacon = true;
  
        sdata->vif.bss_conf.ssid_len = params->ssid_len;
        if (params->ssid_len)
@@@ -1014,15 -1020,8 +1024,15 @@@ static int ieee80211_stop_ap(struct wip
                kfree_rcu(old_probe_resp, rcu_head);
  
        list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
 -              sta_info_flush(local, vlan);
 -      sta_info_flush(local, sdata);
 +              sta_info_flush_defer(vlan);
 +      sta_info_flush_defer(sdata);
 +      rcu_barrier();
 +      list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
 +              sta_info_flush_cleanup(vlan);
 +      sta_info_flush_cleanup(sdata);
 +
 +      sdata->vif.bss_conf.enable_beacon = false;
 +      clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
  
        drv_stop_ap(sdata->local, sdata);
@@@ -1080,58 -1079,6 +1090,58 @@@ static void ieee80211_send_layer2_updat
        netif_rx_ni(skb);
  }
  
 +static int sta_apply_auth_flags(struct ieee80211_local *local,
 +                              struct sta_info *sta,
 +                              u32 mask, u32 set)
 +{
 +      int ret;
 +
 +      if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
 +          set & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
 +          !test_sta_flag(sta, WLAN_STA_AUTH)) {
 +              ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
 +              if (ret)
 +                      return ret;
 +      }
 +
 +      if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
 +          set & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
 +          !test_sta_flag(sta, WLAN_STA_ASSOC)) {
 +              ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
 +              if (ret)
 +                      return ret;
 +      }
 +
 +      if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
 +              if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
 +                      ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
 +              else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
 +                      ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
 +              else
 +                      ret = 0;
 +              if (ret)
 +                      return ret;
 +      }
 +
 +      if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
 +          !(set & BIT(NL80211_STA_FLAG_ASSOCIATED)) &&
 +          test_sta_flag(sta, WLAN_STA_ASSOC)) {
 +              ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
 +              if (ret)
 +                      return ret;
 +      }
 +
 +      if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
 +          !(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) &&
 +          test_sta_flag(sta, WLAN_STA_AUTH)) {
 +              ret = sta_info_move_state(sta, IEEE80211_STA_NONE);
 +              if (ret)
 +                      return ret;
 +      }
 +
 +      return 0;
 +}
 +
  static int sta_apply_parameters(struct ieee80211_local *local,
                                struct sta_info *sta,
                                struct station_parameters *params)
        mask = params->sta_flags_mask;
        set = params->sta_flags_set;
  
 -      /*
 -       * In mesh mode, we can clear AUTHENTICATED flag but must
 -       * also make ASSOCIATED follow appropriately for the driver
 -       * API. See also below, after AUTHORIZED changes.
 -       */
 -      if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
 -              /* cfg80211 should not allow this in non-mesh modes */
 -              if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif)))
 -                      return -EINVAL;
 -
 -              if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
 -                  !test_sta_flag(sta, WLAN_STA_AUTH)) {
 -                      ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
 -                      if (ret)
 -                              return ret;
 -                      ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
 -                      if (ret)
 -                              return ret;
 -              }
 -      }
 -
 -      if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
 -              if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
 -                      ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
 -              else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
 -                      ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
 -              if (ret)
 -                      return ret;
 -      }
 -
 -      if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
 -              /* cfg80211 should not allow this in non-mesh modes */
 -              if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif)))
 -                      return -EINVAL;
 -
 -              if (!(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) &&
 -                  test_sta_flag(sta, WLAN_STA_AUTH)) {
 -                      ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
 -                      if (ret)
 -                              return ret;
 -                      ret = sta_info_move_state(sta, IEEE80211_STA_NONE);
 -                      if (ret)
 -                              return ret;
 -              }
 +      if (ieee80211_vif_is_mesh(&sdata->vif)) {
 +              /*
 +               * In mesh mode, ASSOCIATED isn't part of the nl80211
 +               * API but must follow AUTHENTICATED for driver state.
 +               */
 +              if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED))
 +                      mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
 +              if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
 +                      set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
        }
  
 +      ret = sta_apply_auth_flags(local, sta, mask, set);
 +      if (ret)
 +              return ret;
  
        if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
                if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
                sta->sta.aid = params->aid;
  
        /*
 -       * FIXME: updating the following information is racy when this
 -       *        function is called from ieee80211_change_station().
 -       *        However, all this information should be static so
 -       *        maybe we should just reject attemps to change it.
 +       * Some of the following updates would be racy if called on an
 +       * existing station, via ieee80211_change_station(). However,
 +       * all such changes are rejected by cfg80211 except for updates
 +       * changing the supported rates on an existing but not yet used
 +       * TDLS peer.
         */
  
        if (params->listen_interval >= 0)
  
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
  #ifdef CONFIG_MAC80211_MESH
 -              if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED)
 +              if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) {
 +                      u32 changed = 0;
 +
                        switch (params->plink_state) {
 -                      case NL80211_PLINK_LISTEN:
                        case NL80211_PLINK_ESTAB:
 +                              if (sta->plink_state != NL80211_PLINK_ESTAB)
 +                                      changed = mesh_plink_inc_estab_count(
 +                                                      sdata);
 +                              sta->plink_state = params->plink_state;
 +                              break;
 +                      case NL80211_PLINK_LISTEN:
                        case NL80211_PLINK_BLOCKED:
 +                      case NL80211_PLINK_OPN_SNT:
 +                      case NL80211_PLINK_OPN_RCVD:
 +                      case NL80211_PLINK_CNF_RCVD:
 +                      case NL80211_PLINK_HOLDING:
 +                              if (sta->plink_state == NL80211_PLINK_ESTAB)
 +                                      changed = mesh_plink_dec_estab_count(
 +                                                      sdata);
                                sta->plink_state = params->plink_state;
                                break;
                        default:
                                /*  nothing  */
                                break;
                        }
 -              else
 +                      ieee80211_bss_info_change_notify(sdata, changed);
 +              } else {
                        switch (params->plink_action) {
                        case PLINK_ACTION_OPEN:
                                mesh_plink_open(sta);
                                mesh_plink_block(sta);
                                break;
                        }
 +              }
  #endif
        }
  
@@@ -1313,10 -1275,6 +1323,10 @@@ static int ieee80211_add_station(struc
        if (!sta)
                return -ENOMEM;
  
 +      /*
 +       * defaults -- if userspace wants something else we'll
 +       * change it accordingly in sta_apply_parameters()
 +       */
        sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
        sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
  
  static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac)
  {
 -      struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
  
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (mac)
                return sta_info_destroy_addr_bss(sdata, mac);
  
 -      sta_info_flush(local, sdata);
 +      sta_info_flush(sdata);
        return 0;
  }
  
@@@ -1666,9 -1625,6 +1676,9 @@@ static int copy_mesh_setup(struct ieee8
        memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate,
                                                sizeof(setup->mcast_rate));
  
 +      sdata->vif.bss_conf.beacon_int = setup->beacon_interval;
 +      sdata->vif.bss_conf.dtim_period = setup->dtim_period;
 +
        return 0;
  }
  
@@@ -2251,8 -2207,7 +2261,8 @@@ static int ieee80211_set_power_mgmt(str
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
  
 -      if (sdata->vif.type != NL80211_IFTYPE_STATION)
 +      if (sdata->vif.type != NL80211_IFTYPE_STATION &&
 +          sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
                return -EOPNOTSUPP;
  
        if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
@@@ -405,8 -405,6 +405,8 @@@ struct ieee80211_mgd_assoc_data 
  
        u8 ap_ht_param;
  
 +      struct ieee80211_vht_cap ap_vht_cap;
 +
        size_t ie_len;
        u8 ie[];
  };
@@@ -661,13 -659,10 +661,13 @@@ enum ieee80211_sub_if_data_flags 
   *    change handling while the interface is up
   * @SDATA_STATE_OFFCHANNEL: This interface is currently in offchannel
   *    mode, so queues are stopped
 + * @SDATA_STATE_OFFCHANNEL_BEACON_STOPPED: Beaconing was stopped due
 + *    to offchannel, reset when offchannel returns
   */
  enum ieee80211_sdata_state_bits {
        SDATA_STATE_RUNNING,
        SDATA_STATE_OFFCHANNEL,
 +      SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
  };
  
  /**
@@@ -690,7 -685,6 +690,7 @@@ struct ieee80211_chanctx 
  
        enum ieee80211_chanctx_mode mode;
        int refcount;
 +      bool driver_present;
  
        struct ieee80211_chanctx_conf conf;
  };
@@@ -789,11 -783,6 +789,11 @@@ struct ieee80211_sub_if_data 
                struct dentry *default_mgmt_key;
        } debugfs;
  #endif
 +
 +#ifdef CONFIG_PM
 +      struct ieee80211_bss_conf suspend_bss_conf;
 +#endif
 +
        /* must be last, dynamically sized area in this! */
        struct ieee80211_vif vif;
  };
@@@ -1357,7 -1346,8 +1357,7 @@@ ieee80211_bss_info_update(struct ieee80
                          struct ieee80211_mgmt *mgmt,
                          size_t len,
                          struct ieee802_11_elems *elems,
 -                        struct ieee80211_channel *channel,
 -                        bool beacon);
 +                        struct ieee80211_channel *channel);
  void ieee80211_rx_bss_put(struct ieee80211_local *local,
                          struct ieee80211_bss *bss);
  
@@@ -1368,10 -1358,8 +1368,8 @@@ int ieee80211_request_sched_scan_stop(s
  void ieee80211_sched_scan_stopped_work(struct work_struct *work);
  
  /* off-channel helpers */
- void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
-                                   bool offchannel_ps_enable);
- void ieee80211_offchannel_return(struct ieee80211_local *local,
-                                bool offchannel_ps_disable);
+ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local);
+ void ieee80211_offchannel_return(struct ieee80211_local *local);
  void ieee80211_roc_setup(struct ieee80211_local *local);
  void ieee80211_start_next_roc(struct ieee80211_local *local);
  void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata);
@@@ -1432,8 -1420,7 +1430,8 @@@ void ___ieee80211_stop_rx_ba_session(st
                                     u16 initiator, u16 reason, bool stop);
  void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                                    u16 initiator, u16 reason, bool stop);
 -void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx);
 +void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
 +                                       enum ieee80211_agg_stop_reason reason);
  void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
                             struct sta_info *sta,
                             struct ieee80211_mgmt *mgmt, size_t len);
@@@ -1447,9 -1434,11 +1445,9 @@@ void ieee80211_process_addba_request(st
                                     size_t len);
  
  int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 -                                 enum ieee80211_back_parties initiator,
 -                                 bool tx);
 +                                 enum ieee80211_agg_stop_reason reason);
  int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 -                                  enum ieee80211_back_parties initiator,
 -                                  bool tx);
 +                                  enum ieee80211_agg_stop_reason reason);
  void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
  void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
  void ieee80211_ba_session_work(struct work_struct *work);
diff --combined net/mac80211/mesh_hwmp.c
@@@ -215,18 -215,17 +215,19 @@@ static void prepare_frame_for_deferred_
        skb->priority = 7;
  
        info->control.vif = &sdata->vif;
+       info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
        ieee80211_set_qos_hdr(sdata, skb);
  }
  
  /**
 - * mesh_send_path error - Sends a PERR mesh management frame
 + * mesh_path_error_tx - Sends a PERR mesh management frame
   *
 + * @ttl: allowed remaining hops
   * @target: broken destination
   * @target_sn: SN of the broken destination
   * @target_rcode: reason code for this PERR
   * @ra: node this frame is addressed to
 + * @sdata: local mesh subif
   *
   * Note: This function may be called with driver locks taken that the driver
   * also acquires in the TX path.  To avoid a deadlock we don't transmit the
@@@ -248,11 -247,13 +249,13 @@@ int mesh_path_error_tx(u8 ttl, u8 *targ
                return -EAGAIN;
  
        skb = dev_alloc_skb(local->tx_headroom +
+                           IEEE80211_ENCRYPT_HEADROOM +
+                           IEEE80211_ENCRYPT_TAILROOM +
                            hdr_len +
                            2 + 15 /* PERR IE */);
        if (!skb)
                return -1;
-       skb_reserve(skb, local->tx_headroom);
+       skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM);
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
        memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
@@@ -352,7 -353,6 +355,7 @@@ static u32 airtime_link_metric_get(stru
   * @sdata: local mesh subif
   * @mgmt: mesh management frame
   * @hwmp_ie: hwmp information element (PREP or PREQ)
 + * @action: type of hwmp ie
   *
   * This function updates the path routing information to the originator and the
   * transmitter of a HWMP PREQ or PREP frame.
@@@ -102,8 -102,7 +102,7 @@@ static void ieee80211_offchannel_ps_dis
        ieee80211_sta_reset_conn_monitor(sdata);
  }
  
- void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
-                                   bool offchannel_ps_enable)
+ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
  {
        struct ieee80211_sub_if_data *sdata;
  
                        set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
  
                /* Check to see if we should disable beaconing. */
 -              if (sdata->vif.type == NL80211_IFTYPE_AP ||
 -                  sdata->vif.type == NL80211_IFTYPE_ADHOC ||
 -                  sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
 +              if (sdata->vif.bss_conf.enable_beacon) {
 +                      set_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
 +                              &sdata->state);
 +                      sdata->vif.bss_conf.enable_beacon = false;
                        ieee80211_bss_info_change_notify(
                                sdata, BSS_CHANGED_BEACON_ENABLED);
 +              }
  
                if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
                        netif_tx_stop_all_queues(sdata->dev);
-                       if (offchannel_ps_enable &&
-                           (sdata->vif.type == NL80211_IFTYPE_STATION) &&
+                       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
                            sdata->u.mgd.associated)
                                ieee80211_offchannel_ps_enable(sdata);
                }
        mutex_unlock(&local->iflist_mtx);
  }
  
- void ieee80211_offchannel_return(struct ieee80211_local *local,
-                                bool offchannel_ps_disable)
+ void ieee80211_offchannel_return(struct ieee80211_local *local)
  {
        struct ieee80211_sub_if_data *sdata;
  
                        continue;
  
                /* Tell AP we're back */
-               if (offchannel_ps_disable &&
-                   sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       if (sdata->u.mgd.associated)
-                               ieee80211_offchannel_ps_disable(sdata);
-               }
+               if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+                   sdata->u.mgd.associated)
+                       ieee80211_offchannel_ps_disable(sdata);
  
                if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
                        /*
                        netif_tx_wake_all_queues(sdata->dev);
                }
  
 -              if (sdata->vif.type == NL80211_IFTYPE_AP ||
 -                  sdata->vif.type == NL80211_IFTYPE_ADHOC ||
 -                  sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
 +              if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
 +                                     &sdata->state)) {
 +                      sdata->vif.bss_conf.enable_beacon = true;
                        ieee80211_bss_info_change_notify(
                                sdata, BSS_CHANGED_BEACON_ENABLED);
 +              }
        }
        mutex_unlock(&local->iflist_mtx);
  }
@@@ -388,7 -380,7 +383,7 @@@ void ieee80211_sw_roc_work(struct work_
                        local->tmp_channel = NULL;
                        ieee80211_hw_config(local, 0);
  
-                       ieee80211_offchannel_return(local, true);
+                       ieee80211_offchannel_return(local);
                }
  
                ieee80211_recalc_idle(local);
diff --combined net/mac80211/scan.c
@@@ -65,11 -65,12 +65,11 @@@ static bool is_uapsd_supported(struct i
  struct ieee80211_bss *
  ieee80211_bss_info_update(struct ieee80211_local *local,
                          struct ieee80211_rx_status *rx_status,
 -                        struct ieee80211_mgmt *mgmt,
 -                        size_t len,
 +                        struct ieee80211_mgmt *mgmt, size_t len,
                          struct ieee802_11_elems *elems,
 -                        struct ieee80211_channel *channel,
 -                        bool beacon)
 +                        struct ieee80211_channel *channel)
  {
 +      bool beacon = ieee80211_is_beacon(mgmt->frame_control);
        struct cfg80211_bss *cbss;
        struct ieee80211_bss *bss;
        int clen, srlen;
@@@ -202,7 -203,7 +202,7 @@@ void ieee80211_scan_rx(struct ieee80211
  
        bss = ieee80211_bss_info_update(local, rx_status,
                                        mgmt, skb->len, &elems,
 -                                      channel, beacon);
 +                                      channel);
        if (bss)
                ieee80211_rx_bss_put(local, bss);
  }
@@@ -291,7 -292,7 +291,7 @@@ static void __ieee80211_scan_completed(
        if (!was_hw_scan) {
                ieee80211_configure_filter(local);
                drv_sw_scan_complete(local);
-               ieee80211_offchannel_return(local, true);
+               ieee80211_offchannel_return(local);
        }
  
        ieee80211_recalc_idle(local);
@@@ -340,7 -341,7 +340,7 @@@ static int ieee80211_start_sw_scan(stru
        local->next_scan_state = SCAN_DECISION;
        local->scan_channel_idx = 0;
  
-       ieee80211_offchannel_stop_vifs(local, true);
+       ieee80211_offchannel_stop_vifs(local);
  
        ieee80211_configure_filter(local);
  
@@@ -677,12 -678,8 +677,8 @@@ static void ieee80211_scan_state_suspen
        local->scan_channel = NULL;
        ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
  
-       /*
-        * Re-enable vifs and beaconing.  Leave PS
-        * in off-channel state..will put that back
-        * on-channel at the end of scanning.
-        */
-       ieee80211_offchannel_return(local, false);
+       /* disable PS */
+       ieee80211_offchannel_return(local);
  
        *next_delay = HZ / 5;
        /* afterwards, resume scan & go to next channel */
  static void ieee80211_scan_state_resume(struct ieee80211_local *local,
                                        unsigned long *next_delay)
  {
-       /* PS already is in off-channel mode */
-       ieee80211_offchannel_stop_vifs(local, false);
+       ieee80211_offchannel_stop_vifs(local);
  
        if (local->ops->flush) {
                drv_flush(local, false);
diff --combined net/mac80211/tx.c
@@@ -1673,10 -1673,13 +1673,13 @@@ netdev_tx_t ieee80211_monitor_start_xmi
                        chanctx_conf =
                                rcu_dereference(tmp_sdata->vif.chanctx_conf);
        }
-       if (!chanctx_conf)
-               goto fail_rcu;
  
-       chan = chanctx_conf->def.chan;
+       if (chanctx_conf)
+               chan = chanctx_conf->def.chan;
+       else if (!local->use_chanctx)
+               chan = local->_oper_channel;
+       else
+               goto fail_rcu;
  
        /*
         * Frame injection is not allowed if beaconing is not allowed
@@@ -2261,8 -2264,9 +2264,8 @@@ void ieee80211_tx_pending(unsigned lon
  
  /* functions for drivers to get certain frames */
  
 -static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
 -                                   struct ps_data *ps,
 -                                   struct sk_buff *skb)
 +static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
 +                                     struct ps_data *ps, struct sk_buff *skb)
  {
        u8 *pos, *tim;
        int aid0 = 0;
        }
  }
  
 +static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
 +                                  struct ps_data *ps, struct sk_buff *skb)
 +{
 +      struct ieee80211_local *local = sdata->local;
 +
 +      /*
 +       * Not very nice, but we want to allow the driver to call
 +       * ieee80211_beacon_get() as a response to the set_tim()
 +       * callback. That, however, is already invoked under the
 +       * sta_lock to guarantee consistent and race-free update
 +       * of the tim bitmap in mac80211 and the driver.
 +       */
 +      if (local->tim_in_locked_section) {
 +              __ieee80211_beacon_add_tim(sdata, ps, skb);
 +      } else {
 +              unsigned long flags;
 +
 +              spin_lock_irqsave(&local->tim_lock, flags);
 +              __ieee80211_beacon_add_tim(sdata, ps, skb);
 +              spin_unlock_irqrestore(&local->tim_lock, flags);
 +      }
 +
 +      return 0;
 +}
 +
  struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                                         struct ieee80211_vif *vif,
                                         u16 *tim_offset, u16 *tim_length)
                        memcpy(skb_put(skb, beacon->head_len), beacon->head,
                               beacon->head_len);
  
 -                      /*
 -                       * Not very nice, but we want to allow the driver to call
 -                       * ieee80211_beacon_get() as a response to the set_tim()
 -                       * callback. That, however, is already invoked under the
 -                       * sta_lock to guarantee consistent and race-free update
 -                       * of the tim bitmap in mac80211 and the driver.
 -                       */
 -                      if (local->tim_in_locked_section) {
 -                              ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
 -                      } else {
 -                              unsigned long flags;
 -
 -                              spin_lock_irqsave(&local->tim_lock, flags);
 -                              ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
 -                              spin_unlock_irqrestore(&local->tim_lock, flags);
 -                      }
 +                      ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
  
                        if (tim_offset)
                                *tim_offset = beacon->head_len;