rx.c 39.6 KB
Newer Older
Johannes Berg's avatar
Johannes Berg committed
1 2
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
3
 * Copyright (C) 2012-2014, 2018-2024 Intel Corporation
Johannes Berg's avatar
Johannes Berg committed
4 5 6
 * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
 * Copyright (C) 2016-2017 Intel Deutschland GmbH
 */
7
#include <asm/unaligned.h>
8
#include <linux/etherdevice.h>
9
#include <linux/skbuff.h>
Johannes Berg's avatar
Johannes Berg committed
10 11 12 13 14 15 16 17 18 19
#include "iwl-trans.h"
#include "mvm.h"
#include "fw-api.h"

/*
 * iwl_mvm_rx_rx_phy_cmd - REPLY_RX_PHY_CMD handler
 *
 * Copies the phy information in mvm->last_phy_info, it will be used when the
 * actual data will come from the fw in the next packet.
 */
20
void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
Johannes Berg's avatar
Johannes Berg committed
21 22
{
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
23 24 25 26
	unsigned int pkt_len = iwl_rx_packet_payload_len(pkt);

	if (unlikely(pkt_len < sizeof(mvm->last_phy_info)))
		return;
Johannes Berg's avatar
Johannes Berg committed
27 28 29

	memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info));
	mvm->ampdu_ref++;
30 31 32 33 34 35 36 37

#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
Johannes Berg's avatar
Johannes Berg committed
38 39 40 41 42 43 44 45
}

/*
 * iwl_mvm_pass_packet_to_mac80211 - builds the packet for mac80211
 *
 * Adds the rxb to a new skb and give it to mac80211
 */
static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
46
					    struct ieee80211_sta *sta,
47
					    struct napi_struct *napi,
48
					    struct sk_buff *skb,
Johannes Berg's avatar
Johannes Berg committed
49
					    struct ieee80211_hdr *hdr, u16 len,
50
					    u8 crypt_len,
51
					    struct iwl_rx_cmd_buffer *rxb)
Johannes Berg's avatar
Johannes Berg committed
52
{
53 54 55 56 57 58 59 60 61 62 63 64 65 66
	unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
	unsigned int fraglen;

	/*
	 * The 'hdrlen' (plus the 8 bytes for the SNAP and the crypt_len,
	 * but those are all multiples of 4 long) all goes away, but we
	 * want the *end* of it, which is going to be the start of the IP
	 * header, to be aligned when it gets pulled in.
	 * The beginning of the skb->data is aligned on at least a 4-byte
	 * boundary after allocation. Everything here is aligned at least
	 * on a 2-byte boundary so we can just take hdrlen & 3 and pad by
	 * the result.
	 */
	skb_reserve(skb, hdrlen & 3);
Johannes Berg's avatar
Johannes Berg committed
67 68

	/* If frame is small enough to fit in skb->head, pull it completely.
69 70 71 72 73 74 75 76 77 78
	 * If not, only pull ieee80211_hdr (including crypto if present, and
	 * an additional 8 bytes for SNAP/ethertype, see below) so that
	 * splice() or TCP coalesce are more efficient.
	 *
	 * Since, in addition, ieee80211_data_to_8023() always pull in at
	 * least 8 bytes (possibly more for mesh) we can do the same here
	 * to save the cost of doing it later. That still doesn't pull in
	 * the actual IP header since the typical case has a SNAP header.
	 * If the latter changes (there are efforts in the standards group
	 * to do so) we should revisit this and ieee80211_data_to_8023().
Johannes Berg's avatar
Johannes Berg committed
79
	 */
80
	hdrlen = (len <= skb_tailroom(skb)) ? len : hdrlen + crypt_len + 8;
Johannes Berg's avatar
Johannes Berg committed
81

82
	skb_put_data(skb, hdr, hdrlen);
Johannes Berg's avatar
Johannes Berg committed
83 84 85
	fraglen = len - hdrlen;

	if (fraglen) {
86 87
		int offset = (u8 *)hdr + hdrlen -
			     (u8 *)rxb_addr(rxb) + rxb_offset(rxb);
Johannes Berg's avatar
Johannes Berg committed
88 89 90 91 92

		skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
				fraglen, rxb->truesize);
	}

93
	ieee80211_rx_napi(mvm->hw, sta, skb, napi);
Johannes Berg's avatar
Johannes Berg committed
94 95
}

96 97
/*
 * iwl_mvm_get_signal_strength - use new rx PHY INFO API
98 99 100
 * values are reported by the fw as positive values - need to negate
 * to obtain their dBM.  Account for missing antennas by replacing 0
 * values by -256dBm: practically 0 power and a non-feasible 8 bit value.
101
 */
102 103 104
static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
					struct iwl_rx_phy_info *phy_info,
					struct ieee80211_rx_status *rx_status)
105
{
106
	int energy_a, energy_b, max_energy;
107 108 109 110
	u32 val;

	val =
	    le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_ENERGY_ANT_ABC_IDX]);
111 112
	energy_a = (val & IWL_RX_INFO_ENERGY_ANT_A_MSK) >>
						IWL_RX_INFO_ENERGY_ANT_A_POS;
113
	energy_a = energy_a ? -energy_a : S8_MIN;
114 115
	energy_b = (val & IWL_RX_INFO_ENERGY_ANT_B_MSK) >>
						IWL_RX_INFO_ENERGY_ANT_B_POS;
116
	energy_b = energy_b ? -energy_b : S8_MIN;
117 118
	max_energy = max(energy_a, energy_b);

119 120
	IWL_DEBUG_STATS(mvm, "energy In A %d B %d  , and max %d\n",
			energy_a, energy_b, max_energy);
121

122 123 124 125 126 127
	rx_status->signal = max_energy;
	rx_status->chains = (le16_to_cpu(phy_info->phy_flags) &
				RX_RES_PHY_FLAGS_ANTENNA)
					>> RX_RES_PHY_FLAGS_ANTENNA_POS;
	rx_status->chain_signal[0] = energy_a;
	rx_status->chain_signal[1] = energy_b;
128 129
}

Johannes Berg's avatar
Johannes Berg committed
130 131 132 133 134 135 136 137 138 139 140 141
/*
 * iwl_mvm_set_mac80211_rx_flag - translate fw status to mac80211 format
 * @mvm: the mvm object
 * @hdr: 80211 header
 * @stats: status in mac80211's format
 * @rx_pkt_status: status coming from fw
 *
 * returns non 0 value if the packet should be dropped
 */
static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
					struct ieee80211_hdr *hdr,
					struct ieee80211_rx_status *stats,
142 143
					u32 rx_pkt_status,
					u8 *crypt_len)
Johannes Berg's avatar
Johannes Berg committed
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
{
	if (!ieee80211_has_protected(hdr->frame_control) ||
	    (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
			     RX_MPDU_RES_STATUS_SEC_NO_ENC)
		return 0;

	/* packet was encrypted with unknown alg */
	if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
					RX_MPDU_RES_STATUS_SEC_ENC_ERR)
		return 0;

	switch (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) {
	case RX_MPDU_RES_STATUS_SEC_CCM_ENC:
		/* alg is CCM: check MIC only */
		if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK))
			return -1;

		stats->flag |= RX_FLAG_DECRYPTED;
