Message ID | 20170214132208.8715-4-johannes@sipsolutions.net (mailing list archive) |
---|---|
State | RFC |
Headers | show |
On 14-2-2017 14:22, Johannes Berg wrote: > From: Johannes Berg <johannes.berg@intel.com> > > IEEE 802.11-2016 extended the VHT capability fields to allow > indicating the number of spatial streams depending on the > actually used bandwidth, add support for decoding this. > > Signed-off-by: Johannes Berg <johannes.berg@intel.com> > --- > include/linux/ieee80211.h | 105 +++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 103 insertions(+), 2 deletions(-) > > diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h > index 4a7200c6c9ea..c51d309a45e7 100644 > --- a/include/linux/ieee80211.h > +++ b/include/linux/ieee80211.h > @@ -1457,13 +1457,16 @@ struct ieee80211_ht_operation { > * STA can receive. Rate expressed in units of 1 Mbps. > * If this field is 0 this value should not be used to > * consider the highest RX data rate supported. > - * The top 3 bits of this field are reserved. > + * The top 3 bits of this field indicate the Maximum NSTS,total > + * (a beamformee capability.) > * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams > * @tx_highest: Indicates highest long GI VHT PPDU data rate > * STA can transmit. Rate expressed in units of 1 Mbps. > * If this field is 0 this value should not be used to > * consider the highest TX data rate supported. > - * The top 3 bits of this field are reserved. > + * The top 2 bits of this field are reserved, the > + * 3rd bit from the top indiciates VHT Extended NSS BW > + * Capability. > */ > struct ieee80211_vht_mcs_info { > __le16 rx_mcs_map; > @@ -1472,6 +1475,13 @@ struct ieee80211_vht_mcs_info { > __le16 tx_highest; > } __packed; > > +/* for rx_highest */ > +#define IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT 13 > +#define IEEE80211_VHT_MAX_NSTS_TOTAL_MASK (7 << IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT) > + > +/* for tx_highest */ > +#define IEEE80211_VHT_EXT_NSS_BW_CAPABLE (1 << 13) > + > /** > * enum ieee80211_vht_mcs_support - VHT MCS support definitions > * @IEEE80211_VHT_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the > @@ -1547,6 +1557,7 @@ struct ieee80211_vht_operation { > #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 > #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 > #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x0000000C > +#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT 2 > #define IEEE80211_VHT_CAP_RXLDPC 0x00000010 > #define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 > #define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 > @@ -1575,6 +1586,96 @@ struct ieee80211_vht_operation { > #define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000 > #define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000 > #define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000 > +#define IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT 30 > +#define IEEE80211_VHT_CAP_EXT_NSS_BW_MASK 0xc0000000 > + > +static int __maybe_unused > +ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, > + enum ieee80211_vht_chanwidth bw, > + int mcs) > +{ > + u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map); > + int max_vht_nss; > + int ext_nss_bw; > + int supp_width; > + int i, mcs_encoding; > + > + if (map == 0xffff) > + return 0; > + > + if (WARN_ON(mcs > 9)) > + return 0; > + if (mcs <= 7) > + mcs_encoding = 0; > + else if (mcs == 8) > + mcs_encoding = 1; > + else > + mcs_encoding = 2; > + > + /* find max_vht_nss for the given MCS */ > + for (i = 7; i >= 0; i--) { > + int supp = (map >> (2*i)) & 3; > + > + if (supp == 3) > + continue; > + > + if (supp >= mcs_encoding) { > + max_vht_nss = i; > + break; > + } > + } > + > + if (!(cap->supp_mcs.tx_mcs_map & cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) > + return max_vht_nss; > + > + ext_nss_bw = (le32_to_cpu(cap->vht_cap_info) & > + IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) > + >> IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT; > + supp_width = (le32_to_cpu(cap->vht_cap_info) & > + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) > + >> IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT; > + > + /* > + * Cover all the special cases according to IEEE 802.11-2016 Table 9-250. > + * All other cases are either factor of 1 or not valid/supported. > + */ > + switch (bw) { > + case IEEE80211_VHT_CHANWIDTH_USE_HT: > + case IEEE80211_VHT_CHANWIDTH_80MHZ: > + if ((supp_width == 1 || supp_width == 2) && > + ext_nss_bw == 3) > + return 2 * max_vht_nss; > + break; > + case IEEE80211_VHT_CHANWIDTH_160MHZ: > + if (supp_width == 0 && > + (ext_nss_bw == 1 || ext_nss_bw == 2)) > + return DIV_ROUND_UP(max_vht_nss, 2); > + if (supp_width == 0 && > + ext_nss_bw == 3) > + return DIV_ROUND_UP(3 * max_vht_nss, 4); > + if (supp_width == 1 && > + ext_nss_bw == 3) > + return 2 * max_vht_nss; > + break; > + case IEEE80211_VHT_CHANWIDTH_80P80MHZ: > + if (supp_width == 0 && > + ext_nss_bw == 2) > + return DIV_ROUND_UP(max_vht_nss, 2); > + if (supp_width == 0 && > + ext_nss_bw == 3) > + return DIV_ROUND_UP(3 * max_vht_nss, 4); > + if (supp_width == 1 && > + ext_nss_bw == 1) > + return DIV_ROUND_UP(max_vht_nss, 2); > + if (supp_width == 1 && > + ext_nss_bw == 2) > + return DIV_ROUND_UP(3 * max_vht_nss, 4); > + break; > + } Looks good to me. > + /* not covered or invalid combination received */ Do you want to inform about the invalid/reserved combination. Regards, Arend > + return max_vht_nss; > +} > > /* Authentication algorithms */ > #define WLAN_AUTH_OPEN 0 >
On Wed, 2017-02-15 at 10:08 +0100, Arend Van Spriel wrote: > [snip] > > Looks good to me. Thanks for checking :) > > + /* not covered or invalid combination received */ > > Do you want to inform about the invalid/reserved combination. I'm not really sure what to do - we don't really want to print a message on something that might have been received from the peer, I think? Though I suppose we should return 0 for the invalid combinations, indicating that they're not supported. johannes
On 15-2-2017 10:16, Johannes Berg wrote: > On Wed, 2017-02-15 at 10:08 +0100, Arend Van Spriel wrote: >> [snip] >> >> Looks good to me. > > Thanks for checking :) > >>> + /* not covered or invalid combination received */ >> >> Do you want to inform about the invalid/reserved combination. > > I'm not really sure what to do - we don't really want to print a > message on something that might have been received from the peer, I > think? Though I suppose we should return 0 for the invalid > combinations, indicating that they're not supported. Ah. This is all non-functional code yet, right? At least having a static non-inline function in ieee80211.h will give build issues I would think. Anyway, I would indeed return 0 and have caller deal with that. Regards, Arend
On Wed, 2017-02-15 at 10:36 +0100, Arend Van Spriel wrote: > > > I'm not really sure what to do - we don't really want to print a > > message on something that might have been received from the peer, I > > think? Though I suppose we should return 0 for the invalid > > combinations, indicating that they're not supported. > > Ah. This is all non-functional code yet, right? At least having a > static non-inline function in ieee80211.h will give build issues I > would think. No, I marked it __maybe_unused so it'll be fine. I didn't want to have it inlined if you use it multiple times in a single source file, but I didn't want to move it to somewhere else either ... > Anyway, I would indeed return 0 and have caller deal with that. Yeah, I'll do that. johannes
On 15-2-2017 10:48, Johannes Berg wrote: > On Wed, 2017-02-15 at 10:36 +0100, Arend Van Spriel wrote: >> >>> I'm not really sure what to do - we don't really want to print a >>> message on something that might have been received from the peer, I >>> think? Though I suppose we should return 0 for the invalid >>> combinations, indicating that they're not supported. >> >> Ah. This is all non-functional code yet, right? At least having a >> static non-inline function in ieee80211.h will give build issues I >> would think. > > No, I marked it __maybe_unused so it'll be fine. I didn't want to have > it inlined if you use it multiple times in a single source file, but I > didn't want to move it to somewhere else either ... Ah. Now I understand the trickery ;-) Was there really no "somewhere else" to move it, because honestly it is confusing and a bit wasteful if used multiple times in cfg80211 and/or drivers. Gr. AvS >> Anyway, I would indeed return 0 and have caller deal with that. > > Yeah, I'll do that. > > johannes >
On 15-2-2017 11:34, Arend Van Spriel wrote: > On 15-2-2017 10:48, Johannes Berg wrote: >> On Wed, 2017-02-15 at 10:36 +0100, Arend Van Spriel wrote: >>> >>>> I'm not really sure what to do - we don't really want to print a >>>> message on something that might have been received from the peer, I >>>> think? Though I suppose we should return 0 for the invalid >>>> combinations, indicating that they're not supported. >>> >>> Ah. This is all non-functional code yet, right? At least having a >>> static non-inline function in ieee80211.h will give build issues I >>> would think. >> >> No, I marked it __maybe_unused so it'll be fine. I didn't want to have >> it inlined if you use it multiple times in a single source file, but I >> didn't want to move it to somewhere else either ... > > Ah. Now I understand the trickery ;-) Was there really no "somewhere > else" to move it, because honestly it is confusing and a bit wasteful if > used multiple times in cfg80211 and/or drivers. Although exporting it also comes at a cost. Gr. AvS > Gr. AvS > >>> Anyway, I would indeed return 0 and have caller deal with that. >> >> Yeah, I'll do that. >> >> johannes >>
On Wed, 2017-02-15 at 11:34 +0100, Arend Van Spriel wrote: > On 15-2-2017 11:34, Arend Van Spriel wrote: > > On 15-2-2017 10:48, Johannes Berg wrote: > > > On Wed, 2017-02-15 at 10:36 +0100, Arend Van Spriel wrote: > > > > > > > > > I'm not really sure what to do - we don't really want to > > > > > print a > > > > > message on something that might have been received from the > > > > > peer, I > > > > > think? Though I suppose we should return 0 for the invalid > > > > > combinations, indicating that they're not supported. > > > > > > > > Ah. This is all non-functional code yet, right? At least having > > > > a > > > > static non-inline function in ieee80211.h will give build > > > > issues I > > > > would think. > > > > > > No, I marked it __maybe_unused so it'll be fine. I didn't want to > > > have > > > it inlined if you use it multiple times in a single source file, > > > but I > > > didn't want to move it to somewhere else either ... > > > > Ah. Now I understand the trickery ;-) Was there really no > > "somewhere > > else" to move it, because honestly it is confusing and a bit > > wasteful if > > used multiple times in cfg80211 and/or drivers. > > Although exporting it also comes at a cost. Yeah, we could put it into cfg80211 and export it. I haven't really looked how big it is, but it does seem big. The other thing is that the ieee80211.h file was pretty much standalone definitions of the spec until now - if we move it to cfg80211, should the function prototype really be declared in this file? johannes
On 15-2-2017 11:41, Johannes Berg wrote: > On Wed, 2017-02-15 at 11:34 +0100, Arend Van Spriel wrote: >> On 15-2-2017 11:34, Arend Van Spriel wrote: >>> On 15-2-2017 10:48, Johannes Berg wrote: >>>> On Wed, 2017-02-15 at 10:36 +0100, Arend Van Spriel wrote: >>>>> >>>>>> I'm not really sure what to do - we don't really want to >>>>>> print a >>>>>> message on something that might have been received from the >>>>>> peer, I >>>>>> think? Though I suppose we should return 0 for the invalid >>>>>> combinations, indicating that they're not supported. >>>>> >>>>> Ah. This is all non-functional code yet, right? At least having >>>>> a >>>>> static non-inline function in ieee80211.h will give build >>>>> issues I >>>>> would think. >>>> >>>> No, I marked it __maybe_unused so it'll be fine. I didn't want to >>>> have >>>> it inlined if you use it multiple times in a single source file, >>>> but I >>>> didn't want to move it to somewhere else either ... >>> >>> Ah. Now I understand the trickery ;-) Was there really no >>> "somewhere >>> else" to move it, because honestly it is confusing and a bit >>> wasteful if >>> used multiple times in cfg80211 and/or drivers. >> >> Although exporting it also comes at a cost. > > Yeah, we could put it into cfg80211 and export it. I haven't really > looked how big it is, but it does seem big. > > The other thing is that the ieee80211.h file was pretty much standalone > definitions of the spec until now - if we move it to cfg80211, should > the function prototype really be declared in this file? Well. You can look at it as being close to the spec (and it is), but if it is a function for cfg80211-based drivers it should go in include/net/cfg80211.h, right? Not sure though who will be using it apart from mac80211. So I guess we can do with the trickery. Maybe clearly mark it with a comment in ieee80211.h. Regards, Arend
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 4a7200c6c9ea..c51d309a45e7 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1457,13 +1457,16 @@ struct ieee80211_ht_operation { * STA can receive. Rate expressed in units of 1 Mbps. * If this field is 0 this value should not be used to * consider the highest RX data rate supported. - * The top 3 bits of this field are reserved. + * The top 3 bits of this field indicate the Maximum NSTS,total + * (a beamformee capability.) * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams * @tx_highest: Indicates highest long GI VHT PPDU data rate * STA can transmit. Rate expressed in units of 1 Mbps. * If this field is 0 this value should not be used to * consider the highest TX data rate supported. - * The top 3 bits of this field are reserved. + * The top 2 bits of this field are reserved, the + * 3rd bit from the top indiciates VHT Extended NSS BW + * Capability. */ struct ieee80211_vht_mcs_info { __le16 rx_mcs_map; @@ -1472,6 +1475,13 @@ struct ieee80211_vht_mcs_info { __le16 tx_highest; } __packed; +/* for rx_highest */ +#define IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT 13 +#define IEEE80211_VHT_MAX_NSTS_TOTAL_MASK (7 << IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT) + +/* for tx_highest */ +#define IEEE80211_VHT_EXT_NSS_BW_CAPABLE (1 << 13) + /** * enum ieee80211_vht_mcs_support - VHT MCS support definitions * @IEEE80211_VHT_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the @@ -1547,6 +1557,7 @@ struct ieee80211_vht_operation { #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x0000000C +#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT 2 #define IEEE80211_VHT_CAP_RXLDPC 0x00000010 #define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 #define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 @@ -1575,6 +1586,96 @@ struct ieee80211_vht_operation { #define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000 #define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000 #define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000 +#define IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT 30 +#define IEEE80211_VHT_CAP_EXT_NSS_BW_MASK 0xc0000000 + +static int __maybe_unused +ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, + enum ieee80211_vht_chanwidth bw, + int mcs) +{ + u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map); + int max_vht_nss; + int ext_nss_bw; + int supp_width; + int i, mcs_encoding; + + if (map == 0xffff) + return 0; + + if (WARN_ON(mcs > 9)) + return 0; + if (mcs <= 7) + mcs_encoding = 0; + else if (mcs == 8) + mcs_encoding = 1; + else + mcs_encoding = 2; + + /* find max_vht_nss for the given MCS */ + for (i = 7; i >= 0; i--) { + int supp = (map >> (2*i)) & 3; + + if (supp == 3) + continue; + + if (supp >= mcs_encoding) { + max_vht_nss = i; + break; + } + } + + if (!(cap->supp_mcs.tx_mcs_map & cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) + return max_vht_nss; + + ext_nss_bw = (le32_to_cpu(cap->vht_cap_info) & + IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) + >> IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT; + supp_width = (le32_to_cpu(cap->vht_cap_info) & + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) + >> IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT; + + /* + * Cover all the special cases according to IEEE 802.11-2016 Table 9-250. + * All other cases are either factor of 1 or not valid/supported. + */ + switch (bw) { + case IEEE80211_VHT_CHANWIDTH_USE_HT: + case IEEE80211_VHT_CHANWIDTH_80MHZ: + if ((supp_width == 1 || supp_width == 2) && + ext_nss_bw == 3) + return 2 * max_vht_nss; + break; + case IEEE80211_VHT_CHANWIDTH_160MHZ: + if (supp_width == 0 && + (ext_nss_bw == 1 || ext_nss_bw == 2)) + return DIV_ROUND_UP(max_vht_nss, 2); + if (supp_width == 0 && + ext_nss_bw == 3) + return DIV_ROUND_UP(3 * max_vht_nss, 4); + if (supp_width == 1 && + ext_nss_bw == 3) + return 2 * max_vht_nss; + break; + case IEEE80211_VHT_CHANWIDTH_80P80MHZ: + if (supp_width == 0 && + ext_nss_bw == 2) + return DIV_ROUND_UP(max_vht_nss, 2); + if (supp_width == 0 && + ext_nss_bw == 3) + return DIV_ROUND_UP(3 * max_vht_nss, 4); + if (supp_width == 1 && + ext_nss_bw == 1) + return DIV_ROUND_UP(max_vht_nss, 2); + if (supp_width == 1 && + ext_nss_bw == 2) + return DIV_ROUND_UP(3 * max_vht_nss, 4); + break; + } + + /* not covered or invalid combination received */ + return max_vht_nss; +} /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0