Commit 51458c97 authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'mac80211-for-davem-2020-08-28' of...

Merge tag 'mac80211-for-davem-2020-08-28' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211



Johannes Berg says:

====================
We have:
 * fixes for AQL (airtime queue limits)
 * reduce packet loss detection false positives
 * a small channel number fix for the 6 GHz band
 * a fix for 80+80/160 MHz negotiation
 * an nl80211 attribute (NL80211_ATTR_HE_6GHZ_CAPABILITY) fix
 * add a missing sanity check for the regulatory code
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b43c75ab 2d9b5550
Loading
Loading
Loading
Loading
+146 −56
Original line number Diff line number Diff line
@@ -405,18 +405,14 @@ ieee80211_calc_legacy_rate_duration(u16 bitrate, bool short_pre,
	return duration;
}

u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
static u32 ieee80211_get_rate_duration(struct ieee80211_hw *hw,
				       struct ieee80211_rx_status *status,
			      int len)
				       u32 *overhead)
{
	struct ieee80211_supported_band *sband;
	const struct ieee80211_rate *rate;
	bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI;
	bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE;
	int bw, streams;
	int group, idx;
	u32 duration;
	bool cck;

	switch (status->bw) {
	case RATE_INFO_BW_20:
@@ -437,20 +433,6 @@ u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
	}

	switch (status->encoding) {
	case RX_ENC_LEGACY:
		if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ))
			return 0;

		sband = hw->wiphy->bands[status->band];
		if (!sband || status->rate_idx >= sband->n_bitrates)
			return 0;

		rate = &sband->bitrates[status->rate_idx];
		cck = rate->flags & IEEE80211_RATE_MANDATORY_B;

		return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp,
							   cck, len);

	case RX_ENC_VHT:
		streams = status->nss;
		idx = status->rate_idx;
@@ -477,51 +459,144 @@ u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,

	duration = airtime_mcs_groups[group].duration[idx];
	duration <<= airtime_mcs_groups[group].shift;
	*overhead = 36 + (streams << 2);

	return duration;
}


u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
			      struct ieee80211_rx_status *status,
			      int len)
{
	struct ieee80211_supported_band *sband;
	u32 duration, overhead = 0;

	if (status->encoding == RX_ENC_LEGACY) {
		const struct ieee80211_rate *rate;
		bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE;
		bool cck;

		if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ))
			return 0;

		sband = hw->wiphy->bands[status->band];
		if (!sband || status->rate_idx >= sband->n_bitrates)
			return 0;

		rate = &sband->bitrates[status->rate_idx];
		cck = rate->flags & IEEE80211_RATE_MANDATORY_B;

		return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp,
							   cck, len);
	}

	duration = ieee80211_get_rate_duration(hw, status, &overhead);
	if (!duration)
		return 0;

	duration *= len;
	duration /= AVG_PKT_SIZE;
	duration /= 1024;

	duration += 36 + (streams << 2);

	return duration;
	return duration + overhead;
}
EXPORT_SYMBOL_GPL(ieee80211_calc_rx_airtime);

static u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw,
static bool ieee80211_fill_rate_info(struct ieee80211_hw *hw,
				     struct ieee80211_rx_status *stat, u8 band,
				     struct rate_info *ri)
{
	struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
	int i;

	if (!ri || !sband)
	    return false;

	stat->bw = ri->bw;
	stat->nss = ri->nss;
	stat->rate_idx = ri->mcs;

	if (ri->flags & RATE_INFO_FLAGS_HE_MCS)
		stat->encoding = RX_ENC_HE;
	else if (ri->flags & RATE_INFO_FLAGS_VHT_MCS)
		stat->encoding = RX_ENC_VHT;
	else if (ri->flags & RATE_INFO_FLAGS_MCS)
		stat->encoding = RX_ENC_HT;
	else
		stat->encoding = RX_ENC_LEGACY;

	if (ri->flags & RATE_INFO_FLAGS_SHORT_GI)
		stat->enc_flags |= RX_ENC_FLAG_SHORT_GI;

	stat->he_gi = ri->he_gi;

	if (stat->encoding != RX_ENC_LEGACY)
		return true;

	stat->rate_idx = 0;
	for (i = 0; i < sband->n_bitrates; i++) {
		if (ri->legacy != sband->bitrates[i].bitrate)
			continue;

		stat->rate_idx = i;
		return true;
	}

	return false;
}

static int ieee80211_fill_rx_status(struct ieee80211_rx_status *stat,
				    struct ieee80211_hw *hw,
				    struct ieee80211_tx_rate *rate,
					  u8 band, int len)
				    struct rate_info *ri, u8 band, int len)
{
	struct ieee80211_rx_status stat = {
		.band = band,
	};
	memset(stat, 0, sizeof(*stat));
	stat->band = band;

	if (rate->idx < 0 || !rate->count)
	if (ieee80211_fill_rate_info(hw, stat, band, ri))
		return 0;

	if (rate->idx < 0 || !rate->count)
		return -1;

	if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
		stat.bw = RATE_INFO_BW_80;
		stat->bw = RATE_INFO_BW_80;
	else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
		stat.bw = RATE_INFO_BW_40;
		stat->bw = RATE_INFO_BW_40;
	else
		stat.bw = RATE_INFO_BW_20;
		stat->bw = RATE_INFO_BW_20;

	stat.enc_flags = 0;
	stat->enc_flags = 0;
	if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
		stat.enc_flags |= RX_ENC_FLAG_SHORTPRE;
		stat->enc_flags |= RX_ENC_FLAG_SHORTPRE;
	if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
		stat.enc_flags |= RX_ENC_FLAG_SHORT_GI;
		stat->enc_flags |= RX_ENC_FLAG_SHORT_GI;

	stat.rate_idx = rate->idx;
	stat->rate_idx = rate->idx;
	if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
		stat.encoding = RX_ENC_VHT;
		stat.rate_idx = ieee80211_rate_get_vht_mcs(rate);
		stat.nss = ieee80211_rate_get_vht_nss(rate);
		stat->encoding = RX_ENC_VHT;
		stat->rate_idx = ieee80211_rate_get_vht_mcs(rate);
		stat->nss = ieee80211_rate_get_vht_nss(rate);
	} else if (rate->flags & IEEE80211_TX_RC_MCS) {
		stat.encoding = RX_ENC_HT;
		stat->encoding = RX_ENC_HT;
	} else {
		stat.encoding = RX_ENC_LEGACY;
		stat->encoding = RX_ENC_LEGACY;
	}

	return 0;
}

static u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw,
					  struct ieee80211_tx_rate *rate,
					  struct rate_info *ri,
					  u8 band, int len)
{
	struct ieee80211_rx_status stat;

	if (ieee80211_fill_rx_status(&stat, hw, rate, ri, band, len))
		return 0;

	return ieee80211_calc_rx_airtime(hw, &stat, len);
}

@@ -536,7 +611,7 @@ u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
		struct ieee80211_tx_rate *rate = &info->status.rates[i];
		u32 cur_duration;

		cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate,
		cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate, NULL,
							      info->band, len);
		if (!cur_duration)
			break;
@@ -572,26 +647,41 @@ u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
	if (pubsta) {
		struct sta_info *sta = container_of(pubsta, struct sta_info,
						    sta);
		struct ieee80211_rx_status stat;
		struct ieee80211_tx_rate *rate = &sta->tx_stats.last_rate;
		u32 airtime;
		struct rate_info *ri = &sta->tx_stats.last_rate_info;
		u32 duration, overhead;
		u8 agg_shift;

		if (!(rate->flags & (IEEE80211_TX_RC_VHT_MCS |
				     IEEE80211_TX_RC_MCS)))
			ampdu = false;
		if (ieee80211_fill_rx_status(&stat, hw, rate, ri, band, len))
			return 0;

		if (stat.encoding == RX_ENC_LEGACY || !ampdu)
			return ieee80211_calc_rx_airtime(hw, &stat, len);

		duration = ieee80211_get_rate_duration(hw, &stat, &overhead);
		/*
		 * Assume that HT/VHT transmission on any AC except VO will
		 * use aggregation. Since we don't have reliable reporting
		 * of aggregation length, assume an average of 16.
		 * of aggregation length, assume an average size based on the
		 * tx rate.
		 * This will not be very accurate, but much better than simply
		 * assuming un-aggregated tx.
		 * assuming un-aggregated tx in all cases.
		 */
		airtime = ieee80211_calc_tx_airtime_rate(hw, rate, band,
							 ampdu ? len * 16 : len);
		if (ampdu)
			airtime /= 16;
		if (duration > 400) /* <= VHT20 MCS2 1S */
			agg_shift = 1;
		else if (duration > 250) /* <= VHT20 MCS3 1S or MCS1 2S */
			agg_shift = 2;
		else if (duration > 150) /* <= VHT20 MCS5 1S or MCS3 2S */
			agg_shift = 3;
		else
			agg_shift = 4;

		duration *= len;
		duration /= AVG_PKT_SIZE;
		duration /= 1024;

		return airtime;
		return duration + (overhead >> agg_shift);
	}

	if (!conf)