162
		*crypt_len = IEEE80211_CCMP_HDR_LEN;
Johannes Berg's avatar
Johannes Berg committed
163 164 165 166
		return 0;

	case RX_MPDU_RES_STATUS_SEC_TKIP_ENC:
		/* Don't drop the frame and decrypt it in SW */
167 168 169
		if (!fw_has_api(&mvm->fw->ucode_capa,
				IWL_UCODE_TLV_API_DEPRECATE_TTAK) &&
		    !(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK))
Johannes Berg's avatar
Johannes Berg committed
170
			return 0;
171
		*crypt_len = IEEE80211_TKIP_IV_LEN;
172
		fallthrough;
Johannes Berg's avatar
Johannes Berg committed
173 174 175 176 177 178

	case RX_MPDU_RES_STATUS_SEC_WEP_ENC:
		if (!(rx_pkt_status & RX_MPDU_RES_STATUS_ICV_OK))
			return -1;

		stats->flag |= RX_FLAG_DECRYPTED;
179 180 181
		if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
				RX_MPDU_RES_STATUS_SEC_WEP_ENC)
			*crypt_len = IEEE80211_WEP_IV_LEN;
Johannes Berg's avatar
Johannes Berg committed
182 183
		return 0;

184 185 186 187 188 189
	case RX_MPDU_RES_STATUS_SEC_EXT_ENC:
		if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK))
			return -1;
		stats->flag |= RX_FLAG_DECRYPTED;
		return 0;

Johannes Berg's avatar
Johannes Berg committed
190
	default:
191 192
		/* Expected in monitor (not having the keys) */
		if (!mvm->monitor_on)
193
			IWL_WARN(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);
Johannes Berg's avatar
Johannes Berg committed
194 195 196 197 198
	}

	return 0;
}

199 200 201 202 203 204 205 206 207 208
static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm,
				  struct ieee80211_sta *sta,
				  struct ieee80211_hdr *hdr, u32 len,
				  struct iwl_rx_phy_info *phy_info,
				  u32 rate_n_flags)
{
	struct iwl_mvm_sta *mvmsta;
	struct iwl_mvm_tcm_mac *mdata;
	int mac;
	int ac = IEEE80211_AC_BE; /* treat non-QoS as BE */
209 210 211 212 213 214
	struct iwl_mvm_vif *mvmvif;
	/* expected throughput in 100Kbps, single stream, 20 MHz */
	static const u8 thresh_tpt[] = {
		9, 18, 30, 42, 60, 78, 90, 96, 120, 135,
	};
	u16 thr;
215

216 217 218 219 220 221
	if (ieee80211_is_data_qos(hdr->frame_control)) {
		u8 tid = ieee80211_get_tid(hdr);

		if (tid < IWL_MAX_TID_COUNT)
			ac = tid_to_mac80211_ac[tid];
	}
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236

	mvmsta = iwl_mvm_sta_from_mac80211(sta);
	mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK;

	if (time_after(jiffies, mvm->tcm.ts + MVM_TCM_PERIOD))
		schedule_delayed_work(&mvm->tcm.work, 0);
	mdata = &mvm->tcm.data[mac];
	mdata->rx.pkts[ac]++;

	/* count the airtime only once for each ampdu */
	if (mdata->rx.last_ampdu_ref != mvm->ampdu_ref) {
		mdata->rx.last_ampdu_ref = mvm->ampdu_ref;
		mdata->rx.airtime += le16_to_cpu(phy_info->frame_time);
	}

237
	if (!(rate_n_flags & (RATE_MCS_HT_MSK_V1 | RATE_MCS_VHT_MSK_V1)))
238 239
		return;

240 241 242 243
	mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);

	if (mdata->opened_rx_ba_sessions ||
	    mdata->uapsd_nonagg_detect.detected ||
244 245 246 247
	    (!mvmvif->deflink.queue_params[IEEE80211_AC_VO].uapsd &&
	     !mvmvif->deflink.queue_params[IEEE80211_AC_VI].uapsd &&
	     !mvmvif->deflink.queue_params[IEEE80211_AC_BE].uapsd &&
	     !mvmvif->deflink.queue_params[IEEE80211_AC_BK].uapsd) ||
248
	    mvmsta->deflink.sta_id != mvmvif->deflink.ap_sta_id)
249 250
		return;

251 252 253 254
	if (rate_n_flags & RATE_MCS_HT_MSK_V1) {
		thr = thresh_tpt[rate_n_flags & RATE_HT_MCS_RATE_CODE_MSK_V1];
		thr *= 1 + ((rate_n_flags & RATE_HT_MCS_NSS_MSK_V1) >>
					RATE_HT_MCS_NSS_POS_V1);
255 256 257 258 259
	} else {
		if (WARN_ON((rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK) >=
				ARRAY_SIZE(thresh_tpt)))
			return;
		thr = thresh_tpt[rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK];
260
		thr *= 1 + FIELD_GET(RATE_MCS_NSS_MSK, rate_n_flags);
261 262
	}

263
	thr <<= ((rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK_V1) >>
264 265 266 267
				RATE_MCS_CHAN_WIDTH_POS);

	mdata->uapsd_nonagg_detect.rx_bytes += len;
	ewma_rate_add(&mdata->uapsd_nonagg_detect.rate, thr);
268 269
}

270 271 272 273 274 275 276 277 278 279 280 281 282
static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
			    struct sk_buff *skb,
			    u32 status)
{
	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);

	if (mvmvif->features & NETIF_F_RXCSUM &&
	    status & RX_MPDU_RES_STATUS_CSUM_DONE &&
	    status & RX_MPDU_RES_STATUS_CSUM_OK)
		skb->ip_summed = CHECKSUM_UNNECESSARY;
}

Johannes Berg's avatar
Johannes Berg committed
283 284 285 286 287
/*
 * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler
 *
 * Handles the actual data of the Rx packet from the fw
 */
288 289
void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
			struct iwl_rx_cmd_buffer *rxb)
Johannes Berg's avatar
Johannes Berg committed
290 291
{
	struct ieee80211_hdr *hdr;
292
	struct ieee80211_rx_status *rx_status;
Johannes Berg's avatar
Johannes Berg committed
293 294 295
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
	struct iwl_rx_phy_info *phy_info;
	struct iwl_rx_mpdu_res_start *rx_res;
296
	struct ieee80211_sta *sta = NULL;
297
	struct sk_buff *skb;
298
	u32 len, pkt_len = iwl_rx_packet_payload_len(pkt);
Johannes Berg's avatar
Johannes Berg committed
299 300
	u32 rate_n_flags;
	u32 rx_pkt_status;
301
	u8 crypt_len = 0;
Johannes Berg's avatar
Johannes Berg committed
302

303 304 305 306 307
	if (unlikely(pkt_len < sizeof(*rx_res))) {
		IWL_DEBUG_DROP(mvm, "Bad REPLY_RX_MPDU_CMD size\n");
		return;
	}

Johannes Berg's avatar
Johannes Berg committed
308 309 310 311
	phy_info = &mvm->last_phy_info;
	rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data;
	hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res));
	len = le16_to_cpu(rx_res->byte_count);
