mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-12-22 21:22:37 +01:00
band: Move ht/vht data rate calculation out of ie.c
This commit is contained in:
parent
e41bee377d
commit
842a70a307
89
src/band.c
89
src/band.c
@ -20,9 +20,98 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <ell/ell.h>
|
||||||
|
|
||||||
#include "band.h"
|
#include "band.h"
|
||||||
|
|
||||||
void band_free(struct band *band)
|
void band_free(struct band *band)
|
||||||
{
|
{
|
||||||
l_free(band);
|
l_free(band);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Base RSSI values for 20MHz (both HT and VHT) channel. These values can be
|
||||||
|
* used to calculate the minimum RSSI values for all other channel widths. HT
|
||||||
|
* MCS indexes are grouped into ranges of 8 (per spatial stream) where VHT are
|
||||||
|
* grouped in chunks of 10. This just means HT will not use the last two
|
||||||
|
* index's of this array.
|
||||||
|
*/
|
||||||
|
static const int32_t ht_vht_base_rssi[] = {
|
||||||
|
-82, -79, -77, -74, -70, -66, -65, -64, -59, -57
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data Rate for HT/VHT is obtained according to this formula:
|
||||||
|
* Nsd * Nbpscs * R * Nss / (Tdft + Tgi)
|
||||||
|
*
|
||||||
|
* Where Nsd is [52, 108, 234, 468] for 20/40/80/160 Mhz respectively
|
||||||
|
* Nbpscs is [1, 2, 4, 6, 8] for BPSK/QPSK/16QAM/64QAM/256QAM
|
||||||
|
* R is [1/2, 2/3, 3/4, 5/6] depending on the MCS index
|
||||||
|
* Nss is the number of spatial streams
|
||||||
|
* Tdft = 3.2 us
|
||||||
|
* Tgi = Long/Short GI of 0.8/0.4 us
|
||||||
|
*
|
||||||
|
* Short GI rate can be easily obtained by multiplying by (10 / 9)
|
||||||
|
*
|
||||||
|
* The table was pre-computed using the following python snippet:
|
||||||
|
* rfactors = [ 1/2, 1/2, 3/4, 1/2, 3/4, 2/3, 3/4, 5/6, 3/4, 5/6 ]
|
||||||
|
* nbpscs = [1, 2, 2, 4, 4, 6, 6, 6, 8, 8 ]
|
||||||
|
* nsds = [52, 108, 234, 468]
|
||||||
|
*
|
||||||
|
* for nsd in nsds:
|
||||||
|
* rates = []
|
||||||
|
* for i in xrange(0, 10):
|
||||||
|
* data_rate = (nsd * rfactors[i] * nbpscs[i]) / 0.004
|
||||||
|
* rates.append(int(data_rate) * 1000)
|
||||||
|
* print('rates for nsd: ' + nsd + ': ' + rates)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const uint64_t ht_vht_rates[4][10] = {
|
||||||
|
[OFDM_CHANNEL_WIDTH_20MHZ] = {
|
||||||
|
6500000ULL, 13000000ULL, 19500000ULL, 26000000ULL,
|
||||||
|
39000000ULL, 52000000ULL, 58500000ULL, 65000000ULL,
|
||||||
|
78000000ULL, 86666000ULL },
|
||||||
|
[OFDM_CHANNEL_WIDTH_40MHZ] = {
|
||||||
|
13500000ULL, 27000000ULL, 40500000ULL, 54000000ULL,
|
||||||
|
81000000ULL, 108000000ULL, 121500000ULL, 135000000ULL,
|
||||||
|
162000000ULL, 180000000ULL, },
|
||||||
|
[OFDM_CHANNEL_WIDTH_80MHZ] = {
|
||||||
|
29250000ULL, 58500000ULL, 87750000ULL, 117000000ULL,
|
||||||
|
175500000ULL, 234000000ULL, 263250000ULL, 292500000ULL,
|
||||||
|
351000000ULL, 390000000ULL, },
|
||||||
|
[OFDM_CHANNEL_WIDTH_160MHZ] = {
|
||||||
|
58500000ULL, 117000000ULL, 175500000ULL, 234000000ULL,
|
||||||
|
351000000ULL, 468000000ULL, 526500000ULL, 585000000ULL,
|
||||||
|
702000000ULL, 780000000ULL,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Both HT and VHT rates are calculated in the same fashion. The only difference
|
||||||
|
* is a relative MCS index is used for HT since, for each NSS, the formula
|
||||||
|
* is the same with relative index's. This is why this is called with index % 8
|
||||||
|
* for HT, but not VHT.
|
||||||
|
*/
|
||||||
|
bool band_ofdm_rate(uint8_t index, enum ofdm_channel_width width,
|
||||||
|
int32_t rssi, uint8_t nss, bool sgi,
|
||||||
|
uint64_t *data_rate)
|
||||||
|
{
|
||||||
|
uint64_t rate;
|
||||||
|
int32_t width_adjust = width * 3;
|
||||||
|
|
||||||
|
if (rssi < ht_vht_base_rssi[index] + width_adjust)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rate = ht_vht_rates[width][index];
|
||||||
|
|
||||||
|
if (sgi)
|
||||||
|
rate = rate / 9 * 10;
|
||||||
|
|
||||||
|
rate *= nss;
|
||||||
|
|
||||||
|
*data_rate = rate;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
11
src/band.h
11
src/band.h
@ -20,6 +20,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
enum ofdm_channel_width {
|
||||||
|
OFDM_CHANNEL_WIDTH_20MHZ = 0,
|
||||||
|
OFDM_CHANNEL_WIDTH_40MHZ,
|
||||||
|
OFDM_CHANNEL_WIDTH_80MHZ,
|
||||||
|
OFDM_CHANNEL_WIDTH_160MHZ,
|
||||||
|
};
|
||||||
|
|
||||||
struct band {
|
struct band {
|
||||||
uint8_t vht_mcs_set[8];
|
uint8_t vht_mcs_set[8];
|
||||||
uint8_t vht_capabilities[4];
|
uint8_t vht_capabilities[4];
|
||||||
@ -32,3 +39,7 @@ struct band {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void band_free(struct band *band);
|
void band_free(struct band *band);
|
||||||
|
|
||||||
|
bool band_ofdm_rate(uint8_t index, enum ofdm_channel_width width,
|
||||||
|
int32_t rssi, uint8_t nss, bool sgi,
|
||||||
|
uint64_t *data_rate);
|
||||||
|
119
src/ie.c
119
src/ie.c
@ -31,6 +31,7 @@
|
|||||||
#include "ell/useful.h"
|
#include "ell/useful.h"
|
||||||
#include "src/util.h"
|
#include "src/util.h"
|
||||||
#include "src/crypto.h"
|
#include "src/crypto.h"
|
||||||
|
#include "src/band.h"
|
||||||
#include "src/ie.h"
|
#include "src/ie.h"
|
||||||
|
|
||||||
const unsigned char ieee_oui[3] = { 0x00, 0x0f, 0xac };
|
const unsigned char ieee_oui[3] = { 0x00, 0x0f, 0xac };
|
||||||
@ -1726,98 +1727,6 @@ static int ie_parse_supported_rates_from_data(const uint8_t *supp_rates_ie,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ht_vht_channel_width {
|
|
||||||
HT_VHT_CHANNEL_WIDTH_20MHZ = 0,
|
|
||||||
HT_VHT_CHANNEL_WIDTH_40MHZ,
|
|
||||||
HT_VHT_CHANNEL_WIDTH_80MHZ,
|
|
||||||
HT_VHT_CHANNEL_WIDTH_160MHZ,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Base RSSI values for 20MHz (both HT and VHT) channel. These values can be
|
|
||||||
* used to calculate the minimum RSSI values for all other channel widths. HT
|
|
||||||
* MCS indexes are grouped into ranges of 8 (per spatial stream) where VHT are
|
|
||||||
* grouped in chunks of 10. This just means HT will not use the last two
|
|
||||||
* index's of this array.
|
|
||||||
*/
|
|
||||||
static const int32_t ht_vht_base_rssi[] = {
|
|
||||||
-82, -79, -77, -74, -70, -66, -65, -64, -59, -57
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Data Rate for HT/VHT is obtained according to this formula:
|
|
||||||
* Nsd * Nbpscs * R * Nss / (Tdft + Tgi)
|
|
||||||
*
|
|
||||||
* Where Nsd is [52, 108, 234, 468] for 20/40/80/160 Mhz respectively
|
|
||||||
* Nbpscs is [1, 2, 4, 6, 8] for BPSK/QPSK/16QAM/64QAM/256QAM
|
|
||||||
* R is [1/2, 2/3, 3/4, 5/6] depending on the MCS index
|
|
||||||
* Nss is the number of spatial streams
|
|
||||||
* Tdft = 3.2 us
|
|
||||||
* Tgi = Long/Short GI of 0.8/0.4 us
|
|
||||||
*
|
|
||||||
* Short GI rate can be easily obtained by multiplying by (10 / 9)
|
|
||||||
*
|
|
||||||
* The table was pre-computed using the following python snippet:
|
|
||||||
* rfactors = [ 1/2, 1/2, 3/4, 1/2, 3/4, 2/3, 3/4, 5/6, 3/4, 5/6 ]
|
|
||||||
* nbpscs = [1, 2, 2, 4, 4, 6, 6, 6, 8, 8 ]
|
|
||||||
* nsds = [52, 108, 234, 468]
|
|
||||||
*
|
|
||||||
* for nsd in nsds:
|
|
||||||
* rates = []
|
|
||||||
* for i in xrange(0, 10):
|
|
||||||
* data_rate = (nsd * rfactors[i] * nbpscs[i]) / 0.004
|
|
||||||
* rates.append(int(data_rate) * 1000)
|
|
||||||
* print('rates for nsd: ' + nsd + ': ' + rates)
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const uint64_t ht_vht_rates[4][10] = {
|
|
||||||
[HT_VHT_CHANNEL_WIDTH_20MHZ] = {
|
|
||||||
6500000ULL, 13000000ULL, 19500000ULL, 26000000ULL,
|
|
||||||
39000000ULL, 52000000ULL, 58500000ULL, 65000000ULL,
|
|
||||||
78000000ULL, 86666000ULL },
|
|
||||||
[HT_VHT_CHANNEL_WIDTH_40MHZ] = {
|
|
||||||
13500000ULL, 27000000ULL, 40500000ULL, 54000000ULL,
|
|
||||||
81000000ULL, 108000000ULL, 121500000ULL, 135000000ULL,
|
|
||||||
162000000ULL, 180000000ULL, },
|
|
||||||
[HT_VHT_CHANNEL_WIDTH_80MHZ] = {
|
|
||||||
29250000ULL, 58500000ULL, 87750000ULL, 117000000ULL,
|
|
||||||
175500000ULL, 234000000ULL, 263250000ULL, 292500000ULL,
|
|
||||||
351000000ULL, 390000000ULL, },
|
|
||||||
[HT_VHT_CHANNEL_WIDTH_160MHZ] = {
|
|
||||||
58500000ULL, 117000000ULL, 175500000ULL, 234000000ULL,
|
|
||||||
351000000ULL, 468000000ULL, 526500000ULL, 585000000ULL,
|
|
||||||
702000000ULL, 780000000ULL,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Both HT and VHT rates are calculated in the same fashion. The only difference
|
|
||||||
* is a relative MCS index is used for HT since, for each NSS, the formula
|
|
||||||
* is the same with relative index's. This is why this is called with index % 8
|
|
||||||
* for HT, but not VHT.
|
|
||||||
*/
|
|
||||||
static bool calculate_ht_vht_data_rate(uint8_t index,
|
|
||||||
enum ht_vht_channel_width width,
|
|
||||||
int32_t rssi, uint8_t nss, bool sgi,
|
|
||||||
uint64_t *data_rate)
|
|
||||||
{
|
|
||||||
uint64_t rate;
|
|
||||||
int32_t width_adjust = width * 3;
|
|
||||||
|
|
||||||
if (rssi < ht_vht_base_rssi[index] + width_adjust)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
rate = ht_vht_rates[width][index];
|
|
||||||
|
|
||||||
if (sgi)
|
|
||||||
rate = rate / 9 * 10;
|
|
||||||
|
|
||||||
rate *= nss;
|
|
||||||
|
|
||||||
*data_rate = rate;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ie_parse_ht_capability(struct ie_tlv_iter *iter, int32_t rssi,
|
static int ie_parse_ht_capability(struct ie_tlv_iter *iter, int32_t rssi,
|
||||||
uint64_t *data_rate)
|
uint64_t *data_rate)
|
||||||
{
|
{
|
||||||
@ -1867,19 +1776,15 @@ static int ie_parse_ht_capability(struct ie_tlv_iter *iter, int32_t rssi,
|
|||||||
if (!support_40mhz)
|
if (!support_40mhz)
|
||||||
goto check_20;
|
goto check_20;
|
||||||
|
|
||||||
if (calculate_ht_vht_data_rate(i % 8,
|
if (band_ofdm_rate(i % 8, OFDM_CHANNEL_WIDTH_40MHZ,
|
||||||
HT_VHT_CHANNEL_WIDTH_40MHZ,
|
rssi, (i / 8) + 1, short_gi_40mhz, &drate)) {
|
||||||
rssi, (i / 8) + 1,
|
|
||||||
short_gi_40mhz, &drate)) {
|
|
||||||
*data_rate = drate;
|
*data_rate = drate;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_20:
|
check_20:
|
||||||
if (!calculate_ht_vht_data_rate(i % 8,
|
if (!band_ofdm_rate(i % 8, OFDM_CHANNEL_WIDTH_20MHZ,
|
||||||
HT_VHT_CHANNEL_WIDTH_20MHZ,
|
rssi, (i / 8) + 1, short_gi_20mhz, &drate))
|
||||||
rssi, (i / 8) + 1,
|
|
||||||
short_gi_20mhz, &drate))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!support_40mhz) {
|
if (!support_40mhz) {
|
||||||
@ -2046,31 +1951,31 @@ static int ie_parse_vht_capability(struct ie_tlv_iter *vht_iter,
|
|||||||
* on the channel width for this iteration.
|
* on the channel width for this iteration.
|
||||||
*/
|
*/
|
||||||
switch (width) {
|
switch (width) {
|
||||||
case HT_VHT_CHANNEL_WIDTH_20MHZ:
|
case OFDM_CHANNEL_WIDTH_20MHZ:
|
||||||
sgi = short_gi_20mhz;
|
sgi = short_gi_20mhz;
|
||||||
break;
|
break;
|
||||||
case HT_VHT_CHANNEL_WIDTH_40MHZ:
|
case OFDM_CHANNEL_WIDTH_40MHZ:
|
||||||
sgi = short_gi_40mhz;
|
sgi = short_gi_40mhz;
|
||||||
break;
|
break;
|
||||||
case HT_VHT_CHANNEL_WIDTH_80MHZ:
|
case OFDM_CHANNEL_WIDTH_80MHZ:
|
||||||
sgi = short_gi_80mhz;
|
sgi = short_gi_80mhz;
|
||||||
break;
|
break;
|
||||||
case HT_VHT_CHANNEL_WIDTH_160MHZ:
|
case OFDM_CHANNEL_WIDTH_160MHZ:
|
||||||
sgi = short_gi_160mhz;
|
sgi = short_gi_160mhz;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (nss = minsize(rx_nss, tx_nss); nss > 0; nss--) {
|
for (nss = minsize(rx_nss, tx_nss); nss > 0; nss--) {
|
||||||
/* NSS > 4 does not apply to 20/40MHz */
|
/* NSS > 4 does not apply to 20/40MHz */
|
||||||
if (width <= HT_VHT_CHANNEL_WIDTH_40MHZ && nss > 4)
|
if (width <= OFDM_CHANNEL_WIDTH_40MHZ && nss > 4)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (mcs = minsize(max_rx_mcs, max_tx_mcs);
|
for (mcs = minsize(max_rx_mcs, max_tx_mcs);
|
||||||
mcs >= 0; mcs--) {
|
mcs >= 0; mcs--) {
|
||||||
uint64_t drate;
|
uint64_t drate;
|
||||||
|
|
||||||
if (!calculate_ht_vht_data_rate(mcs, width,
|
if (!band_ofdm_rate(mcs, width, rssi,
|
||||||
rssi, nss, sgi, &drate))
|
nss, sgi, &drate))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (drate > highest_rate)
|
if (drate > highest_rate)
|
||||||
|
Loading…
Reference in New Issue
Block a user