+--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+@@ -510,7 +510,11 @@ int ath9k_hw_process_rxdesc_edma(struct
+ */
+ if (rxsp->status11 & AR_CRCErr)
+ rxs->rs_status |= ATH9K_RXERR_CRC;
+- else if (rxsp->status11 & AR_PHYErr) {
++ else if (rxsp->status11 & AR_DecryptCRCErr)
++ rxs->rs_status |= ATH9K_RXERR_DECRYPT;
++ else if (rxsp->status11 & AR_MichaelErr)
++ rxs->rs_status |= ATH9K_RXERR_MIC;
++ if (rxsp->status11 & AR_PHYErr) {
+ phyerr = MS(rxsp->status11, AR_PHYErrCode);
+ /*
+ * If we reach a point here where AR_PostDelimCRCErr is
+@@ -532,11 +536,7 @@ int ath9k_hw_process_rxdesc_edma(struct
+ rxs->rs_status |= ATH9K_RXERR_PHY;
+ rxs->rs_phyerr = phyerr;
+ }
+-
+- } else if (rxsp->status11 & AR_DecryptCRCErr)
+- rxs->rs_status |= ATH9K_RXERR_DECRYPT;
+- else if (rxsp->status11 & AR_MichaelErr)
+- rxs->rs_status |= ATH9K_RXERR_MIC;
++ };
+ }
+
+ if (rxsp->status11 & AR_KeyMiss)
+--- a/drivers/net/wireless/ath/carl9170/tx.c
++++ b/drivers/net/wireless/ath/carl9170/tx.c
+@@ -1236,6 +1236,7 @@ static bool carl9170_tx_ps_drop(struct a
+ {
+ struct ieee80211_sta *sta;
+ struct carl9170_sta_info *sta_info;
++ struct ieee80211_tx_info *tx_info;
+
+ rcu_read_lock();
+ sta = __carl9170_get_tx_sta(ar, skb);
+@@ -1243,12 +1244,13 @@ static bool carl9170_tx_ps_drop(struct a
+ goto out_rcu;
+
+ sta_info = (void *) sta->drv_priv;
+- if (unlikely(sta_info->sleeping)) {
+- struct ieee80211_tx_info *tx_info;
++ tx_info = IEEE80211_SKB_CB(skb);
+
++ if (unlikely(sta_info->sleeping) &&
++ !(tx_info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER |
++ IEEE80211_TX_CTL_CLEAR_PS_FILT))) {
+ rcu_read_unlock();
+
+- tx_info = IEEE80211_SKB_CB(skb);
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ atomic_dec(&ar->tx_ampdu_upload);
+
+--- a/drivers/net/wireless/iwlegacy/4965-mac.c
++++ b/drivers/net/wireless/iwlegacy/4965-mac.c
+@@ -1694,7 +1694,7 @@ il4965_tx_skb(struct il_priv *il, struct
+ sta_priv = (void *)sta->drv_priv;
+
+ if (sta_priv && sta_priv->asleep &&
+- (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
++ (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
+ /*
+ * This sends an asynchronous command to the device,
+ * but we can rely on it being processed before the
+--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
++++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+@@ -322,7 +322,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
+ sta_priv = (void *)info->control.sta->drv_priv;
+
+ if (sta_priv && sta_priv->asleep &&
+- (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
++ (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
+ /*
+ * This sends an asynchronous command to the device,
+ * but we can rely on it being processed before the
+@@ -331,6 +331,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
+ * counter.
+ * For now set the counter to just 1 since we do not
+ * support uAPSD yet.
++ *
++ * FIXME: If we get two non-bufferable frames one
++ * after the other, we might only send out one of
++ * them because this is racy.
+ */
+ iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
+ }
+--- a/drivers/net/wireless/p54/txrx.c
++++ b/drivers/net/wireless/p54/txrx.c
+@@ -690,7 +690,7 @@ static void p54_tx_80211_header(struct p
+ if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
+ *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
+
+- if (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)
++ if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)
+ *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+
+ if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -341,9 +341,9 @@ struct ieee80211_bss_conf {
+ * used to indicate that a frame was already retried due to PS
+ * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
+ * used to indicate frame should not be encrypted
+- * @IEEE80211_TX_CTL_POLL_RESPONSE: This frame is a response to a poll
+- * frame (PS-Poll or uAPSD) and should be sent although the station
+- * is in powersave mode.
++ * @IEEE80211_TX_CTL_NO_PS_BUFFER: This frame is a response to a poll
++ * frame (PS-Poll or uAPSD) or a non-bufferable MMPDU and must
++ * be sent although the station is in powersave mode.
+ * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the
+ * transmit function after the current frame, this can be used
+ * by drivers to kick the DMA queue only if unset or when the
+@@ -399,7 +399,7 @@ enum mac80211_tx_control_flags {
+ IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
+ IEEE80211_TX_INTFL_RETRIED = BIT(15),
+ IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
+- IEEE80211_TX_CTL_POLL_RESPONSE = BIT(17),
++ IEEE80211_TX_CTL_NO_PS_BUFFER = BIT(17),
+ IEEE80211_TX_CTL_MORE_FRAMES = BIT(18),
+ IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19),
+ /* hole at 20, use later */
+@@ -425,7 +425,7 @@ enum mac80211_tx_control_flags {
+ IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU | \
+ IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK | \
+ IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \
+- IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_POLL_RESPONSE | \
++ IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_NO_PS_BUFFER | \
+ IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \
+ IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP)
+
+@@ -1634,7 +1634,7 @@ void ieee80211_free_txskb(struct ieee802
+ * the station sends a PS-Poll or a uAPSD trigger frame, mac80211
+ * will inform the driver of this with the @allow_buffered_frames
+ * callback; this callback is optional. mac80211 will then transmit
+- * the frames as usual and set the %IEEE80211_TX_CTL_POLL_RESPONSE
++ * the frames as usual and set the %IEEE80211_TX_CTL_NO_PS_BUFFER
+ * on each frame. The last frame in the service period (or the only
+ * response to a PS-Poll) also has %IEEE80211_TX_STATUS_EOSP set to
+ * indicate that it ends the service period; as this frame must have
+@@ -1642,6 +1642,9 @@ void ieee80211_free_txskb(struct ieee802
+ * When TX status is reported for this frame, the service period is
+ * marked has having ended and a new one can be started by the peer.
+ *
++ * Additionally, non-bufferable MMPDUs can also be transmitted by
++ * mac80211 with the %IEEE80211_TX_CTL_NO_PS_BUFFER set in them.
++ *
+ * Another race condition can happen on some devices like iwlwifi
+ * when there are frames queued for the station and it wakes up
+ * or polls; the frames that are already queued could end up being
+@@ -2140,7 +2143,7 @@ enum ieee80211_frame_release_type {
+ * @allow_buffered_frames: Prepare device to allow the given number of frames
+ * to go out to the given station. The frames will be sent by mac80211
+ * via the usual TX path after this call. The TX information for frames
+- * released will also have the %IEEE80211_TX_CTL_POLL_RESPONSE flag set
++ * released will also have the %IEEE80211_TX_CTL_NO_PS_BUFFER flag set
+ * and the last one will also have %IEEE80211_TX_STATUS_EOSP set. In case
+ * frames from multiple TIDs are released and the driver might reorder
+ * them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
-@@ -184,6 +184,8 @@ static void ieee80211_send_addba_resp(st
- memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
- else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+@@ -187,6 +187,8 @@ static void ieee80211_send_addba_resp(st
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
+ else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
+ else if (sdata->vif.type == NL80211_IFTYPE_WDS)
+ memcpy(mgmt->bssid, da, ETH_ALEN);
IEEE80211_STYPE_ACTION);
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
-@@ -79,7 +79,8 @@ static void ieee80211_send_addba_request
- memcpy(mgmt->da, da, ETH_ALEN);
+@@ -81,7 +81,8 @@ static void ieee80211_send_addba_request
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
if (sdata->vif.type == NL80211_IFTYPE_AP ||
-- sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+- sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
++ sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
+ sdata->vif.type == NL80211_IFTYPE_WDS)
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
-@@ -398,7 +399,8 @@ int ieee80211_start_tx_ba_session(struct
- */
- if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+@@ -471,6 +472,7 @@ int ieee80211_start_tx_ba_session(struct
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
-- sdata->vif.type != NL80211_IFTYPE_AP)
-+ sdata->vif.type != NL80211_IFTYPE_AP &&
-+ sdata->vif.type != NL80211_IFTYPE_WDS)
+ sdata->vif.type != NL80211_IFTYPE_AP &&
++ sdata->vif.type != NL80211_IFTYPE_WDS &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
return -EINVAL;
- if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
-@@ -59,7 +59,7 @@ static ssize_t sta_flags_read(struct fil
- char buf[100];
- struct sta_info *sta = file->private_data;
- u32 staflags = get_sta_flags(sta);
-- int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
-+ int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s",
- staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
- staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
- staflags & WLAN_STA_PS_STA ? "PS (sta)\n" : "",
-@@ -67,7 +67,6 @@ static ssize_t sta_flags_read(struct fil
- staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
- staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
- staflags & WLAN_STA_WME ? "WME\n" : "",
-- staflags & WLAN_STA_WDS ? "WDS\n" : "",
- staflags & WLAN_STA_MFP ? "MFP\n" : "");
- return simple_read_from_buffer(userbuf, count, ppos, buf, res);
- }
+@@ -63,11 +63,11 @@ static ssize_t sta_flags_read(struct fil
+ 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",
+ TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
+ TEST(PS_DRIVER), TEST(AUTHORIZED),
+ TEST(SHORT_PREAMBLE),
+- TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
++ TEST(WME), TEST(CLEAR_PS_FILT),
+ TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
+ TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
+ TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -178,7 +178,6 @@ static int ieee80211_do_open(struct net_
u32 changed = 0;
int res;
u32 hw_reconf_flags = 0;
-@@ -290,27 +289,6 @@ static int ieee80211_do_open(struct net_
+@@ -309,28 +308,6 @@ static int ieee80211_do_open(struct net_
set_bit(SDATA_STATE_RUNNING, &sdata->state);
- goto err_del_interface;
- }
-
-- /* no locking required since STA is not live yet */
-- sta->flags |= WLAN_STA_AUTHORIZED;
+- sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
+- sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+- sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
-
- res = sta_info_insert(sta);
- if (res) {
/*
* set_multicast_list will be invoked by the networking core
* which will check whether any increments here were done in
-@@ -344,8 +322,7 @@ static int ieee80211_do_open(struct net_
+@@ -357,8 +334,7 @@ static int ieee80211_do_open(struct net_
netif_tx_start_all_queues(dev);
return 0;
- err_del_interface:
-- drv_remove_interface(local, &sdata->vif);
+- drv_remove_interface(local, sdata);
+
err_stop:
if (!local->open_count)
drv_stop(local);
-@@ -718,6 +695,70 @@ static void ieee80211_if_setup(struct ne
+@@ -722,6 +698,70 @@ static void ieee80211_if_setup(struct ne
dev->destructor = free_netdev;
}
+ sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
+
+ if (elems.ht_cap_elem)
-+ ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
++ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
+ elems.ht_cap_elem, &sta->sta.ht_cap);
+
+ if (elems.wmm_param)
-+ set_sta_flags(sta, WLAN_STA_WME);
++ set_sta_flag(sta, WLAN_STA_WME);
+
+ if (new) {
-+ sta->flags = WLAN_STA_AUTHORIZED;
++ set_sta_flag(sta, WLAN_STA_AUTHORIZED);
+ rate_control_rate_init(sta);
+ sta_info_insert_rcu(sta);
+ }
static void ieee80211_iface_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
-@@ -822,6 +863,9 @@ static void ieee80211_iface_work(struct
+@@ -826,6 +866,9 @@ static void ieee80211_iface_work(struct
break;
ieee80211_mesh_rx_queued_mgmt(sdata, skb);
break;
break;
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
-@@ -2160,7 +2160,8 @@ ieee80211_rx_h_action(struct ieee80211_r
- */
- if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+@@ -2282,6 +2282,7 @@ ieee80211_rx_h_action(struct ieee80211_r
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
-- sdata->vif.type != NL80211_IFTYPE_AP)
-+ sdata->vif.type != NL80211_IFTYPE_AP &&
-+ sdata->vif.type != NL80211_IFTYPE_WDS)
+ sdata->vif.type != NL80211_IFTYPE_AP &&
++ sdata->vif.type != NL80211_IFTYPE_WDS &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
break;
- /* verify action_code is present */
-@@ -2375,13 +2376,14 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
+@@ -2492,14 +2493,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
return RX_DROP_MONITOR;
switch (stype) {
+ case cpu_to_le16(IEEE80211_STYPE_AUTH):
case cpu_to_le16(IEEE80211_STYPE_BEACON):
case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
- /* process for all: mesh, mlme, ibss */
+ /* process for all: mesh, mlme, ibss, wds */
break;
- case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
- case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
-@@ -2724,10 +2726,16 @@ static int prepare_for_handlers(struct i
+ case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
+ case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
+@@ -2853,10 +2855,16 @@ static int prepare_for_handlers(struct i
}
break;
case NL80211_IFTYPE_WDS:
break;
default:
/* should never get here */
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -1050,7 +1050,7 @@ static void ieee80211_send_null_response
+ * exchange. Also set EOSP to indicate this packet
+ * ends the poll/service period.
+ */
+- info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE |
++ info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
+ IEEE80211_TX_STATUS_EOSP |
+ IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+@@ -1177,7 +1177,7 @@ ieee80211_sta_ps_deliver_response(struct
+ * STA may still remain is PS mode after this frame
+ * exchange.
+ */
+- info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE;
++ info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+
+ /*
+ * Use MoreData flag to indicate whether there are
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -31,7 +31,6 @@
+ * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
* frames.
- * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
* @WLAN_STA_WME: Station is a QoS-STA.
- * @WLAN_STA_WDS: Station is one of our WDS peers.
* @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
* IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
* frame to this station is transmitted.
-@@ -54,7 +53,6 @@ enum ieee80211_sta_info_flags {
- WLAN_STA_SHORT_PREAMBLE = 1<<4,
- WLAN_STA_ASSOC_AP = 1<<5,
- WLAN_STA_WME = 1<<6,
-- WLAN_STA_WDS = 1<<7,
- WLAN_STA_CLEAR_PS_FILT = 1<<9,
- WLAN_STA_MFP = 1<<10,
- WLAN_STA_BLOCK_BA = 1<<11,
---- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-@@ -671,7 +671,7 @@ static int ar9003_hw_process_ini(struct
- REG_WRITE_ARRAY(&ah->iniModesAdditional,
- modesIndex, regWrites);
-
-- if (AR_SREV_9300(ah))
-+ if (AR_SREV_9330(ah))
- REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites);
+@@ -62,7 +61,6 @@ enum ieee80211_sta_info_flags {
+ WLAN_STA_AUTHORIZED,
+ WLAN_STA_SHORT_PREAMBLE,
+ WLAN_STA_WME,
+- WLAN_STA_WDS,
+ WLAN_STA_CLEAR_PS_FILT,
+ WLAN_STA_MFP,
+ WLAN_STA_BLOCK_BA,
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -448,18 +448,23 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+ struct ieee80211_local *local = tx->local;
- if (AR_SREV_9340(ah) && !ah->is_clk_25mhz)
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -975,7 +975,10 @@ void ath9k_hw_init_global_settings(struc
- if (ah->misc_mode != 0)
- REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode);
+- if (unlikely(!sta ||
+- ieee80211_is_probe_resp(hdr->frame_control) ||
+- ieee80211_is_auth(hdr->frame_control) ||
+- ieee80211_is_assoc_resp(hdr->frame_control) ||
+- ieee80211_is_reassoc_resp(hdr->frame_control)))
++ if (unlikely(!sta))
+ return TX_CONTINUE;
-- rx_lat = 37;
-+ if (IS_CHAN_A_FAST_CLOCK(ah, chan))
-+ rx_lat = 41;
-+ else
-+ rx_lat = 37;
- tx_lat = 54;
+ if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
+ test_sta_flag(sta, WLAN_STA_PS_DRIVER)) &&
+- !(info->flags & IEEE80211_TX_CTL_POLL_RESPONSE))) {
++ !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
+ int ac = skb_get_queue_mapping(tx->skb);
- if (IS_CHAN_HALF_RATE(chan)) {
-@@ -989,7 +992,7 @@ void ath9k_hw_init_global_settings(struc
- sifstime = 32;
- } else if (IS_CHAN_QUARTER_RATE(chan)) {
- eifs = 340;
-- rx_lat *= 4;
-+ rx_lat = (rx_lat * 4) - 1;
- tx_lat *= 4;
- if (IS_CHAN_A_FAST_CLOCK(ah, chan))
- tx_lat += 22;
-@@ -997,8 +1000,14 @@ void ath9k_hw_init_global_settings(struc
- slottime = 21;
- sifstime = 64;
- } else {
-- eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS)/common->clockrate;
-- reg = REG_READ(ah, AR_USEC);
-+ if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) {
-+ eifs = AR_D_GBL_IFS_EIFS_ASYNC_FIFO;
-+ reg = AR_USEC_ASYNC_FIFO;
-+ } else {
-+ eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS)/
-+ common->clockrate;
-+ reg = REG_READ(ah, AR_USEC);
++ /* only deauth, disassoc and action are bufferable MMPDUs */
++ if (ieee80211_is_mgmt(hdr->frame_control) &&
++ !ieee80211_is_deauth(hdr->frame_control) &&
++ !ieee80211_is_disassoc(hdr->frame_control) &&
++ !ieee80211_is_action(hdr->frame_control)) {
++ info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
++ return TX_CONTINUE;
+ }
- rx_lat = MS(reg, AR_USEC_RX_LAT);
- tx_lat = MS(reg, AR_USEC_TX_LAT);
-
---- a/drivers/net/wireless/ath/ath9k/reg.h
-+++ b/drivers/net/wireless/ath/ath9k/reg.h
-@@ -619,6 +619,7 @@
- #define AR_D_GBL_IFS_EIFS 0x10b0
- #define AR_D_GBL_IFS_EIFS_M 0x0000FFFF
- #define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000
-+#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO 363
-
- #define AR_D_GBL_IFS_MISC 0x10f0
- #define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007
-@@ -1503,6 +1504,7 @@ enum {
- #define AR_USEC_TX_LAT_S 14
- #define AR_USEC_RX_LAT 0x1F800000
- #define AR_USEC_RX_LAT_S 23
-+#define AR_USEC_ASYNC_FIFO 0x12E00074
++
+ #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
+ sta->sta.addr, sta->sta.aid, ac);
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -480,7 +480,7 @@ struct ieee80211_if_ibss {
- #define AR_RESET_TSF 0x8020
- #define AR_RESET_TSF_ONCE 0x01000000
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -582,7 +582,10 @@ static bool ath_lookup_legacy(struct ath
- tx_info = IEEE80211_SKB_CB(skb);
- rates = tx_info->control.rates;
+ bool control_port;
-- for (i = 3; i >= 0; i--) {
-+ for (i = 0; i < 4; i++) {
-+ if (!rates[i].count || rates[i].idx < 0)
-+ break;
-+
- if (!(rates[i].flags & IEEE80211_TX_RC_MCS))
- return true;
- }
+- u8 bssid[ETH_ALEN];
++ u8 bssid[ETH_ALEN] __aligned(2);
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 ssid_len, ie_len;
+ u8 *ie;