312 313 314 315 316 317

	if (unlikely(len + sizeof(*rx_res) + sizeof(__le32) > pkt_len)) {
		IWL_DEBUG_DROP(mvm, "FW lied about packet len\n");
		return;
	}

318
	rx_pkt_status = get_unaligned_le32((__le32 *)
Johannes Berg's avatar
Johannes Berg committed
319 320
		(pkt->data + sizeof(*rx_res) + len));

321 322 323 324 325 326
	/* Dont use dev_alloc_skb(), we'll have enough headroom once
	 * ieee80211_hdr pulled.
	 */
	skb = alloc_skb(128, GFP_ATOMIC);
	if (!skb) {
		IWL_ERR(mvm, "alloc_skb failed\n");
327
		return;
328 329 330
	}

	rx_status = IEEE80211_SKB_RXCB(skb);
Johannes Berg's avatar
Johannes Berg committed
331

332 333 334 335
	/*
	 * Keep packets with CRC errors (and with overrun) for monitor mode
	 * (otherwise the firmware discards them) but mark them as bad.
	 */
Johannes Berg's avatar
Johannes Berg committed
336 337 338
	if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) ||
	    !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) {
		IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status);
339
		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
Johannes Berg's avatar
Johannes Berg committed
340 341 342 343 344 345
	}

	/* This will be used in several places later */
	rate_n_flags = le32_to_cpu(phy_info->rate_n_flags);

	/* rx_status carries information about the packet to mac80211 */
346 347 348
	rx_status->mactime = le64_to_cpu(phy_info->timestamp);
	rx_status->device_timestamp = le32_to_cpu(phy_info->system_timestamp);
	rx_status->band =
Johannes Berg's avatar
Johannes Berg committed
349
		(phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ?
350
				NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
351
	rx_status->freq =
Johannes Berg's avatar
Johannes Berg committed
352
		ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel),
353
					       rx_status->band);
354 355 356

	/* TSF as indicated by the firmware  is at INA time */
	rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
Johannes Berg's avatar
Johannes Berg committed
357

358
	iwl_mvm_get_signal_strength(mvm, phy_info, rx_status);
Johannes Berg's avatar
Johannes Berg committed
359

360 361
	IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status->signal,
			      (unsigned long long)rx_status->mactime);
Johannes Berg's avatar
Johannes Berg committed
362

363
	rcu_read_lock();
364 365 366 367 368
	if (rx_pkt_status & RX_MPDU_RES_STATUS_SRC_STA_FOUND) {
		u32 id = rx_pkt_status & RX_MPDU_RES_STATUS_STA_ID_MSK;

		id >>= RX_MDPU_RES_STATUS_STA_ID_SHIFT;

369
		if (!WARN_ON_ONCE(id >= mvm->fw->ucode_capa.num_stations)) {
370 371 372 373 374 375 376 377 378
			sta = rcu_dereference(mvm->fw_id_to_mac_id[id]);
			if (IS_ERR(sta))
				sta = NULL;
		}
	} else if (!is_multicast_ether_addr(hdr->addr2)) {
		/* This is fine since we prevent two stations with the same
		 * address from being added.
		 */
		sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL);
379 380
	}

381 382 383 384 385 386 387 388 389
	if (sta) {
		struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
		struct ieee80211_vif *vif = mvmsta->vif;
		struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

		/*
		 * Don't even try to decrypt a MCAST frame that was received
		 * before the managed vif is authorized, we'd fail anyway.
		 */
390 391
		if (is_multicast_ether_addr(hdr->addr1) &&
		    vif->type == NL80211_IFTYPE_STATION &&
392
		    !mvmvif->authorized &&
393
		    ieee80211_has_protected(hdr->frame_control)) {
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
			IWL_DEBUG_DROP(mvm, "MCAST before the vif is authorized\n");
			kfree_skb(skb);
			rcu_read_unlock();
			return;
		}
	}

	/*
	 * drop the packet if it has failed being decrypted by HW
	 */
	if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, rx_status, rx_pkt_status,
					 &crypt_len)) {
		IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n",
			       rx_pkt_status);
		kfree_skb(skb);
		rcu_read_unlock();
		return;
	}

413
	if (sta) {
414
		struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
415 416
		struct ieee80211_vif *tx_blocked_vif =
			rcu_dereference(mvm->csa_tx_blocked_vif);
417 418
		struct iwl_fw_dbg_trigger_tlv *trig;
		struct ieee80211_vif *vif = mvmsta->vif;
419

420 421 422 423
		/* We have tx blocked stations (with CS bit). If we heard
		 * frames from a blocked station on a new channel we can
		 * TX to it again.
		 */
424
		if (unlikely(tx_blocked_vif) && vif == tx_blocked_vif) {
425 426 427 428 429 430 431
			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);
		}
432

433
		rs_update_last_rssi(mvm, mvmsta, rx_status);
434

435 436 437 438 439
		trig = iwl_fw_dbg_trigger_on(&mvm->fwrt,
					     ieee80211_vif_to_wdev(vif),
					     FW_DBG_TRIGGER_RSSI);

		if (trig && ieee80211_is_beacon(hdr->frame_control)) {
440 441 442 443 444 445
			struct iwl_fw_dbg_trigger_low_rssi *rssi_trig;
			s32 rssi;

			rssi_trig = (void *)trig->data;
			rssi = le32_to_cpu(rssi_trig->rssi);

446
			if (rx_status->signal < rssi)
447 448
				iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,
							NULL);
449
		}
450

451 452 453 454 455 456
		if (!mvm->tcm.paused && len >= sizeof(*hdr) &&
		    !is_multicast_ether_addr(hdr->addr1) &&
		    ieee80211_is_data(hdr->frame_control))
			iwl_mvm_rx_handle_tcm(mvm, sta, hdr, len, phy_info,
					      rate_n_flags);

457 458 459
		if (ieee80211_is_data(hdr->frame_control))
			iwl_mvm_rx_csum(sta, skb, rx_pkt_status);
	}
460 461
	rcu_read_unlock();

Johannes Berg's avatar
Johannes Berg committed
462 463
	/* set the preamble flag if appropriate */
	if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE))
464
		rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
Johannes Berg's avatar
Johannes Berg committed
465 466 467 468 469 470 471

	if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
		/*
		 * We know which subframes of an A-MPDU belong
		 * together since we get a single PHY response
		 * from the firmware for all of them
		 */
472 473
		rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
		rx_status->ampdu_reference = mvm->ampdu_ref;
Johannes Berg's avatar
Johannes Berg committed
474 475 476
	}

	/* Set up the HT phy flags */
477
	switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK_V1) {
Johannes Berg's avatar
Johannes Berg committed
478 479 480
	case RATE_MCS_CHAN_WIDTH_20:
		break;
	case RATE_MCS_CHAN_WIDTH_40:
481
		rx_status->bw = RATE_INFO_BW_40;
Johannes Berg's avatar
Johannes Berg committed
482 483
		break;
	case RATE_MCS_CHAN_WIDTH_80:
484
		rx_status->bw = RATE_INFO_BW_80;
Johannes Berg's avatar
Johannes Berg committed
485 486
		break;
	case RATE_MCS_CHAN_WIDTH_160:
487
		rx_status->bw = RATE_INFO_BW_160;
Johannes Berg's avatar
Johannes Berg committed
488 489
		break;
	}
