From: Denis Kenzior <denkenz@gmail.com>
To: James Prestwood <prestwoj@gmail.com>, iwd@lists.linux.dev
Subject: Re: [PATCH v2 1/2] band: add band_estimate_he_rx_rate
Date: Tue, 19 Jul 2022 21:36:27 -0500 [thread overview]
Message-ID: <2b2794fd-e207-cea9-d131-258f0ef6fff2@gmail.com> (raw)
In-Reply-To: <20220719233924.559329-1-prestwoj@gmail.com>
Hi James,
On 7/19/22 18:39, James Prestwood wrote:
> Similar to the HT/VHT APIs, this estimates the data rate based on the
> HE Capabilities element, in addition to our own capabilities. The
> logic is much the same as HT/VHT. The major difference being that HE
> uses several MCS tables depending on the channel width. Each width
> MCS set is checked (if supported) and the highest estimated rate out
> of all the MCS sets is used.
> ---
> src/band.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++--
> src/band.h | 3 +-
> 2 files changed, 238 insertions(+), 9 deletions(-)
>
> v2:
> * Removed confusing loop to iterate widths. Replaced with 3 if blocks
> that calculate the rate based on the MCS set
> * Use OFDM enum instead of band_chandef_width. This did require a special
> case for 80+80, but really simplifies everything else.
>
<snip>
> +
> +/*
> + * Finds the best width supported according to capabilities. The 802.11ax spec
> + * has a separate MCS set for 80+80, but in the end 160 and 80+80 are treated
> + * the same in terms of the rate tables. This MCS set still needs to be checked
> + * though which is why the mcs80p80 flag is set in this case.
> + */
> +static enum ofdm_channel_width find_he_width_offset(enum band_freq freq,
> + const struct band_he_capabilities *he_cap,
> + const uint8_t *he_phy, bool *mcs80p80)
> +{
> +
> + uint8_t own_width_set = bit_field(he_cap->he_phy_capa[0], 1, 7);
> + uint8_t peer_width_set = bit_field(he_phy[0], 1, 7);
Why not just & these together and then test just the result?
> + enum ofdm_channel_width max_width = OFDM_CHANNEL_WIDTH_20MHZ;
> +
> + /*
> + * 802.11ax Table 9-322b
> + */
> + switch (freq) {
> + case BAND_FREQ_2_4_GHZ:
> + /* B0 indicates support for 40MHz */
> + if (test_bit(&peer_width_set, 0) && test_bit(&own_width_set, 0))
These test_bit lines end up over 80 chars...
> + max_width = OFDM_CHANNEL_WIDTH_40MHZ;
> +
> + break;
> + case BAND_FREQ_5_GHZ:
> + case BAND_FREQ_6_GHZ:
> + /* B1 indicates support for 40MHz and 80MHz, choose 80 */
> + if (test_bit(&peer_width_set, 1) && test_bit(&own_width_set, 1))
> + max_width = OFDM_CHANNEL_WIDTH_80MHZ;
> +
> + /* B2 indicates support for 160MHz */
> + if (test_bit(&peer_width_set, 2) && test_bit(&own_width_set, 2))
> + max_width = OFDM_CHANNEL_WIDTH_160MHZ;
> +
> + /* B3 indicates support for 80+80MHz */
> + if (test_bit(&peer_width_set, 3) &&
> + test_bit(&own_width_set, 3)) {
> + max_width = OFDM_CHANNEL_WIDTH_160MHZ;
> + *mcs80p80 = true;
If we wanted to be extra paranoid, I guess we should also check that bit 3 is
set IFF bit 2 is set and IFF bit 1 is set. Maybe validating this and the
presence of RX/TX MCS Maps for 160/80+80 fields should be done at entry to
band_estimate_he_rx_rate();
> + }
> +
> + break;
> + }
> +
> + return max_width;
> +}
> +
> +/*
> + * HE data rate is calculated based on 802.11ax - Section 27.5
> + */
> +int band_estimate_he_rx_rate(const struct band *band, const uint8_t *hec,
> + int32_t rssi, uint64_t *out_data_rate)
> +{
> + enum ofdm_channel_width width;
> + const struct band_he_capabilities *he_cap = NULL;
> + const struct l_queue_entry *entry;
> + const uint8_t *rx_map;
> + const uint8_t *tx_map;
> + bool mcs80p80 = false;
> + uint64_t rate = 0;
> + uint64_t new_rate = 0;
> +
> + if (!hec || !band->he_capabilities)
> + return -EBADMSG;
> +
> + for (entry = l_queue_get_entries(band->he_capabilities);
> + entry; entry = entry->next)
> + {
That's not our style. Also, maybe we should introduce QUEUE_FOREACH macro or
something? We can do this later I guess.
> + const struct band_he_capabilities *cap = entry->data;
> +
> + /*
> + * TODO: Station type is assumed here since it is the only
> + * consumer of these data rate estimation APIs. If this
> + * changes the iftype would need to be passed in.
> + */
> + if (he_cap->iftypes & (1 << NETDEV_IFTYPE_STATION)) {
> + he_cap = cap;
> + break;
> + }
> + }
> +
> + if (!he_cap)
> + return -ENOTSUP;
> +
> + /* The maximum width sets where to stop checking MCS sets */
> + width = find_he_width_offset(band->freq, he_cap, hec + 8, &mcs80p80);
> +
What about just checking the capability bits in-line to this function? Something
like:
if (test_bit(intersected_caps, 3)) {
find_rate_he(..., OFDM_CHANNEL_WIDTH_160MHZ);
}
if (test_bit(intersected_caps, 2)) {
find_rate_he(..., OFDM_CHANNEL_WIDTH_160MHZ);
}
if (test_bit(intersected_caps, 1))
max_width = OFDM_CHANNEL_WIDTH_80;
if (test_bit(intersected_caps, 0))
max_width = OFDM_CHANNEL_WIDTH_40;
> + /*
> + * The HE-MCS maps are 19 bytes into the HE Capabilities IE, and
> + * alternate RX/TX every 2 bytes. Start the TX map 19 + 2 bytes
> + * into the MCS set. For each MCS set find the best data rate.
> + *
> + * Note: Since 'hec' is an extended IE index 0 is actually the length
> + * since wiphy offsets data - 2.
> + */
> + rx_map = he_cap->he_mcs_set;
> + tx_map = hec + 21;
> +
> + /* 80+80MHz MCS set */
> + if (mcs80p80) {
> + /* 21 + 8 bytes into the IE, plus 2 for the MCS set itself */
> + if (hec[0] < 31)
> + return -EBADMSG;
> +
> + if (find_rate_he(rx_map + 8, tx_map + 8,
> + OFDM_CHANNEL_WIDTH_160MHZ, rssi, &new_rate))
> + rate = new_rate;
> + }
> +
> + /* 160MHz MCS set */
> + if (width == OFDM_CHANNEL_WIDTH_160MHZ) {
> + /* 21 + 4 bytes into the IE, plus 2 for the MCS set itself */
> + if (hec[0] < 27)
> + return -EBADMSG;
> +
> + if (find_rate_he(rx_map + 4, tx_map + 4,
> + OFDM_CHANNEL_WIDTH_160MHZ, rssi, &new_rate) &&
> + new_rate > rate)
> + rate = new_rate;
> + }
> +
> + /* <= 80MHz MCS set, length checked as this field always exists */
> + if (find_rate_he(rx_map, tx_map, width, rssi, &new_rate) &&
> + new_rate > rate)
> + rate = new_rate;
And looks like this last part should be done in a loop for 80,40,20 (max_width)
in the case of 5G/6G and 40/20 in the case of 2.4G? Similar to how VHT is done?
I think in theory you could have a RSSI where the best rate would be at a lower
channel width...?
Some unit tests would also be nice to verify this.
> +
> + if (!rate)
> + return -EBADMSG;
> +
> + *out_data_rate = rate;
> +
> + return 0;
> +}
> +
Regards,
-Denis
prev parent reply other threads:[~2022-07-20 2:51 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-19 23:39 [PATCH v2 1/2] band: add band_estimate_he_rx_rate James Prestwood
2022-07-19 23:39 ` [PATCH v2 2/2] wiphy: use HE element for data rate estimation James Prestwood
2022-07-20 2:36 ` Denis Kenzior [this message]
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=2b2794fd-e207-cea9-d131-258f0ef6fff2@gmail.com \
--to=denkenz@gmail.com \
--cc=iwd@lists.linux.dev \
--cc=prestwoj@gmail.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox