162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2019 Felix Fietkau <nbd@nbd.name>
462306a36Sopenharmony_ci * Copyright (C) 2021-2022 Intel Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <net/mac80211.h>
862306a36Sopenharmony_ci#include "ieee80211_i.h"
962306a36Sopenharmony_ci#include "sta_info.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define AVG_PKT_SIZE	1024
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/* Number of bits for an average sized packet */
1462306a36Sopenharmony_ci#define MCS_NBITS (AVG_PKT_SIZE << 3)
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/* Number of kilo-symbols (symbols * 1024) for a packet with (bps) bits per
1762306a36Sopenharmony_ci * symbol. We use k-symbols to avoid rounding in the _TIME macros below.
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci#define MCS_N_KSYMS(bps) DIV_ROUND_UP(MCS_NBITS << 10, (bps))
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* Transmission time (in 1024 * usec) for a packet containing (ksyms) * 1024
2262306a36Sopenharmony_ci * symbols.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci#define MCS_SYMBOL_TIME(sgi, ksyms)					\
2562306a36Sopenharmony_ci	(sgi ?								\
2662306a36Sopenharmony_ci	  ((ksyms) * 4 * 18) / 20 :		/* 3.6 us per sym */	\
2762306a36Sopenharmony_ci	  ((ksyms) * 4)			/* 4.0 us per sym */	\
2862306a36Sopenharmony_ci	)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* Transmit duration for the raw data part of an average sized packet */
3162306a36Sopenharmony_ci#define MCS_DURATION(streams, sgi, bps) \
3262306a36Sopenharmony_ci	((u32)MCS_SYMBOL_TIME(sgi, MCS_N_KSYMS((streams) * (bps))))
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define MCS_DURATION_S(shift, streams, sgi, bps)		\
3562306a36Sopenharmony_ci	((u16)((MCS_DURATION(streams, sgi, bps) >> shift)))
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* These should match the values in enum nl80211_he_gi */
3862306a36Sopenharmony_ci#define HE_GI_08 0
3962306a36Sopenharmony_ci#define HE_GI_16 1
4062306a36Sopenharmony_ci#define HE_GI_32 2
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* Transmission time (1024 usec) for a packet containing (ksyms) * k-symbols */
4362306a36Sopenharmony_ci#define HE_SYMBOL_TIME(gi, ksyms)					\
4462306a36Sopenharmony_ci	(gi == HE_GI_08 ?						\
4562306a36Sopenharmony_ci	 ((ksyms) * 16 * 17) / 20 :		/* 13.6 us per sym */	\
4662306a36Sopenharmony_ci	 (gi == HE_GI_16 ?						\
4762306a36Sopenharmony_ci	  ((ksyms) * 16 * 18) / 20 :		/* 14.4 us per sym */	\
4862306a36Sopenharmony_ci	  ((ksyms) * 16)			/* 16.0 us per sym */	\
4962306a36Sopenharmony_ci	 ))
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* Transmit duration for the raw data part of an average sized packet */
5262306a36Sopenharmony_ci#define HE_DURATION(streams, gi, bps) \
5362306a36Sopenharmony_ci	((u32)HE_SYMBOL_TIME(gi, MCS_N_KSYMS((streams) * (bps))))
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define HE_DURATION_S(shift, streams, gi, bps)		\
5662306a36Sopenharmony_ci	(HE_DURATION(streams, gi, bps) >> shift)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define BW_20			0
5962306a36Sopenharmony_ci#define BW_40			1
6062306a36Sopenharmony_ci#define BW_80			2
6162306a36Sopenharmony_ci#define BW_160			3
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * Define group sort order: HT40 -> SGI -> #streams
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_ci#define IEEE80211_MAX_STREAMS		4
6762306a36Sopenharmony_ci#define IEEE80211_HT_STREAM_GROUPS	4 /* BW(=2) * SGI(=2) */
6862306a36Sopenharmony_ci#define IEEE80211_VHT_STREAM_GROUPS	8 /* BW(=4) * SGI(=2) */
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define IEEE80211_HE_MAX_STREAMS	8
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define IEEE80211_HT_GROUPS_NB	(IEEE80211_MAX_STREAMS *	\
7362306a36Sopenharmony_ci				 IEEE80211_HT_STREAM_GROUPS)
7462306a36Sopenharmony_ci#define IEEE80211_VHT_GROUPS_NB	(IEEE80211_MAX_STREAMS *	\
7562306a36Sopenharmony_ci					 IEEE80211_VHT_STREAM_GROUPS)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define IEEE80211_HT_GROUP_0	0
7862306a36Sopenharmony_ci#define IEEE80211_VHT_GROUP_0	(IEEE80211_HT_GROUP_0 + IEEE80211_HT_GROUPS_NB)
7962306a36Sopenharmony_ci#define IEEE80211_HE_GROUP_0	(IEEE80211_VHT_GROUP_0 + IEEE80211_VHT_GROUPS_NB)
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define MCS_GROUP_RATES		12
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#define HT_GROUP_IDX(_streams, _sgi, _ht40)	\
8462306a36Sopenharmony_ci	IEEE80211_HT_GROUP_0 +			\
8562306a36Sopenharmony_ci	IEEE80211_MAX_STREAMS * 2 * _ht40 +	\
8662306a36Sopenharmony_ci	IEEE80211_MAX_STREAMS * _sgi +		\
8762306a36Sopenharmony_ci	_streams - 1
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define _MAX(a, b) (((a)>(b))?(a):(b))
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define GROUP_SHIFT(duration)						\
9262306a36Sopenharmony_ci	_MAX(0, 16 - __builtin_clz(duration))
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/* MCS rate information for an MCS group */
9562306a36Sopenharmony_ci#define __MCS_GROUP(_streams, _sgi, _ht40, _s)				\
9662306a36Sopenharmony_ci	[HT_GROUP_IDX(_streams, _sgi, _ht40)] = {			\
9762306a36Sopenharmony_ci	.shift = _s,							\
9862306a36Sopenharmony_ci	.duration = {							\
9962306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 54 : 26),	\
10062306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 108 : 52),	\
10162306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 162 : 78),	\
10262306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 216 : 104),	\
10362306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 324 : 156),	\
10462306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 432 : 208),	\
10562306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 486 : 234),	\
10662306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 540 : 260)	\
10762306a36Sopenharmony_ci	}								\
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40)				\
11162306a36Sopenharmony_ci	GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26))
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define MCS_GROUP(_streams, _sgi, _ht40)				\
11462306a36Sopenharmony_ci	__MCS_GROUP(_streams, _sgi, _ht40,				\
11562306a36Sopenharmony_ci		    MCS_GROUP_SHIFT(_streams, _sgi, _ht40))
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define VHT_GROUP_IDX(_streams, _sgi, _bw)				\
11862306a36Sopenharmony_ci	(IEEE80211_VHT_GROUP_0 +					\
11962306a36Sopenharmony_ci	 IEEE80211_MAX_STREAMS * 2 * (_bw) +				\
12062306a36Sopenharmony_ci	 IEEE80211_MAX_STREAMS * (_sgi) +				\
12162306a36Sopenharmony_ci	 (_streams) - 1)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define BW2VBPS(_bw, r4, r3, r2, r1)					\
12462306a36Sopenharmony_ci	(_bw == BW_160 ? r4 : _bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#define __VHT_GROUP(_streams, _sgi, _bw, _s)				\
12762306a36Sopenharmony_ci	[VHT_GROUP_IDX(_streams, _sgi, _bw)] = {			\
12862306a36Sopenharmony_ci	.shift = _s,							\
12962306a36Sopenharmony_ci	.duration = {							\
13062306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi,			\
13162306a36Sopenharmony_ci			       BW2VBPS(_bw,  234,  117,  54,  26)),	\
13262306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi,			\
13362306a36Sopenharmony_ci			       BW2VBPS(_bw,  468,  234, 108,  52)),	\
13462306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi,			\
13562306a36Sopenharmony_ci			       BW2VBPS(_bw,  702,  351, 162,  78)),	\
13662306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi,			\
13762306a36Sopenharmony_ci			       BW2VBPS(_bw,  936,  468, 216, 104)),	\
13862306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi,			\
13962306a36Sopenharmony_ci			       BW2VBPS(_bw, 1404,  702, 324, 156)),	\
14062306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi,			\
14162306a36Sopenharmony_ci			       BW2VBPS(_bw, 1872,  936, 432, 208)),	\
14262306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi,			\
14362306a36Sopenharmony_ci			       BW2VBPS(_bw, 2106, 1053, 486, 234)),	\
14462306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi,			\
14562306a36Sopenharmony_ci			       BW2VBPS(_bw, 2340, 1170, 540, 260)),	\
14662306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi,			\
14762306a36Sopenharmony_ci			       BW2VBPS(_bw, 2808, 1404, 648, 312)),	\
14862306a36Sopenharmony_ci		MCS_DURATION_S(_s, _streams, _sgi,			\
14962306a36Sopenharmony_ci			       BW2VBPS(_bw, 3120, 1560, 720, 346))	\
15062306a36Sopenharmony_ci        }								\
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#define VHT_GROUP_SHIFT(_streams, _sgi, _bw)				\
15462306a36Sopenharmony_ci	GROUP_SHIFT(MCS_DURATION(_streams, _sgi,			\
15562306a36Sopenharmony_ci				 BW2VBPS(_bw, 243, 117,  54,  26)))
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#define VHT_GROUP(_streams, _sgi, _bw)					\
15862306a36Sopenharmony_ci	__VHT_GROUP(_streams, _sgi, _bw,				\
15962306a36Sopenharmony_ci		    VHT_GROUP_SHIFT(_streams, _sgi, _bw))
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci#define HE_GROUP_IDX(_streams, _gi, _bw)				\
16362306a36Sopenharmony_ci	(IEEE80211_HE_GROUP_0 +					\
16462306a36Sopenharmony_ci	 IEEE80211_HE_MAX_STREAMS * 3 * (_bw) +			\
16562306a36Sopenharmony_ci	 IEEE80211_HE_MAX_STREAMS * (_gi) +				\
16662306a36Sopenharmony_ci	 (_streams) - 1)
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci#define __HE_GROUP(_streams, _gi, _bw, _s)				\
16962306a36Sopenharmony_ci	[HE_GROUP_IDX(_streams, _gi, _bw)] = {			\
17062306a36Sopenharmony_ci	.shift = _s,							\
17162306a36Sopenharmony_ci	.duration = {							\
17262306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
17362306a36Sopenharmony_ci			      BW2VBPS(_bw,   979,  489,  230,  115)),	\
17462306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
17562306a36Sopenharmony_ci			      BW2VBPS(_bw,  1958,  979,  475,  230)),	\
17662306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
17762306a36Sopenharmony_ci			      BW2VBPS(_bw,  2937, 1468,  705,  345)),	\
17862306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
17962306a36Sopenharmony_ci			      BW2VBPS(_bw,  3916, 1958,  936,  475)),	\
18062306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
18162306a36Sopenharmony_ci			      BW2VBPS(_bw,  5875, 2937, 1411,  705)),	\
18262306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
18362306a36Sopenharmony_ci			      BW2VBPS(_bw,  7833, 3916, 1872,  936)),	\
18462306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
18562306a36Sopenharmony_ci			      BW2VBPS(_bw,  8827, 4406, 2102, 1051)),	\
18662306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
18762306a36Sopenharmony_ci			      BW2VBPS(_bw,  9806, 4896, 2347, 1166)),	\
18862306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
18962306a36Sopenharmony_ci			      BW2VBPS(_bw, 11764, 5875, 2808, 1411)),	\
19062306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
19162306a36Sopenharmony_ci			      BW2VBPS(_bw, 13060, 6523, 3124, 1555)),	\
19262306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
19362306a36Sopenharmony_ci			      BW2VBPS(_bw, 14702, 7344, 3513, 1756)),	\
19462306a36Sopenharmony_ci		HE_DURATION_S(_s, _streams, _gi,			\
19562306a36Sopenharmony_ci			      BW2VBPS(_bw, 16329, 8164, 3902, 1944))	\
19662306a36Sopenharmony_ci        }								\
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci#define HE_GROUP_SHIFT(_streams, _gi, _bw)				\
20062306a36Sopenharmony_ci	GROUP_SHIFT(HE_DURATION(_streams, _gi,			\
20162306a36Sopenharmony_ci				BW2VBPS(_bw,   979,  489,  230,  115)))
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci#define HE_GROUP(_streams, _gi, _bw)					\
20462306a36Sopenharmony_ci	__HE_GROUP(_streams, _gi, _bw,				\
20562306a36Sopenharmony_ci		   HE_GROUP_SHIFT(_streams, _gi, _bw))
20662306a36Sopenharmony_cistruct mcs_group {
20762306a36Sopenharmony_ci	u8 shift;
20862306a36Sopenharmony_ci	u16 duration[MCS_GROUP_RATES];
20962306a36Sopenharmony_ci};
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic const struct mcs_group airtime_mcs_groups[] = {
21262306a36Sopenharmony_ci	MCS_GROUP(1, 0, BW_20),
21362306a36Sopenharmony_ci	MCS_GROUP(2, 0, BW_20),
21462306a36Sopenharmony_ci	MCS_GROUP(3, 0, BW_20),
21562306a36Sopenharmony_ci	MCS_GROUP(4, 0, BW_20),
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	MCS_GROUP(1, 1, BW_20),
21862306a36Sopenharmony_ci	MCS_GROUP(2, 1, BW_20),
21962306a36Sopenharmony_ci	MCS_GROUP(3, 1, BW_20),
22062306a36Sopenharmony_ci	MCS_GROUP(4, 1, BW_20),
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	MCS_GROUP(1, 0, BW_40),
22362306a36Sopenharmony_ci	MCS_GROUP(2, 0, BW_40),
22462306a36Sopenharmony_ci	MCS_GROUP(3, 0, BW_40),
22562306a36Sopenharmony_ci	MCS_GROUP(4, 0, BW_40),
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	MCS_GROUP(1, 1, BW_40),
22862306a36Sopenharmony_ci	MCS_GROUP(2, 1, BW_40),
22962306a36Sopenharmony_ci	MCS_GROUP(3, 1, BW_40),
23062306a36Sopenharmony_ci	MCS_GROUP(4, 1, BW_40),
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	VHT_GROUP(1, 0, BW_20),
23362306a36Sopenharmony_ci	VHT_GROUP(2, 0, BW_20),
23462306a36Sopenharmony_ci	VHT_GROUP(3, 0, BW_20),
23562306a36Sopenharmony_ci	VHT_GROUP(4, 0, BW_20),
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	VHT_GROUP(1, 1, BW_20),
23862306a36Sopenharmony_ci	VHT_GROUP(2, 1, BW_20),
23962306a36Sopenharmony_ci	VHT_GROUP(3, 1, BW_20),
24062306a36Sopenharmony_ci	VHT_GROUP(4, 1, BW_20),
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	VHT_GROUP(1, 0, BW_40),
24362306a36Sopenharmony_ci	VHT_GROUP(2, 0, BW_40),
24462306a36Sopenharmony_ci	VHT_GROUP(3, 0, BW_40),
24562306a36Sopenharmony_ci	VHT_GROUP(4, 0, BW_40),
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	VHT_GROUP(1, 1, BW_40),
24862306a36Sopenharmony_ci	VHT_GROUP(2, 1, BW_40),
24962306a36Sopenharmony_ci	VHT_GROUP(3, 1, BW_40),
25062306a36Sopenharmony_ci	VHT_GROUP(4, 1, BW_40),
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	VHT_GROUP(1, 0, BW_80),
25362306a36Sopenharmony_ci	VHT_GROUP(2, 0, BW_80),
25462306a36Sopenharmony_ci	VHT_GROUP(3, 0, BW_80),
25562306a36Sopenharmony_ci	VHT_GROUP(4, 0, BW_80),
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	VHT_GROUP(1, 1, BW_80),
25862306a36Sopenharmony_ci	VHT_GROUP(2, 1, BW_80),
25962306a36Sopenharmony_ci	VHT_GROUP(3, 1, BW_80),
26062306a36Sopenharmony_ci	VHT_GROUP(4, 1, BW_80),
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	VHT_GROUP(1, 0, BW_160),
26362306a36Sopenharmony_ci	VHT_GROUP(2, 0, BW_160),
26462306a36Sopenharmony_ci	VHT_GROUP(3, 0, BW_160),
26562306a36Sopenharmony_ci	VHT_GROUP(4, 0, BW_160),
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	VHT_GROUP(1, 1, BW_160),
26862306a36Sopenharmony_ci	VHT_GROUP(2, 1, BW_160),
26962306a36Sopenharmony_ci	VHT_GROUP(3, 1, BW_160),
27062306a36Sopenharmony_ci	VHT_GROUP(4, 1, BW_160),
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_08, BW_20),
27362306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_08, BW_20),
27462306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_08, BW_20),
27562306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_08, BW_20),
27662306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_08, BW_20),
27762306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_08, BW_20),
27862306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_08, BW_20),
27962306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_08, BW_20),
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_16, BW_20),
28262306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_16, BW_20),
28362306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_16, BW_20),
28462306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_16, BW_20),
28562306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_16, BW_20),
28662306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_16, BW_20),
28762306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_16, BW_20),
28862306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_16, BW_20),
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_32, BW_20),
29162306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_32, BW_20),
29262306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_32, BW_20),
29362306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_32, BW_20),
29462306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_32, BW_20),
29562306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_32, BW_20),
29662306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_32, BW_20),
29762306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_32, BW_20),
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_08, BW_40),
30062306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_08, BW_40),
30162306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_08, BW_40),
30262306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_08, BW_40),
30362306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_08, BW_40),
30462306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_08, BW_40),
30562306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_08, BW_40),
30662306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_08, BW_40),
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_16, BW_40),
30962306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_16, BW_40),
31062306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_16, BW_40),
31162306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_16, BW_40),
31262306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_16, BW_40),
31362306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_16, BW_40),
31462306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_16, BW_40),
31562306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_16, BW_40),
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_32, BW_40),
31862306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_32, BW_40),
31962306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_32, BW_40),
32062306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_32, BW_40),
32162306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_32, BW_40),
32262306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_32, BW_40),
32362306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_32, BW_40),
32462306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_32, BW_40),
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_08, BW_80),
32762306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_08, BW_80),
32862306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_08, BW_80),
32962306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_08, BW_80),
33062306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_08, BW_80),
33162306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_08, BW_80),
33262306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_08, BW_80),
33362306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_08, BW_80),
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_16, BW_80),
33662306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_16, BW_80),
33762306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_16, BW_80),
33862306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_16, BW_80),
33962306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_16, BW_80),
34062306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_16, BW_80),
34162306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_16, BW_80),
34262306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_16, BW_80),
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_32, BW_80),
34562306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_32, BW_80),
34662306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_32, BW_80),
34762306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_32, BW_80),
34862306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_32, BW_80),
34962306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_32, BW_80),
35062306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_32, BW_80),
35162306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_32, BW_80),
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_08, BW_160),
35462306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_08, BW_160),
35562306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_08, BW_160),
35662306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_08, BW_160),
35762306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_08, BW_160),
35862306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_08, BW_160),
35962306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_08, BW_160),
36062306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_08, BW_160),
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_16, BW_160),
36362306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_16, BW_160),
36462306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_16, BW_160),
36562306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_16, BW_160),
36662306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_16, BW_160),
36762306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_16, BW_160),
36862306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_16, BW_160),
36962306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_16, BW_160),
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	HE_GROUP(1, HE_GI_32, BW_160),
37262306a36Sopenharmony_ci	HE_GROUP(2, HE_GI_32, BW_160),
37362306a36Sopenharmony_ci	HE_GROUP(3, HE_GI_32, BW_160),
37462306a36Sopenharmony_ci	HE_GROUP(4, HE_GI_32, BW_160),
37562306a36Sopenharmony_ci	HE_GROUP(5, HE_GI_32, BW_160),
37662306a36Sopenharmony_ci	HE_GROUP(6, HE_GI_32, BW_160),
37762306a36Sopenharmony_ci	HE_GROUP(7, HE_GI_32, BW_160),
37862306a36Sopenharmony_ci	HE_GROUP(8, HE_GI_32, BW_160),
37962306a36Sopenharmony_ci};
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic u32
38262306a36Sopenharmony_ciieee80211_calc_legacy_rate_duration(u16 bitrate, bool short_pre,
38362306a36Sopenharmony_ci				    bool cck, int len)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	u32 duration;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (cck) {
38862306a36Sopenharmony_ci		duration = 144 + 48; /* preamble + PLCP */
38962306a36Sopenharmony_ci		if (short_pre)
39062306a36Sopenharmony_ci			duration >>= 1;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci		duration += 10; /* SIFS */
39362306a36Sopenharmony_ci	} else {
39462306a36Sopenharmony_ci		duration = 20 + 16; /* premable + SIFS */
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	len <<= 3;
39862306a36Sopenharmony_ci	duration += (len * 10) / bitrate;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	return duration;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic u32 ieee80211_get_rate_duration(struct ieee80211_hw *hw,
40462306a36Sopenharmony_ci				       struct ieee80211_rx_status *status,
40562306a36Sopenharmony_ci				       u32 *overhead)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI;
40862306a36Sopenharmony_ci	int bw, streams;
40962306a36Sopenharmony_ci	int group, idx;
41062306a36Sopenharmony_ci	u32 duration;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	switch (status->bw) {
41362306a36Sopenharmony_ci	case RATE_INFO_BW_20:
41462306a36Sopenharmony_ci		bw = BW_20;
41562306a36Sopenharmony_ci		break;
41662306a36Sopenharmony_ci	case RATE_INFO_BW_40:
41762306a36Sopenharmony_ci		bw = BW_40;
41862306a36Sopenharmony_ci		break;
41962306a36Sopenharmony_ci	case RATE_INFO_BW_80:
42062306a36Sopenharmony_ci		bw = BW_80;
42162306a36Sopenharmony_ci		break;
42262306a36Sopenharmony_ci	case RATE_INFO_BW_160:
42362306a36Sopenharmony_ci		bw = BW_160;
42462306a36Sopenharmony_ci		break;
42562306a36Sopenharmony_ci	default:
42662306a36Sopenharmony_ci		WARN_ON_ONCE(1);
42762306a36Sopenharmony_ci		return 0;
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	switch (status->encoding) {
43162306a36Sopenharmony_ci	case RX_ENC_VHT:
43262306a36Sopenharmony_ci		streams = status->nss;
43362306a36Sopenharmony_ci		idx = status->rate_idx;
43462306a36Sopenharmony_ci		group = VHT_GROUP_IDX(streams, sgi, bw);
43562306a36Sopenharmony_ci		break;
43662306a36Sopenharmony_ci	case RX_ENC_HT:
43762306a36Sopenharmony_ci		streams = ((status->rate_idx >> 3) & 3) + 1;
43862306a36Sopenharmony_ci		idx = status->rate_idx & 7;
43962306a36Sopenharmony_ci		group = HT_GROUP_IDX(streams, sgi, bw);
44062306a36Sopenharmony_ci		break;
44162306a36Sopenharmony_ci	case RX_ENC_HE:
44262306a36Sopenharmony_ci		streams = status->nss;
44362306a36Sopenharmony_ci		idx = status->rate_idx;
44462306a36Sopenharmony_ci		group = HE_GROUP_IDX(streams, status->he_gi, bw);
44562306a36Sopenharmony_ci		break;
44662306a36Sopenharmony_ci	default:
44762306a36Sopenharmony_ci		WARN_ON_ONCE(1);
44862306a36Sopenharmony_ci		return 0;
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (WARN_ON_ONCE((status->encoding != RX_ENC_HE && streams > 4) ||
45262306a36Sopenharmony_ci			 (status->encoding == RX_ENC_HE && streams > 8)))
45362306a36Sopenharmony_ci		return 0;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (idx >= MCS_GROUP_RATES)
45662306a36Sopenharmony_ci		return 0;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	duration = airtime_mcs_groups[group].duration[idx];
45962306a36Sopenharmony_ci	duration <<= airtime_mcs_groups[group].shift;
46062306a36Sopenharmony_ci	*overhead = 36 + (streams << 2);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	return duration;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ciu32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
46762306a36Sopenharmony_ci			      struct ieee80211_rx_status *status,
46862306a36Sopenharmony_ci			      int len)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
47162306a36Sopenharmony_ci	u32 duration, overhead = 0;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (status->encoding == RX_ENC_LEGACY) {
47462306a36Sopenharmony_ci		const struct ieee80211_rate *rate;
47562306a36Sopenharmony_ci		bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE;
47662306a36Sopenharmony_ci		bool cck;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		/* on 60GHz or sub-1GHz band, there are no legacy rates */
47962306a36Sopenharmony_ci		if (WARN_ON_ONCE(status->band == NL80211_BAND_60GHZ ||
48062306a36Sopenharmony_ci				 status->band == NL80211_BAND_S1GHZ))
48162306a36Sopenharmony_ci			return 0;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci		sband = hw->wiphy->bands[status->band];
48462306a36Sopenharmony_ci		if (!sband || status->rate_idx >= sband->n_bitrates)
48562306a36Sopenharmony_ci			return 0;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		rate = &sband->bitrates[status->rate_idx];
48862306a36Sopenharmony_ci		cck = rate->flags & IEEE80211_RATE_MANDATORY_B;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp,
49162306a36Sopenharmony_ci							   cck, len);
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	duration = ieee80211_get_rate_duration(hw, status, &overhead);
49562306a36Sopenharmony_ci	if (!duration)
49662306a36Sopenharmony_ci		return 0;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	duration *= len;
49962306a36Sopenharmony_ci	duration /= AVG_PKT_SIZE;
50062306a36Sopenharmony_ci	duration /= 1024;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	return duration + overhead;
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_calc_rx_airtime);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic bool ieee80211_fill_rate_info(struct ieee80211_hw *hw,
50762306a36Sopenharmony_ci				     struct ieee80211_rx_status *stat, u8 band,
50862306a36Sopenharmony_ci				     struct rate_info *ri)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
51162306a36Sopenharmony_ci	int i;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (!ri || !sband)
51462306a36Sopenharmony_ci	    return false;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	stat->bw = ri->bw;
51762306a36Sopenharmony_ci	stat->nss = ri->nss;
51862306a36Sopenharmony_ci	stat->rate_idx = ri->mcs;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (ri->flags & RATE_INFO_FLAGS_HE_MCS)
52162306a36Sopenharmony_ci		stat->encoding = RX_ENC_HE;
52262306a36Sopenharmony_ci	else if (ri->flags & RATE_INFO_FLAGS_VHT_MCS)
52362306a36Sopenharmony_ci		stat->encoding = RX_ENC_VHT;
52462306a36Sopenharmony_ci	else if (ri->flags & RATE_INFO_FLAGS_MCS)
52562306a36Sopenharmony_ci		stat->encoding = RX_ENC_HT;
52662306a36Sopenharmony_ci	else
52762306a36Sopenharmony_ci		stat->encoding = RX_ENC_LEGACY;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (ri->flags & RATE_INFO_FLAGS_SHORT_GI)
53062306a36Sopenharmony_ci		stat->enc_flags |= RX_ENC_FLAG_SHORT_GI;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	stat->he_gi = ri->he_gi;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	if (stat->encoding != RX_ENC_LEGACY)
53562306a36Sopenharmony_ci		return true;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	stat->rate_idx = 0;
53862306a36Sopenharmony_ci	for (i = 0; i < sband->n_bitrates; i++) {
53962306a36Sopenharmony_ci		if (ri->legacy != sband->bitrates[i].bitrate)
54062306a36Sopenharmony_ci			continue;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		stat->rate_idx = i;
54362306a36Sopenharmony_ci		return true;
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return false;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic int ieee80211_fill_rx_status(struct ieee80211_rx_status *stat,
55062306a36Sopenharmony_ci				    struct ieee80211_hw *hw,
55162306a36Sopenharmony_ci				    struct ieee80211_tx_rate *rate,
55262306a36Sopenharmony_ci				    struct rate_info *ri, u8 band, int len)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	memset(stat, 0, sizeof(*stat));
55562306a36Sopenharmony_ci	stat->band = band;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (ieee80211_fill_rate_info(hw, stat, band, ri))
55862306a36Sopenharmony_ci		return 0;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (rate->idx < 0 || !rate->count)
56162306a36Sopenharmony_ci		return -1;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
56462306a36Sopenharmony_ci		stat->bw = RATE_INFO_BW_160;
56562306a36Sopenharmony_ci	else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
56662306a36Sopenharmony_ci		stat->bw = RATE_INFO_BW_80;
56762306a36Sopenharmony_ci	else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
56862306a36Sopenharmony_ci		stat->bw = RATE_INFO_BW_40;
56962306a36Sopenharmony_ci	else
57062306a36Sopenharmony_ci		stat->bw = RATE_INFO_BW_20;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	stat->enc_flags = 0;
57362306a36Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
57462306a36Sopenharmony_ci		stat->enc_flags |= RX_ENC_FLAG_SHORTPRE;
57562306a36Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
57662306a36Sopenharmony_ci		stat->enc_flags |= RX_ENC_FLAG_SHORT_GI;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	stat->rate_idx = rate->idx;
57962306a36Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
58062306a36Sopenharmony_ci		stat->encoding = RX_ENC_VHT;
58162306a36Sopenharmony_ci		stat->rate_idx = ieee80211_rate_get_vht_mcs(rate);
58262306a36Sopenharmony_ci		stat->nss = ieee80211_rate_get_vht_nss(rate);
58362306a36Sopenharmony_ci	} else if (rate->flags & IEEE80211_TX_RC_MCS) {
58462306a36Sopenharmony_ci		stat->encoding = RX_ENC_HT;
58562306a36Sopenharmony_ci	} else {
58662306a36Sopenharmony_ci		stat->encoding = RX_ENC_LEGACY;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	return 0;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw,
59362306a36Sopenharmony_ci					  struct ieee80211_tx_rate *rate,
59462306a36Sopenharmony_ci					  struct rate_info *ri,
59562306a36Sopenharmony_ci					  u8 band, int len)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	struct ieee80211_rx_status stat;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	if (ieee80211_fill_rx_status(&stat, hw, rate, ri, band, len))
60062306a36Sopenharmony_ci		return 0;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	return ieee80211_calc_rx_airtime(hw, &stat, len);
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ciu32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
60662306a36Sopenharmony_ci			      struct ieee80211_tx_info *info,
60762306a36Sopenharmony_ci			      int len)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	u32 duration = 0;
61062306a36Sopenharmony_ci	int i;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
61362306a36Sopenharmony_ci		struct ieee80211_tx_rate *rate = &info->status.rates[i];
61462306a36Sopenharmony_ci		u32 cur_duration;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate, NULL,
61762306a36Sopenharmony_ci							      info->band, len);
61862306a36Sopenharmony_ci		if (!cur_duration)
61962306a36Sopenharmony_ci			break;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		duration += cur_duration * rate->count;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	return duration;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_calc_tx_airtime);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ciu32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
62962306a36Sopenharmony_ci				       struct ieee80211_vif *vif,
63062306a36Sopenharmony_ci				       struct ieee80211_sta *pubsta,
63162306a36Sopenharmony_ci				       int len, bool ampdu)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
63462306a36Sopenharmony_ci	struct ieee80211_chanctx_conf *conf;
63562306a36Sopenharmony_ci	int rateidx, shift = 0;
63662306a36Sopenharmony_ci	bool cck, short_pream;
63762306a36Sopenharmony_ci	u32 basic_rates;
63862306a36Sopenharmony_ci	u8 band = 0;
63962306a36Sopenharmony_ci	u16 rate;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	len += 38; /* Ethernet header length */
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	conf = rcu_dereference(vif->bss_conf.chanctx_conf);
64462306a36Sopenharmony_ci	if (conf) {
64562306a36Sopenharmony_ci		band = conf->def.chan->band;
64662306a36Sopenharmony_ci		shift = ieee80211_chandef_get_shift(&conf->def);
64762306a36Sopenharmony_ci	}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (pubsta) {
65062306a36Sopenharmony_ci		struct sta_info *sta = container_of(pubsta, struct sta_info,
65162306a36Sopenharmony_ci						    sta);
65262306a36Sopenharmony_ci		struct ieee80211_rx_status stat;
65362306a36Sopenharmony_ci		struct ieee80211_tx_rate *tx_rate = &sta->deflink.tx_stats.last_rate;
65462306a36Sopenharmony_ci		struct rate_info *ri = &sta->deflink.tx_stats.last_rate_info;
65562306a36Sopenharmony_ci		u32 duration, overhead;
65662306a36Sopenharmony_ci		u8 agg_shift;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci		if (ieee80211_fill_rx_status(&stat, hw, tx_rate, ri, band, len))
65962306a36Sopenharmony_ci			return 0;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci		if (stat.encoding == RX_ENC_LEGACY || !ampdu)
66262306a36Sopenharmony_ci			return ieee80211_calc_rx_airtime(hw, &stat, len);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		duration = ieee80211_get_rate_duration(hw, &stat, &overhead);
66562306a36Sopenharmony_ci		/*
66662306a36Sopenharmony_ci		 * Assume that HT/VHT transmission on any AC except VO will
66762306a36Sopenharmony_ci		 * use aggregation. Since we don't have reliable reporting
66862306a36Sopenharmony_ci		 * of aggregation length, assume an average size based on the
66962306a36Sopenharmony_ci		 * tx rate.
67062306a36Sopenharmony_ci		 * This will not be very accurate, but much better than simply
67162306a36Sopenharmony_ci		 * assuming un-aggregated tx in all cases.
67262306a36Sopenharmony_ci		 */
67362306a36Sopenharmony_ci		if (duration > 400 * 1024) /* <= VHT20 MCS2 1S */
67462306a36Sopenharmony_ci			agg_shift = 1;
67562306a36Sopenharmony_ci		else if (duration > 250 * 1024) /* <= VHT20 MCS3 1S or MCS1 2S */
67662306a36Sopenharmony_ci			agg_shift = 2;
67762306a36Sopenharmony_ci		else if (duration > 150 * 1024) /* <= VHT20 MCS5 1S or MCS2 2S */
67862306a36Sopenharmony_ci			agg_shift = 3;
67962306a36Sopenharmony_ci		else if (duration > 70 * 1024) /* <= VHT20 MCS5 2S */
68062306a36Sopenharmony_ci			agg_shift = 4;
68162306a36Sopenharmony_ci		else if (stat.encoding != RX_ENC_HE ||
68262306a36Sopenharmony_ci			 duration > 20 * 1024) /* <= HE40 MCS6 2S */
68362306a36Sopenharmony_ci			agg_shift = 5;
68462306a36Sopenharmony_ci		else
68562306a36Sopenharmony_ci			agg_shift = 6;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci		duration *= len;
68862306a36Sopenharmony_ci		duration /= AVG_PKT_SIZE;
68962306a36Sopenharmony_ci		duration /= 1024;
69062306a36Sopenharmony_ci		duration += (overhead >> agg_shift);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		return max_t(u32, duration, 4);
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	if (!conf)
69662306a36Sopenharmony_ci		return 0;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	/* No station to get latest rate from, so calculate the worst-case
69962306a36Sopenharmony_ci	 * duration using the lowest configured basic rate.
70062306a36Sopenharmony_ci	 */
70162306a36Sopenharmony_ci	sband = hw->wiphy->bands[band];
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	basic_rates = vif->bss_conf.basic_rates;
70462306a36Sopenharmony_ci	short_pream = vif->bss_conf.use_short_preamble;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	rateidx = basic_rates ? ffs(basic_rates) - 1 : 0;
70762306a36Sopenharmony_ci	rate = sband->bitrates[rateidx].bitrate << shift;
70862306a36Sopenharmony_ci	cck = sband->bitrates[rateidx].flags & IEEE80211_RATE_MANDATORY_B;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	return ieee80211_calc_legacy_rate_duration(rate, short_pream, cck, len);
71162306a36Sopenharmony_ci}
712