490 491
	if (!(rate_n_flags & RATE_MCS_CCK_MSK_V1) &&
	    rate_n_flags & RATE_MCS_SGI_MSK_V1)
492
		rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
Johannes Berg's avatar
Johannes Berg committed
493
	if (rate_n_flags & RATE_HT_MCS_GF_MSK)
494
		rx_status->enc_flags |= RX_ENC_FLAG_HT_GF;
495
	if (rate_n_flags & RATE_MCS_LDPC_MSK_V1)
496
		rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
497
	if (rate_n_flags & RATE_MCS_HT_MSK_V1) {
498
		u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
499
				RATE_MCS_STBC_POS;
500
		rx_status->encoding = RX_ENC_HT;
501
		rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK_V1;
502
		rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
503
	} else if (rate_n_flags & RATE_MCS_VHT_MSK_V1) {
504
		u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
505
				RATE_MCS_STBC_POS;
506
		rx_status->nss =
507
			FIELD_GET(RATE_MCS_NSS_MSK, rate_n_flags) + 1;
508
		rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
509
		rx_status->encoding = RX_ENC_VHT;
510
		rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
511
		if (rate_n_flags & RATE_MCS_BF_MSK)
512
			rx_status->enc_flags |= RX_ENC_FLAG_BF;
Johannes Berg's avatar
Johannes Berg committed
513
	} else {
514 515 516 517 518 519 520 521 522 523
		int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
							       rx_status->band);

		if (WARN(rate < 0 || rate > 0xFF,
			 "Invalid rate flags 0x%x, band %d,\n",
			 rate_n_flags, rx_status->band)) {
			kfree_skb(skb);
			return;
		}
		rx_status->rate_idx = rate;
Johannes Berg's avatar
Johannes Berg committed
524 525
	}

526
#ifdef CONFIG_IWLWIFI_DEBUGFS
527
	iwl_mvm_update_frame_stats(mvm, rate_n_flags,
528
				   rx_status->flag & RX_FLAG_AMPDU_DETAILS);
529
#endif
530 531 532 533 534 535

	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;

536 537
	if (unlikely(ieee80211_is_beacon(hdr->frame_control) ||
		     ieee80211_is_probe_resp(hdr->frame_control)))
538
		rx_status->boottime_ns = ktime_get_boottime_ns();
539 540

	iwl_mvm_pass_packet_to_mac80211(mvm, sta, napi, skb, hdr, len,
541
					crypt_len, rxb);
Johannes Berg's avatar
Johannes Berg committed
542
}
543

544 545
struct iwl_mvm_stat_data {
	struct iwl_mvm *mvm;
546
	__le32 flags;
547
	__le32 mac_id;
548
	u8 beacon_filter_average_energy;
549 550
	__le32 *beacon_counter;
	u8 *beacon_average_energy;
551 552
};

553 554 555
struct iwl_mvm_stat_data_all_macs {
	struct iwl_mvm *mvm;
	__le32 flags;
556
	struct iwl_stats_ntfy_per_mac *per_mac;
557 558
};

559
static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig,
560 561
				    struct iwl_mvm_vif_link_info *link_info,
				    struct ieee80211_bss_conf *bss_conf)
562
{
563 564 565
	struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(vif)->mvm;
	int thold = bss_conf->cqm_rssi_thold;
	int hyst = bss_conf->cqm_rssi_hyst;
566
	int last_event;
567
	s8 exit_esr_thresh;
568

569 570 571 572 573
	if (sig == 0) {
		IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n");
		return;
	}

574
	link_info->bf_data.ave_beacon_signal = sig;
575

576
	/* BT Coex */
577 578 579 580 581
	if (link_info->bf_data.bt_coex_min_thold !=
	    link_info->bf_data.bt_coex_max_thold) {
		last_event = link_info->bf_data.last_bt_coex_event;
		if (sig > link_info->bf_data.bt_coex_max_thold &&
		    (last_event <= link_info->bf_data.bt_coex_min_thold ||
582
		     last_event == 0)) {
583
			link_info->bf_data.last_bt_coex_event = sig;
584 585 586
			IWL_DEBUG_RX(mvm, "cqm_iterator bt coex high %d\n",
				     sig);
			iwl_mvm_bt_rssi_event(mvm, vif, RSSI_EVENT_HIGH);
587 588
		} else if (sig < link_info->bf_data.bt_coex_min_thold &&
			   (last_event >= link_info->bf_data.bt_coex_max_thold ||
589
			    last_event == 0)) {
590
			link_info->bf_data.last_bt_coex_event = sig;
591 592 593 594 595 596
			IWL_DEBUG_RX(mvm, "cqm_iterator bt coex low %d\n",
				     sig);
			iwl_mvm_bt_rssi_event(mvm, vif, RSSI_EVENT_LOW);
		}
	}

597 598 599 600
	if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI))
		return;

	/* CQM Notification */
601
	last_event = link_info->bf_data.last_cqm_event;
602 603
	if (thold && sig < thold && (last_event == 0 ||
				     sig < last_event - hyst)) {
604
		link_info->bf_data.last_cqm_event = sig;
605 606 607 608 609
		IWL_DEBUG_RX(mvm, "cqm_iterator cqm low %d\n",
			     sig);
		ieee80211_cqm_rssi_notify(
			vif,
			NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
610
			sig,
611 612 613
			GFP_KERNEL);
	} else if (sig > thold &&
		   (last_event == 0 || sig > last_event + hyst)) {
614
		link_info->bf_data.last_cqm_event = sig;
615 616 617 618 619
		IWL_DEBUG_RX(mvm, "cqm_iterator cqm high %d\n",
			     sig);
		ieee80211_cqm_rssi_notify(
			vif,
			NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
620
			sig,
621 622
			GFP_KERNEL);
	}
623 624 625 626 627 628 629 630 631 632 633 634 635 636

	/* ESR recalculation */
	if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif))
		return;

	exit_esr_thresh =
		iwl_mvm_get_esr_rssi_thresh(mvm,
					    &bss_conf->chanreq.oper,
					    true);

	if (sig < exit_esr_thresh)
		iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_LOW_RSSI,
				 iwl_mvm_get_other_link(vif,
							bss_conf->link_id));
637 638
}

639 640 641 642 643 644 645 646 647 648 649 650 651
static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
				  struct ieee80211_vif *vif)
{
	struct iwl_mvm_stat_data *data = _data;
	int sig = -data->beacon_filter_average_energy;
	u16 id = le32_to_cpu(data->mac_id);
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	u16 vif_id = mvmvif->id;

	/* This doesn't need the MAC ID check since it's not taking the
	 * data copied into the "data" struct, but rather the data from
	 * the notification directly.
	 */
652
	mvmvif->deflink.beacon_stats.num_beacons =
653
		le32_to_cpu(data->beacon_counter[vif_id]);
654
	mvmvif->deflink.beacon_stats.avg_signal =
655 656 657 658 659 660 661 662 663 664 665 666
		-data->beacon_average_energy[vif_id];

