2017-02-14 13:22:13

by Johannes Berg

[permalink] [raw]
Subject: VHT extended NSS BW support framework

Hi,

New version - now with more parsing, and a new function to get
the NSS value for a given bandwidth/MCS combination.

It'd be good if somebody were to review this carefully, this is
a rather complex thing...

johannes


2017-02-14 13:22:14

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 4/7] mac80211: remove local pointer from rate_ctrl_ref

From: Johannes Berg <[email protected]>

This pointer really isn't needed, so remove it.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/rate.c | 10 +++++-----
net/mac80211/rate.h | 1 -
2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 206698bc93f4..094c15645228 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -208,7 +208,6 @@ static struct rate_control_ref *rate_control_alloc(const char *name,
ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
if (!ref)
return NULL;
- ref->local = local;
ref->ops = ieee80211_rate_control_ops_get(name);
if (!ref->ops)
goto free;
@@ -229,13 +228,14 @@ static struct rate_control_ref *rate_control_alloc(const char *name,
return NULL;
}

-static void rate_control_free(struct rate_control_ref *ctrl_ref)
+static void rate_control_free(struct ieee80211_local *local,
+ struct rate_control_ref *ctrl_ref)
{
ctrl_ref->ops->free(ctrl_ref->priv);

#ifdef CONFIG_MAC80211_DEBUGFS
- debugfs_remove_recursive(ctrl_ref->local->debugfs.rcdir);
- ctrl_ref->local->debugfs.rcdir = NULL;
+ debugfs_remove_recursive(local->debugfs.rcdir);
+ local->debugfs.rcdir = NULL;
#endif

kfree(ctrl_ref);
@@ -936,6 +936,6 @@ void rate_control_deinitialize(struct ieee80211_local *local)
return;

local->rate_ctrl = NULL;
- rate_control_free(ref);
+ rate_control_free(local, ref);
}

diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 8d3260785b94..d51a1cce4d4a 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -20,7 +20,6 @@
#include "driver-ops.h"

struct rate_control_ref {
- struct ieee80211_local *local;
const struct rate_control_ops *ops;
void *priv;
};
--
2.9.3

2017-02-15 09:36:55

by Arend Van Spriel

[permalink] [raw]
Subject: Re: [RFC v2 3/7] ieee80211: add new VHT capability fields/parsing



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

2017-02-15 10:34:13

by Arend Van Spriel

[permalink] [raw]
Subject: Re: [RFC v2 3/7] ieee80211: add new VHT capability fields/parsing

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
>

2017-02-14 13:22:15

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 6/7] mac80211: add ability to parse CCFS2

From: Johannes Berg <[email protected]>

With newer VHT implementations, it's necessary to look at the
HT operation's CCFS2 field to identify the actual bandwidth
used.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ibss.c | 4 +++-
net/mac80211/ieee80211_i.h | 4 +++-
net/mac80211/mesh.c | 4 +++-
net/mac80211/mlme.c | 3 ++-
net/mac80211/spectmgmt.c | 5 ++++-
net/mac80211/util.c | 48 ++++++++++++++++++++++++++++++----------------
6 files changed, 47 insertions(+), 21 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 98999d3d5262..a5c0c5818da5 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1065,7 +1065,9 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
struct ieee80211_vht_cap cap_ie;
struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;

- ieee80211_chandef_vht_oper(elems->vht_operation,
+ ieee80211_chandef_vht_oper(&local->hw,
+ elems->vht_operation,
+ elems->ht_operation,
&chandef);
memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 159a1a733725..b5f8bd9dfd8e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2071,7 +2071,9 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
/* channel management */
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
struct cfg80211_chan_def *chandef);
-bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
+bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
+ const struct ieee80211_vht_operation *oper,
+ const struct ieee80211_ht_operation *htop,
struct cfg80211_chan_def *chandef);
u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index c28b0af9c1f2..1b60b4350517 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -92,7 +92,9 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan,
NL80211_CHAN_NO_HT);
ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def);
- ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def);
+ ieee80211_chandef_vht_oper(&sdata->local->hw,
+ ie->vht_operation, ie->ht_operation,
+ &sta_chan_def);

if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
&sta_chan_def))
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6e90301154d5..4d20e574a906 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -213,7 +213,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
}

vht_chandef = *chandef;
- if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
+ if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
+ vht_oper, ht_oper, &vht_chandef)) {
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
sdata_info(sdata,
"AP VHT information is invalid, disable VHT\n");
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 0782e486fe89..5a013b53b4f0 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -138,6 +138,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
wide_bw_chansw_ie->new_center_freq_seg1,
/* .basic_mcs_set doesn't matter */
};
+ struct ieee80211_ht_operation ht_oper = {};

