]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
authorJohn W. Linville <linville@tuxdriver.com>
Thu, 12 Apr 2012 17:49:28 +0000 (13:49 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 12 Apr 2012 17:49:28 +0000 (13:49 -0400)
13 files changed:
1  2 
drivers/net/wireless/ath/ath5k/debug.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/iwlegacy/4965-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
include/net/mac80211.h
net/mac80211/debugfs_netdev.c
net/mac80211/debugfs_sta.c
net/mac80211/mlme.c
net/wireless/nl80211.c

index 9be885707e2039cc75b6a44c5198e61a40086bc0,e5e8f45d86acdb6c74faf067465e783bae96cf0e..9d00dab666a8de1b52aca10190f0b1db542d4f91
@@@ -57,9 -57,6 +57,9 @@@
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   * THE POSSIBILITY OF SUCH DAMAGES.
   */
 +
 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 +
  #include <linux/export.h>
  #include <linux/moduleparam.h>
  
@@@ -74,13 -71,6 +74,6 @@@ static unsigned int ath5k_debug
  module_param_named(debug, ath5k_debug, uint, 0);
  
  
- static int ath5k_debugfs_open(struct inode *inode, struct file *file)
- {
-       file->private_data = inode->i_private;
-       return 0;
- }
  /* debugfs: registers */
  
  struct reg {
@@@ -257,10 -247,10 +250,10 @@@ static ssize_t write_file_beacon(struc
  
        if (strncmp(buf, "disable", 7) == 0) {
                AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
 -              printk(KERN_INFO "debugfs disable beacons\n");
 +              pr_info("debugfs disable beacons\n");
        } else if (strncmp(buf, "enable", 6) == 0) {
                AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
 -              printk(KERN_INFO "debugfs enable beacons\n");
 +              pr_info("debugfs enable beacons\n");
        }
        return count;
  }
  static const struct file_operations fops_beacon = {
        .read = read_file_beacon,
        .write = write_file_beacon,
-       .open = ath5k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -288,7 -278,7 +281,7 @@@ static ssize_t write_file_reset(struct 
  
  static const struct file_operations fops_reset = {
        .write = write_file_reset,
-       .open = ath5k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = noop_llseek,
  };
@@@ -368,7 -358,7 +361,7 @@@ static ssize_t write_file_debug(struct 
  static const struct file_operations fops_debug = {
        .read = read_file_debug,
        .write = write_file_debug,
-       .open = ath5k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -460,19 -450,19 +453,19 @@@ static ssize_t write_file_antenna(struc
  
        if (strncmp(buf, "diversity", 9) == 0) {
                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
 -              printk(KERN_INFO "ath5k debug: enable diversity\n");
 +              pr_info("debug: enable diversity\n");
        } else if (strncmp(buf, "fixed-a", 7) == 0) {
                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A);
 -              printk(KERN_INFO "ath5k debugfs: fixed antenna A\n");
 +              pr_info("debug: fixed antenna A\n");
        } else if (strncmp(buf, "fixed-b", 7) == 0) {
                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B);
 -              printk(KERN_INFO "ath5k debug: fixed antenna B\n");
 +              pr_info("debug: fixed antenna B\n");
        } else if (strncmp(buf, "clear", 5) == 0) {
                for (i = 0; i < ARRAY_SIZE(ah->stats.antenna_rx); i++) {
                        ah->stats.antenna_rx[i] = 0;
                        ah->stats.antenna_tx[i] = 0;
                }
 -              printk(KERN_INFO "ath5k debug: cleared antenna stats\n");
 +              pr_info("debug: cleared antenna stats\n");
        }
        return count;
  }
  static const struct file_operations fops_antenna = {
        .read = read_file_antenna,
        .write = write_file_antenna,
-       .open = ath5k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -535,7 -525,7 +528,7 @@@ static ssize_t read_file_misc(struct fi
  
  static const struct file_operations fops_misc = {
        .read = read_file_misc,
-       .open = ath5k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
  };
  
@@@ -642,7 -632,7 +635,7 @@@ static ssize_t write_file_frameerrors(s
                st->txerr_fifo = 0;
                st->txerr_filt = 0;
                st->tx_all_count = 0;
 -              printk(KERN_INFO "ath5k debug: cleared frameerrors stats\n");
 +              pr_info("debug: cleared frameerrors stats\n");
        }
        return count;
  }
  static const struct file_operations fops_frameerrors = {
        .read = read_file_frameerrors,
        .write = write_file_frameerrors,
-       .open = ath5k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -813,7 -803,7 +806,7 @@@ static ssize_t write_file_ani(struct fi
  static const struct file_operations fops_ani = {
        .read = read_file_ani,
        .write = write_file_ani,
-       .open = ath5k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -884,7 -874,7 +877,7 @@@ static ssize_t write_file_queue(struct 
  static const struct file_operations fops_queue = {
        .read = read_file_queue,
        .write = write_file_queue,
-       .open = ath5k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
index 244723a3ed4108c5a70fbf534880cebe92bc94d3,ff47b32ecaf483fd87b99bf89dbc75fe6e325fcd..04edce941cb7a19cf53c837de2eee62980d85fc6
  #define REG_READ_D(_ah, _reg) \
        ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
  
- static int ath9k_debugfs_open(struct inode *inode, struct file *file)
- {
-       file->private_data = inode->i_private;
-       return 0;
- }
  
  static ssize_t ath9k_debugfs_read_buf(struct file *file, char __user *user_buf,
                                      size_t count, loff_t *ppos)
@@@ -83,7 -78,7 +78,7 @@@ static ssize_t write_file_debug(struct 
  static const struct file_operations fops_debug = {
        .read = read_file_debug,
        .write = write_file_debug,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -129,7 -124,7 +124,7 @@@ static ssize_t write_file_tx_chainmask(
  static const struct file_operations fops_tx_chainmask = {
        .read = read_file_tx_chainmask,
        .write = write_file_tx_chainmask,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -172,7 -167,7 +167,7 @@@ static ssize_t write_file_rx_chainmask(
  static const struct file_operations fops_rx_chainmask = {
        .read = read_file_rx_chainmask,
        .write = write_file_rx_chainmask,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -223,7 -218,7 +218,7 @@@ static ssize_t write_file_disable_ani(s
  static const struct file_operations fops_disable_ani = {
        .read = read_file_disable_ani,
        .write = write_file_disable_ani,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -324,7 -319,7 +319,7 @@@ static ssize_t read_file_dma(struct fil
  
  static const struct file_operations fops_dma = {
        .read = read_file_dma,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -446,7 -441,7 +441,7 @@@ static ssize_t read_file_interrupt(stru
  
  static const struct file_operations fops_interrupt = {
        .read = read_file_interrupt,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -529,7 -524,6 +524,7 @@@ static ssize_t read_file_xmit(struct fi
        PR("hw-put-tx-buf:   ", puttxbuf);
        PR("hw-tx-start:     ", txstart);
        PR("hw-tx-proc-desc: ", txprocdesc);
 +      PR("TX-Failed:       ", txfailed);
        len += snprintf(buf + len, size - len,
                        "%s%11p%11p%10p%10p\n", "txq-memory-address:",
                        sc->tx.txq_map[WME_AC_BE],
@@@ -853,28 -847,28 +848,28 @@@ void ath_debug_stat_tx(struct ath_soft
  
  static const struct file_operations fops_xmit = {
        .read = read_file_xmit,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
  
  static const struct file_operations fops_stations = {
        .read = read_file_stations,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
  
  static const struct file_operations fops_misc = {
        .read = read_file_misc,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
  
  static const struct file_operations fops_reset = {
        .read = read_file_reset,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -916,21 -910,6 +911,21 @@@ static ssize_t read_file_recv(struct fi
        len += snprintf(buf + len, size - len,
                        "%22s : %10u\n", "DECRYPT BUSY ERR",
                        sc->debug.stats.rxstats.decrypt_busy_err);
 +      len += snprintf(buf + len, size - len,
 +                      "%22s : %10u\n", "RX-LENGTH-ERR",
 +                      sc->debug.stats.rxstats.rx_len_err);
 +      len += snprintf(buf + len, size - len,
 +                      "%22s : %10u\n", "RX-OOM-ERR",
 +                      sc->debug.stats.rxstats.rx_oom_err);
 +      len += snprintf(buf + len, size - len,
 +                      "%22s : %10u\n", "RX-RATE-ERR",
 +                      sc->debug.stats.rxstats.rx_rate_err);
 +      len += snprintf(buf + len, size - len,
 +                      "%22s : %10u\n", "RX-DROP-RXFLUSH",
 +                      sc->debug.stats.rxstats.rx_drop_rxflush);
 +      len += snprintf(buf + len, size - len,
 +                      "%22s : %10u\n", "RX-TOO-MANY-FRAGS",
 +                      sc->debug.stats.rxstats.rx_too_many_frags_err);
  
        PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
        PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING);
        len += snprintf(buf + len, size - len,
                        "%22s : %10u\n", "RX-Bytes-All",
                        sc->debug.stats.rxstats.rx_bytes_all);
 +      len += snprintf(buf + len, size - len,
 +                      "%22s : %10u\n", "RX-Beacons",
 +                      sc->debug.stats.rxstats.rx_beacons);
 +      len += snprintf(buf + len, size - len,
 +                      "%22s : %10u\n", "RX-Frags",
 +                      sc->debug.stats.rxstats.rx_frags);
  
        if (len > size)
                len = size;
  
  void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
  {
 -#define RX_STAT_INC(c) sc->debug.stats.rxstats.c++
  #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++
  #define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\
                        [sc->debug.rsidx].c)
  
  #endif
  
 -#undef RX_STAT_INC
  #undef RX_PHY_ERR_INC
  #undef RX_SAMP_DBG
  }
  
  static const struct file_operations fops_recv = {
        .read = read_file_recv,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -1075,7 -1050,7 +1070,7 @@@ static ssize_t write_file_regidx(struc
  static const struct file_operations fops_regidx = {
        .read = read_file_regidx,
        .write = write_file_regidx,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -1122,7 -1097,7 +1117,7 @@@ static ssize_t write_file_regval(struc
  static const struct file_operations fops_regval = {
        .read = read_file_regval,
        .write = write_file_regval,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -1211,7 -1186,7 +1206,7 @@@ static ssize_t read_file_dump_nfcal(str
  
  static const struct file_operations fops_dump_nfcal = {
        .read = read_file_dump_nfcal,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -1239,7 -1214,7 +1234,7 @@@ static ssize_t read_file_base_eeprom(st
  
  static const struct file_operations fops_base_eeprom = {
        .read = read_file_base_eeprom,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
@@@ -1267,7 -1242,7 +1262,7 @@@ static ssize_t read_file_modal_eeprom(s
  
  static const struct file_operations fops_modal_eeprom = {
        .read = read_file_modal_eeprom,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
  };
index 5de648c243bf0a00af4e7da798109d0864d6a040,2504ab00558971d15f77569593e7d8756ede1761..c8d1239571883097ae87707ff8988603b9196e7c
@@@ -118,15 -118,13 +118,13 @@@ void ath9k_ps_restore(struct ath_softc 
        if (--sc->ps_usecount != 0)
                goto unlock;
  
-       if (sc->ps_flags & PS_WAIT_FOR_TX_ACK)
-               goto unlock;
-       if (sc->ps_idle)
+       if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK))
                mode = ATH9K_PM_FULL_SLEEP;
        else if (sc->ps_enabled &&
                 !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
                              PS_WAIT_FOR_CAB |
-                             PS_WAIT_FOR_PSPOLL_DATA)))
+                             PS_WAIT_FOR_PSPOLL_DATA |
+                             PS_WAIT_FOR_TX_ACK)))
                mode = ATH9K_PM_NETWORK_SLEEP;
        else
                goto unlock;
@@@ -243,7 -241,6 +241,7 @@@ static bool ath_prepare_reset(struct at
  
        sc->hw_busy_count = 0;
        del_timer_sync(&common->ani.timer);
 +      del_timer_sync(&sc->rx_poll_timer);
  
        ath9k_debug_samp_bb_mac(sc);
        ath9k_hw_disable_interrupts(ah);
@@@ -285,7 -282,6 +283,7 @@@ static bool ath_complete_reset(struct a
  
                ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
                ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
 +              ath_start_rx_poll(sc, 3);
                if (!common->disable_ani)
                        ath_start_ani(common);
        }
@@@ -642,7 -638,7 +640,7 @@@ static void ath_node_attach(struct ath_
        an->sta = sta;
        an->vif = vif;
  
-       if (sta->ht_cap.ht_supported) {
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
                ath_tx_node_init(sc, an);
                an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
                                     sta->ht_cap.ampdu_factor);
@@@ -661,7 -657,7 +659,7 @@@ static void ath_node_detach(struct ath_
        an->sta = NULL;
  #endif
  
-       if (sta->ht_cap.ht_supported)
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
                ath_tx_node_cleanup(sc, an);
  }
  
@@@ -916,19 -912,10 +914,19 @@@ void ath_hw_check(struct work_struct *w
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        unsigned long flags;
        int busy;
 +      u8 is_alive, nbeacon = 1;
  
        ath9k_ps_wakeup(sc);
 -      if (ath9k_hw_check_alive(sc->sc_ah))
 +      is_alive = ath9k_hw_check_alive(sc->sc_ah);
 +
 +      if (is_alive && !AR_SREV_9300(sc->sc_ah))
                goto out;
 +      else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
 +              ath_dbg(common, RESET,
 +                      "DCU stuck is detected. Schedule chip reset\n");
 +              RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
 +              goto sched_reset;
 +      }
  
        spin_lock_irqsave(&common->cc_lock, flags);
        busy = ath_update_survey_stats(sc);
        if (busy >= 99) {
                if (++sc->hw_busy_count >= 3) {
                        RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
 -                      ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
 +                      goto sched_reset;
                }
 -
 -      } else if (busy >= 0)
 +      } else if (busy >= 0) {
                sc->hw_busy_count = 0;
 +              nbeacon = 3;
 +      }
  
 +      ath_start_rx_poll(sc, nbeacon);
 +      goto out;
 +
 +sched_reset:
 +      ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
  out:
        ath9k_ps_restore(sc);
  }
@@@ -1152,7 -1133,6 +1150,7 @@@ static void ath9k_tx(struct ieee80211_h
  
        if (ath_tx_start(hw, skb, &txctl) != 0) {
                ath_dbg(common, XMIT, "TX failed\n");
 +              TX_STAT_INC(txctl.txq->axq_qnum, txfailed);
                goto exit;
        }
  
@@@ -1171,7 -1151,6 +1169,7 @@@ static void ath9k_stop(struct ieee80211
        mutex_lock(&sc->mutex);
  
        ath_cancel_work(sc);
 +      del_timer_sync(&sc->rx_poll_timer);
  
        if (sc->sc_flags & SC_OP_INVALID) {
                ath_dbg(common, ANY, "Device not present\n");
@@@ -1404,24 -1383,6 +1402,24 @@@ static void ath9k_do_vif_add_setup(stru
        }
  }
  
 +void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
 +{
 +      if (!AR_SREV_9300(sc->sc_ah))
 +              return;
 +
 +      if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF))
 +              return;
 +
 +      mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
 +                      (nbeacon * sc->cur_beacon_conf.beacon_interval));
 +}
 +
 +void ath_rx_poll(unsigned long data)
 +{
 +      struct ath_softc *sc = (struct ath_softc *)data;
 +
 +      ieee80211_queue_work(sc->hw, &sc->hw_check_work);
 +}
  
  static int ath9k_add_interface(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif)
@@@ -1943,8 -1904,6 +1941,8 @@@ static void ath9k_bss_iter(void *data, 
                sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
                sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
  
 +              ath_start_rx_poll(sc, 3);
 +
                if (!common->disable_ani) {
                        sc->sc_flags |= SC_OP_ANI_RUN;
                        ath_start_ani(common);
@@@ -1984,7 -1943,6 +1982,7 @@@ static void ath9k_config_bss(struct ath
                /* Stop ANI */
                sc->sc_flags &= ~SC_OP_ANI_RUN;
                del_timer_sync(&common->ani.timer);
 +              del_timer_sync(&sc->rx_poll_timer);
                memset(&sc->caldata, 0, sizeof(sc->caldata));
        }
  }
@@@ -2028,7 -1986,6 +2026,7 @@@ static void ath9k_bss_info_changed(stru
                } else {
                        sc->sc_flags &= ~SC_OP_ANI_RUN;
                        del_timer_sync(&common->ani.timer);
 +                      del_timer_sync(&sc->rx_poll_timer);
                }
        }
  
index 5fff711fba1d415bfef858d0917311dc6355a59e,08bb45532701125f69bd0e39c7e0defab15e531e..92a6c0a87f894167345a6c779e250de8388226ae
@@@ -1436,7 -1436,7 +1436,7 @@@ static void ath_rate_init(void *priv, s
  
  static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
                            struct ieee80211_sta *sta, void *priv_sta,
 -                          u32 changed, enum nl80211_channel_type oper_chan_type)
 +                          u32 changed)
  {
        struct ath_softc *sc = priv;
        struct ath_rate_priv *ath_rc_priv = priv_sta;
  
        /* FIXME: Handle AP mode later when we support CWM */
  
 -      if (changed & IEEE80211_RC_HT_CHANGED) {
 +      if (changed & IEEE80211_RC_BW_CHANGED) {
                if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
                        return;
  
 -              if (oper_chan_type == NL80211_CHAN_HT40MINUS ||
 -                  oper_chan_type == NL80211_CHAN_HT40PLUS)
 +              if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
                        oper_cw40 = true;
  
                if (oper_cw40)
  
  #ifdef CONFIG_ATH9K_DEBUGFS
  
- static int ath9k_debugfs_open(struct inode *inode, struct file *file)
- {
-       file->private_data = inode->i_private;
-       return 0;
- }
  static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
                                size_t count, loff_t *ppos)
  {
  
  static const struct file_operations fops_rcstat = {
        .read = read_file_rcstat,
-       .open = ath9k_debugfs_open,
+       .open = simple_open,
        .owner = THIS_MODULE
  };
  
index ac4d31b30e467597f9e36e1325ec0e71a0c0020c,11ab1247fae1c841eedc4cf390be9eba167b987f..f3b8e91aa3dcf40272655336b6127d43d742a944
@@@ -873,7 -873,7 +873,7 @@@ il4965_rs_tx_status(void *il_r, struct 
            tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI) ||
            tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ||
            tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA) ||
 -          tbl_type.ant_type != info->antenna_sel_tx ||
 +          tbl_type.ant_type != info->status.antenna ||
            !!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)
            || !!(tx_rate & RATE_MCS_GF_MSK) !=
            !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD) || rs_idx != mac_idx) {
@@@ -2518,12 -2518,6 +2518,6 @@@ il4965_rs_free_sta(void *il_r, struct i
  }
  
  #ifdef CONFIG_MAC80211_DEBUGFS
- static int
- il4965_open_file_generic(struct inode *inode, struct file *file)
- {
-       file->private_data = inode->i_private;
-       return 0;
- }
  
  static void
  il4965_rs_dbgfs_set_mcs(struct il_lq_sta *lq_sta, u32 * rate_n_flags, int idx)
@@@ -2695,7 -2689,7 +2689,7 @@@ il4965_rs_sta_dbgfs_scale_table_read(st
  static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
        .write = il4965_rs_sta_dbgfs_scale_table_write,
        .read = il4965_rs_sta_dbgfs_scale_table_read,
-       .open = il4965_open_file_generic,
+       .open = simple_open,
        .llseek = default_llseek,
  };
  
@@@ -2740,7 -2734,7 +2734,7 @@@ il4965_rs_sta_dbgfs_stats_table_read(st
  
  static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
        .read = il4965_rs_sta_dbgfs_stats_table_read,
-       .open = il4965_open_file_generic,
+       .open = simple_open,
        .llseek = default_llseek,
  };
  
@@@ -2768,7 -2762,7 +2762,7 @@@ il4965_rs_sta_dbgfs_rate_scale_data_rea
  
  static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
        .read = il4965_rs_sta_dbgfs_rate_scale_data_read,
-       .open = il4965_open_file_generic,
+       .open = simple_open,
        .llseek = default_llseek,
  };
  
index f3db23e3efc923ddd43993ef464c0d4038863763,7e590b349dd7523f76db4c1ff235c53b5434d71b..b936ae7e00a36b9fc59a1bb188c93f0ebd349582
@@@ -969,7 -969,7 +969,7 @@@ static void rs_tx_status(void *priv_r, 
            (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
            (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
            (tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA)) ||
 -          (tbl_type.ant_type != info->antenna_sel_tx) ||
 +          (tbl_type.ant_type != info->status.antenna) ||
            (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) ||
            (!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
            (rs_index != mac_index)) {
@@@ -2166,7 -2166,7 +2166,7 @@@ static void rs_stay_in_table(struct iwl
                    (lq_sta->total_success > lq_sta->max_success_limit) ||
                    ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
                     && (flush_interval_passed))) {
 -                      IWL_DEBUG_RATE(priv, "LQ: stay is expired %d %d %d\n:",
 +                      IWL_DEBUG_RATE(priv, "LQ: stay is expired %d %d %d\n",
                                     lq_sta->total_failed,
                                     lq_sta->total_success,
                                     flush_interval_passed);
@@@ -3083,11 -3083,6 +3083,6 @@@ static void rs_free_sta(void *priv_r, s
  }
  
  #ifdef CONFIG_MAC80211_DEBUGFS
- static int open_file_generic(struct inode *inode, struct file *file)
- {
-       file->private_data = inode->i_private;
-       return 0;
- }
  static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
                             u32 *rate_n_flags, int index)
  {
@@@ -3226,7 -3221,7 +3221,7 @@@ static ssize_t rs_sta_dbgfs_scale_table
  static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
        .write = rs_sta_dbgfs_scale_table_write,
        .read = rs_sta_dbgfs_scale_table_read,
-       .open = open_file_generic,
+       .open = simple_open,
        .llseek = default_llseek,
  };
  static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
  
  static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
        .read = rs_sta_dbgfs_stats_table_read,
-       .open = open_file_generic,
+       .open = simple_open,
        .llseek = default_llseek,
  };
  
@@@ -3295,7 -3290,7 +3290,7 @@@ static ssize_t rs_sta_dbgfs_rate_scale_
  
  static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
        .read = rs_sta_dbgfs_rate_scale_data_read,
-       .open = open_file_generic,
+       .open = simple_open,
        .llseek = default_llseek,
  };
  
index 417fc37f0bbbb83e1dca9ac0cddd22071cfdfbf7,2bbaebd99ad42a4a8c057838eead058088686dc0..d109d1bbb3a2e00d10494f3becd9c8d586a0ba73
@@@ -84,17 -84,11 +84,11 @@@ static ssize_t iwl_dbgfs_##name##_write
                                        size_t count, loff_t *ppos);
  
  
- static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
- {
-       file->private_data = inode->i_private;
-       return 0;
- }
  #define DEBUGFS_READ_FILE_OPS(name)                                     \
        DEBUGFS_READ_FUNC(name);                                        \
  static const struct file_operations iwl_dbgfs_##name##_ops = {          \
        .read = iwl_dbgfs_##name##_read,                                \
-       .open = iwl_dbgfs_open_file_generic,                            \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
  };
  
        DEBUGFS_WRITE_FUNC(name);                                       \
  static const struct file_operations iwl_dbgfs_##name##_ops = {          \
        .write = iwl_dbgfs_##name##_write,                              \
-       .open = iwl_dbgfs_open_file_generic,                            \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
  };
  
  static const struct file_operations iwl_dbgfs_##name##_ops = {          \
        .write = iwl_dbgfs_##name##_write,                              \
        .read = iwl_dbgfs_##name##_read,                                \
-       .open = iwl_dbgfs_open_file_generic,                            \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
  };
  
@@@ -240,7 -234,7 +234,7 @@@ static ssize_t iwl_dbgfs_sram_read(stru
                        IWL_ERR(priv, "No uCode has been loadded.\n");
                        return -EINVAL;
                }
 -              img = &priv->fw->img[priv->shrd->ucode_type];
 +              img = &priv->fw->img[priv->cur_ucode];
                priv->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
        }
        len = priv->dbgfs_sram_len;
@@@ -375,19 -369,14 +369,19 @@@ static ssize_t iwl_dbgfs_stations_read(
                                 i, station->sta.sta.addr,
                                 station->sta.station_flags_msk);
                pos += scnprintf(buf + pos, bufsz - pos,
 -                              "TID\tseq_num\trate_n_flags\n");
 +                              "TID seqno  next_rclmd "
 +                              "rate_n_flags state txq\n");
  
                for (j = 0; j < IWL_MAX_TID_COUNT; j++) {
                        tid_data = &priv->tid_data[i][j];
                        pos += scnprintf(buf + pos, bufsz - pos,
 -                              "%d:\t%#x\t%#x",
 +                              "%d:  0x%.4x 0x%.4x     0x%.8x   "
 +                              "%d     %.2d",
                                j, tid_data->seq_number,
 -                              tid_data->agg.rate_n_flags);
 +                              tid_data->next_reclaimed,
 +                              tid_data->agg.rate_n_flags,
 +                              tid_data->agg.state,
 +                              tid_data->agg.txq_id);
  
                        if (tid_data->agg.wait_for_ba)
                                pos += scnprintf(buf + pos, bufsz - pos,
@@@ -555,9 -544,9 +549,9 @@@ static ssize_t iwl_dbgfs_status_read(st
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
                test_bit(STATUS_SCAN_HW, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
 -              test_bit(STATUS_POWER_PMI, &priv->shrd->status));
 +              test_bit(STATUS_POWER_PMI, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
 -              test_bit(STATUS_FW_ERROR, &priv->shrd->status));
 +              test_bit(STATUS_FW_ERROR, &priv->status));
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  }
  
@@@ -2484,44 -2473,6 +2478,44 @@@ static ssize_t iwl_dbgfs_echo_test_writ
        return count;
  }
  
 +static ssize_t iwl_dbgfs_log_event_read(struct file *file,
 +                                       char __user *user_buf,
 +                                       size_t count, loff_t *ppos)
 +{
 +      struct iwl_priv *priv = file->private_data;
 +      char *buf;
 +      int pos = 0;
 +      ssize_t ret = -ENOMEM;
 +
 +      ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true);
 +      if (buf) {
 +              ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 +              kfree(buf);
 +      }
 +      return ret;
 +}
 +
 +static ssize_t iwl_dbgfs_log_event_write(struct file *file,
 +                                      const char __user *user_buf,
 +                                      size_t count, loff_t *ppos)
 +{
 +      struct iwl_priv *priv = file->private_data;
 +      u32 event_log_flag;
 +      char buf[8];
 +      int buf_size;
 +
 +      memset(buf, 0, sizeof(buf));
 +      buf_size = min(count, sizeof(buf) -  1);
 +      if (copy_from_user(buf, user_buf, buf_size))
 +              return -EFAULT;
 +      if (sscanf(buf, "%d", &event_log_flag) != 1)
 +              return -EFAULT;
 +      if (event_log_flag == 1)
 +              iwl_dump_nic_event_log(priv, true, NULL, false);
 +
 +      return count;
 +}
 +
  DEBUGFS_READ_FILE_OPS(rx_statistics);
  DEBUGFS_READ_FILE_OPS(tx_statistics);
  DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@@ -2546,7 -2497,6 +2540,7 @@@ DEBUGFS_READ_FILE_OPS(bt_traffic)
  DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
  DEBUGFS_READ_FILE_OPS(reply_tx_error);
  DEBUGFS_WRITE_FILE_OPS(echo_test);
 +DEBUGFS_READ_WRITE_FILE_OPS(log_event);
  
  /*
   * Create the debugfs files and directories
@@@ -2610,8 -2560,6 +2604,8 @@@ int iwl_dbgfs_register(struct iwl_priv 
        DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR);
 +      DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR);
 +
        if (iwl_advanced_bt_coexist(priv))
                DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
  
index 52e218b2bd375a9f09acb4bd957036757ec44447,4d7b30d3e64855e83b03d1cfaaa4391d6fa8b8d4..9f62283504e35b046ab277e14d127e882949184f
@@@ -180,6 -180,7 +180,6 @@@ static void iwl_trans_rx_hw_init(struc
                           FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
                           FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
                           FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
 -                         FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
                           rb_size|
                           (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
                           (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
@@@ -369,13 -370,21 +369,13 @@@ error
  }
  
  static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
 -                    int slots_num, u32 txq_id)
 +                            int slots_num, u32 txq_id)
  {
        int ret;
  
        txq->need_update = 0;
        memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num);
  
 -      /*
 -       * For the default queues 0-3, set up the swq_id
 -       * already -- all others need to get one later
 -       * (if they need one at all).
 -       */
 -      if (txq_id < 4)
 -              iwl_set_swq_id(txq, txq_id, txq_id);
 -
        /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
         * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
        BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
@@@ -886,6 -895,59 +886,6 @@@ static int iwl_prepare_card_hw(struct i
        return ret;
  }
  
 -#define IWL_AC_UNSET -1
 -
 -struct queue_to_fifo_ac {
 -      s8 fifo, ac;
 -};
 -
 -static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
 -      { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
 -      { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
 -      { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
 -      { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
 -      { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
 -      { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
 -      { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
 -      { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
 -      { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
 -      { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
 -      { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
 -};
 -
 -static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
 -      { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
 -      { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
 -      { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
 -      { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
 -      { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, },
 -      { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, },
 -      { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, },
 -      { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
 -      { IWL_TX_FIFO_BE_IPAN, 2, },
 -      { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
 -      { IWL_TX_FIFO_AUX, IWL_AC_UNSET, },
 -};
 -
 -static const u8 iwlagn_bss_ac_to_fifo[] = {
 -      IWL_TX_FIFO_VO,
 -      IWL_TX_FIFO_VI,
 -      IWL_TX_FIFO_BE,
 -      IWL_TX_FIFO_BK,
 -};
 -static const u8 iwlagn_bss_ac_to_queue[] = {
 -      0, 1, 2, 3,
 -};
 -static const u8 iwlagn_pan_ac_to_fifo[] = {
 -      IWL_TX_FIFO_VO_IPAN,
 -      IWL_TX_FIFO_VI_IPAN,
 -      IWL_TX_FIFO_BE_IPAN,
 -      IWL_TX_FIFO_BK_IPAN,
 -};
 -static const u8 iwlagn_pan_ac_to_queue[] = {
 -      7, 6, 5, 4,
 -};
 -
  /*
   * ucode
   */
@@@ -966,8 -1028,19 +966,8 @@@ static int iwl_trans_pcie_start_fw(stru
                                   const struct fw_img *fw)
  {
        int ret;
 -      struct iwl_trans_pcie *trans_pcie =
 -              IWL_TRANS_GET_PCIE_TRANS(trans);
        bool hw_rfkill;
  
 -      trans_pcie->ac_to_queue[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_queue;
 -      trans_pcie->ac_to_queue[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_queue;
 -
 -      trans_pcie->ac_to_fifo[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_fifo;
 -      trans_pcie->ac_to_fifo[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_fifo;
 -
 -      trans_pcie->mcast_queue[IWL_RXON_CTX_BSS] = 0;
 -      trans_pcie->mcast_queue[IWL_RXON_CTX_PAN] = IWL_IPAN_MCAST_QUEUE;
 -
        /* This may fail if AMT took ownership of the device */
        if (iwl_prepare_card_hw(trans)) {
                IWL_WARN(trans, "Exit HW not ready\n");
@@@ -1025,7 -1098,9 +1025,7 @@@ static void iwl_trans_txq_set_sched(str
  
  static void iwl_tx_start(struct iwl_trans *trans)
  {
 -      const struct queue_to_fifo_ac *queue_to_fifo;
 -      struct iwl_trans_pcie *trans_pcie =
 -              IWL_TRANS_GET_PCIE_TRANS(trans);
 +      struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        u32 a;
        unsigned long flags;
        int i, chan;
        /* Activate all Tx DMA/FIFO channels */
        iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
  
 -      /* map queues to FIFOs */
 -      if (trans->shrd->valid_contexts != BIT(IWL_RXON_CTX_BSS))
 -              queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
 -      else
 -              queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
 -
        iwl_trans_set_wr_ptrs(trans, trans_pcie->cmd_queue, 0);
  
 -      /* make sure all queue are not stopped */
 -      memset(&trans_pcie->queue_stopped[0], 0,
 -              sizeof(trans_pcie->queue_stopped));
 -      for (i = 0; i < 4; i++)
 -              atomic_set(&trans_pcie->queue_stop_count[i], 0);
 +      /* make sure all queue are not stopped/used */
 +      memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
 +      memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
  
 -      /* reset to 0 to enable all the queue first */
 -      trans_pcie->txq_ctx_active_msk = 0;
 +      for (i = 0; i < trans_pcie->n_q_to_fifo; i++) {
 +              int fifo = trans_pcie->setup_q_to_fifo[i];
  
 -      BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) <
 -                                              IWLAGN_FIRST_AMPDU_QUEUE);
 -      BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) <
 -                                              IWLAGN_FIRST_AMPDU_QUEUE);
 +              set_bit(i, trans_pcie->queue_used);
  
 -      for (i = 0; i < IWLAGN_FIRST_AMPDU_QUEUE; i++) {
 -              int fifo = queue_to_fifo[i].fifo;
 -              int ac = queue_to_fifo[i].ac;
 -
 -              iwl_txq_ctx_activate(trans_pcie, i);
 -
 -              if (fifo == IWL_TX_FIFO_UNUSED)
 -                      continue;
 -
 -              if (ac != IWL_AC_UNSET)
 -                      iwl_set_swq_id(&trans_pcie->txq[i], ac, i);
                iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[i],
 -                                            fifo, 0);
 +                                            fifo, true);
        }
  
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
@@@ -1228,32 -1325,70 +1228,32 @@@ static void iwl_trans_pcie_wowlan_suspe
  }
  
  static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
 -              struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
 -              u8 sta_id, u8 tid)
 +                           struct iwl_device_cmd *dev_cmd, int txq_id)
  {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 -      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
        struct iwl_cmd_meta *out_meta;
        struct iwl_tx_queue *txq;
        struct iwl_queue *q;
 -
        dma_addr_t phys_addr = 0;
        dma_addr_t txcmd_phys;
        dma_addr_t scratch_phys;
        u16 len, firstlen, secondlen;
        u8 wait_write_ptr = 0;
 -      u8 txq_id;
 -      bool is_agg = false;
        __le16 fc = hdr->frame_control;
        u8 hdr_len = ieee80211_hdrlen(fc);
        u16 __maybe_unused wifi_seq;
  
 -      /*
 -       * Send this frame after DTIM -- there's a special queue
 -       * reserved for this for contexts that support AP mode.
 -       */
 -      if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
 -              txq_id = trans_pcie->mcast_queue[ctx];
 -
 -              /*
 -               * The microcode will clear the more data
 -               * bit in the last frame it transmits.
 -               */
 -              hdr->frame_control |=
 -                      cpu_to_le16(IEEE80211_FCTL_MOREDATA);
 -      } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
 -              txq_id = IWL_AUX_QUEUE;
 -      else
 -              txq_id =
 -                  trans_pcie->ac_to_queue[ctx][skb_get_queue_mapping(skb)];
 -
 -      /* aggregation is on for this <sta,tid> */
 -      if (info->flags & IEEE80211_TX_CTL_AMPDU) {
 -              WARN_ON(tid >= IWL_MAX_TID_COUNT);
 -              txq_id = trans_pcie->agg_txq[sta_id][tid];
 -              is_agg = true;
 -      }
 -
        txq = &trans_pcie->txq[txq_id];
        q = &txq->q;
  
 -      spin_lock(&txq->lock);
 +      if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) {
 +              WARN_ON_ONCE(1);
 +              return -EINVAL;
 +      }
  
 -      /* In AGG mode, the index in the ring must correspond to the WiFi
 -       * sequence number. This is a HW requirements to help the SCD to parse
 -       * the BA.
 -       * Check here that the packets are in the right place on the ring.
 -       */
 -#ifdef CONFIG_IWLWIFI_DEBUG
 -      wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
 -      WARN_ONCE(is_agg && ((wifi_seq & 0xff) != q->write_ptr),
 -                "Q: %d WiFi Seq %d tfdNum %d",
 -                txq_id, wifi_seq, q->write_ptr);
 -#endif
 +      spin_lock(&txq->lock);
  
        /* Set up driver data for this TFD */
        txq->skbs[q->write_ptr] = skb;
@@@ -1430,8 -1565,8 +1430,8 @@@ static void iwl_trans_pcie_stop_hw(stru
        iwl_enable_rfkill_int(trans);
  }
  
 -static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
 -                    int txq_id, int ssn, struct sk_buff_head *skbs)
 +static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
 +                                 struct sk_buff_head *skbs)
  {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
  
        txq->time_stamp = jiffies;
  
 -      if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE &&
 -                   tid != IWL_TID_NON_QOS &&
 -                   txq_id != trans_pcie->agg_txq[sta_id][tid])) {
 -              /*
 -               * FIXME: this is a uCode bug which need to be addressed,
 -               * log the information and return for now.
 -               * Since it is can possibly happen very often and in order
 -               * not to fill the syslog, don't use IWL_ERR or IWL_WARN
 -               */
 -              IWL_DEBUG_TX_QUEUES(trans, "Bad queue mapping txq_id %d, "
 -                      "agg_txq[sta_id[tid] %d", txq_id,
 -                      trans_pcie->agg_txq[sta_id][tid]);
 -              spin_unlock(&txq->lock);
 -              return 1;
 -      }
 -
        if (txq->q.read_ptr != tfd_num) {
 -              IWL_DEBUG_TX_REPLY(trans, "[Q %d | AC %d] %d -> %d (%d)\n",
 -                              txq_id, iwl_get_queue_ac(txq), txq->q.read_ptr,
 -                              tfd_num, ssn);
 +              IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n",
 +                                 txq_id, txq->q.read_ptr, tfd_num, ssn);
                freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
                if (iwl_queue_space(&txq->q) > txq->q.low_mark)
                        iwl_wake_queue(trans, txq);
        }
  
        spin_unlock(&txq->lock);
 -      return 0;
  }
  
  static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
@@@ -1470,7 -1623,7 +1470,7 @@@ static u32 iwl_trans_pcie_read32(struc
  }
  
  static void iwl_trans_pcie_configure(struct iwl_trans *trans,
 -                            const struct iwl_trans_config *trans_cfg)
 +                                   const struct iwl_trans_config *trans_cfg)
  {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
  
        if (trans_pcie->n_no_reclaim_cmds)
                memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds,
                       trans_pcie->n_no_reclaim_cmds * sizeof(u8));
 +
 +      trans_pcie->n_q_to_fifo = trans_cfg->n_queue_to_fifo;
 +
 +      if (WARN_ON(trans_pcie->n_q_to_fifo > IWL_MAX_HW_QUEUES))
 +              trans_pcie->n_q_to_fifo = IWL_MAX_HW_QUEUES;
 +
 +      /* at least the command queue must be mapped */
 +      WARN_ON(!trans_pcie->n_q_to_fifo);
 +
 +      memcpy(trans_pcie->setup_q_to_fifo, trans_cfg->queue_to_fifo,
 +             trans_pcie->n_q_to_fifo * sizeof(u8));
  }
  
  static void iwl_trans_pcie_free(struct iwl_trans *trans)
        kfree(trans);
  }
  
 +static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
 +{
 +      struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 +
 +      if (state)
 +              set_bit(STATUS_POWER_PMI, &trans_pcie->status);
 +      else
 +              clear_bit(STATUS_POWER_PMI, &trans_pcie->status);
 +}
 +
  #ifdef CONFIG_PM_SLEEP
  static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
  {
@@@ -1766,17 -1898,11 +1766,11 @@@ static ssize_t iwl_dbgfs_##name##_write
                                        size_t count, loff_t *ppos);
  
  
- static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
- {
-       file->private_data = inode->i_private;
-       return 0;
- }
  #define DEBUGFS_READ_FILE_OPS(name)                                   \
        DEBUGFS_READ_FUNC(name);                                        \
  static const struct file_operations iwl_dbgfs_##name##_ops = {                \
        .read = iwl_dbgfs_##name##_read,                                \
-       .open = iwl_dbgfs_open_file_generic,                            \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
  };
  
        DEBUGFS_WRITE_FUNC(name);                                       \
  static const struct file_operations iwl_dbgfs_##name##_ops = {          \
        .write = iwl_dbgfs_##name##_write,                              \
-       .open = iwl_dbgfs_open_file_generic,                            \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
  };
  
  static const struct file_operations iwl_dbgfs_##name##_ops = {                \
        .write = iwl_dbgfs_##name##_write,                              \
        .read = iwl_dbgfs_##name##_read,                                \
-       .open = iwl_dbgfs_open_file_generic,                            \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
  };
  
@@@ -1826,10 -1952,18 +1820,10 @@@ static ssize_t iwl_dbgfs_tx_queue_read(
                txq = &trans_pcie->txq[cnt];
                q = &txq->q;
                pos += scnprintf(buf + pos, bufsz - pos,
 -                              "hwq %.2d: read=%u write=%u stop=%d"
 -                              " swq_id=%#.2x (ac %d/hwq %d)\n",
 +                              "hwq %.2d: read=%u write=%u use=%d stop=%d\n",
                                cnt, q->read_ptr, q->write_ptr,
 -                              !!test_bit(cnt, trans_pcie->queue_stopped),
 -                              txq->swq_id, txq->swq_id & 3,
 -                              (txq->swq_id >> 2) & 0x1f);
 -              if (cnt >= 4)
 -                      continue;
 -              /* for the ACs, display the stop count too */
 -              pos += scnprintf(buf + pos, bufsz - pos,
 -                      "        stop-count: %d\n",
 -                      atomic_read(&trans_pcie->queue_stop_count[cnt]));
 +                              !!test_bit(cnt, trans_pcie->queue_used),
 +                              !!test_bit(cnt, trans_pcie->queue_stopped));
        }
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
        kfree(buf);
@@@ -1863,6 -1997,44 +1857,6 @@@ static ssize_t iwl_dbgfs_rx_queue_read(
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  }
  
 -static ssize_t iwl_dbgfs_log_event_read(struct file *file,
 -                                       char __user *user_buf,
 -                                       size_t count, loff_t *ppos)
 -{
 -      struct iwl_trans *trans = file->private_data;
 -      char *buf;
 -      int pos = 0;
 -      ssize_t ret = -ENOMEM;
 -
 -      ret = pos = iwl_dump_nic_event_log(trans, true, &buf, true);
 -      if (buf) {
 -              ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 -              kfree(buf);
 -      }
 -      return ret;
 -}
 -
 -static ssize_t iwl_dbgfs_log_event_write(struct file *file,
 -                                      const char __user *user_buf,
 -                                      size_t count, loff_t *ppos)
 -{
 -      struct iwl_trans *trans = file->private_data;
 -      u32 event_log_flag;
 -      char buf[8];
 -      int buf_size;
 -
 -      memset(buf, 0, sizeof(buf));
 -      buf_size = min(count, sizeof(buf) -  1);
 -      if (copy_from_user(buf, user_buf, buf_size))
 -              return -EFAULT;
 -      if (sscanf(buf, "%d", &event_log_flag) != 1)
 -              return -EFAULT;
 -      if (event_log_flag == 1)
 -              iwl_dump_nic_event_log(trans, true, NULL, false);
 -
 -      return count;
 -}
 -
  static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
                                        char __user *user_buf,
                                        size_t count, loff_t *ppos) {
@@@ -1989,6 -2161,7 +1983,6 @@@ static ssize_t iwl_dbgfs_fh_reg_read(st
        return ret;
  }
  
 -DEBUGFS_READ_WRITE_FILE_OPS(log_event);
  DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
  DEBUGFS_READ_FILE_OPS(fh_reg);
  DEBUGFS_READ_FILE_OPS(rx_queue);
@@@ -2004,6 -2177,7 +1998,6 @@@ static int iwl_trans_pcie_dbgfs_registe
  {
        DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
        DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
 -      DEBUGFS_ADD_FILE(log_event, dir, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
        DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
@@@ -2031,6 -2205,7 +2025,6 @@@ const struct iwl_trans_ops trans_ops_pc
        .reclaim = iwl_trans_pcie_reclaim,
  
        .tx_agg_disable = iwl_trans_pcie_tx_agg_disable,
 -      .tx_agg_alloc = iwl_trans_pcie_tx_agg_alloc,
        .tx_agg_setup = iwl_trans_pcie_tx_agg_setup,
  
        .free = iwl_trans_pcie_free,
        .write32 = iwl_trans_pcie_write32,
        .read32 = iwl_trans_pcie_read32,
        .configure = iwl_trans_pcie_configure,
 +      .set_pmi = iwl_trans_pcie_set_pmi,
  };
  
  struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd,
diff --combined include/net/mac80211.h
index 838a4db1c8480a2360e869f3593e6e49696cf87d,9210bdc7bd8d417b94cf721b9ac671f7f2e700ed..32cd5171fa227c028119a6f44a2ceb9350ddb1de
@@@ -95,11 -95,9 +95,11 @@@ struct device
   * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues.
   */
  enum ieee80211_max_queues {
 -      IEEE80211_MAX_QUEUES =          4,
 +      IEEE80211_MAX_QUEUES =          16,
  };
  
 +#define IEEE80211_INVAL_HW_QUEUE      0xff
 +
  /**
   * enum ieee80211_ac_numbers - AC numbers as used in mac80211
   * @IEEE80211_AC_VO: voice
@@@ -246,7 -244,7 +246,7 @@@ enum ieee80211_rssi_event 
   * @channel_type: Channel type for this BSS -- the hardware might be
   *    configured for HT40+ while this BSS only uses no-HT, for
   *    example.
 - * @ht_operation_mode: HT operation mode (like in &struct ieee80211_ht_info).
 + * @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation.
   *    This field is only valid when the channel type is one of the HT types.
   * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
   *    implies disabled
@@@ -524,7 -522,7 +524,7 @@@ struct ieee80211_tx_rate 
   *
   * @flags: transmit info flags, defined above
   * @band: the band to transmit on (use for checking for races)
 - * @antenna_sel_tx: antenna to use, 0 for automatic diversity
 + * @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC
   * @ack_frame_id: internal frame ID for TX status, used internally
   * @control: union for control data
   * @status: union for status data
@@@ -540,7 -538,7 +540,7 @@@ struct ieee80211_tx_info 
        u32 flags;
        u8 band;
  
 -      u8 antenna_sel_tx;
 +      u8 hw_queue;
  
        u16 ack_frame_id;
  
                        u8 ampdu_ack_len;
                        int ack_signal;
                        u8 ampdu_len;
 -                      /* 15 bytes free */
 +                      u8 antenna;
 +                      /* 14 bytes free */
                } status;
                struct {
                        struct ieee80211_tx_rate driver_rates[
@@@ -891,8 -888,6 +891,8 @@@ enum ieee80211_vif_flags 
   *    these need to be set (or cleared) when the interface is added
   *    or, if supported by the driver, the interface type is changed
   *    at runtime, mac80211 will never touch this field
 + * @hw_queue: hardware queue for each AC
 + * @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only
   * @drv_priv: data area for driver use, will always be aligned to
   *    sizeof(void *).
   */
@@@ -901,12 -896,7 +901,12 @@@ struct ieee80211_vif 
        struct ieee80211_bss_conf bss_conf;
        u8 addr[ETH_ALEN];
        bool p2p;
 +
 +      u8 cab_queue;
 +      u8 hw_queue[IEEE80211_NUM_ACS];
 +
        u32 driver_flags;
 +
        /* must be last */
        u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
  };
@@@ -1184,15 -1174,6 +1184,15 @@@ enum sta_notify_cmd 
   * @IEEE80211_HW_SCAN_WHILE_IDLE: The device can do hw scan while
   *    being idle (i.e. mac80211 doesn't have to go idle-off during the
   *    the scan).
 + *
 + * @IEEE80211_HW_WANT_MONITOR_VIF: The driver would like to be informed of
 + *    a virtual monitor interface when monitor interfaces are the only
 + *    active interfaces.
 + *
 + * @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface
 + *    queue mapping in order to use different queues (not just one per AC)
 + *    for different virtual interfaces. See the doc section on HW queue
 + *    control for more details.
   */
  enum ieee80211_hw_flags {
        IEEE80211_HW_HAS_RATE_CONTROL                   = 1<<0,
        IEEE80211_HW_PS_NULLFUNC_STACK                  = 1<<11,
        IEEE80211_HW_SUPPORTS_DYNAMIC_PS                = 1<<12,
        IEEE80211_HW_MFP_CAPABLE                        = 1<<13,
 -      /* reuse bit 14 */
 +      IEEE80211_HW_WANT_MONITOR_VIF                   = 1<<14,
        IEEE80211_HW_SUPPORTS_STATIC_SMPS               = 1<<15,
        IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS              = 1<<16,
        IEEE80211_HW_SUPPORTS_UAPSD                     = 1<<17,
        IEEE80211_HW_REPORTS_TX_ACK_STATUS              = 1<<18,
        IEEE80211_HW_CONNECTION_MONITOR                 = 1<<19,
 -      /* reuse bit 20 */
 +      IEEE80211_HW_QUEUE_CONTROL                      = 1<<20,
        IEEE80211_HW_SUPPORTS_PER_STA_GTK               = 1<<21,
        IEEE80211_HW_AP_LINK_PS                         = 1<<22,
        IEEE80211_HW_TX_AMPDU_SETUP_IN_HW               = 1<<23,
   * @max_tx_aggregation_subframes: maximum number of subframes in an
   *    aggregate an HT driver will transmit, used by the peer as a
   *    hint to size its reorder buffer.
 + *
 + * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX
 + *    (if %IEEE80211_HW_QUEUE_CONTROL is set)
   */
  struct ieee80211_hw {
        struct ieee80211_conf conf;
        u8 max_rate_tries;
        u8 max_rx_aggregation_subframes;
        u8 max_tx_aggregation_subframes;
 +      u8 offchannel_tx_hw_queue;
  };
  
  /**
@@@ -1350,7 -1327,7 +1350,7 @@@ static inline struct ieee80211_rate 
  ieee80211_get_tx_rate(const struct ieee80211_hw *hw,
                      const struct ieee80211_tx_info *c)
  {
-       if (WARN_ON(c->control.rates[0].idx < 0))
+       if (WARN_ON_ONCE(c->control.rates[0].idx < 0))
                return NULL;
        return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx];
  }
@@@ -1716,61 -1693,6 +1716,61 @@@ void ieee80211_free_txskb(struct ieee80
   * The driver may also use ieee80211_sta_eosp_irqsafe() in this case.
   */
  
 +/**
 + * DOC: HW queue control
 + *
 + * Before HW queue control was introduced, mac80211 only had a single static
 + * assignment of per-interface AC software queues to hardware queues. This
 + * was problematic for a few reasons:
 + * 1) off-channel transmissions might get stuck behind other frames
 + * 2) multiple virtual interfaces couldn't be handled correctly
 + * 3) after-DTIM frames could get stuck behind other frames
 + *
 + * To solve this, hardware typically uses multiple different queues for all
 + * the different usages, and this needs to be propagated into mac80211 so it
 + * won't have the same problem with the software queues.
 + *
 + * Therefore, mac80211 now offers the %IEEE80211_HW_QUEUE_CONTROL capability
 + * flag that tells it that the driver implements its own queue control. To do
 + * so, the driver will set up the various queues in each &struct ieee80211_vif
 + * and the offchannel queue in &struct ieee80211_hw. In response, mac80211 will
 + * use those queue IDs in the hw_queue field of &struct ieee80211_tx_info and
 + * if necessary will queue the frame on the right software queue that mirrors
 + * the hardware queue.
 + * Additionally, the driver has to then use these HW queue IDs for the queue
 + * management functions (ieee80211_stop_queue() et al.)
 + *
 + * The driver is free to set up the queue mappings as needed, multiple virtual
 + * interfaces may map to the same hardware queues if needed. The setup has to
 + * happen during add_interface or change_interface callbacks. For example, a
 + * driver supporting station+station and station+AP modes might decide to have
 + * 10 hardware queues to handle different scenarios:
 + *
 + * 4 AC HW queues for 1st vif: 0, 1, 2, 3
 + * 4 AC HW queues for 2nd vif: 4, 5, 6, 7
 + * after-DTIM queue for AP:   8
 + * off-channel queue:         9
 + *
 + * It would then set up the hardware like this:
 + *   hw.offchannel_tx_hw_queue = 9
 + *
 + * and the first virtual interface that is added as follows:
 + *   vif.hw_queue[IEEE80211_AC_VO] = 0
 + *   vif.hw_queue[IEEE80211_AC_VI] = 1
 + *   vif.hw_queue[IEEE80211_AC_BE] = 2
 + *   vif.hw_queue[IEEE80211_AC_BK] = 3
 + *   vif.cab_queue = 8 // if AP mode, otherwise %IEEE80211_INVAL_HW_QUEUE
 + * and the second virtual interface with 4-7.
 + *
 + * If queue 6 gets full, for example, mac80211 would only stop the second
 + * virtual interface's BE queue since virtual interface queues are per AC.
 + *
 + * Note that the vif.cab_queue value should be set to %IEEE80211_INVAL_HW_QUEUE
 + * whenever the queue is not used (i.e. the interface is not in AP mode) if the
 + * queue could potentially be shared since mac80211 will look at cab_queue when
 + * a queue is stopped/woken even if the interface is not in AP mode.
 + */
 +
  /**
   * enum ieee80211_filter_flags - hardware filter flags
   *
@@@ -1857,18 -1779,6 +1857,18 @@@ enum ieee80211_frame_release_type 
        IEEE80211_FRAME_RELEASE_UAPSD,
  };
  
 +/**
 + * enum ieee80211_rate_control_changed - flags to indicate what changed
 + *
 + * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit
 + *    to this station changed.
 + * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed.
 + */
 +enum ieee80211_rate_control_changed {
 +      IEEE80211_RC_BW_CHANGED         = BIT(0),
 +      IEEE80211_RC_SMPS_CHANGED       = BIT(1),
 +};
 +
  /**
   * struct ieee80211_ops - callbacks from mac80211 to the driver
   *
   *    up the list of states.
   *    The callback can sleep.
   *
 + * @sta_rc_update: Notifies the driver of changes to the bitrates that can be
 + *    used to transmit to the station. The changes are advertised with bits
 + *    from &enum ieee80211_rate_control_changed and the values are reflected
 + *    in the station data. This callback should only be used when the driver
 + *    uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since
 + *    otherwise the rate control algorithm is notified directly.
 + *    Must be atomic.
 + *
   * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
   *    bursting) for a hardware TX queue.
   *    Returns a negative error code on failure.
@@@ -2233,7 -2135,6 +2233,7 @@@ struct ieee80211_ops 
  #ifdef CONFIG_PM
        int (*suspend)(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
        int (*resume)(struct ieee80211_hw *hw);
 +      void (*set_wakeup)(struct ieee80211_hw *hw, bool enabled);
  #endif
        int (*add_interface)(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif);
                         struct ieee80211_sta *sta,
                         enum ieee80211_sta_state old_state,
                         enum ieee80211_sta_state new_state);
 +      void (*sta_rc_update)(struct ieee80211_hw *hw,
 +                            struct ieee80211_vif *vif,
 +                            struct ieee80211_sta *sta,
 +                            u32 changed);
        int (*conf_tx)(struct ieee80211_hw *hw,
 -                     struct ieee80211_vif *vif, u16 queue,
 +                     struct ieee80211_vif *vif, u16 ac,
                       const struct ieee80211_tx_queue_params *params);
        u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
        void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@@ -3614,6 -3511,19 +3614,6 @@@ void ieee80211_send_bar(struct ieee8021
  
  /* Rate control API */
  
 -/**
 - * enum rate_control_changed - flags to indicate which parameter changed
 - *
 - * @IEEE80211_RC_HT_CHANGED: The HT parameters of the operating channel have
 - *    changed, rate control algorithm can update its internal state if needed.
 - * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed, the rate
 - *    control algorithm needs to adjust accordingly.
 - */
 -enum rate_control_changed {
 -      IEEE80211_RC_HT_CHANGED         = BIT(0),
 -      IEEE80211_RC_SMPS_CHANGED       = BIT(1),
 -};
 -
  /**
   * struct ieee80211_tx_rate_control - rate control information for/from RC algo
   *
@@@ -3659,8 -3569,9 +3659,8 @@@ struct rate_control_ops 
        void (*rate_init)(void *priv, struct ieee80211_supported_band *sband,
                          struct ieee80211_sta *sta, void *priv_sta);
        void (*rate_update)(void *priv, struct ieee80211_supported_band *sband,
 -                          struct ieee80211_sta *sta,
 -                          void *priv_sta, u32 changed,
 -                          enum nl80211_channel_type oper_chan_type);
 +                          struct ieee80211_sta *sta, void *priv_sta,
 +                          u32 changed);
        void (*free_sta)(void *priv, struct ieee80211_sta *sta,
                         void *priv_sta);
  
@@@ -3795,9 -3706,8 +3795,9 @@@ void ieee80211_enable_rssi_reports(stru
  
  void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
  
 -int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb);
 +int ieee80211_add_srates_ie(struct ieee80211_vif *vif,
 +                          struct sk_buff *skb, bool need_basic);
  
  int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif,
 -                              struct sk_buff *skb);
 +                              struct sk_buff *skb, bool need_basic);
  #endif /* MAC80211_H */
index b0fc205411c173cfa5d8221c4b4a32b44e4895b5,30f99c344847c0802a9dd21c820a06bd99371a7e..e7af5227e322e08ea0e7ceaf507b357de9251026
@@@ -135,7 -135,7 +135,7 @@@ static ssize_t ieee80211_if_read_##name
  static const struct file_operations name##_ops = {                    \
        .read = ieee80211_if_read_##name,                               \
        .write = (_write),                                              \
-       .open = mac80211_open_file_generic,                             \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
  }
  
@@@ -424,7 -424,6 +424,7 @@@ static ssize_t ieee80211_if_parse_tsf
        struct ieee80211_local *local = sdata->local;
        unsigned long long tsf;
        int ret;
 +      int tsf_is_delta = 0;
  
        if (strncmp(buf, "reset", 5) == 0) {
                if (local->ops->reset_tsf) {
                        wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
                }
        } else {
 +              if (buflen > 10 && buf[1] == '=') {
 +                      if (buf[0] == '+')
 +                              tsf_is_delta = 1;
 +                      else if (buf[0] == '-')
 +                              tsf_is_delta = -1;
 +                      else
 +                              return -EINVAL;
 +                      buf += 2;
 +              }
                ret = kstrtoull(buf, 10, &tsf);
                if (ret < 0)
                        return -EINVAL;
 +              if (tsf_is_delta)
 +                      tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf;
                if (local->ops->set_tsf) {
                        drv_set_tsf(local, sdata, tsf);
                        wiphy_info(local->hw.wiphy,
@@@ -511,23 -499,26 +511,23 @@@ IEEE80211_IF_FILE(dot11MeshForwarding, 
  IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);
  #endif
  
 -
 -#define DEBUGFS_ADD(name) \
 -      debugfs_create_file(#name, 0400, sdata->debugfs.dir, \
 -                          sdata, &name##_ops);
 -
  #define DEBUGFS_ADD_MODE(name, mode) \
        debugfs_create_file(#name, mode, sdata->debugfs.dir, \
                            sdata, &name##_ops);
  
 -static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 +#define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400)
 +
 +static void add_common_files(struct ieee80211_sub_if_data *sdata)
  {
        DEBUGFS_ADD(drop_unencrypted);
 -      DEBUGFS_ADD(flags);
 -      DEBUGFS_ADD(state);
 -      DEBUGFS_ADD(channel_type);
        DEBUGFS_ADD(rc_rateidx_mask_2ghz);
        DEBUGFS_ADD(rc_rateidx_mask_5ghz);
        DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
        DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
 +}
  
 +static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 +{
        DEBUGFS_ADD(bssid);
        DEBUGFS_ADD(aid);
        DEBUGFS_ADD(last_beacon);
  
  static void add_ap_files(struct ieee80211_sub_if_data *sdata)
  {
 -      DEBUGFS_ADD(drop_unencrypted);
 -      DEBUGFS_ADD(flags);
 -      DEBUGFS_ADD(state);
 -      DEBUGFS_ADD(channel_type);
 -      DEBUGFS_ADD(rc_rateidx_mask_2ghz);
 -      DEBUGFS_ADD(rc_rateidx_mask_5ghz);
 -      DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
 -      DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
 -
        DEBUGFS_ADD(num_sta_authorized);
        DEBUGFS_ADD(num_sta_ps);
        DEBUGFS_ADD(dtim_count);
  
  static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
  {
 -      DEBUGFS_ADD(channel_type);
 -      DEBUGFS_ADD(rc_rateidx_mask_2ghz);
 -      DEBUGFS_ADD(rc_rateidx_mask_5ghz);
 -      DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
 -      DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
 -
        DEBUGFS_ADD_MODE(tsf, 0600);
  }
  
  static void add_wds_files(struct ieee80211_sub_if_data *sdata)
  {
 -      DEBUGFS_ADD(drop_unencrypted);
 -      DEBUGFS_ADD(flags);
 -      DEBUGFS_ADD(state);
 -      DEBUGFS_ADD(channel_type);
 -      DEBUGFS_ADD(rc_rateidx_mask_2ghz);
 -      DEBUGFS_ADD(rc_rateidx_mask_5ghz);
 -      DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
 -      DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
 -
        DEBUGFS_ADD(peer);
  }
  
 -static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 -{
 -      DEBUGFS_ADD(drop_unencrypted);
 -      DEBUGFS_ADD(flags);
 -      DEBUGFS_ADD(state);
 -      DEBUGFS_ADD(channel_type);
 -      DEBUGFS_ADD(rc_rateidx_mask_2ghz);
 -      DEBUGFS_ADD(rc_rateidx_mask_5ghz);
 -      DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
 -      DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
 -}
 -
 -static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
 -{
 -      DEBUGFS_ADD(flags);
 -      DEBUGFS_ADD(state);
 -      DEBUGFS_ADD(channel_type);
 -}
 -
  #ifdef CONFIG_MAC80211_MESH
  
  static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
@@@ -617,13 -651,6 +617,13 @@@ static void add_files(struct ieee80211_
        if (!sdata->debugfs.dir)
                return;
  
 +      DEBUGFS_ADD(flags);
 +      DEBUGFS_ADD(state);
 +      DEBUGFS_ADD(channel_type);
 +
 +      if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
 +              add_common_files(sdata);
 +
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_MESH_POINT:
  #ifdef CONFIG_MAC80211_MESH
        case NL80211_IFTYPE_WDS:
                add_wds_files(sdata);
                break;
 -      case NL80211_IFTYPE_MONITOR:
 -              add_monitor_files(sdata);
 -              break;
 -      case NL80211_IFTYPE_AP_VLAN:
 -              add_vlan_files(sdata);
 -              break;
        default:
                break;
        }
index ceeefd42410373419744b8fc83f2feed945d041d,832b2da5e4cd8955b11920e9fe4537e7e0981687..5ccec2c1e9f669165763372176e62fbc2562d049
@@@ -33,7 -33,7 +33,7 @@@ static ssize_t sta_ ##name## _read(stru
  #define STA_OPS(name)                                                 \
  static const struct file_operations sta_ ##name## _ops = {            \
        .read = sta_##name##_read,                                      \
-       .open = mac80211_open_file_generic,                             \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
  }
  
@@@ -41,7 -41,7 +41,7 @@@
  static const struct file_operations sta_ ##name## _ops = {            \
        .read = sta_##name##_read,                                      \
        .write = sta_##name##_write,                                    \
-       .open = mac80211_open_file_generic,                             \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
  }
  
@@@ -63,7 -63,7 +63,7 @@@ static ssize_t sta_flags_read(struct fi
        test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
  
        int res = scnprintf(buf, sizeof(buf),
 -                          "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
 +                          "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
                            TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
                            TEST(PS_DRIVER), TEST(AUTHORIZED),
                            TEST(SHORT_PREAMBLE),
@@@ -71,8 -71,7 +71,8 @@@
                            TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
                            TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
                            TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
 -                          TEST(INSERTED), TEST(RATE_CONTROL));
 +                          TEST(INSERTED), TEST(RATE_CONTROL),
 +                          TEST(TOFFSET_KNOWN));
  #undef TEST
        return simple_read_from_buffer(userbuf, count, ppos, buf, res);
  }
diff --combined net/mac80211/mlme.c
index 12ca9820689afdaabdfbf9f651c2fec9b3b33cd6,f76da5b3f5c5864f0b649187fca47517d244ce77..bbf1100d90d6d7a50e3566f435fc9551508a735b
@@@ -171,64 -171,122 +171,64 @@@ static int ecw2cw(int ecw
        return (1 << ecw) - 1;
  }
  
 -/*
 - * ieee80211_enable_ht should be called only after the operating band
 - * has been determined as ht configuration depends on the hw's
 - * HT abilities for a specific band.
 - */
 -static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
 -                             struct ieee80211_ht_info *hti,
 -                             const u8 *bssid, u16 ap_ht_cap_flags,
 -                             bool beacon_htcap_ie)
 +static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
 +                                struct ieee80211_ht_operation *ht_oper,
 +                                const u8 *bssid, bool reconfig)
  {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
        struct sta_info *sta;
        u32 changed = 0;
 -      int hti_cfreq;
        u16 ht_opmode;
 -      bool enable_ht = true;
 -      enum nl80211_channel_type prev_chantype;
 -      enum nl80211_channel_type rx_channel_type = NL80211_CHAN_NO_HT;
 -      enum nl80211_channel_type tx_channel_type;
 +      bool disable_40 = false;
  
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 -      prev_chantype = sdata->vif.bss_conf.channel_type;
 -
  
 -      hti_cfreq = ieee80211_channel_to_frequency(hti->control_chan,
 -                                                 sband->band);
 -      /* check that channel matches the right operating channel */
 -      if (local->hw.conf.channel->center_freq != hti_cfreq) {
 -              /* Some APs mess this up, evidently.
 -               * Netgear WNDR3700 sometimes reports 4 higher than
 -               * the actual channel, for instance.
 -               */
 -              printk(KERN_DEBUG
 -                     "%s: Wrong control channel in association"
 -                     " response: configured center-freq: %d"
 -                     " hti-cfreq: %d  hti->control_chan: %d"
 -                     " band: %d.  Disabling HT.\n",
 -                     sdata->name,
 -                     local->hw.conf.channel->center_freq,
 -                     hti_cfreq, hti->control_chan,
 -                     sband->band);
 -              enable_ht = false;
 -      }
 -
 -      if (enable_ht) {
 -              rx_channel_type = NL80211_CHAN_HT20;
 -
 -              if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
 -                  !ieee80111_cfg_override_disables_ht40(sdata) &&
 -                  (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
 -                  (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
 -                      switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
 -                      case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
 -                              rx_channel_type = NL80211_CHAN_HT40PLUS;
 -                              break;
 -                      case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
 -                              rx_channel_type = NL80211_CHAN_HT40MINUS;
 -                              break;
 -                      }
 -              }
 +      switch (sdata->vif.bss_conf.channel_type) {
 +      case NL80211_CHAN_HT40PLUS:
 +              if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
 +                      disable_40 = true;
 +              break;
 +      case NL80211_CHAN_HT40MINUS:
 +              if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
 +                      disable_40 = true;
 +              break;
 +      default:
 +              break;
        }
  
 -      tx_channel_type = ieee80211_get_tx_channel_type(local, rx_channel_type);
 -
 -      if (local->tmp_channel)
 -              local->tmp_channel_type = rx_channel_type;
 +      /* This can change during the lifetime of the BSS */
 +      if (!(ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
 +              disable_40 = true;
  
 -      if (!ieee80211_set_channel_type(local, sdata, rx_channel_type)) {
 -              /* can only fail due to HT40+/- mismatch */
 -              rx_channel_type = NL80211_CHAN_HT20;
 -              WARN_ON(!ieee80211_set_channel_type(local, sdata,
 -                                                  rx_channel_type));
 -      }
 -
 -      if (beacon_htcap_ie && (prev_chantype != rx_channel_type)) {
 -              /*
 -               * Whenever the AP announces the HT mode change that can be
 -               * 40MHz intolerant or etc., it would be safer to stop tx
 -               * queues before doing hw config to avoid buffer overflow.
 -               */
 -              ieee80211_stop_queues_by_reason(&sdata->local->hw,
 -                              IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
 +      mutex_lock(&local->sta_mtx);
 +      sta = sta_info_get(sdata, bssid);
  
 -              /* flush out all packets */
 -              synchronize_net();
 +      WARN_ON_ONCE(!sta);
  
 -              drv_flush(local, false);
 -      }
 +      if (sta && !sta->supports_40mhz)
 +              disable_40 = true;
  
 -      /* channel_type change automatically detected */
 -      ieee80211_hw_config(local, 0);
 +      if (sta && (!reconfig ||
 +                  (disable_40 != !!(sta->sta.ht_cap.cap &
 +                                      IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) {
  
 -      if (prev_chantype != tx_channel_type) {
 -              rcu_read_lock();
 -              sta = sta_info_get(sdata, bssid);
 -              if (sta)
 -                      rate_control_rate_update(local, sband, sta,
 -                                               IEEE80211_RC_HT_CHANGED,
 -                                               tx_channel_type);
 -              rcu_read_unlock();
 +              if (disable_40)
 +                      sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 +              else
 +                      sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
  
 -              if (beacon_htcap_ie)
 -                      ieee80211_wake_queues_by_reason(&sdata->local->hw,
 -                              IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
 +              rate_control_rate_update(local, sband, sta,
 +                                       IEEE80211_RC_BW_CHANGED);
        }
 +      mutex_unlock(&local->sta_mtx);
  
 -      ht_opmode = le16_to_cpu(hti->operation_mode);
 +      ht_opmode = le16_to_cpu(ht_oper->operation_mode);
  
        /* if bss configuration changed store the new one */
 -      if (sdata->ht_opmode_valid != enable_ht ||
 -          sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
 -          prev_chantype != rx_channel_type) {
 +      if (!reconfig || (sdata->vif.bss_conf.ht_operation_mode != ht_opmode)) {
                changed |= BSS_CHANGED_HT;
                sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
 -              sdata->ht_opmode_valid = enable_ht;
        }
  
        return changed;
@@@ -258,12 -316,12 +258,12 @@@ static int ieee80211_compatible_rates(c
  }
  
  static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
 -                              struct sk_buff *skb, const u8 *ht_info_ie,
 +                              struct sk_buff *skb, const u8 *ht_oper_ie,
                                struct ieee80211_supported_band *sband,
                                struct ieee80211_channel *channel,
                                enum ieee80211_smps_mode smps)
  {
 -      struct ieee80211_ht_info *ht_info;
 +      struct ieee80211_ht_operation *ht_oper;
        u8 *pos;
        u32 flags = channel->flags;
        u16 cap;
  
        BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
  
 -      if (!ht_info_ie)
 +      if (!ht_oper_ie)
                return;
  
 -      if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
 +      if (ht_oper_ie[1] < sizeof(struct ieee80211_ht_operation))
                return;
  
        memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
        ieee80211_apply_htcap_overrides(sdata, &ht_cap);
  
 -      ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
 +      ht_oper = (struct ieee80211_ht_operation *)(ht_oper_ie + 2);
  
        /* determine capability flags */
        cap = ht_cap.cap;
  
 -      switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
 +      switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
        case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
                if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
                        cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
                break;
        }
  
 +      /*
 +       * If 40 MHz was disabled associate as though we weren't
 +       * capable of 40 MHz -- some broken APs will never fall
 +       * back to trying to transmit in 20 MHz.
 +       */
 +      if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_40MHZ) {
 +              cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 +              cap &= ~IEEE80211_HT_CAP_SGI_40;
 +      }
 +
        /* set SM PS mode properly */
        cap &= ~IEEE80211_HT_CAP_SM_PS;
        switch (smps) {
@@@ -509,7 -557,7 +509,7 @@@ static void ieee80211_send_assoc(struc
        }
  
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
 -              ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_information_ie,
 +              ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_operation_ie,
                                    sband, local->oper_channel, ifmgd->ap_smps);
  
        /* if present, add any custom non-vendor IEs that go after HT */
@@@ -1134,7 -1182,7 +1134,7 @@@ static void ieee80211_sta_wmm_params(st
        if (!local->ops->conf_tx)
                return;
  
 -      if (local->hw.queues < 4)
 +      if (local->hw.queues < IEEE80211_NUM_ACS)
                return;
  
        if (!wmm_param)
@@@ -1387,6 -1435,7 +1387,6 @@@ static void ieee80211_set_disassoc(stru
        sdata->vif.bss_conf.assoc = false;
  
        /* on the next assoc, re-program HT parameters */
 -      sdata->ht_opmode_valid = false;
        memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
        memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
  
@@@ -1518,23 -1567,14 +1518,23 @@@ static void ieee80211_mgd_probe_ap_send
                ifmgd->nullfunc_failed = false;
                ieee80211_send_nullfunc(sdata->local, sdata, 0);
        } else {
 +              int ssid_len;
 +
                ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
 -              ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0,
 -                                       (u32) -1, true, false);
 +              if (WARN_ON_ONCE(ssid == NULL))
 +                      ssid_len = 0;
 +              else
 +                      ssid_len = ssid[1];
 +
 +              ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL,
 +                                       0, (u32) -1, true, false);
        }
  
        ifmgd->probe_send_count++;
        ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
        run_again(ifmgd, ifmgd->probe_timeout);
 +      if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
 +              drv_flush(sdata->local, false);
  }
  
  static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
@@@ -1603,7 -1643,6 +1603,7 @@@ struct sk_buff *ieee80211_ap_probereq_g
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct sk_buff *skb;
        const u8 *ssid;
 +      int ssid_len;
  
        if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
                return NULL;
                return NULL;
  
        ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
 +      if (WARN_ON_ONCE(ssid == NULL))
 +              ssid_len = 0;
 +      else
 +              ssid_len = ssid[1];
 +
        skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid,
 -                                      (u32) -1, ssid + 2, ssid[1],
 +                                      (u32) -1, ssid + 2, ssid_len,
                                        NULL, 0, true);
  
        return skb;
@@@ -1966,6 -2000,7 +1966,6 @@@ static bool ieee80211_assoc_success(str
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
        u32 changed = 0;
        int err;
 -      u16 ap_ht_cap_flags;
  
        /* AssocResp and ReassocResp have identical structure */
  
                ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                                elems.ht_cap_elem, &sta->sta.ht_cap);
  
 -      ap_ht_cap_flags = sta->sta.ht_cap.cap;
 +      sta->supports_40mhz =
 +              sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
  
        rate_control_rate_init(sta);
  
                ieee80211_set_wmm_default(sdata, false);
        changed |= BSS_CHANGED_QOS;
  
 -      if (elems.ht_info_elem && elems.wmm_param &&
 +      if (elems.ht_operation && elems.wmm_param &&
            !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
 -              changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
 -                                             cbss->bssid, ap_ht_cap_flags,
 -                                             false);
 +              changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
 +                                                cbss->bssid, false);
  
        /* set AID and assoc capability,
         * ieee80211_set_associated() will tell the driver */
@@@ -2284,7 -2319,7 +2284,7 @@@ static const u64 care_about_ies 
        (1ULL << WLAN_EID_CHANNEL_SWITCH) |
        (1ULL << WLAN_EID_PWR_CONSTRAINT) |
        (1ULL << WLAN_EID_HT_CAPABILITY) |
 -      (1ULL << WLAN_EID_HT_INFORMATION);
 +      (1ULL << WLAN_EID_HT_OPERATION);
  
  static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_mgmt *mgmt,
        if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
                if (directed_tim) {
                        if (local->hw.conf.dynamic_ps_timeout > 0) {
 -                              local->hw.conf.flags &= ~IEEE80211_CONF_PS;
 -                              ieee80211_hw_config(local,
 -                                                  IEEE80211_CONF_CHANGE_PS);
 +                              if (local->hw.conf.flags & IEEE80211_CONF_PS) {
 +                                      local->hw.conf.flags &= ~IEEE80211_CONF_PS;
 +                                      ieee80211_hw_config(local,
 +                                                          IEEE80211_CONF_CHANGE_PS);
 +                              }
                                ieee80211_send_nullfunc(local, sdata, 0);
 -                      } else {
 +                      } else if (!local->pspolling && sdata->u.mgd.powersave) {
                                local->pspolling = true;
  
                                /*
                        erp_valid, erp_value);
  
  
 -      if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
 +      if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param &&
            !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) {
 -              struct sta_info *sta;
                struct ieee80211_supported_band *sband;
 -              u16 ap_ht_cap_flags;
 -
 -              rcu_read_lock();
 -
 -              sta = sta_info_get(sdata, bssid);
 -              if (WARN_ON(!sta)) {
 -                      rcu_read_unlock();
 -                      return;
 -              }
  
                sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
  
 -              ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
 -                              elems.ht_cap_elem, &sta->sta.ht_cap);
 -
 -              ap_ht_cap_flags = sta->sta.ht_cap.cap;
 -
 -              rcu_read_unlock();
 -
 -              changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
 -                                             bssid, ap_ht_cap_flags, true);
 +              changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
 +                                                bssid, true);
        }
  
        /* Note: country IE parsing is done for us by cfg80211 */
@@@ -3010,11 -3060,6 +3010,11 @@@ static int ieee80211_prep_connection(st
        struct sta_info *sta;
        bool have_sta = false;
        int err;
 +      int ht_cfreq;
 +      enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
 +      const u8 *ht_oper_ie;
 +      const struct ieee80211_ht_operation *ht_oper = NULL;
 +      struct ieee80211_supported_band *sband;
  
        if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
                return -EINVAL;
        mutex_unlock(&local->mtx);
  
        /* switch to the right channel */
 +      sband = local->hw.wiphy->bands[cbss->channel->band];
 +
 +      ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ;
 +
 +      if (sband->ht_cap.ht_supported) {
 +              ht_oper_ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION,
 +                                            cbss->information_elements,
 +                                            cbss->len_information_elements);
 +              if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper))
 +                      ht_oper = (void *)(ht_oper_ie + 2);
 +      }
 +
 +      if (ht_oper) {
 +              ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
 +                                                        cbss->channel->band);
 +              /* check that channel matches the right operating channel */
 +              if (cbss->channel->center_freq != ht_cfreq) {
 +                      /*
 +                       * It's possible that some APs are confused here;
 +                       * Netgear WNDR3700 sometimes reports 4 higher than
 +                       * the actual channel in association responses, but
 +                       * since we look at probe response/beacon data here
 +                       * it should be OK.
 +                       */
 +                      printk(KERN_DEBUG
 +                             "%s: Wrong control channel: center-freq: %d"
 +                             " ht-cfreq: %d ht->primary_chan: %d"
 +                             " band: %d. Disabling HT.\n",
 +                             sdata->name, cbss->channel->center_freq,
 +                             ht_cfreq, ht_oper->primary_chan,
 +                             cbss->channel->band);
 +                      ht_oper = NULL;
 +              }
 +      }
 +
 +      if (ht_oper) {
 +              channel_type = NL80211_CHAN_HT20;
 +
 +              if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
 +                      switch (ht_oper->ht_param &
 +                                      IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
 +                      case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
 +                              channel_type = NL80211_CHAN_HT40PLUS;
 +                              break;
 +                      case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
 +                              channel_type = NL80211_CHAN_HT40MINUS;
 +                              break;
 +                      }
 +              }
 +      }
 +
 +      if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
 +              /* can only fail due to HT40+/- mismatch */
 +              channel_type = NL80211_CHAN_HT20;
 +              printk(KERN_DEBUG
 +                     "%s: disabling 40 MHz due to multi-vif mismatch\n",
 +                     sdata->name);
 +              ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
 +              WARN_ON(!ieee80211_set_channel_type(local, sdata,
 +                                                  channel_type));
 +      }
 +
        local->oper_channel = cbss->channel;
 -      ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 +      ieee80211_hw_config(local, 0);
  
        if (!have_sta) {
 -              struct ieee80211_supported_band *sband;
                u32 rates = 0, basic_rates = 0;
                bool have_higher_than_11mbit;
                int min_rate = INT_MAX, min_rate_index = -1;
  
 -              sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
 -
                ieee80211_get_rates(sband, bss->supp_rates,
                                    bss->supp_rates_len,
                                    &rates, &basic_rates,
@@@ -3325,7 -3311,7 +3325,7 @@@ int ieee80211_mgd_assoc(struct ieee8021
        /* Also disable HT if we don't support it or the AP doesn't use WMM */
        sband = local->hw.wiphy->bands[req->bss->channel->band];
        if (!sband->ht_cap.ht_supported ||
 -          local->hw.queues < 4 || !bss->wmm_used)
 +          local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used)
                ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
  
        memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
                ifmgd->ap_smps = ifmgd->req_smps;
  
        assoc_data->capability = req->bss->capability;
 -      assoc_data->wmm = bss->wmm_used && (local->hw.queues >= 4);
 +      assoc_data->wmm = bss->wmm_used &&
 +                        (local->hw.queues >= IEEE80211_NUM_ACS);
        assoc_data->supp_rates = bss->supp_rates;
        assoc_data->supp_rates_len = bss->supp_rates_len;
 -      assoc_data->ht_information_ie =
 -              ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION);
 +      assoc_data->ht_operation_ie =
 +              ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
  
        if (bss->wmm_used && bss->uapsd_supported &&
            (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
                 */
                printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
                       sdata->name, ifmgd->bssid);
-               assoc_data->timeout = jiffies +
-                               TU_TO_EXP_TIME(req->bss->beacon_interval);
+               assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
        } else {
                assoc_data->have_beacon = true;
                assoc_data->sent_assoc = false;
diff --combined net/wireless/nl80211.c
index c3e82af72bf56eac0d5e04d9cdb62bd52be7b88e,f432c57af05d03addc5f856bfff8a784c19f19a1..5e261234d2718fbd452ada23dbab3d41d3be3ed3
@@@ -1104,20 -1104,17 +1104,20 @@@ static const struct nla_policy txq_para
  static int parse_txq_params(struct nlattr *tb[],
                            struct ieee80211_txq_params *txq_params)
  {
 -      if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] ||
 +      if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
            !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
            !tb[NL80211_TXQ_ATTR_AIFS])
                return -EINVAL;
  
 -      txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]);
 +      txq_params->ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
        txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
        txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
        txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
        txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
  
 +      if (txq_params->ac >= NL80211_NUM_ACS)
 +              return -EINVAL;
 +
        return 0;
  }
  
@@@ -1297,6 -1294,11 +1297,11 @@@ static int nl80211_set_wiphy(struct sk_
                        goto bad_res;
                }
  
+               if (!netif_running(netdev)) {
+                       result = -ENETDOWN;
+                       goto bad_res;
+               }
                nla_for_each_nested(nl_txq_params,
                                    info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
                                    rem_txq_params) {
@@@ -2490,9 -2492,6 +2495,9 @@@ static int nl80211_send_station(struct 
                NLA_PUT(msg, NL80211_STA_INFO_STA_FLAGS,
                        sizeof(struct nl80211_sta_flag_update),
                        &sinfo->sta_flags);
 +      if (sinfo->filled & STATION_INFO_T_OFFSET)
 +              NLA_PUT_U64(msg, NL80211_STA_INFO_T_OFFSET,
 +                          sinfo->t_offset);
        nla_nest_end(msg, sinfoattr);
  
        if (sinfo->filled & STATION_INFO_ASSOC_REQ_IES)
@@@ -3291,8 -3290,6 +3296,8 @@@ static int nl80211_get_mesh_config(stru
                        cur_params.element_ttl);
        NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
                        cur_params.auto_open_plinks);
 +      NLA_PUT_U32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
 +                      cur_params.dot11MeshNbrOffsetMaxNeighbor);
        NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
                        cur_params.dot11MeshHWMPmaxPREQretries);
        NLA_PUT_U32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
@@@ -3337,7 -3334,6 +3342,7 @@@ static const struct nla_policy nl80211_
        [NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
        [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
        [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
 +      [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
  
        [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
        [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
  
  static const struct nla_policy
        nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
 +      [NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
        [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
        [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
        [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
@@@ -3408,9 -3403,6 +3413,9 @@@ do {
                        mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks,
                        mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8);
 +      FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
 +                      mask, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
 +                      nla_get_u32);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries,
                        mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
                        nla_get_u8);
@@@ -3468,12 -3460,6 +3473,12 @@@ static int nl80211_parse_mesh_setup(str
                             nl80211_mesh_setup_params_policy))
                return -EINVAL;
  
 +      if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
 +              setup->sync_method =
 +              (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
 +               IEEE80211_SYNC_METHOD_VENDOR :
 +               IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;
 +
        if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
                setup->path_sel_proto =
                (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
@@@ -6014,7 -6000,6 +6019,7 @@@ static int nl80211_set_wowlan(struct sk
        struct cfg80211_wowlan new_triggers = {};
        struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan;
        int err, i;
 +      bool prev_enabled = rdev->wowlan;
  
        if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns)
                return -EOPNOTSUPP;
                rdev->wowlan = NULL;
        }
  
 +      if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan)
 +              rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan);
 +
        return 0;
   error:
        for (i = 0; i < new_triggers.n_patterns; i++)
@@@ -6407,7 -6389,7 +6412,7 @@@ static struct genl_ops nl80211_ops[] = 
                .doit = nl80211_get_key,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .doit = nl80211_set_beacon,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .doit = nl80211_start_ap,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .doit = nl80211_stop_ap,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .doit = nl80211_set_station,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .doit = nl80211_del_station,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .doit = nl80211_del_mpath,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .doit = nl80211_set_bss,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .doit = nl80211_get_mesh_config,
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .doit = nl80211_setdel_pmksa,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .doit = nl80211_setdel_pmksa,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .doit = nl80211_flush_pmksa,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
                .doit = nl80211_probe_client,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
@@@ -7922,38 -7904,6 +7927,38 @@@ void nl80211_pmksa_candidate_notify(str
        nlmsg_free(msg);
  }
  
 +void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
 +                            struct net_device *netdev, int freq,
 +                            enum nl80211_channel_type type, gfp_t gfp)
 +{
 +      struct sk_buff *msg;
 +      void *hdr;
 +
 +      msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
 +      if (!msg)
 +              return;
 +
 +      hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CH_SWITCH_NOTIFY);
 +      if (!hdr) {
 +              nlmsg_free(msg);
 +              return;
 +      }
 +
 +      NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
 +      NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
 +      NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, type);
 +
 +      genlmsg_end(msg, hdr);
 +
 +      genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
 +                              nl80211_mlme_mcgrp.id, gfp);
 +      return;
 +
 + nla_put_failure:
 +      genlmsg_cancel(msg, hdr);
 +      nlmsg_free(msg);
 +}
 +
  void
  nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
                                struct net_device *netdev, const u8 *peer,