2 * Copyright (c) 2010 Broadcom Corporation
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.
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 ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 #include <net/mac80211.h>
20 #include "phy/phy_hal.h"
25 /* max number of mpdus in an ampdu */
26 #define AMPDU_MAX_MPDU 32
27 /* max number of mpdus in an ampdu to a legacy */
28 #define AMPDU_NUM_MPDU_LEGACY 16
29 /* max Tx ba window size (in pdu) */
30 #define AMPDU_TX_BA_MAX_WSIZE 64
31 /* default Tx ba window size (in pdu) */
32 #define AMPDU_TX_BA_DEF_WSIZE 64
33 /* default Rx ba window size (in pdu) */
34 #define AMPDU_RX_BA_DEF_WSIZE 64
35 /* max Rx ba window size (in pdu) */
36 #define AMPDU_RX_BA_MAX_WSIZE 64
37 /* max dur of tx ampdu (in msec) */
38 #define AMPDU_MAX_DUR 5
39 /* default tx retry limit */
40 #define AMPDU_DEF_RETRY_LIMIT 5
41 /* default tx retry limit at reg rate */
42 #define AMPDU_DEF_RR_RETRY_LIMIT 2
43 /* default weight of ampdu in txfifo */
44 #define AMPDU_DEF_TXPKT_WEIGHT 2
45 /* default ffpld reserved bytes */
46 #define AMPDU_DEF_FFPLD_RSVD 2048
47 /* # of inis to be freed on detach */
48 #define AMPDU_INI_FREE 10
49 /* max # of mpdus released at a time */
50 #define AMPDU_SCB_MAX_RELEASE 20
52 #define NUM_FFPLD_FIFO 4 /* number of fifo concerned by pre-loading */
53 #define FFPLD_TX_MAX_UNFL 200 /* default value of the average number of ampdu
56 #define FFPLD_MPDU_SIZE 1800 /* estimate of maximum mpdu size */
57 #define FFPLD_MAX_MCS 23 /* we don't deal with mcs 32 */
58 #define FFPLD_PLD_INCR 1000 /* increments in bytes */
59 #define FFPLD_MAX_AMPDU_CNT 5000 /* maximum number of ampdu we
60 * accumulate between resets.
63 #define AMPDU_DELIMITER_LEN 4
65 /* max allowed number of mpdus in an ampdu (2 streams) */
66 #define AMPDU_NUM_MPDU 16
68 #define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
70 /* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
71 #define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\
72 AMPDU_DELIMITER_LEN + 3\
73 + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
75 /* modulo add/sub, bound = 2^k */
76 #define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1))
77 #define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1))
79 /* structure to hold tx fifo information and pre-loading state
80 * counters specific to tx underflows of ampdus
81 * some counters might be redundant with the ones in wlc or ampdu structures.
82 * This allows to maintain a specific state independently of
83 * how often and/or when the wlc counters are updated.
85 * ampdu_pld_size: number of bytes to be pre-loaded
86 * mcs2ampdu_table: per-mcs max # of mpdus in an ampdu
87 * prev_txfunfl: num of underflows last read from the HW macstats counter
88 * accum_txfunfl: num of underflows since we modified pld params
89 * accum_txampdu: num of tx ampdu since we modified pld params
90 * prev_txampdu: previous reading of tx ampdu
91 * dmaxferrate: estimated dma avg xfer rate in kbits/sec
93 struct brcms_fifo_info
{
95 u8 mcs2ampdu_table
[FFPLD_MAX_MCS
+ 1];
103 /* AMPDU module specific state
105 * wlc: pointer to main wlc structure
106 * scb_handle: scb cubby handle to retrieve data from scb
107 * ini_enable: per-tid initiator enable/disable of ampdu
108 * ba_tx_wsize: Tx ba window size (in pdu)
109 * ba_rx_wsize: Rx ba window size (in pdu)
110 * retry_limit: mpdu transmit retry limit
111 * rr_retry_limit: mpdu transmit retry limit at regular rate
112 * retry_limit_tid: per-tid mpdu transmit retry limit
113 * rr_retry_limit_tid: per-tid mpdu transmit retry limit at regular rate
114 * mpdu_density: min mpdu spacing (0-7) ==> 2^(x-1)/8 usec
115 * max_pdu: max pdus allowed in ampdu
116 * dur: max duration of an ampdu (in msec)
117 * txpkt_weight: weight of ampdu in txfifo; reduces rate lag
118 * rx_factor: maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes
119 * ffpld_rsvd: number of bytes to reserve for preload
120 * max_txlen: max size of ampdu per mcs, bw and sgi
121 * mfbr: enable multiple fallback rate
122 * tx_max_funl: underflows should be kept such that
123 * (tx_max_funfl*underflows) < tx frames
124 * fifo_tb: table of fifo infos
127 struct brcms_c_info
*wlc
;
129 u8 ini_enable
[AMPDU_MAX_SCB_TID
];
134 u8 retry_limit_tid
[AMPDU_MAX_SCB_TID
];
135 u8 rr_retry_limit_tid
[AMPDU_MAX_SCB_TID
];
142 u32 max_txlen
[MCS_TABLE_SIZE
][2][2];
145 struct brcms_fifo_info fifo_tb
[NUM_FFPLD_FIFO
];
148 /* used for flushing ampdu packets */
149 struct cb_del_ampdu_pars
{
150 struct ieee80211_sta
*sta
;
154 static void brcms_c_scb_ampdu_update_max_txlen(struct ampdu_info
*ampdu
, u8 dur
)
158 for (mcs
= 0; mcs
< MCS_TABLE_SIZE
; mcs
++) {
159 /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
161 rate
= mcs_2_rate(mcs
, false, false);
162 ampdu
->max_txlen
[mcs
][0][0] = (rate
* dur
) >> 3;
164 rate
= mcs_2_rate(mcs
, true, false);
165 ampdu
->max_txlen
[mcs
][1][0] = (rate
* dur
) >> 3;
167 rate
= mcs_2_rate(mcs
, false, true);
168 ampdu
->max_txlen
[mcs
][0][1] = (rate
* dur
) >> 3;
170 rate
= mcs_2_rate(mcs
, true, true);
171 ampdu
->max_txlen
[mcs
][1][1] = (rate
* dur
) >> 3;
175 static bool brcms_c_ampdu_cap(struct ampdu_info
*ampdu
)
177 if (BRCMS_PHY_11N_CAP(ampdu
->wlc
->band
))
183 static int brcms_c_ampdu_set(struct ampdu_info
*ampdu
, bool on
)
185 struct brcms_c_info
*wlc
= ampdu
->wlc
;
187 wlc
->pub
->_ampdu
= false;
190 if (!(wlc
->pub
->_n_enab
& SUPPORT_11N
)) {
191 wiphy_err(ampdu
->wlc
->wiphy
, "wl%d: driver not "
192 "nmode enabled\n", wlc
->pub
->unit
);
195 if (!brcms_c_ampdu_cap(ampdu
)) {
196 wiphy_err(ampdu
->wlc
->wiphy
, "wl%d: device not "
197 "ampdu capable\n", wlc
->pub
->unit
);
200 wlc
->pub
->_ampdu
= on
;
206 static void brcms_c_ffpld_init(struct ampdu_info
*ampdu
)
209 struct brcms_fifo_info
*fifo
;
211 for (j
= 0; j
< NUM_FFPLD_FIFO
; j
++) {
212 fifo
= (ampdu
->fifo_tb
+ j
);
213 fifo
->ampdu_pld_size
= 0;
214 for (i
= 0; i
<= FFPLD_MAX_MCS
; i
++)
215 fifo
->mcs2ampdu_table
[i
] = 255;
216 fifo
->dmaxferrate
= 0;
217 fifo
->accum_txampdu
= 0;
218 fifo
->prev_txfunfl
= 0;
219 fifo
->accum_txfunfl
= 0;
224 struct ampdu_info
*brcms_c_ampdu_attach(struct brcms_c_info
*wlc
)
226 struct ampdu_info
*ampdu
;
229 ampdu
= kzalloc(sizeof(struct ampdu_info
), GFP_ATOMIC
);
235 for (i
= 0; i
< AMPDU_MAX_SCB_TID
; i
++)
236 ampdu
->ini_enable
[i
] = true;
237 /* Disable ampdu for VO by default */
238 ampdu
->ini_enable
[PRIO_8021D_VO
] = false;
239 ampdu
->ini_enable
[PRIO_8021D_NC
] = false;
241 /* Disable ampdu for BK by default since not enough fifo space */
242 ampdu
->ini_enable
[PRIO_8021D_NONE
] = false;
243 ampdu
->ini_enable
[PRIO_8021D_BK
] = false;
245 ampdu
->ba_tx_wsize
= AMPDU_TX_BA_DEF_WSIZE
;
246 ampdu
->ba_rx_wsize
= AMPDU_RX_BA_DEF_WSIZE
;
247 ampdu
->mpdu_density
= AMPDU_DEF_MPDU_DENSITY
;
248 ampdu
->max_pdu
= AUTO
;
249 ampdu
->dur
= AMPDU_MAX_DUR
;
250 ampdu
->txpkt_weight
= AMPDU_DEF_TXPKT_WEIGHT
;
252 ampdu
->ffpld_rsvd
= AMPDU_DEF_FFPLD_RSVD
;
254 * bump max ampdu rcv size to 64k for all 11n
255 * devices except 4321A0 and 4321A1
257 if (BRCMS_ISNPHY(wlc
->band
) && NREV_LT(wlc
->band
->phyrev
, 2))
258 ampdu
->rx_factor
= IEEE80211_HT_MAX_AMPDU_32K
;
260 ampdu
->rx_factor
= IEEE80211_HT_MAX_AMPDU_64K
;
261 ampdu
->retry_limit
= AMPDU_DEF_RETRY_LIMIT
;
262 ampdu
->rr_retry_limit
= AMPDU_DEF_RR_RETRY_LIMIT
;
264 for (i
= 0; i
< AMPDU_MAX_SCB_TID
; i
++) {
265 ampdu
->retry_limit_tid
[i
] = ampdu
->retry_limit
;
266 ampdu
->rr_retry_limit_tid
[i
] = ampdu
->rr_retry_limit
;
269 brcms_c_scb_ampdu_update_max_txlen(ampdu
, ampdu
->dur
);
271 /* try to set ampdu to the default value */
272 brcms_c_ampdu_set(ampdu
, wlc
->pub
->_ampdu
);
274 ampdu
->tx_max_funl
= FFPLD_TX_MAX_UNFL
;
275 brcms_c_ffpld_init(ampdu
);
280 void brcms_c_ampdu_detach(struct ampdu_info
*ampdu
)
285 static void brcms_c_scb_ampdu_update_config(struct ampdu_info
*ampdu
,
288 struct scb_ampdu
*scb_ampdu
= &scb
->scb_ampdu
;
291 scb_ampdu
->max_pdu
= AMPDU_NUM_MPDU
;
293 /* go back to legacy size if some preloading is occurring */
294 for (i
= 0; i
< NUM_FFPLD_FIFO
; i
++) {
295 if (ampdu
->fifo_tb
[i
].ampdu_pld_size
> FFPLD_PLD_INCR
)
296 scb_ampdu
->max_pdu
= AMPDU_NUM_MPDU_LEGACY
;
299 /* apply user override */
300 if (ampdu
->max_pdu
!= AUTO
)
301 scb_ampdu
->max_pdu
= (u8
) ampdu
->max_pdu
;
303 scb_ampdu
->release
= min_t(u8
, scb_ampdu
->max_pdu
,
304 AMPDU_SCB_MAX_RELEASE
);
306 if (scb_ampdu
->max_rx_ampdu_bytes
)
307 scb_ampdu
->release
= min_t(u8
, scb_ampdu
->release
,
308 scb_ampdu
->max_rx_ampdu_bytes
/ 1600);
310 scb_ampdu
->release
= min(scb_ampdu
->release
,
311 ampdu
->fifo_tb
[TX_AC_BE_FIFO
].
312 mcs2ampdu_table
[FFPLD_MAX_MCS
]);
315 static void brcms_c_scb_ampdu_update_config_all(struct ampdu_info
*ampdu
)
317 brcms_c_scb_ampdu_update_config(ampdu
, &du
->wlc
->pri_scb
);
320 static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info
*ampdu
, int f
)
323 u32 phy_rate
, dma_rate
, tmp
;
325 struct brcms_fifo_info
*fifo
= (ampdu
->fifo_tb
+ f
);
327 /* recompute the dma rate */
328 /* note : we divide/multiply by 100 to avoid integer overflows */
329 max_mpdu
= min_t(u8
, fifo
->mcs2ampdu_table
[FFPLD_MAX_MCS
],
330 AMPDU_NUM_MPDU_LEGACY
);
331 phy_rate
= mcs_2_rate(FFPLD_MAX_MCS
, true, false);
334 (max_mpdu
* FFPLD_MPDU_SIZE
- fifo
->ampdu_pld_size
))
335 / (max_mpdu
* FFPLD_MPDU_SIZE
)) * 100;
336 fifo
->dmaxferrate
= dma_rate
;
338 /* fill up the mcs2ampdu table; do not recalc the last mcs */
339 dma_rate
= dma_rate
>> 7;
340 for (i
= 0; i
< FFPLD_MAX_MCS
; i
++) {
341 /* shifting to keep it within integer range */
342 phy_rate
= mcs_2_rate(i
, true, false) >> 7;
343 if (phy_rate
> dma_rate
) {
344 tmp
= ((fifo
->ampdu_pld_size
* phy_rate
) /
345 ((phy_rate
- dma_rate
) * FFPLD_MPDU_SIZE
)) + 1;
346 tmp
= min_t(u32
, tmp
, 255);
347 fifo
->mcs2ampdu_table
[i
] = (u8
) tmp
;
352 /* evaluate the dma transfer rate using the tx underflows as feedback.
353 * If necessary, increase tx fifo preloading. If not enough,
354 * decrease maximum ampdu size for each mcs till underflows stop
355 * Return 1 if pre-loading not active, -1 if not an underflow event,
356 * 0 if pre-loading module took care of the event.
358 static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info
*wlc
, int fid
)
360 struct ampdu_info
*ampdu
= wlc
->ampdu
;
361 u32 phy_rate
= mcs_2_rate(FFPLD_MAX_MCS
, true, false);
364 u32 current_ampdu_cnt
= 0;
367 struct brcms_fifo_info
*fifo
= (ampdu
->fifo_tb
+ fid
);
371 /* return if we got here for a different reason than underflows */
372 cur_txunfl
= brcms_b_read_shm(wlc
->hw
,
374 offsetof(struct macstat
, txfunfl
[fid
]));
375 new_txunfl
= (u16
) (cur_txunfl
- fifo
->prev_txfunfl
);
376 if (new_txunfl
== 0) {
377 BCMMSG(wlc
->wiphy
, "TX status FRAG set but no tx underflows\n");
380 fifo
->prev_txfunfl
= cur_txunfl
;
382 if (!ampdu
->tx_max_funl
)
385 /* check if fifo is big enough */
386 if (brcms_b_xmtfifo_sz_get(wlc
->hw
, fid
, &xmtfifo_sz
))
389 if ((TXFIFO_SIZE_UNIT
* (u32
) xmtfifo_sz
) <= ampdu
->ffpld_rsvd
)
392 max_pld_size
= TXFIFO_SIZE_UNIT
* xmtfifo_sz
- ampdu
->ffpld_rsvd
;
393 fifo
->accum_txfunfl
+= new_txunfl
;
395 /* we need to wait for at least 10 underflows */
396 if (fifo
->accum_txfunfl
< 10)
399 BCMMSG(wlc
->wiphy
, "ampdu_count %d tx_underflows %d\n",
400 current_ampdu_cnt
, fifo
->accum_txfunfl
);
403 compute the current ratio of tx unfl per ampdu.
404 When the current ampdu count becomes too
405 big while the ratio remains small, we reset
406 the current count in order to not
407 introduce too big of a latency in detecting a
408 large amount of tx underflows later.
411 txunfl_ratio
= current_ampdu_cnt
/ fifo
->accum_txfunfl
;
413 if (txunfl_ratio
> ampdu
->tx_max_funl
) {
414 if (current_ampdu_cnt
>= FFPLD_MAX_AMPDU_CNT
)
415 fifo
->accum_txfunfl
= 0;
419 max_mpdu
= min_t(u8
, fifo
->mcs2ampdu_table
[FFPLD_MAX_MCS
],
420 AMPDU_NUM_MPDU_LEGACY
);
422 /* In case max value max_pdu is already lower than
423 the fifo depth, there is nothing more we can do.
426 if (fifo
->ampdu_pld_size
>= max_mpdu
* FFPLD_MPDU_SIZE
) {
427 fifo
->accum_txfunfl
= 0;
431 if (fifo
->ampdu_pld_size
< max_pld_size
) {
433 /* increment by TX_FIFO_PLD_INC bytes */
434 fifo
->ampdu_pld_size
+= FFPLD_PLD_INCR
;
435 if (fifo
->ampdu_pld_size
> max_pld_size
)
436 fifo
->ampdu_pld_size
= max_pld_size
;
438 /* update scb release size */
439 brcms_c_scb_ampdu_update_config_all(ampdu
);
442 * compute a new dma xfer rate for max_mpdu @ max mcs.
443 * This is the minimum dma rate that can achieve no
444 * underflow condition for the current mpdu size.
446 * note : we divide/multiply by 100 to avoid integer overflows
450 (max_mpdu
* FFPLD_MPDU_SIZE
- fifo
->ampdu_pld_size
))
451 / (max_mpdu
* FFPLD_MPDU_SIZE
)) * 100;
453 BCMMSG(wlc
->wiphy
, "DMA estimated transfer rate %d; "
454 "pre-load size %d\n",
455 fifo
->dmaxferrate
, fifo
->ampdu_pld_size
);
458 /* decrease ampdu size */
459 if (fifo
->mcs2ampdu_table
[FFPLD_MAX_MCS
] > 1) {
460 if (fifo
->mcs2ampdu_table
[FFPLD_MAX_MCS
] == 255)
461 fifo
->mcs2ampdu_table
[FFPLD_MAX_MCS
] =
462 AMPDU_NUM_MPDU_LEGACY
- 1;
464 fifo
->mcs2ampdu_table
[FFPLD_MAX_MCS
] -= 1;
466 /* recompute the table */
467 brcms_c_ffpld_calc_mcs2ampdu_table(ampdu
, fid
);
469 /* update scb release size */
470 brcms_c_scb_ampdu_update_config_all(ampdu
);
473 fifo
->accum_txfunfl
= 0;
478 brcms_c_ampdu_tx_operational(struct brcms_c_info
*wlc
, u8 tid
,
479 u8 ba_wsize
, /* negotiated ba window size (in pdu) */
480 uint max_rx_ampdu_bytes
) /* from ht_cap in beacon */
482 struct scb_ampdu
*scb_ampdu
;
483 struct scb_ampdu_tid_ini
*ini
;
484 struct ampdu_info
*ampdu
= wlc
->ampdu
;
485 struct scb
*scb
= &wlc
->pri_scb
;
486 scb_ampdu
= &scb
->scb_ampdu
;
488 if (!ampdu
->ini_enable
[tid
]) {
489 wiphy_err(ampdu
->wlc
->wiphy
, "%s: Rejecting tid %d\n",
494 ini
= &scb_ampdu
->ini
[tid
];
496 ini
->scb
= scb_ampdu
->scb
;
497 ini
->ba_wsize
= ba_wsize
;
498 scb_ampdu
->max_rx_ampdu_bytes
= max_rx_ampdu_bytes
;
502 brcms_c_sendampdu(struct ampdu_info
*ampdu
, struct brcms_txq_info
*qi
,
503 struct sk_buff
**pdu
, int prec
)
505 struct brcms_c_info
*wlc
;
506 struct sk_buff
*p
, *pkt
[AMPDU_MAX_MPDU
];
509 u8 preamble_type
= BRCMS_GF_PREAMBLE
;
510 u8 fbr_preamble_type
= BRCMS_GF_PREAMBLE
;
511 u8 rts_preamble_type
= BRCMS_LONG_PREAMBLE
;
512 u8 rts_fbr_preamble_type
= BRCMS_LONG_PREAMBLE
;
514 bool rr
= true, fbr
= false;
515 uint i
, count
= 0, fifo
, seg_cnt
= 0;
516 u16 plen
, len
, seq
= 0, mcl
, mch
, index
, frameid
, dma_len
= 0;
517 u32 ampdu_len
, max_ampdu_bytes
= 0;
518 struct d11txh
*txh
= NULL
;
520 struct ieee80211_hdr
*h
;
522 struct scb_ampdu
*scb_ampdu
;
523 struct scb_ampdu_tid_ini
*ini
;
525 bool use_rts
= false, use_cts
= false;
526 u32 rspec
= 0, rspec_fallback
= 0;
527 u32 rts_rspec
= 0, rts_rspec_fallback
= 0;
528 u16 mimo_ctlchbw
= PHY_TXC1_BW_20MHZ
;
529 struct ieee80211_rts
*rts
;
531 struct brcms_fifo_info
*f
;
533 struct ieee80211_tx_info
*tx_info
;
541 tid
= (u8
) (p
->priority
);
543 f
= ampdu
->fifo_tb
+ prio2fifo
[tid
];
546 scb_ampdu
= &scb
->scb_ampdu
;
547 ini
= &scb_ampdu
->ini
[tid
];
549 /* Let pressure continue to build ... */
550 qlen
= pktq_plen(&qi
->q
, prec
);
551 if (ini
->tx_in_transit
> 0 &&
552 qlen
< min(scb_ampdu
->max_pdu
, ini
->ba_wsize
))
553 /* Collect multiple MPDU's to be sent in the next AMPDU */
556 /* at this point we intend to transmit an AMPDU */
557 rr_retry_limit
= ampdu
->rr_retry_limit_tid
[tid
];
561 struct ieee80211_tx_rate
*txrate
;
563 tx_info
= IEEE80211_SKB_CB(p
);
564 txrate
= tx_info
->status
.rates
;
566 if (tx_info
->flags
& IEEE80211_TX_CTL_AMPDU
) {
567 err
= brcms_c_prep_pdu(wlc
, p
, &fifo
);
569 wiphy_err(wiphy
, "%s: AMPDU flag is off!\n", __func__
);
577 wiphy_err(wiphy
, "wl%d: sendampdu: "
578 "prep_xdu retry; seq 0x%x\n",
579 wlc
->pub
->unit
, seq
);
584 /* error in the packet; reject it */
585 wiphy_err(wiphy
, "wl%d: sendampdu: prep_xdu "
586 "rejected; seq 0x%x\n", wlc
->pub
->unit
, seq
);
591 /* pkt is good to be aggregated */
592 txh
= (struct d11txh
*) p
->data
;
593 plcp
= (u8
*) (txh
+ 1);
594 h
= (struct ieee80211_hdr
*)(plcp
+ D11_PHY_HDR_LEN
);
595 seq
= le16_to_cpu(h
->seq_ctrl
) >> SEQNUM_SHIFT
;
596 index
= TX_SEQ_TO_INDEX(seq
);
598 /* check mcl fields and test whether it can be agg'd */
599 mcl
= le16_to_cpu(txh
->MacTxControlLow
);
600 mcl
&= ~TXC_AMPDU_MASK
;
601 fbr_iscck
= !(le16_to_cpu(txh
->XtraFrameTypes
) & 0x3);
602 txh
->PreloadSize
= 0; /* always default to 0 */
604 /* Handle retry limits */
605 if (txrate
[0].count
<= rr_retry_limit
) {
615 /* extract the length info */
616 len
= fbr_iscck
? BRCMS_GET_CCK_PLCP_LEN(txh
->FragPLCPFallback
)
617 : BRCMS_GET_MIMO_PLCP_LEN(txh
->FragPLCPFallback
);
619 /* retrieve null delimiter count */
620 ndelim
= txh
->RTSPLCPFallback
[AMPDU_FBR_NULL_DELIM
];
623 BCMMSG(wlc
->wiphy
, "wl%d: mpdu %d plcp_len %d\n",
624 wlc
->pub
->unit
, count
, len
);
627 * aggregateable mpdu. For ucode/hw agg,
628 * test whether need to break or change the epoch
631 mcl
|= (TXC_AMPDU_FIRST
<< TXC_AMPDU_SHIFT
);
632 /* refill the bits since might be a retx mpdu */
633 mcl
|= TXC_STARTMSDU
;
634 rts
= (struct ieee80211_rts
*)&txh
->rts_frame
;
636 if (ieee80211_is_rts(rts
->frame_control
)) {
640 if (ieee80211_is_cts(rts
->frame_control
)) {
645 mcl
|= (TXC_AMPDU_MIDDLE
<< TXC_AMPDU_SHIFT
);
646 mcl
&= ~(TXC_STARTMSDU
| TXC_SENDRTS
| TXC_SENDCTS
);
649 len
= roundup(len
, 4);
650 ampdu_len
+= (len
+ (ndelim
+ 1) * AMPDU_DELIMITER_LEN
);
652 dma_len
+= (u16
) brcmu_pkttotlen(p
);
654 BCMMSG(wlc
->wiphy
, "wl%d: ampdu_len %d"
655 " seg_cnt %d null delim %d\n",
656 wlc
->pub
->unit
, ampdu_len
, seg_cnt
, ndelim
);
658 txh
->MacTxControlLow
= cpu_to_le16(mcl
);
660 /* this packet is added */
663 /* patch the first MPDU */
665 u8 plcp0
, plcp3
, is40
, sgi
;
666 struct ieee80211_sta
*sta
;
668 sta
= tx_info
->control
.sta
;
674 plcp0
= txh
->FragPLCPFallback
[0];
675 plcp3
= txh
->FragPLCPFallback
[3];
678 is40
= (plcp0
& MIMO_PLCP_40MHZ
) ? 1 : 0;
679 sgi
= plcp3_issgi(plcp3
) ? 1 : 0;
680 mcs
= plcp0
& ~MIMO_PLCP_40MHZ
;
682 min(scb_ampdu
->max_rx_ampdu_bytes
,
683 ampdu
->max_txlen
[mcs
][is40
][sgi
]);
687 CHSPEC_SB_UPPER(wlc_phy_chanspec_get(
689 ? PHY_TXC1_BW_20MHZ_UP
: PHY_TXC1_BW_20MHZ
;
691 /* rebuild the rspec and rspec_fallback */
692 rspec
= RSPEC_MIMORATE
;
693 rspec
|= plcp
[0] & ~MIMO_PLCP_40MHZ
;
694 if (plcp
[0] & MIMO_PLCP_40MHZ
)
695 rspec
|= (PHY_TXC1_BW_40MHZ
<< RSPEC_BW_SHIFT
);
697 if (fbr_iscck
) /* CCK */
698 rspec_fallback
= cck_rspec(cck_phy2mac_rate
699 (txh
->FragPLCPFallback
[0]));
701 rspec_fallback
= RSPEC_MIMORATE
;
703 txh
->FragPLCPFallback
[0] & ~MIMO_PLCP_40MHZ
;
704 if (txh
->FragPLCPFallback
[0] & MIMO_PLCP_40MHZ
)
706 (PHY_TXC1_BW_40MHZ
<<
710 if (use_rts
|| use_cts
) {
712 brcms_c_rspec_to_rts_rspec(wlc
,
713 rspec
, false, mimo_ctlchbw
);
715 brcms_c_rspec_to_rts_rspec(wlc
,
716 rspec_fallback
, false, mimo_ctlchbw
);
720 /* if (first mpdu for host agg) */
721 /* test whether to add more */
722 if ((mcs_2_rate(mcs
, true, false) >= f
->dmaxferrate
) &&
723 (count
== f
->mcs2ampdu_table
[mcs
])) {
724 BCMMSG(wlc
->wiphy
, "wl%d: PR 37644: stopping"
725 " ampdu at %d for mcs %d\n",
726 wlc
->pub
->unit
, count
, mcs
);
730 if (count
== scb_ampdu
->max_pdu
)
734 * check to see if the next pkt is
735 * a candidate for aggregation
737 p
= pktq_ppeek(&qi
->q
, prec
);
738 /* tx_info must be checked with current p */
739 tx_info
= IEEE80211_SKB_CB(p
);
742 if ((tx_info
->flags
& IEEE80211_TX_CTL_AMPDU
) &&
743 ((u8
) (p
->priority
) == tid
)) {
745 plen
= brcmu_pkttotlen(p
) +
746 AMPDU_MAX_MPDU_OVERHEAD
;
747 plen
= max(scb_ampdu
->min_len
, plen
);
749 if ((plen
+ ampdu_len
) > max_ampdu_bytes
) {
755 * check if there are enough
756 * descriptors available
758 if (*wlc
->core
->txavail
[fifo
] <= seg_cnt
+ 1) {
759 wiphy_err(wiphy
, "%s: No fifo space "
764 p
= brcmu_pktq_pdeq(&qi
->q
, prec
);
771 ini
->tx_in_transit
+= count
;
774 /* patch up the last txh */
775 txh
= (struct d11txh
*) pkt
[count
- 1]->data
;
776 mcl
= le16_to_cpu(txh
->MacTxControlLow
);
777 mcl
&= ~TXC_AMPDU_MASK
;
778 mcl
|= (TXC_AMPDU_LAST
<< TXC_AMPDU_SHIFT
);
779 txh
->MacTxControlLow
= cpu_to_le16(mcl
);
781 /* remove the null delimiter after last mpdu */
782 ndelim
= txh
->RTSPLCPFallback
[AMPDU_FBR_NULL_DELIM
];
783 txh
->RTSPLCPFallback
[AMPDU_FBR_NULL_DELIM
] = 0;
784 ampdu_len
-= ndelim
* AMPDU_DELIMITER_LEN
;
786 /* remove the pad len from last mpdu */
787 fbr_iscck
= ((le16_to_cpu(txh
->XtraFrameTypes
) & 0x3) == 0);
788 len
= fbr_iscck
? BRCMS_GET_CCK_PLCP_LEN(txh
->FragPLCPFallback
)
789 : BRCMS_GET_MIMO_PLCP_LEN(txh
->FragPLCPFallback
);
790 ampdu_len
-= roundup(len
, 4) - len
;
792 /* patch up the first txh & plcp */
793 txh
= (struct d11txh
*) pkt
[0]->data
;
794 plcp
= (u8
*) (txh
+ 1);
796 BRCMS_SET_MIMO_PLCP_LEN(plcp
, ampdu_len
);
797 /* mark plcp to indicate ampdu */
798 BRCMS_SET_MIMO_PLCP_AMPDU(plcp
);
800 /* reset the mixed mode header durations */
803 brcms_c_calc_lsig_len(wlc
, rspec
, ampdu_len
);
804 txh
->MModeLen
= cpu_to_le16(mmodelen
);
805 preamble_type
= BRCMS_MM_PREAMBLE
;
807 if (txh
->MModeFbrLen
) {
809 brcms_c_calc_lsig_len(wlc
, rspec_fallback
,
811 txh
->MModeFbrLen
= cpu_to_le16(mmfbrlen
);
812 fbr_preamble_type
= BRCMS_MM_PREAMBLE
;
815 /* set the preload length */
816 if (mcs_2_rate(mcs
, true, false) >= f
->dmaxferrate
) {
817 dma_len
= min(dma_len
, f
->ampdu_pld_size
);
818 txh
->PreloadSize
= cpu_to_le16(dma_len
);
820 txh
->PreloadSize
= 0;
822 mch
= le16_to_cpu(txh
->MacTxControlHigh
);
824 /* update RTS dur fields */
825 if (use_rts
|| use_cts
) {
827 rts
= (struct ieee80211_rts
*)&txh
->rts_frame
;
828 if ((mch
& TXC_PREAMBLE_RTS_MAIN_SHORT
) ==
829 TXC_PREAMBLE_RTS_MAIN_SHORT
)
830 rts_preamble_type
= BRCMS_SHORT_PREAMBLE
;
832 if ((mch
& TXC_PREAMBLE_RTS_FB_SHORT
) ==
833 TXC_PREAMBLE_RTS_FB_SHORT
)
834 rts_fbr_preamble_type
= BRCMS_SHORT_PREAMBLE
;
837 brcms_c_compute_rtscts_dur(wlc
, use_cts
, rts_rspec
,
838 rspec
, rts_preamble_type
,
839 preamble_type
, ampdu_len
,
841 rts
->duration
= cpu_to_le16(durid
);
842 durid
= brcms_c_compute_rtscts_dur(wlc
, use_cts
,
845 rts_fbr_preamble_type
,
848 txh
->RTSDurFallback
= cpu_to_le16(durid
);
849 /* set TxFesTimeNormal */
850 txh
->TxFesTimeNormal
= rts
->duration
;
851 /* set fallback rate version of TxFesTimeNormal */
852 txh
->TxFesTimeFallback
= txh
->RTSDurFallback
;
855 /* set flag and plcp for fallback rate */
857 mch
|= TXC_AMPDU_FBR
;
858 txh
->MacTxControlHigh
= cpu_to_le16(mch
);
859 BRCMS_SET_MIMO_PLCP_AMPDU(plcp
);
860 BRCMS_SET_MIMO_PLCP_AMPDU(txh
->FragPLCPFallback
);
863 BCMMSG(wlc
->wiphy
, "wl%d: count %d ampdu_len %d\n",
864 wlc
->pub
->unit
, count
, ampdu_len
);
866 /* inform rate_sel if it this is a rate probe pkt */
867 frameid
= le16_to_cpu(txh
->TxFrameID
);
868 if (frameid
& TXFID_RATE_PROBE_MASK
)
869 wiphy_err(wiphy
, "%s: XXX what to do with "
870 "TXFID_RATE_PROBE_MASK!?\n", __func__
);
872 for (i
= 0; i
< count
; i
++)
873 brcms_c_txfifo(wlc
, fifo
, pkt
[i
], i
== (count
- 1),
874 ampdu
->txpkt_weight
);
882 brcms_c_ampdu_rate_status(struct brcms_c_info
*wlc
,
883 struct ieee80211_tx_info
*tx_info
,
884 struct tx_status
*txs
, u8 mcs
)
886 struct ieee80211_tx_rate
*txrate
= tx_info
->status
.rates
;
889 /* clear the rest of the rates */
890 for (i
= 2; i
< IEEE80211_TX_MAX_RATES
; i
++) {
897 brcms_c_ampdu_dotxstatus_complete(struct ampdu_info
*ampdu
, struct scb
*scb
,
898 struct sk_buff
*p
, struct tx_status
*txs
,
901 struct scb_ampdu
*scb_ampdu
;
902 struct brcms_c_info
*wlc
= ampdu
->wlc
;
903 struct scb_ampdu_tid_ini
*ini
;
904 u8 bitmap
[8], queue
, tid
;
907 struct ieee80211_hdr
*h
;
908 u16 seq
, start_seq
= 0, bindex
, index
, mcl
;
910 bool ba_recd
= false, ack_recd
= false;
911 u8 suc_mpdu
= 0, tot_mpdu
= 0;
913 bool update_rate
= true, retry
= true, tx_error
= false;
916 u8 retry_limit
, rr_retry_limit
;
917 struct ieee80211_tx_info
*tx_info
= IEEE80211_SKB_CB(p
);
918 struct wiphy
*wiphy
= wlc
->wiphy
;
921 u8 hole
[AMPDU_MAX_MPDU
];
922 memset(hole
, 0, sizeof(hole
));
925 scb_ampdu
= &scb
->scb_ampdu
;
926 tid
= (u8
) (p
->priority
);
928 ini
= &scb_ampdu
->ini
[tid
];
929 retry_limit
= ampdu
->retry_limit_tid
[tid
];
930 rr_retry_limit
= ampdu
->rr_retry_limit_tid
[tid
];
931 memset(bitmap
, 0, sizeof(bitmap
));
932 queue
= txs
->frameid
& TXFID_QUEUE_MASK
;
933 supr_status
= txs
->status
& TX_STATUS_SUPR_MASK
;
935 if (txs
->status
& TX_STATUS_ACK_RCV
) {
936 if (TX_STATUS_SUPR_UF
== supr_status
)
939 WARN_ON(!(txs
->status
& TX_STATUS_INTERMEDIATE
));
940 start_seq
= txs
->sequence
>> SEQNUM_SHIFT
;
941 bitmap
[0] = (txs
->status
& TX_STATUS_BA_BMAP03_MASK
) >>
942 TX_STATUS_BA_BMAP03_SHIFT
;
944 WARN_ON(s1
& TX_STATUS_INTERMEDIATE
);
945 WARN_ON(!(s1
& TX_STATUS_AMPDU
));
948 (s1
& TX_STATUS_BA_BMAP47_MASK
) <<
949 TX_STATUS_BA_BMAP47_SHIFT
;
950 bitmap
[1] = (s1
>> 8) & 0xff;
951 bitmap
[2] = (s1
>> 16) & 0xff;
952 bitmap
[3] = (s1
>> 24) & 0xff;
954 bitmap
[4] = s2
& 0xff;
955 bitmap
[5] = (s2
>> 8) & 0xff;
956 bitmap
[6] = (s2
>> 16) & 0xff;
957 bitmap
[7] = (s2
>> 24) & 0xff;
963 if (supr_status
== TX_STATUS_SUPR_BADCH
) {
964 wiphy_err(wiphy
, "%s: Pkt tx suppressed, "
965 "illegal channel possibly %d\n",
966 __func__
, CHSPEC_CHANNEL(
967 wlc
->default_bss
->chanspec
));
969 if (supr_status
!= TX_STATUS_SUPR_FRAG
)
970 wiphy_err(wiphy
, "%s:"
971 "supr_status 0x%x\n",
972 __func__
, supr_status
);
974 /* no need to retry for badch; will fail again */
975 if (supr_status
== TX_STATUS_SUPR_BADCH
||
976 supr_status
== TX_STATUS_SUPR_EXPTIME
) {
978 } else if (supr_status
== TX_STATUS_SUPR_EXPTIME
) {
980 * try tuning pre-loading or ampdu size
982 } else if (supr_status
== TX_STATUS_SUPR_FRAG
) {
984 * if there were underflows, but pre-loading
985 * is not active, notify rate adaptation.
987 if (brcms_c_ffpld_check_txfunfl(wlc
,
991 } else if (txs
->phyerr
) {
993 wiphy_err(wiphy
, "wl%d: ampdu tx phy "
994 "error (0x%x)\n", wlc
->pub
->unit
,
997 if (brcm_msg_level
& LOG_ERROR_VAL
) {
998 brcmu_prpkt("txpkt (AMPDU)", p
);
999 brcms_c_print_txdesc((struct d11txh
*) p
->data
);
1001 brcms_c_print_txstatus(txs
);
1005 /* loop through all pkts and retry if not acked */
1007 tx_info
= IEEE80211_SKB_CB(p
);
1008 txh
= (struct d11txh
*) p
->data
;
1009 mcl
= le16_to_cpu(txh
->MacTxControlLow
);
1010 plcp
= (u8
*) (txh
+ 1);
1011 h
= (struct ieee80211_hdr
*)(plcp
+ D11_PHY_HDR_LEN
);
1012 seq
= le16_to_cpu(h
->seq_ctrl
) >> SEQNUM_SHIFT
;
1014 if (tot_mpdu
== 0) {
1015 mcs
= plcp
[0] & MIMO_PLCP_MCS_MASK
;
1016 mimoantsel
= le16_to_cpu(txh
->ABI_MimoAntSel
);
1019 index
= TX_SEQ_TO_INDEX(seq
);
1022 bindex
= MODSUB_POW2(seq
, start_seq
, SEQNUM_MAX
);
1023 BCMMSG(wlc
->wiphy
, "tid %d seq %d,"
1024 " start_seq %d, bindex %d set %d, index %d\n",
1025 tid
, seq
, start_seq
, bindex
,
1026 isset(bitmap
, bindex
), index
);
1027 /* if acked then clear bit and free packet */
1028 if ((bindex
< AMPDU_TX_BA_MAX_WSIZE
)
1029 && isset(bitmap
, bindex
)) {
1030 ini
->tx_in_transit
--;
1031 ini
->txretry
[index
] = 0;
1035 * number of acked aggregated frames
1037 /* ampdu_len: number of aggregated frames */
1038 brcms_c_ampdu_rate_status(wlc
, tx_info
, txs
,
1040 tx_info
->flags
|= IEEE80211_TX_STAT_ACK
;
1041 tx_info
->flags
|= IEEE80211_TX_STAT_AMPDU
;
1042 tx_info
->status
.ampdu_ack_len
=
1043 tx_info
->status
.ampdu_len
= 1;
1045 skb_pull(p
, D11_PHY_HDR_LEN
);
1046 skb_pull(p
, D11_TXH_LEN
);
1048 ieee80211_tx_status_irqsafe(wlc
->pub
->ieee_hw
,
1054 /* either retransmit or send bar if ack not recd */
1056 struct ieee80211_tx_rate
*txrate
=
1057 tx_info
->status
.rates
;
1058 if (retry
&& (txrate
[0].count
< (int)retry_limit
)) {
1059 ini
->txretry
[index
]++;
1060 ini
->tx_in_transit
--;
1062 * Use high prededence for retransmit to
1065 /* brcms_c_txq_enq(wlc, scb, p,
1066 * BRCMS_PRIO_TO_PREC(tid)); */
1067 brcms_c_txq_enq(wlc
, scb
, p
,
1068 BRCMS_PRIO_TO_HI_PREC(tid
));
1071 ini
->tx_in_transit
--;
1072 ieee80211_tx_info_clear_status(tx_info
);
1073 tx_info
->status
.ampdu_ack_len
= 0;
1074 tx_info
->status
.ampdu_len
= 1;
1076 IEEE80211_TX_STAT_AMPDU_NO_BACK
;
1077 skb_pull(p
, D11_PHY_HDR_LEN
);
1078 skb_pull(p
, D11_TXH_LEN
);
1079 wiphy_err(wiphy
, "%s: BA Timeout, seq %d, in_"
1080 "transit %d\n", "AMPDU status", seq
,
1081 ini
->tx_in_transit
);
1082 ieee80211_tx_status_irqsafe(wlc
->pub
->ieee_hw
,
1088 /* break out if last packet of ampdu */
1089 if (((mcl
& TXC_AMPDU_MASK
) >> TXC_AMPDU_SHIFT
) ==
1093 p
= dma_getnexttxp(wlc
->hw
->di
[queue
], DMA_RANGE_TRANSMITTED
);
1095 brcms_c_send_q(wlc
);
1097 /* update rate state */
1098 antselid
= brcms_c_antsel_antsel2id(wlc
->asi
, mimoantsel
);
1100 brcms_c_txfifo_complete(wlc
, queue
, ampdu
->txpkt_weight
);
1104 brcms_c_ampdu_dotxstatus(struct ampdu_info
*ampdu
, struct scb
*scb
,
1105 struct sk_buff
*p
, struct tx_status
*txs
)
1107 struct scb_ampdu
*scb_ampdu
;
1108 struct brcms_c_info
*wlc
= ampdu
->wlc
;
1109 struct scb_ampdu_tid_ini
*ini
;
1111 struct ieee80211_tx_info
*tx_info
;
1113 tx_info
= IEEE80211_SKB_CB(p
);
1115 /* BMAC_NOTE: For the split driver, second level txstatus comes later
1116 * So if the ACK was received then wait for the second level else just
1117 * call the first one
1119 if (txs
->status
& TX_STATUS_ACK_RCV
) {
1120 u8 status_delay
= 0;
1122 /* wait till the next 8 bytes of txstatus is available */
1123 while (((s1
= R_REG(&wlc
->regs
->frmtxstatus
)) & TXS_V
) == 0) {
1126 if (status_delay
> 10)
1127 return; /* error condition */
1130 s2
= R_REG(&wlc
->regs
->frmtxstatus2
);
1134 scb_ampdu
= &scb
->scb_ampdu
;
1135 ini
= &scb_ampdu
->ini
[p
->priority
];
1136 brcms_c_ampdu_dotxstatus_complete(ampdu
, scb
, p
, txs
, s1
, s2
);
1138 /* loop through all pkts and free */
1139 u8 queue
= txs
->frameid
& TXFID_QUEUE_MASK
;
1143 tx_info
= IEEE80211_SKB_CB(p
);
1144 txh
= (struct d11txh
*) p
->data
;
1145 mcl
= le16_to_cpu(txh
->MacTxControlLow
);
1146 brcmu_pkt_buf_free_skb(p
);
1147 /* break out if last packet of ampdu */
1148 if (((mcl
& TXC_AMPDU_MASK
) >> TXC_AMPDU_SHIFT
) ==
1151 p
= dma_getnexttxp(wlc
->hw
->di
[queue
],
1152 DMA_RANGE_TRANSMITTED
);
1154 brcms_c_txfifo_complete(wlc
, queue
, ampdu
->txpkt_weight
);
1158 void brcms_c_ampdu_macaddr_upd(struct brcms_c_info
*wlc
)
1160 char template[T_RAM_ACCESS_SZ
* 2];
1162 /* driver needs to write the ta in the template; ta is at offset 16 */
1163 memset(template, 0, sizeof(template));
1164 memcpy(template, wlc
->pub
->cur_etheraddr
, ETH_ALEN
);
1165 brcms_b_write_template_ram(wlc
->hw
, (T_BA_TPL_BASE
+ 16),
1166 (T_RAM_ACCESS_SZ
* 2),
1170 bool brcms_c_aggregatable(struct brcms_c_info
*wlc
, u8 tid
)
1172 return wlc
->ampdu
->ini_enable
[tid
];
1175 void brcms_c_ampdu_shm_upd(struct ampdu_info
*ampdu
)
1177 struct brcms_c_info
*wlc
= ampdu
->wlc
;
1180 * Extend ucode internal watchdog timer to
1181 * match larger received frames
1183 if ((ampdu
->rx_factor
& IEEE80211_HT_AMPDU_PARM_FACTOR
) ==
1184 IEEE80211_HT_MAX_AMPDU_64K
) {
1185 brcms_b_write_shm(wlc
->hw
, M_MIMO_MAXSYM
, MIMO_MAXSYM_MAX
);
1186 brcms_b_write_shm(wlc
->hw
, M_WATCHDOG_8TU
, WATCHDOG_8TU_MAX
);
1188 brcms_b_write_shm(wlc
->hw
, M_MIMO_MAXSYM
, MIMO_MAXSYM_DEF
);
1189 brcms_b_write_shm(wlc
->hw
, M_WATCHDOG_8TU
, WATCHDOG_8TU_DEF
);
1194 * callback function that helps flushing ampdu packets from a priority queue
1196 static bool cb_del_ampdu_pkt(struct sk_buff
*mpdu
, void *arg_a
)
1198 struct ieee80211_tx_info
*tx_info
= IEEE80211_SKB_CB(mpdu
);
1199 struct cb_del_ampdu_pars
*ampdu_pars
=
1200 (struct cb_del_ampdu_pars
*)arg_a
;
1203 rc
= tx_info
->flags
& IEEE80211_TX_CTL_AMPDU
? true : false;
1204 rc
= rc
&& (tx_info
->control
.sta
== NULL
|| ampdu_pars
->sta
== NULL
||
1205 tx_info
->control
.sta
== ampdu_pars
->sta
);
1206 rc
= rc
&& ((u8
)(mpdu
->priority
) == ampdu_pars
->tid
);
1211 * callback function that helps invalidating ampdu packets in a DMA queue
1213 static void dma_cb_fn_ampdu(void *txi
, void *arg_a
)
1215 struct ieee80211_sta
*sta
= arg_a
;
1216 struct ieee80211_tx_info
*tx_info
= (struct ieee80211_tx_info
*)txi
;
1218 if ((tx_info
->flags
& IEEE80211_TX_CTL_AMPDU
) &&
1219 (tx_info
->control
.sta
== sta
|| sta
== NULL
))
1220 tx_info
->control
.sta
= NULL
;
1224 * When a remote party is no longer available for ampdu communication, any
1225 * pending tx ampdu packets in the driver have to be flushed.
1227 void brcms_c_ampdu_flush(struct brcms_c_info
*wlc
,
1228 struct ieee80211_sta
*sta
, u16 tid
)
1230 struct brcms_txq_info
*qi
= wlc
->pkt_queue
;
1231 struct pktq
*pq
= &qi
->q
;
1233 struct cb_del_ampdu_pars ampdu_pars
;
1235 ampdu_pars
.sta
= sta
;
1236 ampdu_pars
.tid
= tid
;
1237 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
1238 brcmu_pktq_pflush(pq
, prec
, true, cb_del_ampdu_pkt
,
1239 (void *)&du_pars
);
1240 brcms_c_inval_dma_pkts(wlc
->hw
, sta
, dma_cb_fn_ampdu
);