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:
Johannes Berg 2012-11-09 14:56:41 +01:00
parent 4bf88530be
commit db9c64cf8d
4 changed files with 144 additions and 24 deletions

View File

@ -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;
};
/**

View File

@ -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,

View File

@ -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];

View File

@ -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))