forked from Minki/linux
nl80211/cfg80211: add VHT MCS support
Add support for reporting and calculating VHT MCSes. Note that I'm not completely sure that the bitrate calculations are correct, nor that they can't be simplified. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
4bf88530be
commit
db9c64cf8d
@ -662,16 +662,24 @@ enum station_info_flags {
|
||||
* Used by the driver to indicate the specific rate transmission
|
||||
* type for 802.11n transmissions.
|
||||
*
|
||||
* @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
|
||||
* @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
|
||||
* @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS
|
||||
* @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
|
||||
* @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 MHz width transmission
|
||||
* @RATE_INFO_FLAGS_80_MHZ_WIDTH: 80 MHz width transmission
|
||||
* @RATE_INFO_FLAGS_80P80_MHZ_WIDTH: 80+80 MHz width transmission
|
||||
* @RATE_INFO_FLAGS_160_MHZ_WIDTH: 160 MHz width transmission
|
||||
* @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
|
||||
* @RATE_INFO_FLAGS_60G: 60gHz MCS
|
||||
* @RATE_INFO_FLAGS_60G: 60GHz MCS
|
||||
*/
|
||||
enum rate_info_flags {
|
||||
RATE_INFO_FLAGS_MCS = 1<<0,
|
||||
RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1,
|
||||
RATE_INFO_FLAGS_SHORT_GI = 1<<2,
|
||||
RATE_INFO_FLAGS_60G = 1<<3,
|
||||
RATE_INFO_FLAGS_MCS = BIT(0),
|
||||
RATE_INFO_FLAGS_VHT_MCS = BIT(1),
|
||||
RATE_INFO_FLAGS_40_MHZ_WIDTH = BIT(2),
|
||||
RATE_INFO_FLAGS_80_MHZ_WIDTH = BIT(3),
|
||||
RATE_INFO_FLAGS_80P80_MHZ_WIDTH = BIT(4),
|
||||
RATE_INFO_FLAGS_160_MHZ_WIDTH = BIT(5),
|
||||
RATE_INFO_FLAGS_SHORT_GI = BIT(6),
|
||||
RATE_INFO_FLAGS_60G = BIT(7),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -682,11 +690,13 @@ enum rate_info_flags {
|
||||
* @flags: bitflag of flags from &enum rate_info_flags
|
||||
* @mcs: mcs index if struct describes a 802.11n bitrate
|
||||
* @legacy: bitrate in 100kbit/s for 802.11abg
|
||||
* @nss: number of streams (VHT only)
|
||||
*/
|
||||
struct rate_info {
|
||||
u8 flags;
|
||||
u8 mcs;
|
||||
u16 legacy;
|
||||
u8 nss;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1734,10 +1734,15 @@ struct nl80211_sta_flag_update {
|
||||
* @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
|
||||
* @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
|
||||
* @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
|
||||
* @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
|
||||
* @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate
|
||||
* @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
|
||||
* @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s)
|
||||
* @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
|
||||
* @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
|
||||
* @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
|
||||
* @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
|
||||
* @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
|
||||
* @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
|
||||
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
|
||||
*/
|
||||
enum nl80211_rate_info {
|
||||
@ -1747,6 +1752,11 @@ enum nl80211_rate_info {
|
||||
NL80211_RATE_INFO_40_MHZ_WIDTH,
|
||||
NL80211_RATE_INFO_SHORT_GI,
|
||||
NL80211_RATE_INFO_BITRATE32,
|
||||
NL80211_RATE_INFO_VHT_MCS,
|
||||
NL80211_RATE_INFO_VHT_NSS,
|
||||
NL80211_RATE_INFO_80_MHZ_WIDTH,
|
||||
NL80211_RATE_INFO_80P80_MHZ_WIDTH,
|
||||
NL80211_RATE_INFO_160_MHZ_WIDTH,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_RATE_INFO_AFTER_LAST,
|
||||
|
@ -2890,29 +2890,52 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||
|
||||
rate = nla_nest_start(msg, attr);
|
||||
if (!rate)
|
||||
goto nla_put_failure;
|
||||
return false;
|
||||
|
||||
/* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
|
||||
bitrate = cfg80211_calculate_bitrate(info);
|
||||
/* report 16-bit bitrate only if we can */
|
||||
bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
|
||||
if ((bitrate > 0 &&
|
||||
nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) ||
|
||||
(bitrate_compat > 0 &&
|
||||
nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) ||
|
||||
((info->flags & RATE_INFO_FLAGS_MCS) &&
|
||||
nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) ||
|
||||
((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) &&
|
||||
nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) ||
|
||||
((info->flags & RATE_INFO_FLAGS_SHORT_GI) &&
|
||||
nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)))
|
||||
goto nla_put_failure;
|
||||
if (bitrate > 0 &&
|
||||
nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
|
||||
return false;
|
||||
if (bitrate_compat > 0 &&
|
||||
nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
|
||||
return false;
|
||||
|
||||
if (info->flags & RATE_INFO_FLAGS_MCS) {
|
||||
if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
|
||||
return false;
|
||||
if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
|
||||
nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
|
||||
return false;
|
||||
if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
|
||||
nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
|
||||
return false;
|
||||
} else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
|
||||
if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
|
||||
return false;
|
||||
if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
|
||||
return false;
|
||||
if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
|
||||
nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
|
||||
return false;
|
||||
if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH &&
|
||||
nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH))
|
||||
return false;
|
||||
if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH &&
|
||||
nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH))
|
||||
return false;
|
||||
if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH &&
|
||||
nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH))
|
||||
return false;
|
||||
if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
|
||||
nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
|
||||
return false;
|
||||
}
|
||||
|
||||
nla_nest_end(msg, rate);
|
||||
return true;
|
||||
|
||||
nla_put_failure:
|
||||
return false;
|
||||
}
|
||||
|
||||
static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
@ -5475,6 +5498,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
|
||||
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef))
|
||||
return -EINVAL;
|
||||
|
||||
if (ibss.chandef.width > NL80211_CHAN_WIDTH_40)
|
||||
return -EINVAL;
|
||||
if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
|
||||
|
||||
ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
|
||||
ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
|
||||
|
||||
|
@ -944,14 +944,86 @@ static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate)
|
||||
return __mcs2bitrate[rate->mcs];
|
||||
}
|
||||
|
||||
static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
|
||||
{
|
||||
static const u32 base[4][10] = {
|
||||
{ 6500000,
|
||||
13000000,
|
||||
19500000,
|
||||
26000000,
|
||||
39000000,
|
||||
52000000,
|
||||
58500000,
|
||||
65000000,
|
||||
78000000,
|
||||
0,
|
||||
},
|
||||
{ 13500000,
|
||||
27000000,
|
||||
40500000,
|
||||
54000000,
|
||||
81000000,
|
||||
108000000,
|
||||
121500000,
|
||||
135000000,
|
||||
162000000,
|
||||
180000000,
|
||||
},
|
||||
{ 29300000,
|
||||
58500000,
|
||||
87800000,
|
||||
117000000,
|
||||
175500000,
|
||||
234000000,
|
||||
263300000,
|
||||
292500000,
|
||||
351000000,
|
||||
390000000,
|
||||
},
|
||||
{ 58500000,
|
||||
117000000,
|
||||
175500000,
|
||||
234000000,
|
||||
351000000,
|
||||
468000000,
|
||||
526500000,
|
||||
585000000,
|
||||
702000000,
|
||||
780000000,
|
||||
},
|
||||
};
|
||||
u32 bitrate;
|
||||
int idx;
|
||||
|
||||
if (WARN_ON_ONCE(rate->mcs > 9))
|
||||
return 0;
|
||||
|
||||
idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH |
|
||||
RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 :
|
||||
rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 :
|
||||
rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0;
|
||||
|
||||
bitrate = base[idx][rate->mcs];
|
||||
bitrate *= rate->nss;
|
||||
|
||||
if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
|
||||
bitrate = (bitrate / 9) * 10;
|
||||
|
||||
/* do NOT round down here */
|
||||
return (bitrate + 50000) / 100000;
|
||||
}
|
||||
|
||||
u32 cfg80211_calculate_bitrate(struct rate_info *rate)
|
||||
{
|
||||
int modulation, streams, bitrate;
|
||||
|
||||
if (!(rate->flags & RATE_INFO_FLAGS_MCS))
|
||||
if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
|
||||
!(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
|
||||
return rate->legacy;
|
||||
if (rate->flags & RATE_INFO_FLAGS_60G)
|
||||
return cfg80211_calculate_bitrate_60g(rate);
|
||||
if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
|
||||
return cfg80211_calculate_bitrate_vht(rate);
|
||||
|
||||
/* the formula below does only work for MCS values smaller than 32 */
|
||||
if (WARN_ON_ONCE(rate->mcs >= 32))
|
||||
|
Loading…
Reference in New Issue
Block a user