u16 grade;
};
-#define RSSI_TO_GRADE_LINE(_lb, _hb_uhb, _grade) \
+#define RSSI_TO_GRADE_LINE_WITH_LB(_lb, _hb_uhb, _grade) \
{ \
.rssi = {_lb, _hb_uhb}, \
.grade = _grade \
}
-/*
- * This array must be sorted by increasing RSSI for proper functionality.
- * The grades are actually estimated throughput, represented as fixed-point
- * with a scale factor of 1/10.
- */
-static const struct iwl_mld_rssi_to_grade rssi_to_grade_map[] = {
- RSSI_TO_GRADE_LINE(-85, -89, 172),
- RSSI_TO_GRADE_LINE(-83, -86, 344),
- RSSI_TO_GRADE_LINE(-82, -85, 516),
- RSSI_TO_GRADE_LINE(-80, -83, 688),
- RSSI_TO_GRADE_LINE(-77, -79, 1032),
- RSSI_TO_GRADE_LINE(-73, -76, 1376),
- RSSI_TO_GRADE_LINE(-70, -74, 1548),
- RSSI_TO_GRADE_LINE(-69, -72, 1720),
- RSSI_TO_GRADE_LINE(-65, -68, 2064),
- RSSI_TO_GRADE_LINE(-61, -66, 2294),
- RSSI_TO_GRADE_LINE(-58, -61, 2580),
- RSSI_TO_GRADE_LINE(-55, -58, 2868),
- RSSI_TO_GRADE_LINE(-46, -55, 3098),
- RSSI_TO_GRADE_LINE(-43, -54, 3442)
+#define RSSI_TO_GRADE_LINE(_rssi, _grade) \
+ RSSI_TO_GRADE_LINE_WITH_LB(_rssi, _rssi, _grade)
+
+/* Tables must be sorted by increasing RSSI */
+
+/* 20 MHz Operational BW Grading Table */
+static const struct iwl_mld_rssi_to_grade rssi_to_grade_20mhz[] = {
+ RSSI_TO_GRADE_LINE_WITH_LB(-94, -95, 9),
+ RSSI_TO_GRADE_LINE_WITH_LB(-92, -93, 17),
+ RSSI_TO_GRADE_LINE_WITH_LB(-90, -90, 34),
+ RSSI_TO_GRADE_LINE_WITH_LB(-87, -87, 52),
+ RSSI_TO_GRADE_LINE_WITH_LB(-83, -84, 69),
+ RSSI_TO_GRADE_LINE_WITH_LB(-79, -80, 103),
+ RSSI_TO_GRADE_LINE_WITH_LB(-75, -75, 137),
+ RSSI_TO_GRADE_LINE_WITH_LB(-72, -73, 155),
+ RSSI_TO_GRADE_LINE_WITH_LB(-70, -71, 172),
+ RSSI_TO_GRADE_LINE_WITH_LB(-67, -68, 206),
+ RSSI_TO_GRADE_LINE_WITH_LB(-64, -65, 230),
+ RSSI_TO_GRADE_LINE_WITH_LB(-59, -60, 258),
+ RSSI_TO_GRADE_LINE_WITH_LB(-57, -58, 287),
+ RSSI_TO_GRADE_LINE_WITH_LB(-52, -53, 310),
+ RSSI_TO_GRADE_LINE_WITH_LB(-50, -50, 345),
};
-#define MAX_GRADE (rssi_to_grade_map[ARRAY_SIZE(rssi_to_grade_map) - 1].grade)
+/* 40 MHz Operational BW Grading Table */
+static const struct iwl_mld_rssi_to_grade rssi_to_grade_40mhz[] = {
+ RSSI_TO_GRADE_LINE_WITH_LB(-95, -95, 9),
+ RSSI_TO_GRADE_LINE_WITH_LB(-93, -93, 17),
+ RSSI_TO_GRADE_LINE_WITH_LB(-91, -92, 18),
+ RSSI_TO_GRADE_LINE_WITH_LB(-89, -90, 34),
+ RSSI_TO_GRADE_LINE_WITH_LB(-87, -87, 68),
+ RSSI_TO_GRADE_LINE_WITH_LB(-84, -84, 104),
+ RSSI_TO_GRADE_LINE_WITH_LB(-80, -81, 138),
+ RSSI_TO_GRADE_LINE_WITH_LB(-77, -77, 206),
+ RSSI_TO_GRADE_LINE_WITH_LB(-72, -72, 274),
+ RSSI_TO_GRADE_LINE_WITH_LB(-69, -70, 310),
+ RSSI_TO_GRADE_LINE_WITH_LB(-67, -68, 344),
+ RSSI_TO_GRADE_LINE_WITH_LB(-64, -65, 412),
+ RSSI_TO_GRADE_LINE_WITH_LB(-61, -62, 460),
+ RSSI_TO_GRADE_LINE_WITH_LB(-56, -57, 516),
+ RSSI_TO_GRADE_LINE_WITH_LB(-54, -55, 574),
+ RSSI_TO_GRADE_LINE_WITH_LB(-49, -50, 620),
+ RSSI_TO_GRADE_LINE_WITH_LB(-46, -47, 690),
+};
+
+/* 80 MHz Operational BW Grading Table */
+static const struct iwl_mld_rssi_to_grade rssi_to_grade_80mhz[] = {
+ RSSI_TO_GRADE_LINE(-95, 9),
+ RSSI_TO_GRADE_LINE(-93, 17),
+ RSSI_TO_GRADE_LINE(-92, 18),
+ RSSI_TO_GRADE_LINE(-90, 34),
+ RSSI_TO_GRADE_LINE(-89, 36),
+ RSSI_TO_GRADE_LINE(-87, 68),
+ RSSI_TO_GRADE_LINE(-83, 136),
+ RSSI_TO_GRADE_LINE(-80, 208),
+ RSSI_TO_GRADE_LINE(-77, 276),
+ RSSI_TO_GRADE_LINE(-74, 412),
+ RSSI_TO_GRADE_LINE(-69, 548),
+ RSSI_TO_GRADE_LINE(-67, 620),
+ RSSI_TO_GRADE_LINE(-66, 688),
+ RSSI_TO_GRADE_LINE(-61, 824),
+ RSSI_TO_GRADE_LINE(-59, 920),
+ RSSI_TO_GRADE_LINE(-54, 1032),
+ RSSI_TO_GRADE_LINE(-52, 1148),
+ RSSI_TO_GRADE_LINE(-47, 1240),
+ RSSI_TO_GRADE_LINE(-44, 1380),
+};
+
+/* 160 MHz Operational BW Grading Table */
+static const struct iwl_mld_rssi_to_grade rssi_to_grade_160mhz[] = {
+ RSSI_TO_GRADE_LINE(-95, 9),
+ RSSI_TO_GRADE_LINE(-93, 17),
+ RSSI_TO_GRADE_LINE(-92, 18),
+ RSSI_TO_GRADE_LINE(-90, 34),
+ RSSI_TO_GRADE_LINE(-89, 36),
+ RSSI_TO_GRADE_LINE(-87, 68),
+ RSSI_TO_GRADE_LINE(-86, 72),
+ RSSI_TO_GRADE_LINE(-84, 136),
+ RSSI_TO_GRADE_LINE(-81, 272),
+ RSSI_TO_GRADE_LINE(-78, 416),
+ RSSI_TO_GRADE_LINE(-75, 552),
+ RSSI_TO_GRADE_LINE(-71, 824),
+ RSSI_TO_GRADE_LINE(-67, 1096),
+ RSSI_TO_GRADE_LINE(-65, 1240),
+ RSSI_TO_GRADE_LINE(-63, 1376),
+ RSSI_TO_GRADE_LINE(-59, 1648),
+ RSSI_TO_GRADE_LINE(-57, 1840),
+ RSSI_TO_GRADE_LINE(-52, 2064),
+ RSSI_TO_GRADE_LINE(-50, 2296),
+ RSSI_TO_GRADE_LINE(-46, 2480),
+ RSSI_TO_GRADE_LINE(-42, 2760),
+};
+
+/* 320 MHz Operational BW Grading Table */
+static const struct iwl_mld_rssi_to_grade rssi_to_grade_320mhz[] = {
+ RSSI_TO_GRADE_LINE(-95, 9),
+ RSSI_TO_GRADE_LINE(-93, 17),
+ RSSI_TO_GRADE_LINE(-92, 18),
+ RSSI_TO_GRADE_LINE(-90, 34),
+ RSSI_TO_GRADE_LINE(-89, 36),
+ RSSI_TO_GRADE_LINE(-87, 68),
+ RSSI_TO_GRADE_LINE(-86, 72),
+ RSSI_TO_GRADE_LINE(-84, 136),
+ RSSI_TO_GRADE_LINE(-83, 144),
+ RSSI_TO_GRADE_LINE(-81, 272),
+ RSSI_TO_GRADE_LINE(-78, 544),
+ RSSI_TO_GRADE_LINE(-75, 832),
+ RSSI_TO_GRADE_LINE(-72, 1104),
+ RSSI_TO_GRADE_LINE(-69, 1648),
+ RSSI_TO_GRADE_LINE(-64, 2192),
+ RSSI_TO_GRADE_LINE(-62, 2480),
+ RSSI_TO_GRADE_LINE(-61, 2752),
+ RSSI_TO_GRADE_LINE(-57, 3296),
+ RSSI_TO_GRADE_LINE(-55, 3680),
+ RSSI_TO_GRADE_LINE(-50, 4128),
+ RSSI_TO_GRADE_LINE(-47, 4592),
+ RSSI_TO_GRADE_LINE(-43, 4960),
+ RSSI_TO_GRADE_LINE(-40, 5520),
+};
#define DEFAULT_CHAN_LOAD_2GHZ 30
#define DEFAULT_CHAN_LOAD_5GHZ 15
#define SCALE_FACTOR 256
#define MAX_CHAN_LOAD 256
-static unsigned int
-iwl_mld_get_n_subchannels(const struct ieee80211_bss_conf *link_conf)
+static void
+iwl_mld_apply_puncturing_penalty(const struct ieee80211_bss_conf *link_conf,
+ unsigned int *grade, int bw_mhz)
{
- enum nl80211_chan_width chan_width =
- link_conf->chanreq.oper.width;
- int mhz = nl80211_chan_width_to_mhz(chan_width);
- unsigned int n_subchannels;
+ unsigned int n_punctured, n_subchannels;
- if (WARN_ONCE(mhz < 20 || mhz > 320,
- "Invalid channel width : (%d)\n", mhz))
- return 1;
+ /* Puncturing only applicable for BW >= 80 MHz */
+ if (bw_mhz < 80)
+ return;
- /* total number of subchannels */
- n_subchannels = mhz / 20;
+ n_punctured = hweight16(link_conf->chanreq.oper.punctured);
+ if (n_punctured == 0)
+ return;
- /* No puncturing if less than 80 MHz */
- if (mhz >= 80)
- n_subchannels -= hweight16(link_conf->chanreq.oper.punctured);
+ n_subchannels = bw_mhz / 20;
- return n_subchannels;
+ *grade = *grade * (n_subchannels - n_punctured) / n_subchannels;
}
static int
unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld,
struct ieee80211_bss_conf *link_conf)
{
+ const struct iwl_mld_rssi_to_grade *grade_table;
enum nl80211_band band;
- int rssi_idx;
+ int rssi_idx, table_size, bw_mhz;
s32 link_rssi;
- unsigned int grade = MAX_GRADE;
+ unsigned int grade;
if (WARN_ON_ONCE(!link_conf || !link_conf->bss))
return 0;
+ bw_mhz = nl80211_chan_width_to_mhz(link_conf->chanreq.oper.width);
+ if (bw_mhz < 0)
+ return 0;
+
band = link_conf->chanreq.oper.chan->band;
if (WARN_ONCE(band != NL80211_BAND_2GHZ &&
band != NL80211_BAND_5GHZ &&
link_rssi += rssi_adj_6g;
}
+ /* Select grading table based on operational bandwidth */
+ switch (bw_mhz) {
+ case 20:
+ grade_table = rssi_to_grade_20mhz;
+ table_size = ARRAY_SIZE(rssi_to_grade_20mhz);
+ break;
+ case 40:
+ grade_table = rssi_to_grade_40mhz;
+ table_size = ARRAY_SIZE(rssi_to_grade_40mhz);
+ break;
+ case 80:
+ grade_table = rssi_to_grade_80mhz;
+ table_size = ARRAY_SIZE(rssi_to_grade_80mhz);
+ break;
+ case 160:
+ grade_table = rssi_to_grade_160mhz;
+ table_size = ARRAY_SIZE(rssi_to_grade_160mhz);
+ break;
+ case 320:
+ grade_table = rssi_to_grade_320mhz;
+ table_size = ARRAY_SIZE(rssi_to_grade_320mhz);
+ break;
+ default:
+ WARN_ONCE(1, "Invalid bandwidth: %d MHz\n", bw_mhz);
+ return 0;
+ }
+
+ /* Initialize grade to maximum value from selected table */
+ grade = grade_table[table_size - 1].grade;
+
rssi_idx = band == NL80211_BAND_2GHZ ? 0 : 1;
- /* No valid RSSI - take the lowest grade */
+ /* No valid RSSI - take the lowest grade from selected table */
if (!link_rssi)
- link_rssi = rssi_to_grade_map[0].rssi[rssi_idx];
+ link_rssi = grade_table[0].rssi[rssi_idx];
IWL_DEBUG_EHT(mld,
- "Calculating grade of link %d: band = %d, bandwidth = %d, punctured subchannels =0x%x RSSI = %d\n",
- link_conf->link_id, band,
- link_conf->chanreq.oper.width,
+ "Calculating grade of link %d: band = %d, BW = %d, punct subchannels = 0x%x RSSI = %d\n",
+ link_conf->link_id, band, bw_mhz,
link_conf->chanreq.oper.punctured, link_rssi);
- /* Get grade based on RSSI */
- for (int i = 0; i < ARRAY_SIZE(rssi_to_grade_map); i++) {
- const struct iwl_mld_rssi_to_grade *line =
- &rssi_to_grade_map[i];
+ /* Get grade based on RSSI from the bandwidth-specific table */
+ for (int i = 0; i < table_size; i++) {
+ const struct iwl_mld_rssi_to_grade *line = &grade_table[i];
if (link_rssi > line->rssi[rssi_idx])
continue;
}
/* Apply the channel load and puncturing factors */
- grade = grade * iwl_mld_get_avail_chan_load(mld, link_conf) / SCALE_FACTOR;
- grade = grade * iwl_mld_get_n_subchannels(link_conf);
+ grade = grade * iwl_mld_get_avail_chan_load(mld, link_conf) /
+ SCALE_FACTOR;
+
+ iwl_mld_apply_puncturing_penalty(link_conf, &grade, bw_mhz);
IWL_DEBUG_EHT(mld, "Link %d's grade: %d\n", link_conf->link_id, grade);