|
@@ -65,19 +65,6 @@
|
|
|
#include "fw-api.h"
|
|
|
#include "fw-dbg.h"
|
|
|
|
|
|
-void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
|
|
-{
|
|
|
- mvm->ampdu_ref++;
|
|
|
-
|
|
|
-#ifdef CONFIG_IWLWIFI_DEBUGFS
|
|
|
- if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
|
|
|
- spin_lock(&mvm->drv_stats_lock);
|
|
|
- mvm->drv_rx_stats.ampdu_count++;
|
|
|
- spin_unlock(&mvm->drv_stats_lock);
|
|
|
- }
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|
|
int queue, struct ieee80211_sta *sta)
|
|
|
{
|
|
@@ -587,6 +574,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
|
|
|
struct sk_buff *tail;
|
|
|
u32 reorder = le32_to_cpu(desc->reorder_data);
|
|
|
bool amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU;
|
|
|
+ bool last_subframe =
|
|
|
+ desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME;
|
|
|
u8 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
|
|
u8 sub_frame_idx = desc->amsdu_info &
|
|
|
IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK;
|
|
@@ -651,7 +640,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
|
|
|
/* release immediately if allowed by nssn and no stored frames */
|
|
|
if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {
|
|
|
if (iwl_mvm_is_sn_less(buffer->head_sn, nssn,
|
|
|
- buffer->buf_size))
|
|
|
+ buffer->buf_size) &&
|
|
|
+ (!amsdu || last_subframe))
|
|
|
buffer->head_sn = nssn;
|
|
|
/* No need to update AMSDU last SN - we are moving the head */
|
|
|
spin_unlock_bh(&buffer->lock);
|
|
@@ -685,7 +675,20 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
|
|
|
buffer->last_sub_index = sub_frame_idx;
|
|
|
}
|
|
|
|
|
|
- iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn);
|
|
|
+ /*
|
|
|
+ * We cannot trust NSSN for AMSDU sub-frames that are not the last.
|
|
|
+ * The reason is that NSSN advances on the first sub-frame, and may
|
|
|
+ * cause the reorder buffer to advance before all the sub-frames arrive.
|
|
|
+ * Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with
|
|
|
+ * SN 1. NSSN for first sub frame will be 3 with the result of driver
|
|
|
+ * releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is
|
|
|
+ * already ahead and it will be dropped.
|
|
|
+ * If the last sub-frame is not on this queue - we will get frame
|
|
|
+ * release notification with up to date NSSN.
|
|
|
+ */
|
|
|
+ if (!amsdu || last_subframe)
|
|
|
+ iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn);
|
|
|
+
|
|
|
spin_unlock_bh(&buffer->lock);
|
|
|
return true;
|
|
|
|
|
@@ -734,6 +737,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|
|
struct ieee80211_hdr *hdr = (void *)(pkt->data + sizeof(*desc));
|
|
|
u32 len = le16_to_cpu(desc->mpdu_len);
|
|
|
u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags);
|
|
|
+ u16 phy_info = le16_to_cpu(desc->phy_info);
|
|
|
struct ieee80211_sta *sta = NULL;
|
|
|
struct sk_buff *skb;
|
|
|
u8 crypt_len = 0;
|
|
@@ -764,16 +768,34 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|
|
le16_to_cpu(desc->status));
|
|
|
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
|
|
}
|
|
|
-
|
|
|
- rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise);
|
|
|
+ /* set the preamble flag if appropriate */
|
|
|
+ if (phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE)
|
|
|
+ rx_status->flag |= RX_FLAG_SHORTPRE;
|
|
|
+
|
|
|
+ if (likely(!(phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) {
|
|
|
+ rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise);
|
|
|
+ /* TSF as indicated by the firmware is at INA time */
|
|
|
+ rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
|
|
|
+ }
|
|
|
rx_status->device_timestamp = le32_to_cpu(desc->gp2_on_air_rise);
|
|
|
rx_status->band = desc->channel > 14 ? NL80211_BAND_5GHZ :
|
|
|
NL80211_BAND_2GHZ;
|
|
|
rx_status->freq = ieee80211_channel_to_frequency(desc->channel,
|
|
|
rx_status->band);
|
|
|
iwl_mvm_get_signal_strength(mvm, desc, rx_status);
|
|
|
- /* TSF as indicated by the firmware is at INA time */
|
|
|
- rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
|
|
|
+
|
|
|
+ /* update aggregation data for monitor sake on default queue */
|
|
|
+ if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
|
|
|
+ bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE;
|
|
|
+
|
|
|
+ rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
|
|
|
+ rx_status->ampdu_reference = mvm->ampdu_ref;
|
|
|
+ /* toggle is switched whenever new aggregation starts */
|
|
|
+ if (toggle_bit != mvm->ampdu_toggle) {
|
|
|
+ mvm->ampdu_ref++;
|
|
|
+ mvm->ampdu_toggle = toggle_bit;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
@@ -795,6 +817,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|
|
|
|
|
if (sta) {
|
|
|
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
|
|
+ struct ieee80211_vif *tx_blocked_vif =
|
|
|
+ rcu_dereference(mvm->csa_tx_blocked_vif);
|
|
|
u8 baid = (u8)((le32_to_cpu(desc->reorder_data) &
|
|
|
IWL_RX_MPDU_REORDER_BAID_MASK) >>
|
|
|
IWL_RX_MPDU_REORDER_BAID_SHIFT);
|
|
@@ -804,8 +828,15 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|
|
* frames from a blocked station on a new channel we can
|
|
|
* TX to it again.
|
|
|
*/
|
|
|
- if (unlikely(mvm->csa_tx_block_bcn_timeout))
|
|
|
- iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
|
|
|
+ if (unlikely(tx_blocked_vif) &&
|
|
|
+ tx_blocked_vif == mvmsta->vif) {
|
|
|
+ struct iwl_mvm_vif *mvmvif =
|
|
|
+ iwl_mvm_vif_from_mac80211(tx_blocked_vif);
|
|
|
+
|
|
|
+ if (mvmvif->csa_target_freq == rx_status->freq)
|
|
|
+ iwl_mvm_sta_modify_disable_tx_ap(mvm, sta,
|
|
|
+ false);
|
|
|
+ }
|
|
|
|
|
|
rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status);
|
|
|
|
|
@@ -828,8 +859,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|
|
iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL);
|
|
|
}
|
|
|
|
|
|
- /* TODO: multi queue TCM */
|
|
|
-
|
|
|
if (ieee80211_is_data(hdr->frame_control))
|
|
|
iwl_mvm_rx_csum(sta, skb, desc);
|
|
|
|
|
@@ -854,14 +883,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|
|
iwl_mvm_agg_rx_received(mvm, baid);
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * TODO: PHY info.
|
|
|
- * Verify we don't have the information in the MPDU descriptor and
|
|
|
- * that it is not needed.
|
|
|
- * Make sure for monitor mode that we are on default queue, update
|
|
|
- * ampdu_ref and the rest of phy info then
|
|
|
- */
|
|
|
-
|
|
|
/* Set up the HT phy flags */
|
|
|
switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
|
|
|
case RATE_MCS_CHAN_WIDTH_20:
|
|
@@ -905,8 +926,18 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|
|
rx_status->band);
|
|
|
}
|
|
|
|
|
|
- /* TODO: PHY info - update ampdu queue statistics (for debugfs) */
|
|
|
- /* TODO: PHY info - gscan */
|
|
|
+ /* management stuff on default queue */
|
|
|
+ if (!queue) {
|
|
|
+ if (unlikely((ieee80211_is_beacon(hdr->frame_control) ||
|
|
|
+ ieee80211_is_probe_resp(hdr->frame_control)) &&
|
|
|
+ mvm->sched_scan_pass_all ==
|
|
|
+ SCHED_SCAN_PASS_ALL_ENABLED))
|
|
|
+ mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_FOUND;
|
|
|
+
|
|
|
+ if (unlikely(ieee80211_is_beacon(hdr->frame_control) ||
|
|
|
+ ieee80211_is_probe_resp(hdr->frame_control)))
|
|
|
+ rx_status->boottime_ns = ktime_get_boot_ns();
|
|
|
+ }
|
|
|
|
|
|
iwl_mvm_create_skb(skb, hdr, len, crypt_len, rxb);
|
|
|
if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc))
|