From: Arend van Spriel <arend.vanspriel@broadcom.com>
To: Luca Coelho <luca@coelho.fi>, johannes@sipsolutions.net
Cc: linux-wireless@vger.kernel.org,
Luca Coelho <luciano.coelho@intel.com>,
Liad Kaufman <liad.kaufman@intel.com>,
Johannes Berg <johannes.berg@intel.com>,
Ilan Peer <ilan.peer@intel.com>, Ido Yariv <idox.yariv@intel.com>
Subject: Re: [RFC 1/3] cfg80211: Add support for HE
Date: Mon, 21 May 2018 21:47:21 +0200 [thread overview]
Message-ID: <5B032249.2020900@broadcom.com> (raw)
In-Reply-To: <20180518140543.13620-2-luca@coelho.fi>
On 5/18/2018 4:05 PM, Luca Coelho wrote:
> From: Luca Coelho <luciano.coelho@intel.com>
>
> Add support for the HE in cfg80211 and also add userspace API to
> nl80211 to send rate information out, conforming with P802.11ax_D1.4.
A couple of things changed in D2.0 so does it make sense to introduce
stuff from older draft?
> Additionally, remove the IEEE80211_MAX_AMPDU_BUF definition from some
> realtek drivers in staging because they are now conflicting with the
> new definitions and are not used anyway.
>
> Signed-off-by: Liad Kaufman <liad.kaufman@intel.com>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> Signed-off-by: Ilan Peer <ilan.peer@intel.com>
> Signed-off-by: Ido Yariv <idox.yariv@intel.com>
> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
> ---
> drivers/staging/rtl8188eu/include/wifi.h | 1 -
> drivers/staging/rtl8712/wifi.h | 1 -
> drivers/staging/rtl8723bs/include/wifi.h | 1 -
> include/linux/ieee80211.h | 431 ++++++++++++++++++++++-
> include/net/cfg80211.h | 102 +++++-
> include/uapi/linux/nl80211.h | 87 ++++-
> net/wireless/core.c | 21 +-
> net/wireless/nl80211.c | 99 +++++-
> net/wireless/util.c | 82 +++++
> 9 files changed, 813 insertions(+), 12 deletions(-)
[snip]
> diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
> index 8fe7e4306816..7e1a650be329 100644
> --- a/include/linux/ieee80211.h
> +++ b/include/linux/ieee80211.h
[snip]
> +/**
> + * struct ieee80211_he_mcs_nss_supp - HE Tx/Rx HE MCS NSS Support Field
> + *
> + * This structure holds the data required for the Tx/Rx HE MCS NSS Support Field
> + * described in P802.11ax_D1.4 section 9.4.2.237.4
> + *
> + * @rx_msc_80: Rx MCS map 2 bits for each stream, total 8 streams, for channel
> + * widths less than 80MHz.
> + * @tx_msc_80: Tx MCS map 2 bits for each stream, total 8 streams, for channel
> + * widths less than 80MHz.
> + * @rx_msc_160: Rx MCS map 2 bits for each stream, total 8 streams, for channel
> + * width 160MHz.
> + * @tx_msc_160: Tx MCS map 2 bits for each stream, total 8 streams, for channel
> + * width 160MHz.
> + * @rx_msc_80p80: Rx MCS map 2 bits for each stream, total 8 streams, for
> + * channel width 80p80MHz.
> + * @tx_msc_80p80: Tx MCS map 2 bits for each stream, total 8 streams, for
> + * channel width 80p80MHz.
> + */
> +struct ieee80211_he_mcs_nss_supp {
> + __le16 rx_msc_80;
Should 'msc' in these fields be 'mcs'?
> + __le16 tx_msc_80;
> + __le16 rx_msc_160;
> + __le16 tx_msc_160;
> + __le16 rx_msc_80p80;
> + __le16 tx_msc_80p80;
> +} __packed;
> +
> +/**
> + * struct ieee80211_he_operation - HE capabilities element
> + *
> + * This structure is the "HE operation element" fields as
> + * described in P802.11ax_D1.4 section 9.4.2.238
> + */
> +struct ieee80211_he_operation {
> + __le32 he_oper_params;
> + __le16 he_mcs_nss_set;
> + /* Optional 0,1,3 or 4 bytes: depends on %he_oper_params */
> + u8 optional[0];
> +} __packed;
If I recall correctly the he operation element changed significantly in
later revisions of the spec. So do we want to introduce (stale) D1.4
stuff when currently at D2.3?
> +/**
> + * struct ieee80211_he_mu_edca_param_ac_rec - MU AC Parameter Record field
> + *
> + * This structure is the "MU AC Parameter Record" fields as
> + * described in P802.11ax_D1.4 section 9.4.2.240
> + */
[snip]
> @@ -1577,6 +1679,322 @@ struct ieee80211_vht_operation {
> #define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000
> #define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000
>
> +/* 802.11ax HE MAC capabilities */
> +#define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01
[snip]
> +
> +/* Link adaptation is split between byte #2 and byte #3. It should be set only
> + * if IEEE80211_HE_MAC_CAP0_HTC_HE in which case the following values apply:
> + * 0 = No feedback.
> + * 1 = reserved.
> + * 2 = Unsolicited feedback.
> + * 3 = both
> + */
> +#define IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION 0x80
This is confusing. I suspect 'byte #2' is HE_MAC_CAP1 and 'byte #3' is
HE_MAC_CAP2. Just refer to that instead of the byte-number reference.
> +#define IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION 0x01
> +#define IEEE80211_HE_MAC_CAP2_ALL_ACK 0x02
> +#define IEEE80211_HE_MAC_CAP2_UL_MU_RESP_SCHED 0x04
[snip]
> +/**
> + * struct ieee80211_sband_iftype_data
> + *
> + * This structure encapsulates sband data that is relevant for the interface
> + * types defined in %types
> + *
> + * @types: interface types (bits)
maybe better named @types_mask.
> + * @he_cap: holds the HE capabilities
> + */
> +struct ieee80211_sband_iftype_data {
> + u16 types;
> + struct ieee80211_sta_he_cap he_cap;
> +};
> +
> /**
> * struct ieee80211_supported_band - frequency band definition
> *
> @@ -301,6 +335,8 @@ struct ieee80211_sta_vht_cap {
> * @n_bitrates: Number of bitrates in @bitrates
> * @ht_cap: HT capabilities in this band
> * @vht_cap: VHT capabilities in this band
> + * @n_iftype_data: number of iftype data entries
> + * @iftype_data: interface type data entries
> */
> struct ieee80211_supported_band {
> struct ieee80211_channel *channels;
> @@ -310,8 +346,55 @@ struct ieee80211_supported_band {
> int n_bitrates;
> struct ieee80211_sta_ht_cap ht_cap;
> struct ieee80211_sta_vht_cap vht_cap;
> + u16 n_iftype_data;
> + const struct ieee80211_sband_iftype_data *iftype_data;
> };
>
> +/**
> + * ieee80211_get_sband_ift_data - return sband data for a given iftype
> + * @sband: the sband to search for the STA on
> + * @iftype: enum nl80211_iftype
> + *
> + * Return: pointer to the struct ieee80211_sband_iftype_data, or NULL is none found
> + */
> +static inline const struct ieee80211_sband_iftype_data *
> +ieee80211_get_sband_ift_data(const struct ieee80211_supported_band *sband,
Just call this function ieee80211_get_sband_iftype_data. It's only 3
additional chars.
> + u8 iftype)
> +{
> + int i;
> +
> + if (WARN_ON(iftype >= NL80211_IFTYPE_MAX))
> + return NULL;
> +
> + for (i = 0; i < sband->n_iftype_data; i++) {
> + const struct ieee80211_sband_iftype_data *data =
> + &sband->iftype_data[i];
> +
> + if (data->types & BIT(iftype))
> + return data;
> + }
> +
> + return NULL;
> +}
[snip]
> diff --git a/net/wireless/core.c b/net/wireless/core.c
> index a6f3cac8c640..848d16631643 100644
> --- a/net/wireless/core.c
> +++ b/net/wireless/core.c
[snip]
> @@ -781,6 +783,23 @@ int wiphy_register(struct wiphy *wiphy)
> sband->channels[i].band = band;
> }
>
> + for (i = 0; i < sband->n_iftype_data; i++) {
> + const struct ieee80211_sband_iftype_data *iftd;
> +
> + iftd = &sband->iftype_data[i];
> +
> + if (WARN_ON(!iftd->types))
> + return -EINVAL;
> + if (WARN_ON(types & iftd->types))
> + return -EINVAL;
I suspected the types mask was not allowed to overlap for the
iftype_data entries, but may be worth documenting that in struct
ieee80211_sband_iftype_data kerneldoc.
> + /* at least one piece of information must be present */
> + if (WARN_ON(!iftd->he_cap.has_he))
> + return -EINVAL;
> +
> + types |= iftd->types;
> + }
> +
> have_band = true;
> }
>
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
> index f7715b85fd2b..661728dbf989 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -428,6 +428,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
> [NL80211_ATTR_TXQ_LIMIT] = { .type = NLA_U32 },
> [NL80211_ATTR_TXQ_MEMORY_LIMIT] = { .type = NLA_U32 },
> [NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
> + [NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY,
> + .len = NL80211_HE_MAX_CAPABILITY_LEN },
> };
>
> /* policy for the key attributes */
> @@ -1324,6 +1326,34 @@ static int nl80211_send_coalesce(struct sk_buff *msg,
> return 0;
> }
>
> +static int
> +nl80211_send_ift_data(struct sk_buff *msg,
> + const struct ieee80211_sband_iftype_data *iftdata)
make it nl80211_send_iftype_data.
> +{
> + const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap;
> +
> + if (nl80211_put_iftypes(msg, NL80211_BAND_IFT_ATTR_IFTYPES,
> + iftdata->types))
> + return -ENOBUFS;
> +
> + if (he_cap->has_he) {
> + if (nla_put(msg, NL80211_BAND_IFT_ATTR_HE_CAP_MAC,
> + sizeof(he_cap->he_cap_elem.mac_cap_info),
> + he_cap->he_cap_elem.mac_cap_info) ||
> + nla_put(msg, NL80211_BAND_IFT_ATTR_HE_CAP_PHY,
> + sizeof(he_cap->he_cap_elem.phy_cap_info),
> + he_cap->he_cap_elem.phy_cap_info) ||
> + nla_put(msg, NL80211_BAND_IFT_ATTR_HE_CAP_MCS_SET,
> + sizeof(he_cap->he_mcs_nss_supp),
> + &he_cap->he_mcs_nss_supp) ||
> + nla_put(msg, NL80211_BAND_IFT_ATTR_HE_CAP_PPE,
> + sizeof(he_cap->ppe_thres), he_cap->ppe_thres))
> + return -ENOBUFS;
> + }
> +
> + return 0;
> +}
> +
> static int nl80211_send_band_rateinfo(struct sk_buff *msg,
> struct ieee80211_supported_band *sband)
> {
> @@ -1353,6 +1383,32 @@ static int nl80211_send_band_rateinfo(struct sk_buff *msg,
> sband->vht_cap.cap)))
> return -ENOBUFS;
>
> + if (sband->n_iftype_data) {
> + struct nlattr *nl_iftype_data =
> + nla_nest_start(msg, NL80211_BAND_ATTR_IFTYPE_DATA);
> + int err;
> +
> + if (!nl_iftype_data)
> + return -ENOBUFS;
> +
> + for (i = 0; i < sband->n_iftype_data; i++) {
> + struct nlattr *iftdata;
> +
> + iftdata = nla_nest_start(msg, i + 1);
> + if (!iftdata)
> + return -ENOBUFS;
bit inconsistent dealing with error path. Here errno is returned....
> + err = nl80211_send_ift_data(msg,
> + &sband->iftype_data[i]);
> + if (err)
> + return err;
> +
> + nla_nest_end(msg, iftdata);
> + }
> +
> + nla_nest_end(msg, nl_iftype_data);
> + }
> +
> /* add bitrates */
> nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
> if (!nl_rates)
> @@ -4471,6 +4527,9 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
> case RATE_INFO_BW_160:
> rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
> break;
> + case RATE_INFO_BW_HE_RU:
> + rate_flg = 0;
> + WARN_ON(!(info->flags & RATE_INFO_FLAGS_HE_MCS));
> }
>
> if (rate_flg && nla_put_flag(msg, rate_flg))
> @@ -4490,6 +4549,19 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
> 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_HE_MCS) {
> + if (nla_put_u8(msg, NL80211_RATE_INFO_HE_MCS, info->mcs))
> + return false;
... and here bool is returned. Admittedly, this seems to have been the
case already before this patch.
> + if (nla_put_u8(msg, NL80211_RATE_INFO_HE_NSS, info->nss))
> + return false;
> + if (nla_put_u8(msg, NL80211_RATE_INFO_HE_GI, info->he_gi))
> + return false;
> + if (nla_put_u8(msg, NL80211_RATE_INFO_HE_DCM, info->he_dcm))
> + return false;
> + if (info->bw == RATE_INFO_BW_HE_RU &&
> + nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC,
> + info->he_ru_alloc))
> + return false;
> }
>
> nla_nest_end(msg, rate);
[snip]
> diff --git a/net/wireless/util.c b/net/wireless/util.c
> index d112e9a89364..b66a68a41cd6 100644
> --- a/net/wireless/util.c
> +++ b/net/wireless/util.c
> @@ -4,6 +4,7 @@
> *
> * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
> * Copyright 2013-2014 Intel Mobile Communications GmbH
> + * Copyright 2017 Intel Deutschland GmbH
> */
> #include <linux/export.h>
> #include <linux/bitops.h>
> @@ -1142,6 +1143,85 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
> return 0;
> }
>
> +static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate)
> +{
> +#define SCALE 2048
> + u16 mcs_divisors[12] = {
> + 34133, /* 16.666666... */
> + 17067, /* 8.333333... */
> + 11378, /* 5.555555... */
> + 8533, /* 4.166666... */
> + 5689, /* 2.777777... */
> + 4267, /* 2.083333... */
> + 3923, /* 1.851851... */
> + 3413, /* 1.666666... */
> + 2844, /* 1.388888... */
> + 2560, /* 1.250000... */
> + 2276, /* 1.111111... */
> + 2048, /* 1.000000... */
> + };
> + u32 rates_160M[3] = { 960777777, 907400000, 816666666 };
> + u32 rates_969[3] = { 480388888, 453700000, 408333333 };
> + u32 rates_484[3] = { 229411111, 216666666, 195000000 };
> + u32 rates_242[3] = { 114711111, 108333333, 97500000 };
> + u32 rates_106[3] = { 40000000, 37777777, 34000000 };
> + u32 rates_52[3] = { 18820000, 17777777, 16000000 };
> + u32 rates_26[3] = { 9411111, 8888888, 8000000 };
> + u64 tmp;
> + u32 result;
> +
> + if (WARN_ON_ONCE(rate->mcs > 11))
> + return 0;
> +
> + if (WARN_ON_ONCE(rate->he_gi > NL80211_RATE_INFO_HE_GI_3_2))
> + return 0;
> + if (WARN_ON_ONCE(rate->he_ru_alloc >
> + NL80211_RATE_INFO_HE_RU_ALLOC_2x996))
> + return 0;
> + if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8))
> + return 0;
> +
> + if (rate->bw == RATE_INFO_BW_160)
> + result = rates_160M[rate->he_gi];
> + else if (rate->bw == RATE_INFO_BW_80 ||
> + (rate->bw == RATE_INFO_BW_HE_RU &&
> + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_996))
> + result = rates_969[rate->he_gi];
> + else if (rate->bw == RATE_INFO_BW_40 ||
> + (rate->bw == RATE_INFO_BW_HE_RU &&
> + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_484))
> + result = rates_484[rate->he_gi];
> + else if (rate->bw == RATE_INFO_BW_20 ||
> + (rate->bw == RATE_INFO_BW_HE_RU &&
> + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_242))
> + result = rates_242[rate->he_gi];
> + else if (rate->bw == RATE_INFO_BW_HE_RU &&
> + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_106)
> + result = rates_106[rate->he_gi];
> + else if (rate->bw == RATE_INFO_BW_HE_RU &&
> + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_52)
> + result = rates_52[rate->he_gi];
> + else if (rate->bw == RATE_INFO_BW_HE_RU &&
> + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_26)
> + result = rates_26[rate->he_gi];
> + else if (WARN(1, "invalid HE MCS: bw:%d, ru:%d\n",
> + rate->bw, rate->he_ru_alloc))
> + return 0;
> +
Could consider shifts below iso multiply/division.
> + /* now scale to the appropriate MCS */
> + tmp = result;
> + tmp *= SCALE;
tmp <<= 11;
> + do_div(tmp, mcs_divisors[rate->mcs]);
> + result = tmp;
> +
> + /* and take NSS, DCM into account */
> + result = (result * rate->nss) / 8;
result = (result * rate->nss) >> 3;
> + if (rate->he_dcm)
> + result /= 2;
result >>= 1;
> +
> + return result;
> +}
> +
> u32 cfg80211_calculate_bitrate(struct rate_info *rate)
> {
> if (rate->flags & RATE_INFO_FLAGS_MCS)
> @@ -1150,6 +1230,8 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)
> return cfg80211_calculate_bitrate_60g(rate);
> if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
> return cfg80211_calculate_bitrate_vht(rate);
> + if (rate->flags & RATE_INFO_FLAGS_HE_MCS)
> + return cfg80211_calculate_bitrate_he(rate);
>
> return rate->legacy;
> }
>
next prev parent reply other threads:[~2018-05-21 19:47 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-05-18 14:05 [RFC 0/3] cfg80211/mac80211: add support for IEEE802.11ax Luca Coelho
2018-05-18 14:05 ` [RFC 1/3] cfg80211: Add support for HE Luca Coelho
2018-05-21 19:47 ` Arend van Spriel [this message]
2018-05-25 10:11 ` Luca Coelho
2018-05-25 10:34 ` Arend van Spriel
2018-05-25 19:51 ` Luca Coelho
2018-05-28 9:05 ` Arend van Spriel
2018-05-18 14:05 ` [RFC 2/3] radiotap: add structs " Luca Coelho
2018-05-18 14:05 ` [RFC 3/3] mac80211: add support " Luca Coelho
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5B032249.2020900@broadcom.com \
--to=arend.vanspriel@broadcom.com \
--cc=idox.yariv@intel.com \
--cc=ilan.peer@intel.com \
--cc=johannes.berg@intel.com \
--cc=johannes@sipsolutions.net \
--cc=liad.kaufman@intel.com \
--cc=linux-wireless@vger.kernel.org \
--cc=luca@coelho.fi \
--cc=luciano.coelho@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.