	if (mvmvif->id != id)
		return;

	if (vif->type != NL80211_IFTYPE_STATION)
		return;

	/* make sure that beacon statistics don't go backwards with TCM
	 * request to clear statistics
	 */
	if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR)
667 668
		mvmvif->deflink.beacon_stats.accu_num_beacons +=
			mvmvif->deflink.beacon_stats.num_beacons;
669

670
	/* This is used in pre-MLO API so use deflink */
671
	iwl_mvm_update_link_sig(vif, sig, &mvmvif->deflink, &vif->bss_conf);
672 673 674 675 676 677
}

static void iwl_mvm_stat_iterator_all_macs(void *_data, u8 *mac,
					   struct ieee80211_vif *vif)
{
	struct iwl_mvm_stat_data_all_macs *data = _data;
678
	struct iwl_stats_ntfy_per_mac *mac_stats;
679 680 681 682
	int sig;
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	u16 vif_id = mvmvif->id;

683
	if (WARN_ONCE(vif_id >= MAC_INDEX_AUX, "invalid vif id: %d", vif_id))
684 685 686 687 688
		return;

	if (vif->type != NL80211_IFTYPE_STATION)
		return;

689
	mac_stats = &data->per_mac[vif_id];
690

691
	mvmvif->deflink.beacon_stats.num_beacons =
692
		le32_to_cpu(mac_stats->beacon_counter);
693
	mvmvif->deflink.beacon_stats.avg_signal =
694 695 696 697 698 699
		-le32_to_cpu(mac_stats->beacon_average_energy);

	/* make sure that beacon statistics don't go backwards with TCM
	 * request to clear statistics
	 */
	if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR)
700 701
		mvmvif->deflink.beacon_stats.accu_num_beacons +=
			mvmvif->deflink.beacon_stats.num_beacons;
702 703

	sig = -le32_to_cpu(mac_stats->beacon_filter_average_energy);
704 705

	/* This is used in pre-MLO API so use deflink */
706
	iwl_mvm_update_link_sig(vif, sig, &mvmvif->deflink, &vif->bss_conf);
707 708
}

709 710 711 712 713 714 715
static inline void
iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt)
{
	struct iwl_fw_dbg_trigger_tlv *trig;
	struct iwl_fw_dbg_trigger_stats *trig_stats;
	u32 trig_offset, trig_thold;

716 717
	trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL, FW_DBG_TRIGGER_STATS);
	if (!trig)
718 719 720 721 722 723 724 725 726 727 728 729 730
		return;

	trig_stats = (void *)trig->data;

	trig_offset = le32_to_cpu(trig_stats->stop_offset);
	trig_thold = le32_to_cpu(trig_stats->stop_threshold);

	if (WARN_ON_ONCE(trig_offset >= iwl_rx_packet_payload_len(pkt)))
		return;

	if (le32_to_cpup((__le32 *) (pkt->data + trig_offset)) < trig_thold)
		return;

731
	iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, NULL);
732 733
}

734 735
static void iwl_mvm_stats_energy_iter(void *_data,
				      struct ieee80211_sta *sta)
736
{
737 738
	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
	u8 *energy = _data;
739
	u32 sta_id = mvmsta->deflink.sta_id;
740

741 742
	if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT_MAX, "sta_id %d >= %d",
		      sta_id, IWL_MVM_STATION_COUNT_MAX))
743 744
		return;

745
	if (energy[sta_id])
746
		mvmsta->deflink.avg_energy = energy[sta_id];
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773

}

static void
iwl_mvm_update_tcm_from_stats(struct iwl_mvm *mvm, __le32 *air_time_le,
			      __le32 *rx_bytes_le)
{
	int i;

	spin_lock(&mvm->tcm.lock);
	for (i = 0; i < NUM_MAC_INDEX_DRIVER; i++) {
		struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[i];
		u32 rx_bytes = le32_to_cpu(rx_bytes_le[i]);
		u32 airtime = le32_to_cpu(air_time_le[i]);

		mdata->rx.airtime += airtime;
		mdata->uapsd_nonagg_detect.rx_bytes += rx_bytes;
		if (airtime) {
			/* re-init every time to store rate from FW */
			ewma_rate_init(&mdata->uapsd_nonagg_detect.rate);
			ewma_rate_add(&mdata->uapsd_nonagg_detect.rate,
				      rx_bytes * 8 / airtime);
		}
	}
	spin_unlock(&mvm->tcm.lock);
}

774 775 776 777 778 779 780 781 782 783 784 785 786
static void iwl_mvm_handle_per_phy_stats(struct iwl_mvm *mvm,
					 struct iwl_stats_ntfy_per_phy *per_phy)
{
	int i;

	for (i = 0; i < NUM_PHY_CTX; i++) {
		if (!mvm->phy_ctxts[i].ref)
			continue;
		mvm->phy_ctxts[i].channel_load_by_us =
			le32_to_cpu(per_phy[i].channel_load_by_us);
	}
}

787
static void
788 789 790 791 792 793
iwl_mvm_stats_ver_15(struct iwl_mvm *mvm,
		     struct iwl_statistics_operational_ntfy *stats)
{
	struct iwl_mvm_stat_data_all_macs data = {
		.mvm = mvm,
		.flags = stats->flags,
794
		.per_mac = stats->per_mac,
795 796 797 798 799 800
	};

	ieee80211_iterate_active_interfaces(mvm->hw,
					    IEEE80211_IFACE_ITER_NORMAL,
					    iwl_mvm_stat_iterator_all_macs,
					    &data);
801
	iwl_mvm_handle_per_phy_stats(mvm, stats->per_phy);
802 803 804 805 806
}

static void
iwl_mvm_stats_ver_14(struct iwl_mvm *mvm,
		     struct iwl_statistics_operational_ntfy_ver_14 *stats)
807 808 809 810
{
	struct iwl_mvm_stat_data data = {
		.mvm = mvm,
	};
811

812 813 814 815 816 817 818 819 820 821 822
	u8 beacon_average_energy[MAC_INDEX_AUX];
	__le32 flags;
	int i;

	flags = stats->flags;

	data.mac_id = stats->mac_id;
	data.beacon_filter_average_energy =
		le32_to_cpu(stats->beacon_filter_average_energy);
	data.flags = flags;
	data.beacon_counter = stats->beacon_counter;
823

824 825 826 827 828 829 830 831 832 833
	for (i = 0; i < ARRAY_SIZE(beacon_average_energy); i++)
		beacon_average_energy[i] =
			le32_to_cpu(stats->beacon_average_energy[i]);

	data.beacon_average_energy = beacon_average_energy;

	ieee80211_iterate_active_interfaces(mvm->hw,
					    IEEE80211_IFACE_ITER_NORMAL,
					    iwl_mvm_stat_iterator,
					    &data);
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
}