/* default, for the case of IEEE80211_VHT_CHANWIDTH_USE_HT,
* to the previously parsed chandef
@@ -145,7 +146,9 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
new_vht_chandef = csa_ie->chandef;

/* ignore if parsing fails */
- if (!ieee80211_chandef_vht_oper(&vht_oper, &new_vht_chandef))
+ if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
+ &vht_oper, &ht_oper,
+ &new_vht_chandef))
new_vht_chandef.chan = NULL;

if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ &&
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7a37ce78bb38..152aae54b67f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2482,49 +2482,65 @@ bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
return true;
}

-bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
+bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
+ const struct ieee80211_vht_operation *oper,
+ const struct ieee80211_ht_operation *htop,
struct cfg80211_chan_def *chandef)
{
struct cfg80211_chan_def new = *chandef;
- int cf1, cf2;
+ int cf0, cf1;
+ int ccfs0, ccfs1, ccfs2;
+ int ccf0, ccf1;

- if (!oper)
+ if (!oper || !htop)
return false;

- cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg0_idx,
- chandef->chan->band);
- cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
- chandef->chan->band);
+ ccfs0 = oper->center_freq_seg0_idx;
+ ccfs1 = oper->center_freq_seg1_idx;
+ ccfs2 = (le16_to_cpu(htop->operation_mode) &
+ IEEE80211_HT_OP_MODE_CCFS2_MASK)
+ >> IEEE80211_HT_OP_MODE_CCFS2_SHIFT;
+
+ /* when parsing (and we know how to) CCFS1 and CCFS2 are equivalent */
+ ccf0 = ccfs0;
+ ccf1 = ccfs1;
+ if (!ccfs1 && ieee80211_hw_check(hw, SUPPORTS_VHT_EXT_NSS_BW))
+ ccf1 = ccfs2;
+
+ cf0 = ieee80211_channel_to_frequency(ccf0, chandef->chan->band);
+ cf1 = ieee80211_channel_to_frequency(ccf1, chandef->chan->band);

switch (oper->chan_width) {
case IEEE80211_VHT_CHANWIDTH_USE_HT:
+ /* just use HT information directly */
break;
case IEEE80211_VHT_CHANWIDTH_80MHZ:
new.width = NL80211_CHAN_WIDTH_80;
- new.center_freq1 = cf1;
+ new.center_freq1 = cf0;
/* If needed, adjust based on the newer interop workaround. */
- if (oper->center_freq_seg1_idx) {
+ if (ccf1) {
unsigned int diff;

- diff = abs(oper->center_freq_seg1_idx -
- oper->center_freq_seg0_idx);
+ diff = abs(ccf1 - ccf0);
if (diff == 8) {
new.width = NL80211_CHAN_WIDTH_160;
- new.center_freq1 = cf2;
+ new.center_freq1 = cf1;
} else if (diff > 8) {
new.width = NL80211_CHAN_WIDTH_80P80;
- new.center_freq2 = cf2;
+ new.center_freq2 = cf1;
}
}
break;
case IEEE80211_VHT_CHANWIDTH_160MHZ:
+ /* deprecated encoding */
new.width = NL80211_CHAN_WIDTH_160;
- new.center_freq1 = cf1;
+ new.center_freq1 = cf0;
break;
case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+ /* deprecated encoding */
new.width = NL80211_CHAN_WIDTH_80P80;
- new.center_freq1 = cf1;
- new.center_freq2 = cf2;
+ new.center_freq1 = cf0;
+ new.center_freq2 = cf1;
break;
default:
return false;
--
2.9.3

2017-02-14 13:22:13

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 3/7] ieee80211: add new VHT capability fields/parsing

From: Johannes Berg <[email protected]>

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 <[email protected]>
---
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;
+ }
+
+ /* not covered or invalid combination received */
+ return max_vht_nss;
+}

/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
--
2.9.3

2017-02-14 13:22:14

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 5/7] mac80211: introduce capability flags for VHT EXT NSS support

From: Johannes Berg <[email protected]>

