1 | /* |
2 | * Copyright (c) 2014, Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> |
3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #include "ath9k.h" |
18 | #include "hw.h" |
19 | #include "dynack.h" |
20 | |
21 | #define COMPUTE_TO (5 * HZ) |
22 | #define LATEACK_DELAY (10 * HZ) |
23 | #define EWMA_LEVEL 96 |
24 | #define EWMA_DIV 128 |
25 | |
26 | /** |
27 | * ath_dynack_get_max_to - set max timeout according to channel width |
28 | * @ah: ath hw |
29 | * |
30 | */ |
31 | static u32 ath_dynack_get_max_to(struct ath_hw *ah) |
32 | { |
33 | const struct ath9k_channel *chan = ah->curchan; |
34 | |
35 | if (!chan) |
36 | return 300; |
37 | |
38 | if (IS_CHAN_HT40(chan)) |
39 | return 300; |
40 | if (IS_CHAN_HALF_RATE(chan)) |
41 | return 750; |
42 | if (IS_CHAN_QUARTER_RATE(chan)) |
43 | return 1500; |
44 | return 600; |
45 | } |
46 | |
47 | /* |
48 | * ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation |
49 | */ |
50 | static inline int ath_dynack_ewma(int old, int new) |
51 | { |
52 | if (old > 0) |
53 | return (new * (EWMA_DIV - EWMA_LEVEL) + |
54 | old * EWMA_LEVEL) / EWMA_DIV; |
55 | else |
56 | return new; |
57 | } |
58 | |
59 | /** |
60 | * ath_dynack_get_sifs - get sifs time based on phy used |
61 | * @ah: ath hw |
62 | * @phy: phy used |
63 | * |
64 | */ |
65 | static inline u32 ath_dynack_get_sifs(struct ath_hw *ah, int phy) |
66 | { |
67 | u32 sifs = CCK_SIFS_TIME; |
68 | |
69 | if (phy == WLAN_RC_PHY_OFDM) { |
70 | if (IS_CHAN_QUARTER_RATE(ah->curchan)) |
71 | sifs = OFDM_SIFS_TIME_QUARTER; |
72 | else if (IS_CHAN_HALF_RATE(ah->curchan)) |
73 | sifs = OFDM_SIFS_TIME_HALF; |
74 | else |
75 | sifs = OFDM_SIFS_TIME; |
76 | } |
77 | return sifs; |
78 | } |
79 | |
80 | /** |
81 | * ath_dynack_bssidmask - filter out ACK frames based on BSSID mask |
82 | * @ah: ath hw |
83 | * @mac: receiver address |
84 | */ |
85 | static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac) |
86 | { |
87 | int i; |
88 | struct ath_common *common = ath9k_hw_common(ah); |
89 | |
90 | for (i = 0; i < ETH_ALEN; i++) { |
91 | if ((common->macaddr[i] & common->bssidmask[i]) != |
92 | (mac[i] & common->bssidmask[i])) |
93 | return false; |
94 | } |
95 | |
96 | return true; |
97 | } |
98 | |
99 | /** |
100 | * ath_dynack_set_timeout - configure timeouts/slottime registers |
101 | * @ah: ath hw |
102 | * @to: timeout value |
103 | * |
104 | */ |
105 | static void ath_dynack_set_timeout(struct ath_hw *ah, int to) |
106 | { |
107 | struct ath_common *common = ath9k_hw_common(ah); |
108 | int slottime = (to - 3) / 2; |
109 | |
110 | ath_dbg(common, DYNACK, "ACK timeout %u slottime %u\n" , |
111 | to, slottime); |
112 | ath9k_hw_setslottime(ah, us: slottime); |
113 | ath9k_hw_set_ack_timeout(ah, us: to); |
114 | ath9k_hw_set_cts_timeout(ah, us: to); |
115 | } |
116 | |
117 | /** |
118 | * ath_dynack_compute_ackto - compute ACK timeout as the maximum STA timeout |
119 | * @ah: ath hw |
120 | * |
121 | * should be called while holding qlock |
122 | */ |
123 | static void ath_dynack_compute_ackto(struct ath_hw *ah) |
124 | { |
125 | struct ath_dynack *da = &ah->dynack; |
126 | struct ath_node *an; |
127 | int to = 0; |
128 | |
129 | list_for_each_entry(an, &da->nodes, list) |
130 | if (an->ackto > to) |
131 | to = an->ackto; |
132 | |
133 | if (to && da->ackto != to) { |
134 | ath_dynack_set_timeout(ah, to); |
135 | da->ackto = to; |
136 | } |
137 | } |
138 | |
139 | /** |
140 | * ath_dynack_compute_to - compute STA ACK timeout |
141 | * @ah: ath hw |
142 | * |
143 | * should be called while holding qlock |
144 | */ |
145 | static void ath_dynack_compute_to(struct ath_hw *ah) |
146 | { |
147 | struct ath_dynack *da = &ah->dynack; |
148 | u32 ackto, ack_ts, max_to; |
149 | struct ieee80211_sta *sta; |
150 | struct ts_info *st_ts; |
151 | struct ath_node *an; |
152 | u8 *dst, *src; |
153 | |
154 | rcu_read_lock(); |
155 | |
156 | max_to = ath_dynack_get_max_to(ah); |
157 | while (da->st_rbf.h_rb != da->st_rbf.t_rb && |
158 | da->ack_rbf.h_rb != da->ack_rbf.t_rb) { |
159 | ack_ts = da->ack_rbf.tstamp[da->ack_rbf.h_rb]; |
160 | st_ts = &da->st_rbf.ts[da->st_rbf.h_rb]; |
161 | dst = da->st_rbf.addr[da->st_rbf.h_rb].h_dest; |
162 | src = da->st_rbf.addr[da->st_rbf.h_rb].h_src; |
163 | |
164 | ath_dbg(ath9k_hw_common(ah), DYNACK, |
165 | "ack_ts %u st_ts %u st_dur %u [%u-%u]\n" , |
166 | ack_ts, st_ts->tstamp, st_ts->dur, |
167 | da->ack_rbf.h_rb, da->st_rbf.h_rb); |
168 | |
169 | if (ack_ts > st_ts->tstamp + st_ts->dur) { |
170 | ackto = ack_ts - st_ts->tstamp - st_ts->dur; |
171 | |
172 | if (ackto < max_to) { |
173 | sta = ieee80211_find_sta_by_ifaddr(hw: ah->hw, addr: dst, |
174 | localaddr: src); |
175 | if (sta) { |
176 | an = (struct ath_node *)sta->drv_priv; |
177 | an->ackto = ath_dynack_ewma(old: an->ackto, |
178 | new: ackto); |
179 | ath_dbg(ath9k_hw_common(ah), DYNACK, |
180 | "%pM to %d [%u]\n" , dst, |
181 | an->ackto, ackto); |
182 | if (time_is_before_jiffies(da->lto)) { |
183 | ath_dynack_compute_ackto(ah); |
184 | da->lto = jiffies + COMPUTE_TO; |
185 | } |
186 | } |
187 | INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); |
188 | } |
189 | INCR(da->st_rbf.h_rb, ATH_DYN_BUF); |
190 | } else { |
191 | INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); |
192 | } |
193 | } |
194 | |
195 | rcu_read_unlock(); |
196 | } |
197 | |
198 | /** |
199 | * ath_dynack_sample_tx_ts - status timestamp sampling method |
200 | * @ah: ath hw |
201 | * @skb: socket buffer |
202 | * @ts: tx status info |
203 | * @sta: station pointer |
204 | * |
205 | */ |
206 | void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, |
207 | struct ath_tx_status *ts, |
208 | struct ieee80211_sta *sta) |
209 | { |
210 | struct ieee80211_hdr *hdr; |
211 | struct ath_dynack *da = &ah->dynack; |
212 | struct ath_common *common = ath9k_hw_common(ah); |
213 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
214 | u32 dur = ts->duration; |
215 | u8 ridx; |
216 | |
217 | if (!da->enabled || (info->flags & IEEE80211_TX_CTL_NO_ACK)) |
218 | return; |
219 | |
220 | spin_lock_bh(lock: &da->qlock); |
221 | |
222 | hdr = (struct ieee80211_hdr *)skb->data; |
223 | |
224 | /* late ACK */ |
225 | if (ts->ts_status & ATH9K_TXERR_XRETRY) { |
226 | if (ieee80211_is_assoc_req(fc: hdr->frame_control) || |
227 | ieee80211_is_assoc_resp(fc: hdr->frame_control) || |
228 | ieee80211_is_auth(fc: hdr->frame_control)) { |
229 | u32 max_to = ath_dynack_get_max_to(ah); |
230 | |
231 | ath_dbg(common, DYNACK, "late ack\n" ); |
232 | ath_dynack_set_timeout(ah, to: max_to); |
233 | if (sta) { |
234 | struct ath_node *an; |
235 | |
236 | an = (struct ath_node *)sta->drv_priv; |
237 | an->ackto = -1; |
238 | } |
239 | da->lto = jiffies + LATEACK_DELAY; |
240 | } |
241 | |
242 | spin_unlock_bh(lock: &da->qlock); |
243 | return; |
244 | } |
245 | |
246 | ridx = ts->ts_rateindex; |
247 | |
248 | da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp; |
249 | |
250 | /* ether_addr_copy() gives a false warning on gcc-10 so use memcpy() |
251 | * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97490 |
252 | */ |
253 | memcpy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1, ETH_ALEN); |
254 | memcpy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2, ETH_ALEN); |
255 | |
256 | if (!(info->status.rates[ridx].flags & IEEE80211_TX_RC_MCS)) { |
257 | const struct ieee80211_rate *rate; |
258 | struct ieee80211_tx_rate *rates = info->status.rates; |
259 | u32 phy; |
260 | |
261 | rate = &common->sbands[info->band].bitrates[rates[ridx].idx]; |
262 | if (info->band == NL80211_BAND_2GHZ && |
263 | !(rate->flags & IEEE80211_RATE_ERP_G)) |
264 | phy = WLAN_RC_PHY_CCK; |
265 | else |
266 | phy = WLAN_RC_PHY_OFDM; |
267 | |
268 | dur -= ath_dynack_get_sifs(ah, phy); |
269 | } |
270 | da->st_rbf.ts[da->st_rbf.t_rb].dur = dur; |
271 | |
272 | INCR(da->st_rbf.t_rb, ATH_DYN_BUF); |
273 | if (da->st_rbf.t_rb == da->st_rbf.h_rb) |
274 | INCR(da->st_rbf.h_rb, ATH_DYN_BUF); |
275 | |
276 | ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n" , |
277 | hdr->addr1, ts->ts_tstamp, dur, da->st_rbf.h_rb, |
278 | da->st_rbf.t_rb); |
279 | |
280 | ath_dynack_compute_to(ah); |
281 | |
282 | spin_unlock_bh(lock: &da->qlock); |
283 | } |
284 | EXPORT_SYMBOL(ath_dynack_sample_tx_ts); |
285 | |
286 | /** |
287 | * ath_dynack_sample_ack_ts - ACK timestamp sampling method |
288 | * @ah: ath hw |
289 | * @skb: socket buffer |
290 | * @ts: rx timestamp |
291 | * |
292 | */ |
293 | void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, |
294 | u32 ts) |
295 | { |
296 | struct ath_dynack *da = &ah->dynack; |
297 | struct ath_common *common = ath9k_hw_common(ah); |
298 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
299 | |
300 | if (!da->enabled || !ath_dynack_bssidmask(ah, mac: hdr->addr1)) |
301 | return; |
302 | |
303 | spin_lock_bh(lock: &da->qlock); |
304 | da->ack_rbf.tstamp[da->ack_rbf.t_rb] = ts; |
305 | |
306 | INCR(da->ack_rbf.t_rb, ATH_DYN_BUF); |
307 | if (da->ack_rbf.t_rb == da->ack_rbf.h_rb) |
308 | INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); |
309 | |
310 | ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n" , |
311 | ts, da->ack_rbf.h_rb, da->ack_rbf.t_rb); |
312 | |
313 | ath_dynack_compute_to(ah); |
314 | |
315 | spin_unlock_bh(lock: &da->qlock); |
316 | } |
317 | EXPORT_SYMBOL(ath_dynack_sample_ack_ts); |
318 | |
319 | /** |
320 | * ath_dynack_node_init - init ath_node related info |
321 | * @ah: ath hw |
322 | * @an: ath node |
323 | * |
324 | */ |
325 | void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an) |
326 | { |
327 | struct ath_dynack *da = &ah->dynack; |
328 | |
329 | an->ackto = da->ackto; |
330 | |
331 | spin_lock_bh(lock: &da->qlock); |
332 | list_add_tail(new: &an->list, head: &da->nodes); |
333 | spin_unlock_bh(lock: &da->qlock); |
334 | } |
335 | EXPORT_SYMBOL(ath_dynack_node_init); |
336 | |
337 | /** |
338 | * ath_dynack_node_deinit - deinit ath_node related info |
339 | * @ah: ath hw |
340 | * @an: ath node |
341 | * |
342 | */ |
343 | void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an) |
344 | { |
345 | struct ath_dynack *da = &ah->dynack; |
346 | |
347 | spin_lock_bh(lock: &da->qlock); |
348 | list_del(entry: &an->list); |
349 | spin_unlock_bh(lock: &da->qlock); |
350 | } |
351 | EXPORT_SYMBOL(ath_dynack_node_deinit); |
352 | |
353 | /** |
354 | * ath_dynack_reset - reset dynack processing |
355 | * @ah: ath hw |
356 | * |
357 | */ |
358 | void ath_dynack_reset(struct ath_hw *ah) |
359 | { |
360 | struct ath_dynack *da = &ah->dynack; |
361 | struct ath_node *an; |
362 | |
363 | spin_lock_bh(lock: &da->qlock); |
364 | |
365 | da->lto = jiffies + COMPUTE_TO; |
366 | |
367 | da->st_rbf.t_rb = 0; |
368 | da->st_rbf.h_rb = 0; |
369 | da->ack_rbf.t_rb = 0; |
370 | da->ack_rbf.h_rb = 0; |
371 | |
372 | da->ackto = ath_dynack_get_max_to(ah); |
373 | list_for_each_entry(an, &da->nodes, list) |
374 | an->ackto = da->ackto; |
375 | |
376 | /* init acktimeout */ |
377 | ath_dynack_set_timeout(ah, to: da->ackto); |
378 | |
379 | spin_unlock_bh(lock: &da->qlock); |
380 | } |
381 | EXPORT_SYMBOL(ath_dynack_reset); |
382 | |
383 | /** |
384 | * ath_dynack_init - init dynack data structure |
385 | * @ah: ath hw |
386 | * |
387 | */ |
388 | void ath_dynack_init(struct ath_hw *ah) |
389 | { |
390 | struct ath_dynack *da = &ah->dynack; |
391 | |
392 | memset(da, 0, sizeof(struct ath_dynack)); |
393 | |
394 | spin_lock_init(&da->qlock); |
395 | INIT_LIST_HEAD(list: &da->nodes); |
396 | /* ackto = slottime + sifs + air delay */ |
397 | da->ackto = 9 + 16 + 64; |
398 | |
399 | ah->hw->wiphy->features |= NL80211_FEATURE_ACKTO_ESTIMATION; |
400 | } |
401 | |