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