static bool iwl_mvm_verify_stats_len(struct iwl_mvm *mvm,
				     struct iwl_rx_packet *pkt,
				     u32 expected_size)
{
	struct iwl_statistics_ntfy_hdr *hdr;

	if (WARN_ONCE(iwl_rx_packet_payload_len(pkt) < expected_size,
		      "received invalid statistics size (%d)!, expected_size: %d\n",
		      iwl_rx_packet_payload_len(pkt), expected_size))
		return false;

	hdr = (void *)&pkt->data;

	if (WARN_ONCE((hdr->type & IWL_STATISTICS_TYPE_MSK) != FW_STATISTICS_OPERATIONAL ||
		      hdr->version !=
		      iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, STATISTICS_NOTIFICATION, 0),
		      "received unsupported hdr type %d, version %d\n",
		      hdr->type, hdr->version))
		return false;

	if (WARN_ONCE(le16_to_cpu(hdr->size) != expected_size,
		      "received invalid statistics size in header (%d)!, expected_size: %d\n",
		      le16_to_cpu(hdr->size), expected_size))
		return false;

	return true;
}

864 865 866 867 868 869 870 871 872 873 874 875 876
static void
iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm,
				struct iwl_stats_ntfy_per_link *per_link)
{
	u32 air_time[MAC_INDEX_AUX] = {};
	u32 rx_bytes[MAC_INDEX_AUX] = {};
	int fw_link_id;

	for (fw_link_id = 0; fw_link_id < ARRAY_SIZE(mvm->link_id_to_link_conf);
	     fw_link_id++) {
		struct iwl_stats_ntfy_per_link *link_stats;
		struct ieee80211_bss_conf *bss_conf;
		struct iwl_mvm_vif *mvmvif;
877
		struct iwl_mvm_vif_link_info *link_info;
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
		int link_id;
		int sig;

		bss_conf = iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, fw_link_id,
							       false);
		if (!bss_conf)
			continue;

		if (bss_conf->vif->type != NL80211_IFTYPE_STATION)
			continue;

		link_id = bss_conf->link_id;
		if (link_id >= ARRAY_SIZE(mvmvif->link))
			continue;

		mvmvif = iwl_mvm_vif_from_mac80211(bss_conf->vif);
894 895
		link_info = mvmvif->link[link_id];
		if (!link_info)
896 897 898 899
			continue;

		link_stats = &per_link[fw_link_id];

900
		link_info->beacon_stats.num_beacons =
901 902 903 904 905
			le32_to_cpu(link_stats->beacon_counter);

		/* we basically just use the u8 to store 8 bits and then treat
		 * it as a s8 whenever we take it out to a different type.
		 */
906
		link_info->beacon_stats.avg_signal =
907 908
			-le32_to_cpu(link_stats->beacon_average_energy);

909 910
		if (link_info->phy_ctxt &&
		    link_info->phy_ctxt->channel->band == NL80211_BAND_2GHZ)
911 912
			iwl_mvm_bt_coex_update_link_esr(mvm, bss_conf->vif,
							link_id);
913

914 915 916 917 918 919 920 921
		/* make sure that beacon statistics don't go backwards with TCM
		 * request to clear statistics
		 */
		if (mvm->statistics_clear)
			mvmvif->link[link_id]->beacon_stats.accu_num_beacons +=
				mvmvif->link[link_id]->beacon_stats.num_beacons;

		sig = -le32_to_cpu(link_stats->beacon_filter_average_energy);
922 923
		iwl_mvm_update_link_sig(bss_conf->vif, sig, link_info,
					bss_conf);
924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952

		if (WARN_ONCE(mvmvif->id >= MAC_INDEX_AUX,
			      "invalid mvmvif id: %d", mvmvif->id))
			continue;

		air_time[mvmvif->id] +=
			le32_to_cpu(per_link[fw_link_id].air_time);
		rx_bytes[mvmvif->id] +=
			le32_to_cpu(per_link[fw_link_id].rx_bytes);
	}

	/* Don't update in case the statistics are not cleared, since
	 * we will end up counting twice the same airtime, once in TCM
	 * request and once in statistics notification.
	 */
	if (mvm->statistics_clear) {
		__le32 air_time_le[MAC_INDEX_AUX];
		__le32 rx_bytes_le[MAC_INDEX_AUX];
		int vif_id;

		for (vif_id = 0; vif_id < ARRAY_SIZE(air_time_le); vif_id++) {
			air_time_le[vif_id] = cpu_to_le32(air_time[vif_id]);
			rx_bytes_le[vif_id] = cpu_to_le32(rx_bytes[vif_id]);
		}

		iwl_mvm_update_tcm_from_stats(mvm, air_time_le, rx_bytes_le);
	}
}

953 954 955 956
#define SEC_LINK_MIN_PERC 10
#define SEC_LINK_MIN_TX 3000
#define SEC_LINK_MIN_RX 400

957 958 959 960 961 962
static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm)
{
	struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm);
	struct iwl_mvm_vif *mvmvif;
	struct iwl_mvm_sta *mvmsta;
	unsigned long total_tx = 0, total_rx = 0;
963 964 965
	unsigned long sec_link_tx = 0, sec_link_rx = 0;
	u8 sec_link_tx_perc, sec_link_rx_perc;
	u8 sec_link;
966 967 968

	lockdep_assert_held(&mvm->mutex);

969
	if (IS_ERR_OR_NULL(bss_vif))
970 971 972 973 974 975 976 977 978 979 980 981
		return;

	mvmvif = iwl_mvm_vif_from_mac80211(bss_vif);

	if (!mvmvif->esr_active || !mvmvif->ap_sta)
		return;

	mvmsta = iwl_mvm_sta_from_mac80211(mvmvif->ap_sta);
	/* We only count for the AP sta in a MLO connection */
	if (!mvmsta->mpdu_counters)
		return;

982 983 984 985 986 987 988
	/* Get the FW ID of the secondary link */
	sec_link = iwl_mvm_get_other_link(bss_vif,
					  iwl_mvm_get_primary_link(bss_vif));
	if (WARN_ON(!mvmvif->link[sec_link]))
		return;
	sec_link = mvmvif->link[sec_link]->fw_link_id;