Depending on whether or not rate control supports selecting
rates depending on the bandwidth, we can use VHT extended
NSS support. In essence, this is dot11VHTExtendedNSSBWCapable
from the spec, since depending on that we'll need to parse
the bandwidth.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/mac80211.h | 18 ++++++++++++++++++
net/mac80211/debugfs.c | 1 +
net/mac80211/main.c | 6 ++++++
3 files changed, 25 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index b9a08cd1d97d..68f90180a470 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2043,6 +2043,11 @@ struct ieee80211_txq {
* The stack will not do fragmentation.
* The callback for @set_frag_threshold should be set as well.
*
+ * @IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW: (Hardware) rate control supports VHT
+ * extended NSS BW (dot11VHTExtendedNSSBWCapable). This flag will be set if
+ * the selected rate control algorithm sets %RATE_CTRL_CAPA_VHT_EXT_NSS_BW
+ * but if the rate control is built-in then it must be set by the driver.
+ *
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
@@ -2085,6 +2090,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_TX_FRAG_LIST,
IEEE80211_HW_REPORTS_LOW_ACK,
IEEE80211_HW_SUPPORTS_TX_FRAG,
+ IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW,

/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS
@@ -5458,7 +5464,19 @@ struct ieee80211_tx_rate_control {
bool bss;
};

+/**
+ * enum rate_control_capabilities - rate control capabilities
+ */
+enum rate_control_capabilities {
+ /**
+ * @RATE_CTRL_CAPA_VHT_EXT_NSS_BW:
+ * support for extended NSS BW support (dot11VHTExtendedNSSCapable)
+ */
+ RATE_CTRL_CAPA_VHT_EXT_NSS_BW = BIT(0),
+};
+
struct rate_control_ops {
+ unsigned long capa;
const char *name;
void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir);
void (*free)(void *priv);
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 5fae001f286c..a431514ea01c 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -211,6 +211,7 @@ static const char *hw_flag_names[] = {
FLAG(TX_FRAG_LIST),
FLAG(REPORTS_LOW_ACK),
FLAG(SUPPORTS_TX_FRAG),
+ FLAG(SUPPORTS_VHT_EXT_NSS_BW),
#undef FLAG
};

diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 56fb47953b72..91e2faf174dd 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1095,6 +1095,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
goto fail_rate;
}

+ if (local->rate_ctrl) {
+ clear_bit(IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW, hw->flags);
+ if (local->rate_ctrl->ops->capa & RATE_CTRL_CAPA_VHT_EXT_NSS_BW)
+ ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
+ }
+
/* add one default STA interface if supported */
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) &&
!ieee80211_hw_check(hw, NO_AUTO_VIF)) {
--
2.9.3

2017-02-15 10:41:46

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 3/7] ieee80211: add new VHT capability fields/parsing

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

2017-02-15 10:35:00

by Arend Van Spriel

[permalink] [raw]
Subject: Re: [RFC v2 3/7] ieee80211: add new VHT capability fields/parsing

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

2017-02-15 09:08:12

by Arend Van Spriel

[permalink] [raw]
Subject: Re: [RFC v2 3/7] ieee80211: add new VHT capability fields/parsing

On 14-2-2017 14:22, Johannes Berg wrote:
> From: Johannes Berg <[email protected]>
>
> 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 <[email protected]>
> ---
> 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
>

2017-02-14 13:22:13

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 2/7] ieee80211: define HT operation CCFS2 field

From: Johannes Berg <[email protected]>

The Channel Center Frequency Segment 2 field is used in
802.11-2016 for encoding the actual channel position of
the 80+80/160 MHz channel, if the max NSS is restricted.
This is used for backwards compatibility.

Signed-off-by: Johannes Berg <[email protected]>
---
include/linux/ieee80211.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 4a15e77d9d66..4a7200c6c9ea 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1411,6 +1411,8 @@ struct ieee80211_ht_operation {
#define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED 3
#define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT 0x0004
#define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT 0x0010
+#define IEEE80211_HT_OP_MODE_CCFS2_SHIFT 5
+#define IEEE80211_HT_OP_MODE_CCFS2_MASK 0x1fe0

/* for stbc_param */
#define IEEE80211_HT_STBC_PARAM_DUAL_BEACON 0x0040
--
2.9.3

2017-02-14 13:22:15

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 7/7] mac80211: copy VHT EXT NSS BW Support/Capable data to station

From: Johannes Berg <[email protected]>

When taking VHT capabilities for a station, copy the new
fields if we support them as a transmitted.

Also, since it was missing, copy tx_highest and rx_highest.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/vht.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index 19ec2189d3ac..c75d37f9bff0 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -197,6 +197,20 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
break;
}

+ /* keep these, no need to limit to our own */
+ vht_cap->vht_mcs.tx_highest = vht_cap_ie->supp_mcs.tx_highest;
+ vht_cap->vht_mcs.rx_highest = vht_cap_ie->supp_mcs.rx_highest;
+
+ /*
+ * copy these only if rate control supports it, since otherwise some
+ * helper functions might return data that's not valid
+ */
+ if (ieee80211_hw_check(&sdata->local->hw, SUPPORTS_VHT_EXT_NSS_BW))
+ vht_cap->cap |= (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK);
+ else
+ vht_cap->vht_mcs.tx_highest &=
+ ~cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
+
/* symmetric capabilities */
vht_cap->cap |= cap_info & own_cap.cap &
(IEEE80211_VHT_CAP_SHORT_GI_80 |
--
2.9.3

2017-02-15 10:54:47

by Arend Van Spriel

[permalink] [raw]
Subject: Re: [RFC v2 3/7] ieee80211: add new VHT capability fields/parsing

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

2017-02-15 09:48:36

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 3/7] ieee80211: add new VHT capability fields/parsing

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

2017-02-14 13:22:13

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 1/7] ieee80211: rename CCFS1/CCFS2 to CCFS0/CCFS1

From: Johannes Berg <[email protected]>

This matches the spec, and otherwise things are really
confusing with the next patch adding CCFS2.

Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/tdls.c | 2 +-
include/linux/ieee80211.h | 4 ++--
net/mac80211/spectmgmt.c | 4 ++--
net/mac80211/util.c | 22 +++++++++++-----------
4 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c
index df9704de0715..5fc8319ed302 100644
--- a/drivers/net/wireless/marvell/mwifiex/tdls.c
+++ b/drivers/net/wireless/marvell/mwifiex/tdls.c
@@ -349,7 +349,7 @@ static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,
chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT;
break;
}
- vht_oper->center_freq_seg1_idx =
+ vht_oper->center_freq_seg0_idx =
mwifiex_get_center_freq_index(priv, BAND_AAC,
bss_desc->channel,
chan_bw);
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 0dd9498c694f..4a15e77d9d66 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1525,14 +1525,14 @@ enum ieee80211_vht_chanwidth {
* This structure is the "VHT operation element" as
* described in 802.11ac D3.0 8.4.2.161
* @chan_width: Operating channel width
+ * @center_freq_seg0_idx: center freq segment 0 index
* @center_freq_seg1_idx: center freq segment 1 index
- * @center_freq_seg2_idx: center freq segment 2 index
* @basic_mcs_set: VHT Basic MCS rate set
*/
struct ieee80211_vht_operation {
u8 chan_width;
+ u8 center_freq_seg0_idx;
u8 center_freq_seg1_idx;
- u8 center_freq_seg2_idx;
__le16 basic_mcs_set;
} __packed;

diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 97f4c9d6b54c..0782e486fe89 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -132,9 +132,9 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_vht_operation vht_oper = {
.chan_width =
wide_bw_chansw_ie->new_channel_width,
- .center_freq_seg1_idx =
+ .center_freq_seg0_idx =
wide_bw_chansw_ie->new_center_freq_seg0,
- .center_freq_seg2_idx =
+ .center_freq_seg1_idx =
wide_bw_chansw_ie->new_center_freq_seg1,
/* .basic_mcs_set doesn't matter */
};
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ac59fbd280df..7a37ce78bb38 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2413,13 +2413,13 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(struct ieee80211_vht_operation);
vht_oper = (struct ieee80211_vht_operation *)pos;
- vht_oper->center_freq_seg1_idx = ieee80211_frequency_to_channel(
+ vht_oper->center_freq_seg0_idx = ieee80211_frequency_to_channel(
chandef->center_freq1);
if (chandef->center_freq2)
- vht_oper->center_freq_seg2_idx =
+ vht_oper->center_freq_seg1_idx =
ieee80211_frequency_to_channel(chandef->center_freq2);
else
- vht_oper->center_freq_seg2_idx = 0x00;
+ vht_oper->center_freq_seg1_idx = 0x00;

switch (chandef->width) {
case NL80211_CHAN_WIDTH_160:
@@ -2428,11 +2428,11 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
* workaround.
*/
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
- vht_oper->center_freq_seg2_idx = vht_oper->center_freq_seg1_idx;
+ vht_oper->center_freq_seg1_idx = vht_oper->center_freq_seg0_idx;
if (chandef->chan->center_freq < chandef->center_freq1)
- vht_oper->center_freq_seg1_idx -= 8;
+ vht_oper->center_freq_seg0_idx -= 8;
else
- vht_oper->center_freq_seg1_idx += 8;
+ vht_oper->center_freq_seg0_idx += 8;
break;
case NL80211_CHAN_WIDTH_80P80:
/*
@@ -2491,9 +2491,9 @@ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
if (!oper)
return false;

- cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
+ cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg0_idx,
chandef->chan->band);
- cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
+ cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
chandef->chan->band);

switch (oper->chan_width) {
@@ -2503,11 +2503,11 @@ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
new.width = NL80211_CHAN_WIDTH_80;
new.center_freq1 = cf1;
/* If needed, adjust based on the newer interop workaround. */
- if (oper->center_freq_seg2_idx) {
+ if (oper->center_freq_seg1_idx) {
unsigned int diff;

- diff = abs(oper->center_freq_seg2_idx -
- oper->center_freq_seg1_idx);
+ diff = abs(oper->center_freq_seg1_idx -
+ oper->center_freq_seg0_idx);
if (diff == 8) {
new.width = NL80211_CHAN_WIDTH_160;
new.center_freq1 = cf2;
--
2.9.3

2017-02-15 09:17:00

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 3/7] ieee80211: add new VHT capability fields/parsing

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