1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Thu, 21 Jan 2021 18:29:30 +0100
3 Subject: [PATCH] mac80211: minstrel_ht: use bitfields to encode rate
6 Get rid of a lot of divisions and modulo operations
7 Reduces code size and improves performance
9 Signed-off-by: Felix Fietkau <nbd@nbd.name>
12 --- a/net/mac80211/rc80211_minstrel_ht.c
13 +++ b/net/mac80211/rc80211_minstrel_ht.c
14 @@ -379,14 +379,14 @@ out:
15 static inline struct minstrel_rate_stats *
16 minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
18 - return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES];
19 + return &mi->groups[MI_RATE_GROUP(index)].rates[MI_RATE_IDX(index)];
23 -minstrel_get_duration(int index)
24 +static inline int minstrel_get_duration(int index)
26 - const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
27 - unsigned int duration = group->duration[index % MCS_GROUP_RATES];
28 + const struct mcs_group *group = &minstrel_mcs_groups[MI_RATE_GROUP(index)];
29 + unsigned int duration = group->duration[MI_RATE_IDX(index)];
31 return duration << group->shift;
34 @@ -398,7 +398,7 @@ minstrel_ht_avg_ampdu_len(struct minstre
35 if (mi->avg_ampdu_len)
36 return MINSTREL_TRUNC(mi->avg_ampdu_len);
38 - if (minstrel_ht_is_legacy_group(mi->max_tp_rate[0] / MCS_GROUP_RATES))
39 + if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_tp_rate[0])))
42 duration = minstrel_get_duration(mi->max_tp_rate[0]);
43 @@ -465,14 +465,14 @@ minstrel_ht_sort_best_tp_rates(struct mi
44 int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob;
45 int j = MAX_THR_RATES;
47 - cur_group = index / MCS_GROUP_RATES;
48 - cur_idx = index % MCS_GROUP_RATES;
49 + cur_group = MI_RATE_GROUP(index);
50 + cur_idx = MI_RATE_IDX(index);
51 cur_prob = mi->groups[cur_group].rates[cur_idx].prob_avg;
52 cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob);
55 - tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
56 - tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
57 + tmp_group = MI_RATE_GROUP(tp_list[j - 1]);
58 + tmp_idx = MI_RATE_IDX(tp_list[j - 1]);
59 tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg;
60 tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx,
62 @@ -504,23 +504,23 @@ minstrel_ht_set_best_prob_rate(struct mi
63 int max_gpr_group, max_gpr_idx;
64 int max_gpr_tp_avg, max_gpr_prob;
66 - cur_group = index / MCS_GROUP_RATES;
67 - cur_idx = index % MCS_GROUP_RATES;
68 - mg = &mi->groups[index / MCS_GROUP_RATES];
69 - mrs = &mg->rates[index % MCS_GROUP_RATES];
70 + cur_group = MI_RATE_GROUP(index);
71 + cur_idx = MI_RATE_IDX(index);
72 + mg = &mi->groups[cur_group];
73 + mrs = &mg->rates[cur_idx];
75 - tmp_group = *dest / MCS_GROUP_RATES;
76 - tmp_idx = *dest % MCS_GROUP_RATES;
77 + tmp_group = MI_RATE_GROUP(*dest);
78 + tmp_idx = MI_RATE_IDX(*dest);
79 tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg;
80 tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
82 /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from
83 * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */
84 - max_tp_group = mi->max_tp_rate[0] / MCS_GROUP_RATES;
85 - max_tp_idx = mi->max_tp_rate[0] % MCS_GROUP_RATES;
86 + max_tp_group = MI_RATE_GROUP(mi->max_tp_rate[0]);
87 + max_tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]);
88 max_tp_prob = mi->groups[max_tp_group].rates[max_tp_idx].prob_avg;
90 - if (minstrel_ht_is_legacy_group(index / MCS_GROUP_RATES) &&
91 + if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(index)) &&
92 !minstrel_ht_is_legacy_group(max_tp_group))
95 @@ -529,8 +529,8 @@ minstrel_ht_set_best_prob_rate(struct mi
96 mrs->prob_avg < max_tp_prob)
99 - max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
100 - max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
101 + max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate);
102 + max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate);
103 max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg;
105 if (mrs->prob_avg > MINSTREL_FRAC(75, 100)) {
106 @@ -567,13 +567,13 @@ minstrel_ht_assign_best_tp_rates(struct
107 unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob;
110 - tmp_group = tmp_legacy_tp_rate[0] / MCS_GROUP_RATES;
111 - tmp_idx = tmp_legacy_tp_rate[0] % MCS_GROUP_RATES;
112 + tmp_group = MI_RATE_GROUP(tmp_legacy_tp_rate[0]);
113 + tmp_idx = MI_RATE_IDX(tmp_legacy_tp_rate[0]);
114 tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg;
115 tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
117 - tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES;
118 - tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES;
119 + tmp_group = MI_RATE_GROUP(tmp_mcs_tp_rate[0]);
120 + tmp_idx = MI_RATE_IDX(tmp_mcs_tp_rate[0]);
121 tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg;
122 tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
124 @@ -600,14 +600,14 @@ minstrel_ht_prob_rate_reduce_streams(str
125 if (!mi->sta->ht_cap.ht_supported)
128 - tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] /
129 - MCS_GROUP_RATES].streams;
130 + group = MI_RATE_GROUP(mi->max_tp_rate[0]);
131 + tmp_max_streams = minstrel_mcs_groups[group].streams;
132 for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
133 mg = &mi->groups[group];
134 if (!mi->supported[group] || group == MINSTREL_CCK_GROUP)
137 - tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
138 + tmp_idx = MI_RATE_IDX(mg->max_group_prob_rate);
139 tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg;
141 if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) &&
142 @@ -644,8 +644,8 @@ minstrel_ht_find_probe_rates(struct mins
146 - tp_group = &minstrel_mcs_groups[mi->max_tp_rate[0] / MCS_GROUP_RATES];
147 - tp_idx = mi->max_tp_rate[0] % MCS_GROUP_RATES;
148 + tp_group = &minstrel_mcs_groups[MI_RATE_GROUP(mi->max_tp_rate[0])];
149 + tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]);
151 max_dur = minstrel_get_duration(mi->max_tp_rate[0]);
153 @@ -670,7 +670,7 @@ minstrel_ht_find_probe_rates(struct mins
154 if ((group->duration[i] << group->shift) > max_dur)
157 - idx = g * MCS_GROUP_RATES + i;
158 + idx = MI_RATE(g, i);
159 if (idx == mi->max_tp_rate[0])
162 @@ -712,10 +712,10 @@ minstrel_ht_rate_sample_switch(struct mi
164 /* If no suitable rate was found, try to pick the next one in the group */
166 - int g_idx = mi->max_tp_rate[0] / MCS_GROUP_RATES;
167 + int g_idx = MI_RATE_GROUP(mi->max_tp_rate[0]);
168 u16 supported = mi->supported[g_idx];
170 - supported >>= mi->max_tp_rate[0] % MCS_GROUP_RATES;
171 + supported >>= MI_RATE_IDX(mi->max_tp_rate[0]);
172 for (i = 0; supported; supported >>= 1, i++) {
173 if (!(supported & 1))
175 @@ -856,22 +856,26 @@ minstrel_ht_update_stats(struct minstrel
177 memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate));
178 memset(tmp_legacy_tp_rate, 0, sizeof(tmp_legacy_tp_rate));
180 if (mi->supported[MINSTREL_CCK_GROUP])
181 - for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++)
182 - tmp_legacy_tp_rate[j] = MINSTREL_CCK_GROUP * MCS_GROUP_RATES;
183 + group = MINSTREL_CCK_GROUP;
184 else if (mi->supported[MINSTREL_OFDM_GROUP])
185 - for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++)
186 - tmp_legacy_tp_rate[j] = MINSTREL_OFDM_GROUP * MCS_GROUP_RATES;
187 + group = MINSTREL_OFDM_GROUP;
189 + index = MI_RATE(group, 0);
190 + for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++)
191 + tmp_legacy_tp_rate[j] = index;
193 if (mi->supported[MINSTREL_VHT_GROUP_0])
194 - index = MINSTREL_VHT_GROUP_0 * MCS_GROUP_RATES;
195 + group = MINSTREL_VHT_GROUP_0;
196 else if (ht_supported)
197 - index = MINSTREL_HT_GROUP_0 * MCS_GROUP_RATES;
198 + group = MINSTREL_HT_GROUP_0;
199 else if (mi->supported[MINSTREL_CCK_GROUP])
200 - index = MINSTREL_CCK_GROUP * MCS_GROUP_RATES;
201 + group = MINSTREL_CCK_GROUP;
203 - index = MINSTREL_OFDM_GROUP * MCS_GROUP_RATES;
204 + group = MINSTREL_OFDM_GROUP;
206 + index = MI_RATE(group, 0);
207 tmp_max_prob_rate = index;
208 for (j = 0; j < ARRAY_SIZE(tmp_mcs_tp_rate); j++)
209 tmp_mcs_tp_rate[j] = index;
210 @@ -888,7 +892,7 @@ minstrel_ht_update_stats(struct minstrel
212 /* (re)Initialize group rate indexes */
213 for(j = 0; j < MAX_THR_RATES; j++)
214 - tmp_group_tp_rate[j] = MCS_GROUP_RATES * group;
215 + tmp_group_tp_rate[j] = MI_RATE(group, 0);
217 if (group == MINSTREL_CCK_GROUP && ht_supported)
218 tp_rate = tmp_legacy_tp_rate;
219 @@ -897,7 +901,7 @@ minstrel_ht_update_stats(struct minstrel
220 if (!(mi->supported[group] & BIT(i)))
223 - index = MCS_GROUP_RATES * group + i;
224 + index = MI_RATE(group, i);
227 mrs->retry_updated = false;
228 @@ -929,13 +933,13 @@ minstrel_ht_update_stats(struct minstrel
231 mg = &mi->groups[group];
232 - mg->max_group_prob_rate = MCS_GROUP_RATES * group;
233 + mg->max_group_prob_rate = MI_RATE(group, 0);
235 for (i = 0; i < MCS_GROUP_RATES; i++) {
236 if (!(mi->supported[group] & BIT(i)))
239 - index = MCS_GROUP_RATES * group + i;
240 + index = MI_RATE(group, i);
242 /* Find max probability rate per group and global */
243 minstrel_ht_set_best_prob_rate(mi, &tmp_max_prob_rate,
244 @@ -1022,7 +1026,7 @@ minstrel_downgrade_rate(struct minstrel_
246 int group, orig_group;
248 - orig_group = group = *idx / MCS_GROUP_RATES;
249 + orig_group = group = MI_RATE_GROUP(*idx);
253 @@ -1206,7 +1210,7 @@ minstrel_calc_retransmit(struct minstrel
254 ctime += (t_slot * cw) >> 1;
255 cw = min((cw << 1) | 1, mp->cw_max);
257 - if (minstrel_ht_is_legacy_group(index / MCS_GROUP_RATES)) {
258 + if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(index))) {
259 overhead = mi->overhead_legacy;
260 overhead_rtscts = mi->overhead_legacy_rtscts;
262 @@ -1239,7 +1243,7 @@ static void
263 minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
264 struct ieee80211_sta_rates *ratetbl, int offset, int index)
266 - int group_idx = index / MCS_GROUP_RATES;
267 + int group_idx = MI_RATE_GROUP(index);
268 const struct mcs_group *group = &minstrel_mcs_groups[group_idx];
269 struct minstrel_rate_stats *mrs;
271 @@ -1259,7 +1263,7 @@ minstrel_ht_set_rate(struct minstrel_pri
272 ratetbl->rate[offset].count_rts = mrs->retry_count_rtscts;
275 - index %= MCS_GROUP_RATES;
276 + index = MI_RATE_IDX(index);
277 if (group_idx == MINSTREL_CCK_GROUP)
278 idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
279 else if (group_idx == MINSTREL_OFDM_GROUP)
280 @@ -1289,17 +1293,17 @@ minstrel_ht_set_rate(struct minstrel_pri
282 minstrel_ht_get_prob_avg(struct minstrel_ht_sta *mi, int rate)
284 - int group = rate / MCS_GROUP_RATES;
285 - rate %= MCS_GROUP_RATES;
286 + int group = MI_RATE_GROUP(rate);
287 + rate = MI_RATE_IDX(rate);
288 return mi->groups[group].rates[rate].prob_avg;
292 minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi)
294 - int group = mi->max_prob_rate / MCS_GROUP_RATES;
295 + int group = MI_RATE_GROUP(mi->max_prob_rate);
296 const struct mcs_group *g = &minstrel_mcs_groups[group];
297 - int rate = mi->max_prob_rate % MCS_GROUP_RATES;
298 + int rate = MI_RATE_IDX(mi->max_prob_rate);
299 unsigned int duration;
301 /* Disable A-MSDU if max_prob_rate is bad */
302 @@ -1405,7 +1409,7 @@ minstrel_get_sample_rate(struct minstrel
305 mrs = &mg->rates[sample_idx];
306 - sample_idx += sample_group * MCS_GROUP_RATES;
307 + sample_idx += MI_RATE(sample_group, 0);
309 tp_rate1 = mi->max_tp_rate[0];
311 @@ -1455,8 +1459,7 @@ minstrel_get_sample_rate(struct minstrel
312 * if the link is working perfectly.
315 - cur_max_tp_streams = minstrel_mcs_groups[tp_rate1 /
316 - MCS_GROUP_RATES].streams;
317 + cur_max_tp_streams = minstrel_mcs_groups[MI_RATE_GROUP(tp_rate1)].streams;
318 if (sample_dur >= minstrel_get_duration(tp_rate2) &&
319 (cur_max_tp_streams - 1 <
320 minstrel_mcs_groups[sample_group].streams ||
321 @@ -1484,7 +1487,7 @@ minstrel_ht_get_rate(void *priv, struct
324 if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
325 - !minstrel_ht_is_legacy_group(mi->max_prob_rate / MCS_GROUP_RATES))
326 + !minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_prob_rate)))
327 minstrel_aggr_check(sta, txrc->skb);
329 info->flags |= mi->tx_flags;
330 @@ -1512,8 +1515,8 @@ minstrel_ht_get_rate(void *priv, struct
334 - sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES];
335 - sample_idx %= MCS_GROUP_RATES;
336 + sample_group = &minstrel_mcs_groups[MI_RATE_GROUP(sample_idx)];
337 + sample_idx = MI_RATE_IDX(sample_idx);
339 if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP] &&
340 (sample_idx >= 4) != txrc->short_preamble)
341 @@ -1529,7 +1532,7 @@ minstrel_ht_get_rate(void *priv, struct
342 int idx = sample_idx % ARRAY_SIZE(mp->ofdm_rates[0]);
343 rate->idx = mp->ofdm_rates[mi->band][idx];
344 } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) {
345 - ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES,
346 + ieee80211_rate_set_vht(rate, MI_RATE_IDX(sample_idx),
347 sample_group->streams);
349 rate->idx = sample_idx + (sample_group->streams - 1) * 8;
350 @@ -1898,8 +1901,8 @@ static u32 minstrel_ht_get_expected_thro
351 struct minstrel_ht_sta *mi = priv_sta;
352 int i, j, prob, tp_avg;
354 - i = mi->max_tp_rate[0] / MCS_GROUP_RATES;
355 - j = mi->max_tp_rate[0] % MCS_GROUP_RATES;
356 + i = MI_RATE_GROUP(mi->max_tp_rate[0]);
357 + j = MI_RATE_IDX(mi->max_tp_rate[0]);
358 prob = mi->groups[i].rates[j].prob_avg;
360 /* convert tp_avg from pkt per second in kbps */
361 --- a/net/mac80211/rc80211_minstrel_ht.h
362 +++ b/net/mac80211/rc80211_minstrel_ht.h
364 #ifndef __RC_MINSTREL_HT_H
365 #define __RC_MINSTREL_HT_H
367 +#include <linux/bitfield.h>
369 /* number of highest throughput rates to consider*/
370 #define MAX_THR_RATES 4
371 #define SAMPLE_COLUMNS 10 /* number of columns in sample table */
374 #define MCS_GROUP_RATES 10
376 +#define MI_RATE_IDX_MASK GENMASK(3, 0)
377 +#define MI_RATE_GROUP_MASK GENMASK(15, 4)
379 +#define MI_RATE(_group, _idx) \
380 + (FIELD_PREP(MI_RATE_GROUP_MASK, _group) | \
381 + FIELD_PREP(MI_RATE_IDX_MASK, _idx))
383 +#define MI_RATE_IDX(_rate) FIELD_GET(MI_RATE_IDX_MASK, _rate)
384 +#define MI_RATE_GROUP(_rate) FIELD_GET(MI_RATE_GROUP_MASK, _rate)
387 struct minstrel_priv {
388 struct ieee80211_hw *hw;
390 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
391 +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
392 @@ -56,7 +56,7 @@ minstrel_ht_stats_dump(struct minstrel_h
394 for (j = 0; j < MCS_GROUP_RATES; j++) {
395 struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j];
396 - int idx = i * MCS_GROUP_RATES + j;
397 + int idx = MI_RATE(i, j);
398 unsigned int duration;
400 if (!(mi->supported[i] & BIT(j)))
401 @@ -201,7 +201,7 @@ minstrel_ht_stats_csv_dump(struct minstr
403 for (j = 0; j < MCS_GROUP_RATES; j++) {
404 struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j];
405 - int idx = i * MCS_GROUP_RATES + j;
406 + int idx = MI_RATE(i, j);
407 unsigned int duration;
409 if (!(mi->supported[i] & BIT(j)))