989 990 991 992 993 994 995 996 997
	/* Sum up RX and TX MPDUs from the different queues/links */
	for (int q = 0; q < mvm->trans->num_rx_queues; q++) {
		spin_lock_bh(&mvmsta->mpdu_counters[q].lock);

		/* The link IDs that doesn't exist will contain 0 */
		for (int link = 0; link < IWL_MVM_FW_MAX_LINK_ID; link++) {
			total_tx += mvmsta->mpdu_counters[q].per_link[link].tx;
			total_rx += mvmsta->mpdu_counters[q].per_link[link].rx;
		}
998 999 1000 1001

		sec_link_tx += mvmsta->mpdu_counters[q].per_link[sec_link].tx;
		sec_link_rx += mvmsta->mpdu_counters[q].per_link[sec_link].rx;

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
		/*
		 * In EMLSR we have statistics every 5 seconds, so we can reset
		 * the counters upon every statistics notification.
		 */
		memset(mvmsta->mpdu_counters[q].per_link, 0,
		       sizeof(mvmsta->mpdu_counters[q].per_link));

		spin_unlock_bh(&mvmsta->mpdu_counters[q].lock);
	}

	/* If we don't have enough MPDUs - exit EMLSR */
	if (total_tx < IWL_MVM_ENTER_ESR_TPT_THRESH &&
1014
	    total_rx < IWL_MVM_ENTER_ESR_TPT_THRESH) {
1015 1016
		iwl_mvm_block_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_TPT,
				  iwl_mvm_get_primary_link(bss_vif));
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
		return;
	}

	/* Calculate the percentage of the secondary link TX/RX */
	sec_link_tx_perc = total_tx ? sec_link_tx * 100 / total_tx : 0;
	sec_link_rx_perc = total_rx ? sec_link_rx * 100 / total_rx : 0;

	/*
	 * The TX/RX percentage is checked only if it exceeds the required
	 * minimum. In addition, RX is checked only if the TX check failed.
	 */
	if ((total_tx > SEC_LINK_MIN_TX &&
	     sec_link_tx_perc < SEC_LINK_MIN_PERC) ||
	    (total_rx > SEC_LINK_MIN_RX &&
	     sec_link_rx_perc < SEC_LINK_MIN_PERC))
		iwl_mvm_exit_esr(mvm, bss_vif, IWL_MVM_ESR_EXIT_LINK_USAGE,
				 iwl_mvm_get_primary_link(bss_vif));
1034 1035
}

1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
void iwl_mvm_handle_rx_system_oper_stats(struct iwl_mvm *mvm,
					 struct iwl_rx_cmd_buffer *rxb)
{
	u8 average_energy[IWL_MVM_STATION_COUNT_MAX];
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
	struct iwl_system_statistics_notif_oper *stats;
	int i;
	u32 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, STATISTICS_GROUP,
						STATISTICS_OPER_NOTIF, 0);

	if (notif_ver != 3) {
		IWL_FW_CHECK_FAILED(mvm,
				    "Oper stats notif ver %d is not supported\n",
				    notif_ver);
		return;
	}

	stats = (void *)&pkt->data;
	iwl_mvm_stat_iterator_all_links(mvm, stats->per_link);

	for (i = 0; i < ARRAY_SIZE(average_energy); i++)
		average_energy[i] =
			le32_to_cpu(stats->per_sta[i].average_energy);

	ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_stats_energy_iter,
					  average_energy);
1062
	iwl_mvm_handle_per_phy_stats(mvm, stats->per_phy);
1063 1064

	iwl_mvm_update_esr_mode_tpt(mvm);
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
}

void iwl_mvm_handle_rx_system_oper_part1_stats(struct iwl_mvm *mvm,
					       struct iwl_rx_cmd_buffer *rxb)
{
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
	struct iwl_system_statistics_part1_notif_oper *part1_stats;
	int i;
	u32 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, STATISTICS_GROUP,
						STATISTICS_OPER_PART1_NOTIF, 0);

	if (notif_ver != 4) {
		IWL_FW_CHECK_FAILED(mvm,
				    "Part1 stats notif ver %d is not supported\n",
				    notif_ver);
		return;
	}

	part1_stats = (void *)&pkt->data;
	mvm->radio_stats.rx_time = 0;
	mvm->radio_stats.tx_time = 0;
	for (i = 0; i < ARRAY_SIZE(part1_stats->per_link); i++) {
		mvm->radio_stats.rx_time +=
			le64_to_cpu(part1_stats->per_link[i].rx_time);
		mvm->radio_stats.tx_time +=
			le64_to_cpu(part1_stats->per_link[i].tx_time);
	}
}

1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
static void
iwl_mvm_handle_rx_statistics_tlv(struct iwl_mvm *mvm,
				 struct iwl_rx_packet *pkt)
{
	u8 average_energy[IWL_MVM_STATION_COUNT_MAX];
	__le32 air_time[MAC_INDEX_AUX];
	__le32 rx_bytes[MAC_INDEX_AUX];
	__le32 flags = 0;
	int i;
	u32 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
					      STATISTICS_NOTIFICATION, 0);

	if (WARN_ONCE(notif_ver > 15,
		      "invalid statistics version id: %d\n", notif_ver))
		return;

	if (notif_ver == 14) {
		struct iwl_statistics_operational_ntfy_ver_14 *stats =
			(void *)pkt->data;

		if (!iwl_mvm_verify_stats_len(mvm, pkt, sizeof(*stats)))
			return;

		iwl_mvm_stats_ver_14(mvm, stats);

		flags = stats->flags;
		mvm->radio_stats.rx_time = le64_to_cpu(stats->rx_time);
		mvm->radio_stats.tx_time = le64_to_cpu(stats->tx_time);
		mvm->radio_stats.on_time_rf = le64_to_cpu(stats->on_time_rf);
		mvm->radio_stats.on_time_scan =
			le64_to_cpu(stats->on_time_scan);

		for (i = 0; i < ARRAY_SIZE(average_energy); i++)
			average_energy[i] = le32_to_cpu(stats->average_energy[i]);

		for (i = 0; i < ARRAY_SIZE(air_time); i++) {
			air_time[i] = stats->air_time[i];
			rx_bytes[i] = stats->rx_bytes[i];
		}
	}

	if (notif_ver == 15) {
		struct iwl_statistics_operational_ntfy *stats =
			(void *)pkt->data;

		if (!iwl_mvm_verify_stats_len(mvm, pkt, sizeof(*stats)))
			return;

		iwl_mvm_stats_ver_15(mvm, stats);

		flags = stats->flags;
		mvm->radio_stats.rx_time = le64_to_cpu(stats->rx_time);
		mvm->radio_stats.tx_time = le64_to_cpu(stats->tx_time);
		mvm->radio_stats.on_time_rf = le64_to_cpu(stats->on_time_rf);
		mvm->radio_stats.on_time_scan =
			le64_to_cpu(stats->on_time_scan);

		for (i = 0; i < ARRAY_SIZE(average_energy); i++)
			average_energy[i] =
1153
				le32_to_cpu(stats->per_sta[i].average_energy);
1154 1155

		for (i = 0; i < ARRAY_SIZE(air_time); i++) {
1156 1157
			air_time[i] = stats->per_mac[i].air_time;
			rx_bytes[i] = stats->per_mac[i].rx_bytes;
1158 1159 1160 1161
		}
	}

	iwl_mvm_rx_stats_check_trigger(mvm, pkt);
1162

1163 1164
	ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_stats_energy_iter,
					  average_energy);
1165 1166 1167 1168 1169 1170
	/*
	 * Don't update in case the statistics are not cleared, since
	 * we will end up counting twice the same airtime, once in TCM
	 * request and once in statistics notification.
	 */
	if (le32_to_cpu(flags) & IWL_STATISTICS_REPLY_FLG_CLEAR)
1171
		iwl_mvm_update_tcm_from_stats(mvm, air_time, rx_bytes);
1172 1173
}

1174 1175
void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
				  struct iwl_rx_packet *pkt)