+3 −2
Original line number Diff line number Diff line
@@ -524,7 +524,7 @@ struct ieee80211_sta_rx_stats {
 * @status_stats.retry_failed: # of frames that failed after retry
 * @status_stats.retry_count: # of retries attempted
 * @status_stats.lost_packets: # of lost packets
 * @status_stats.last_tdls_pkt_time: timestamp of last TDLS packet
 * @status_stats.last_pkt_time: timestamp of last ACKed packet
 * @status_stats.msdu_retries: # of MSDU retries
 * @status_stats.msdu_failed: # of failed MSDUs
 * @status_stats.last_ack: last ack timestamp (jiffies)
@@ -597,7 +597,7 @@ struct sta_info {
		unsigned long filtered;
		unsigned long retry_failed, retry_count;
		unsigned int lost_packets;
		unsigned long last_tdls_pkt_time;
		unsigned long last_pkt_time;
		u64 msdu_retries[IEEE80211_NUM_TIDS + 1];
		u64 msdu_failed[IEEE80211_NUM_TIDS + 1];
		unsigned long last_ack;
@@ -611,6 +611,7 @@ struct sta_info {
		u64 packets[IEEE80211_NUM_ACS];
		u64 bytes[IEEE80211_NUM_ACS];
		struct ieee80211_tx_rate last_rate;
		struct rate_info last_rate_info;
		u64 msdu[IEEE80211_NUM_TIDS + 1];
	} tx_stats;
	u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
+23 −20
Original line number Diff line number Diff line
@@ -755,12 +755,16 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
 *  - current throughput (higher value for higher tpt)?
 */
#define STA_LOST_PKT_THRESHOLD	50
#define STA_LOST_PKT_TIME	HZ		/* 1 sec since last ACK */
#define STA_LOST_TDLS_PKT_THRESHOLD	10
#define STA_LOST_TDLS_PKT_TIME		(10*HZ) /* 10secs since last ACK */

static void ieee80211_lost_packet(struct sta_info *sta,
				  struct ieee80211_tx_info *info)
{
	unsigned long pkt_time = STA_LOST_PKT_TIME;
	unsigned int pkt_thr = STA_LOST_PKT_THRESHOLD;

	/* If driver relies on its own algorithm for station kickout, skip
	 * mac80211 packet loss mechanism.
	 */
@@ -773,21 +777,20 @@ static void ieee80211_lost_packet(struct sta_info *sta,
		return;

	sta->status_stats.lost_packets++;
	if (!sta->sta.tdls &&
	    sta->status_stats.lost_packets < STA_LOST_PKT_THRESHOLD)
		return;
	if (sta->sta.tdls) {
		pkt_time = STA_LOST_TDLS_PKT_TIME;
		pkt_thr = STA_LOST_PKT_THRESHOLD;
	}

	/*
	 * If we're in TDLS mode, make sure that all STA_LOST_TDLS_PKT_THRESHOLD
	 * of the last packets were lost, and that no ACK was received in the
	 * last STA_LOST_TDLS_PKT_TIME ms, before triggering the CQM packet-loss
	 * mechanism.
	 * For non-TDLS, use STA_LOST_PKT_THRESHOLD and STA_LOST_PKT_TIME
	 */
	if (sta->sta.tdls &&
	    (sta->status_stats.lost_packets < STA_LOST_TDLS_PKT_THRESHOLD ||
	     time_before(jiffies,
			 sta->status_stats.last_tdls_pkt_time +
			 STA_LOST_TDLS_PKT_TIME)))
	if (sta->status_stats.lost_packets < pkt_thr ||
	    !time_after(jiffies, sta->status_stats.last_pkt_time + pkt_time))
		return;

	cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
@@ -1033,9 +1036,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
					sta->status_stats.lost_packets = 0;

				/* Track when last TDLS packet was ACKed */
				if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
					sta->status_stats.last_tdls_pkt_time =
						jiffies;
				sta->status_stats.last_pkt_time = jiffies;
			} else if (noack_success) {
				/* nothing to do here, do not account as lost */
			} else {
@@ -1137,9 +1138,17 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
	struct ieee80211_tx_info *info = status->info;
	struct ieee80211_sta *pubsta = status->sta;
	struct ieee80211_supported_band *sband;
	struct sta_info *sta;
	int retry_count;
	bool acked, noack_success;

	if (pubsta) {
		sta = container_of(pubsta, struct sta_info, sta);

		if (status->rate)
			sta->tx_stats.last_rate_info = *status->rate;
	}

	if (status->skb)
		return __ieee80211_tx_status(hw, status);

@@ -1154,10 +1163,6 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
	noack_success = !!(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED);

	if (pubsta) {
		struct sta_info *sta;

		sta = container_of(pubsta, struct sta_info, sta);

		if (!acked && !noack_success)
			sta->status_stats.retry_failed++;
		sta->status_stats.retry_count += retry_count;
@@ -1168,9 +1173,8 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
			if (sta->status_stats.lost_packets)
				sta->status_stats.lost_packets = 0;

			/* Track when last TDLS packet was ACKed */
			if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
				sta->status_stats.last_tdls_pkt_time = jiffies;
			/* Track when last packet was ACKed */
			sta->status_stats.last_pkt_time = jiffies;
		} else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
			return;
		} else if (noack_success) {
@@ -1259,8 +1263,7 @@ void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
			if (sta->status_stats.lost_packets)
				sta->status_stats.lost_packets = 0;

			if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
				sta->status_stats.last_tdls_pkt_time = jiffies;
			sta->status_stats.last_pkt_time = jiffies;
		} else {
			ieee80211_lost_packet(sta, info);
		}
+11 −4
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
 */

#include <linux/export.h>
#include <linux/bitfield.h>
#include <net/cfg80211.h>
#include "core.h"
#include "rdev-ops.h"
@@ -912,6 +913,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
	struct ieee80211_sta_vht_cap *vht_cap;
	struct ieee80211_edmg *edmg_cap;
	u32 width, control_freq, cap;
	bool support_80_80 = false;

	if (WARN_ON(!cfg80211_chandef_valid(chandef)))
		return false;
@@ -979,9 +981,13 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
			return false;
		break;
	case NL80211_CHAN_WIDTH_80P80:
		cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
		if (chandef->chan->band != NL80211_BAND_6GHZ &&
		    cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
		cap = vht_cap->cap;
		support_80_80 =
			(cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) ||
			(cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
			 cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) ||
			u32_get_bits(cap, IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) > 1;
		if (chandef->chan->band != NL80211_BAND_6GHZ && !support_80_80)
			return false;
		/* fall through */
	case NL80211_CHAN_WIDTH_80:
@@ -1001,7 +1007,8 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
			return false;
		cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
		if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
		    cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
		    cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ &&
		    !(vht_cap->cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK))
			return false;
		break;
	default:
+1 −1
Original line number Diff line number Diff line
@@ -6011,7 +6011,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)

	if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
		params.he_6ghz_capa =
			nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
			nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);

	if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
		params.airtime_weight =
Loading