1176
{
1177 1178 1179
	struct iwl_mvm_stat_data data = {
		.mvm = mvm,
	};
1180
	__le32 *bytes, *air_time, flags;
1181
	int expected_size;
1182
	u8 *energy;
1183 1184 1185 1186 1187 1188 1189
	u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
					   WIDE_ID(SYSTEM_GROUP,
						   SYSTEM_STATISTICS_CMD),
					   IWL_FW_CMD_VER_UNKNOWN);

	if (cmd_ver != IWL_FW_CMD_VER_UNKNOWN)
		return;
1190 1191

	/* From ver 14 and up we use TLV statistics format */
1192 1193
	if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
				    STATISTICS_NOTIFICATION, 0) >= 14)
1194
		return iwl_mvm_handle_rx_statistics_tlv(mvm, pkt);
1195

1196 1197 1198 1199 1200 1201
	if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
		if (iwl_mvm_has_new_rx_api(mvm))
			expected_size = sizeof(struct iwl_notif_statistics_v11);
		else
			expected_size = sizeof(struct iwl_notif_statistics_v10);
	} else {
1202
		expected_size = sizeof(struct iwl_notif_statistics);
1203
	}
1204

1205 1206 1207
	if (WARN_ONCE(iwl_rx_packet_payload_len(pkt) != expected_size,
		      "received invalid statistics size (%d)!\n",
		      iwl_rx_packet_payload_len(pkt)))
1208
		return;
1209

1210 1211
	if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
		struct iwl_notif_statistics_v11 *stats = (void *)&pkt->data;
1212

1213 1214 1215
		data.mac_id = stats->rx.general.mac_id;
		data.beacon_filter_average_energy =
			stats->general.common.beacon_filter_average_energy;
1216

1217
		mvm->rx_stats_v3 = stats->rx;
1218

1219 1220 1221 1222 1223 1224 1225 1226 1227
		mvm->radio_stats.rx_time =
			le64_to_cpu(stats->general.common.rx_time);
		mvm->radio_stats.tx_time =
			le64_to_cpu(stats->general.common.tx_time);
		mvm->radio_stats.on_time_rf =
			le64_to_cpu(stats->general.common.on_time_rf);
		mvm->radio_stats.on_time_scan =
			le64_to_cpu(stats->general.common.on_time_scan);

1228 1229 1230
		data.beacon_counter = stats->general.beacon_counter;
		data.beacon_average_energy =
			stats->general.beacon_average_energy;
1231 1232
		flags = stats->flag;
	} else {
1233
		struct iwl_notif_statistics *stats = (void *)&pkt->data;
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249

		data.mac_id = stats->rx.general.mac_id;
		data.beacon_filter_average_energy =
			stats->general.common.beacon_filter_average_energy;

		mvm->rx_stats = stats->rx;

		mvm->radio_stats.rx_time =
			le64_to_cpu(stats->general.common.rx_time);
		mvm->radio_stats.tx_time =
			le64_to_cpu(stats->general.common.tx_time);
		mvm->radio_stats.on_time_rf =
			le64_to_cpu(stats->general.common.on_time_rf);
		mvm->radio_stats.on_time_scan =
			le64_to_cpu(stats->general.common.on_time_scan);

1250 1251 1252
		data.beacon_counter = stats->general.beacon_counter;
		data.beacon_average_energy =
			stats->general.beacon_average_energy;
1253 1254
		flags = stats->flag;
	}
1255
	data.flags = flags;
1256

1257 1258
	iwl_mvm_rx_stats_check_trigger(mvm, pkt);

1259 1260 1261 1262
	ieee80211_iterate_active_interfaces(mvm->hw,
					    IEEE80211_IFACE_ITER_NORMAL,
					    iwl_mvm_stat_iterator,
					    &data);
1263 1264 1265 1266

	if (!iwl_mvm_has_new_rx_api(mvm))
		return;

1267 1268
	if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
		struct iwl_notif_statistics_v11 *v11 = (void *)&pkt->data;
1269 1270

		energy = (void *)&v11->load_stats.avg_energy;
1271
		bytes = (void *)&v11->load_stats.byte_count;
1272 1273
		air_time = (void *)&v11->load_stats.air_time;
	} else {
1274
		struct iwl_notif_statistics *stats = (void *)&pkt->data;
1275

1276
		energy = (void *)&stats->load_stats.avg_energy;
1277
		bytes = (void *)&stats->load_stats.byte_count;
1278 1279
		air_time = (void *)&stats->load_stats.air_time;
	}
1280 1281
	ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_stats_energy_iter,
					  energy);
1282 1283 1284 1285 1286 1287

	/*
	 * Don't update in case the statistics are not cleared, since
	 * we will end up counting twice the same airtime, once in TCM
	 * request and once in statistics notification.
	 */
1288 1289
	if (le32_to_cpu(flags) & IWL_STATISTICS_REPLY_FLG_CLEAR)
		iwl_mvm_update_tcm_from_stats(mvm, air_time, bytes);
1290

1291 1292
}

1293
void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
1294 1295
{
	iwl_mvm_handle_rx_statistics(mvm, rxb_addr(rxb));
1296
}
1297 1298 1299 1300 1301 1302 1303 1304

void iwl_mvm_window_status_notif(struct iwl_mvm *mvm,
				 struct iwl_rx_cmd_buffer *rxb)
{
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
	struct iwl_ba_window_status_notif *notif = (void *)pkt->data;
	int i;

1305 1306 1307 1308
	BUILD_BUG_ON(ARRAY_SIZE(notif->ra_tid) != BA_WINDOW_STREAMS_MAX);
	BUILD_BUG_ON(ARRAY_SIZE(notif->mpdu_rx_count) != BA_WINDOW_STREAMS_MAX);
	BUILD_BUG_ON(ARRAY_SIZE(notif->bitmap) != BA_WINDOW_STREAMS_MAX);
	BUILD_BUG_ON(ARRAY_SIZE(notif->start_seq_num) != BA_WINDOW_STREAMS_MAX);
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343

	rcu_read_lock();
	for (i = 0; i < BA_WINDOW_STREAMS_MAX; i++) {
		struct ieee80211_sta *sta;
		u8 sta_id, tid;
		u64 bitmap;
		u32 ssn;
		u16 ratid;
		u16 received_mpdu;

		ratid = le16_to_cpu(notif->ra_tid[i]);
		/* check that this TID is valid */
		if (!(ratid & BA_WINDOW_STATUS_VALID_MSK))
			continue;

		received_mpdu = le16_to_cpu(notif->mpdu_rx_count[i]);
		if (received_mpdu == 0)
			continue;

		tid = ratid & BA_WINDOW_STATUS_TID_MSK;
		/* get the station */
		sta_id = (ratid & BA_WINDOW_STATUS_STA_ID_MSK)
			 >> BA_WINDOW_STATUS_STA_ID_POS;
		sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
		if (IS_ERR_OR_NULL(sta))
			continue;
		bitmap = le64_to_cpu(notif->bitmap[i]);
		ssn = le32_to_cpu(notif->start_seq_num[i]);

		/* update mac80211 with the bitmap for the reordering buffer */
		ieee80211_mark_rx_ba_filtered_frames(sta, tid, ssn, bitmap,
						     received_mpdu);
	}
	rcu_read_unlock();
}