~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2010 Broadcom Corporation
 
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 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.
 
15
 */
 
16
#include <linux/kernel.h>
 
17
#include <net/mac80211.h>
 
18
 
 
19
#include <bcmdefs.h>
 
20
#include <bcmutils.h>
 
21
#include <aiutils.h>
 
22
#include <wlioctl.h>
 
23
#include <sbhnddma.h>
 
24
#include <hnddma.h>
 
25
#include <d11.h>
 
26
 
 
27
#include "wlc_types.h"
 
28
#include "wlc_cfg.h"
 
29
#include "wlc_rate.h"
 
30
#include "wlc_scb.h"
 
31
#include "wlc_pub.h"
 
32
#include "wlc_key.h"
 
33
#include "phy/wlc_phy_hal.h"
 
34
#include "wlc_antsel.h"
 
35
#include "wl_export.h"
 
36
#include "wl_dbg.h"
 
37
#include "wlc_channel.h"
 
38
#include "wlc_main.h"
 
39
#include "wlc_ampdu.h"
 
40
 
 
41
#define AMPDU_MAX_MPDU          32      /* max number of mpdus in an ampdu */
 
42
#define AMPDU_NUM_MPDU_LEGACY   16      /* max number of mpdus in an ampdu to a legacy */
 
43
#define AMPDU_TX_BA_MAX_WSIZE   64      /* max Tx ba window size (in pdu) */
 
44
#define AMPDU_TX_BA_DEF_WSIZE   64      /* default Tx ba window size (in pdu) */
 
45
#define AMPDU_RX_BA_DEF_WSIZE   64      /* max Rx ba window size (in pdu) */
 
46
#define AMPDU_RX_BA_MAX_WSIZE   64      /* default Rx ba window size (in pdu) */
 
47
#define AMPDU_MAX_DUR           5       /* max dur of tx ampdu (in msec) */
 
48
#define AMPDU_DEF_RETRY_LIMIT   5       /* default tx retry limit */
 
49
#define AMPDU_DEF_RR_RETRY_LIMIT        2       /* default tx retry limit at reg rate */
 
50
#define AMPDU_DEF_TXPKT_WEIGHT  2       /* default weight of ampdu in txfifo */
 
51
#define AMPDU_DEF_FFPLD_RSVD    2048    /* default ffpld reserved bytes */
 
52
#define AMPDU_INI_FREE          10      /* # of inis to be freed on detach */
 
53
#define AMPDU_SCB_MAX_RELEASE   20      /* max # of mpdus released at a time */
 
54
 
 
55
#define NUM_FFPLD_FIFO 4        /* number of fifo concerned by pre-loading */
 
56
#define FFPLD_TX_MAX_UNFL   200 /* default value of the average number of ampdu
 
57
                                 * without underflows
 
58
                                 */
 
59
#define FFPLD_MPDU_SIZE 1800    /* estimate of maximum mpdu size */
 
60
#define FFPLD_MAX_MCS 23        /* we don't deal with mcs 32 */
 
61
#define FFPLD_PLD_INCR 1000     /* increments in bytes */
 
62
#define FFPLD_MAX_AMPDU_CNT 5000        /* maximum number of ampdu we
 
63
                                         * accumulate between resets.
 
64
                                         */
 
65
 
 
66
#define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
 
67
 
 
68
/* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
 
69
#define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\
 
70
        AMPDU_DELIMITER_LEN + 3\
 
71
        + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
 
72
 
 
73
/* structure to hold tx fifo information and pre-loading state
 
74
 * counters specific to tx underflows of ampdus
 
75
 * some counters might be redundant with the ones in wlc or ampdu structures.
 
76
 * This allows to maintain a specific state independently of
 
77
 * how often and/or when the wlc counters are updated.
 
78
 */
 
79
typedef struct wlc_fifo_info {
 
80
        u16 ampdu_pld_size;     /* number of bytes to be pre-loaded */
 
81
        u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1];  /* per-mcs max # of mpdus in an ampdu */
 
82
        u16 prev_txfunfl;       /* num of underflows last read from the HW macstats counter */
 
83
        u32 accum_txfunfl;      /* num of underflows since we modified pld params */
 
84
        u32 accum_txampdu;      /* num of tx ampdu since we modified pld params  */
 
85
        u32 prev_txampdu;       /* previous reading of tx ampdu */
 
86
        u32 dmaxferrate;        /* estimated dma avg xfer rate in kbits/sec */
 
87
} wlc_fifo_info_t;
 
88
 
 
89
/* AMPDU module specific state */
 
90
struct ampdu_info {
 
91
        struct wlc_info *wlc;   /* pointer to main wlc structure */
 
92
        int scb_handle;         /* scb cubby handle to retrieve data from scb */
 
93
        u8 ini_enable[AMPDU_MAX_SCB_TID];       /* per-tid initiator enable/disable of ampdu */
 
94
        u8 ba_tx_wsize; /* Tx ba window size (in pdu) */
 
95
        u8 ba_rx_wsize; /* Rx ba window size (in pdu) */
 
96
        u8 retry_limit; /* mpdu transmit retry limit */
 
97
        u8 rr_retry_limit;      /* mpdu transmit retry limit at regular rate */
 
98
        u8 retry_limit_tid[AMPDU_MAX_SCB_TID];  /* per-tid mpdu transmit retry limit */
 
99
        /* per-tid mpdu transmit retry limit at regular rate */
 
100
        u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID];
 
101
        u8 mpdu_density;        /* min mpdu spacing (0-7) ==> 2^(x-1)/8 usec */
 
102
        s8 max_pdu;             /* max pdus allowed in ampdu */
 
103
        u8 dur;         /* max duration of an ampdu (in msec) */
 
104
        u8 txpkt_weight;        /* weight of ampdu in txfifo; reduces rate lag */
 
105
        u8 rx_factor;   /* maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes */
 
106
        u32 ffpld_rsvd; /* number of bytes to reserve for preload */
 
107
        u32 max_txlen[MCS_TABLE_SIZE][2][2];    /* max size of ampdu per mcs, bw and sgi */
 
108
        void *ini_free[AMPDU_INI_FREE]; /* array of ini's to be freed on detach */
 
109
        bool mfbr;              /* enable multiple fallback rate */
 
110
        u32 tx_max_funl;        /* underflows should be kept such that
 
111
                                 * (tx_max_funfl*underflows) < tx frames
 
112
                                 */
 
113
        wlc_fifo_info_t fifo_tb[NUM_FFPLD_FIFO];        /* table of fifo infos  */
 
114
 
 
115
};
 
116
 
 
117
/* used for flushing ampdu packets */
 
118
struct cb_del_ampdu_pars {
 
119
        struct ieee80211_sta *sta;
 
120
        u16 tid;
 
121
};
 
122
 
 
123
#define AMPDU_CLEANUPFLAG_RX   (0x1)
 
124
#define AMPDU_CLEANUPFLAG_TX   (0x2)
 
125
 
 
126
#define SCB_AMPDU_CUBBY(ampdu, scb) (&(scb->scb_ampdu))
 
127
#define SCB_AMPDU_INI(scb_ampdu, tid) (&(scb_ampdu->ini[tid]))
 
128
 
 
129
static void wlc_ffpld_init(struct ampdu_info *ampdu);
 
130
static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int f);
 
131
static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f);
 
132
 
 
133
static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
 
134
                                                   scb_ampdu_t *scb_ampdu,
 
135
                                                   u8 tid, bool override);
 
136
static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur);
 
137
static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb);
 
138
static void scb_ampdu_update_config_all(struct ampdu_info *ampdu);
 
139
 
 
140
#define wlc_ampdu_txflowcontrol(a, b, c)        do {} while (0)
 
141
 
 
142
static void wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu,
 
143
                                          struct scb *scb,
 
144
                                          struct sk_buff *p, tx_status_t *txs,
 
145
                                          u32 frmtxstatus, u32 frmtxstatus2);
 
146
static bool wlc_ampdu_cap(struct ampdu_info *ampdu);
 
147
static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on);
 
148
 
 
149
struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc)
 
150
{
 
151
        struct ampdu_info *ampdu;
 
152
        int i;
 
153
 
 
154
        ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
 
155
        if (!ampdu) {
 
156
                wiphy_err(wlc->wiphy, "wl%d: wlc_ampdu_attach: out of mem\n",
 
157
                          wlc->pub->unit);
 
158
                return NULL;
 
159
        }
 
160
        ampdu->wlc = wlc;
 
161
 
 
162
        for (i = 0; i < AMPDU_MAX_SCB_TID; i++)
 
163
                ampdu->ini_enable[i] = true;
 
164
        /* Disable ampdu for VO by default */
 
165
        ampdu->ini_enable[PRIO_8021D_VO] = false;
 
166
        ampdu->ini_enable[PRIO_8021D_NC] = false;
 
167
 
 
168
        /* Disable ampdu for BK by default since not enough fifo space */
 
169
        ampdu->ini_enable[PRIO_8021D_NONE] = false;
 
170
        ampdu->ini_enable[PRIO_8021D_BK] = false;
 
171
 
 
172
        ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE;
 
173
        ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE;
 
174
        ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
 
175
        ampdu->max_pdu = AUTO;
 
176
        ampdu->dur = AMPDU_MAX_DUR;
 
177
        ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT;
 
178
 
 
179
        ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
 
180
        /* bump max ampdu rcv size to 64k for all 11n devices except 4321A0 and 4321A1 */
 
181
        if (WLCISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2))
 
182
                ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_32K;
 
183
        else
 
184
                ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_64K;
 
185
        ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT;
 
186
        ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT;
 
187
 
 
188
        for (i = 0; i < AMPDU_MAX_SCB_TID; i++) {
 
189
                ampdu->retry_limit_tid[i] = ampdu->retry_limit;
 
190
                ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit;
 
191
        }
 
192
 
 
193
        ampdu_update_max_txlen(ampdu, ampdu->dur);
 
194
        ampdu->mfbr = false;
 
195
        /* try to set ampdu to the default value */
 
196
        wlc_ampdu_set(ampdu, wlc->pub->_ampdu);
 
197
 
 
198
        ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL;
 
199
        wlc_ffpld_init(ampdu);
 
200
 
 
201
        return ampdu;
 
202
}
 
203
 
 
204
void wlc_ampdu_detach(struct ampdu_info *ampdu)
 
205
{
 
206
        int i;
 
207
 
 
208
        if (!ampdu)
 
209
                return;
 
210
 
 
211
        /* free all ini's which were to be freed on callbacks which were never called */
 
212
        for (i = 0; i < AMPDU_INI_FREE; i++) {
 
213
                kfree(ampdu->ini_free[i]);
 
214
        }
 
215
 
 
216
        wlc_module_unregister(ampdu->wlc->pub, "ampdu", ampdu);
 
217
        kfree(ampdu);
 
218
}
 
219
 
 
220
static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb)
 
221
{
 
222
        scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
 
223
        int i;
 
224
 
 
225
        scb_ampdu->max_pdu = (u8) ampdu->wlc->pub->tunables->ampdunummpdu;
 
226
 
 
227
        /* go back to legacy size if some preloading is occurring */
 
228
        for (i = 0; i < NUM_FFPLD_FIFO; i++) {
 
229
                if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR)
 
230
                        scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY;
 
231
        }
 
232
 
 
233
        /* apply user override */
 
234
        if (ampdu->max_pdu != AUTO)
 
235
                scb_ampdu->max_pdu = (u8) ampdu->max_pdu;
 
236
 
 
237
        scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu, AMPDU_SCB_MAX_RELEASE);
 
238
 
 
239
        if (scb_ampdu->max_rxlen)
 
240
                scb_ampdu->release =
 
241
                    min_t(u8, scb_ampdu->release, scb_ampdu->max_rxlen / 1600);
 
242
 
 
243
        scb_ampdu->release = min(scb_ampdu->release,
 
244
                                 ampdu->fifo_tb[TX_AC_BE_FIFO].
 
245
                                 mcs2ampdu_table[FFPLD_MAX_MCS]);
 
246
}
 
247
 
 
248
static void scb_ampdu_update_config_all(struct ampdu_info *ampdu)
 
249
{
 
250
        scb_ampdu_update_config(ampdu, ampdu->wlc->pub->global_scb);
 
251
}
 
252
 
 
253
static void wlc_ffpld_init(struct ampdu_info *ampdu)
 
254
{
 
255
        int i, j;
 
256
        wlc_fifo_info_t *fifo;
 
257
 
 
258
        for (j = 0; j < NUM_FFPLD_FIFO; j++) {
 
259
                fifo = (ampdu->fifo_tb + j);
 
260
                fifo->ampdu_pld_size = 0;
 
261
                for (i = 0; i <= FFPLD_MAX_MCS; i++)
 
262
                        fifo->mcs2ampdu_table[i] = 255;
 
263
                fifo->dmaxferrate = 0;
 
264
                fifo->accum_txampdu = 0;
 
265
                fifo->prev_txfunfl = 0;
 
266
                fifo->accum_txfunfl = 0;
 
267
 
 
268
        }
 
269
}
 
270
 
 
271
/* evaluate the dma transfer rate using the tx underflows as feedback.
 
272
 * If necessary, increase tx fifo preloading. If not enough,
 
273
 * decrease maximum ampdu size for each mcs till underflows stop
 
274
 * Return 1 if pre-loading not active, -1 if not an underflow event,
 
275
 * 0 if pre-loading module took care of the event.
 
276
 */
 
277
static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid)
 
278
{
 
279
        struct ampdu_info *ampdu = wlc->ampdu;
 
280
        u32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
 
281
        u32 txunfl_ratio;
 
282
        u8 max_mpdu;
 
283
        u32 current_ampdu_cnt = 0;
 
284
        u16 max_pld_size;
 
285
        u32 new_txunfl;
 
286
        wlc_fifo_info_t *fifo = (ampdu->fifo_tb + fid);
 
287
        uint xmtfifo_sz;
 
288
        u16 cur_txunfl;
 
289
 
 
290
        /* return if we got here for a different reason than underflows */
 
291
        cur_txunfl =
 
292
            wlc_read_shm(wlc,
 
293
                         M_UCODE_MACSTAT + offsetof(macstat_t, txfunfl[fid]));
 
294
        new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
 
295
        if (new_txunfl == 0) {
 
296
                BCMMSG(wlc->wiphy, "TX status FRAG set but no tx underflows\n");
 
297
                return -1;
 
298
        }
 
299
        fifo->prev_txfunfl = cur_txunfl;
 
300
 
 
301
        if (!ampdu->tx_max_funl)
 
302
                return 1;
 
303
 
 
304
        /* check if fifo is big enough */
 
305
        if (wlc_xmtfifo_sz_get(wlc, fid, &xmtfifo_sz)) {
 
306
                return -1;
 
307
        }
 
308
 
 
309
        if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd)
 
310
                return 1;
 
311
 
 
312
        max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd;
 
313
        fifo->accum_txfunfl += new_txunfl;
 
314
 
 
315
        /* we need to wait for at least 10 underflows */
 
316
        if (fifo->accum_txfunfl < 10)
 
317
                return 0;
 
318
 
 
319
        BCMMSG(wlc->wiphy, "ampdu_count %d  tx_underflows %d\n",
 
320
                current_ampdu_cnt, fifo->accum_txfunfl);
 
321
 
 
322
        /*
 
323
           compute the current ratio of tx unfl per ampdu.
 
324
           When the current ampdu count becomes too
 
325
           big while the ratio remains small, we reset
 
326
           the current count in order to not
 
327
           introduce too big of a latency in detecting a
 
328
           large amount of tx underflows later.
 
329
         */
 
330
 
 
331
        txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl;
 
332
 
 
333
        if (txunfl_ratio > ampdu->tx_max_funl) {
 
334
                if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT) {
 
335
                        fifo->accum_txfunfl = 0;
 
336
                }
 
337
                return 0;
 
338
        }
 
339
        max_mpdu =
 
340
            min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
 
341
 
 
342
        /* In case max value max_pdu is already lower than
 
343
           the fifo depth, there is nothing more we can do.
 
344
         */
 
345
 
 
346
        if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) {
 
347
                fifo->accum_txfunfl = 0;
 
348
                return 0;
 
349
        }
 
350
 
 
351
        if (fifo->ampdu_pld_size < max_pld_size) {
 
352
 
 
353
                /* increment by TX_FIFO_PLD_INC bytes */
 
354
                fifo->ampdu_pld_size += FFPLD_PLD_INCR;
 
355
                if (fifo->ampdu_pld_size > max_pld_size)
 
356
                        fifo->ampdu_pld_size = max_pld_size;
 
357
 
 
358
                /* update scb release size */
 
359
                scb_ampdu_update_config_all(ampdu);
 
360
 
 
361
                /*
 
362
                   compute a new dma xfer rate for max_mpdu @ max mcs.
 
363
                   This is the minimum dma rate that
 
364
                   can achieve no underflow condition for the current mpdu size.
 
365
                 */
 
366
                /* note : we divide/multiply by 100 to avoid integer overflows */
 
367
                fifo->dmaxferrate =
 
368
                    (((phy_rate / 100) *
 
369
                      (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
 
370
                     / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
 
371
 
 
372
                BCMMSG(wlc->wiphy, "DMA estimated transfer rate %d; "
 
373
                        "pre-load size %d\n",
 
374
                        fifo->dmaxferrate, fifo->ampdu_pld_size);
 
375
        } else {
 
376
 
 
377
                /* decrease ampdu size */
 
378
                if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) {
 
379
                        if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255)
 
380
                                fifo->mcs2ampdu_table[FFPLD_MAX_MCS] =
 
381
                                    AMPDU_NUM_MPDU_LEGACY - 1;
 
382
                        else
 
383
                                fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1;
 
384
 
 
385
                        /* recompute the table */
 
386
                        wlc_ffpld_calc_mcs2ampdu_table(ampdu, fid);
 
387
 
 
388
                        /* update scb release size */
 
389
                        scb_ampdu_update_config_all(ampdu);
 
390
                }
 
391
        }
 
392
        fifo->accum_txfunfl = 0;
 
393
        return 0;
 
394
}
 
395
 
 
396
static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
 
397
{
 
398
        int i;
 
399
        u32 phy_rate, dma_rate, tmp;
 
400
        u8 max_mpdu;
 
401
        wlc_fifo_info_t *fifo = (ampdu->fifo_tb + f);
 
402
 
 
403
        /* recompute the dma rate */
 
404
        /* note : we divide/multiply by 100 to avoid integer overflows */
 
405
        max_mpdu =
 
406
            min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
 
407
        phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
 
408
        dma_rate =
 
409
            (((phy_rate / 100) *
 
410
              (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
 
411
             / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
 
412
        fifo->dmaxferrate = dma_rate;
 
413
 
 
414
        /* fill up the mcs2ampdu table; do not recalc the last mcs */
 
415
        dma_rate = dma_rate >> 7;
 
416
        for (i = 0; i < FFPLD_MAX_MCS; i++) {
 
417
                /* shifting to keep it within integer range */
 
418
                phy_rate = MCS_RATE(i, true, false) >> 7;
 
419
                if (phy_rate > dma_rate) {
 
420
                        tmp = ((fifo->ampdu_pld_size * phy_rate) /
 
421
                               ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
 
422
                        tmp = min_t(u32, tmp, 255);
 
423
                        fifo->mcs2ampdu_table[i] = (u8) tmp;
 
424
                }
 
425
        }
 
426
}
 
427
 
 
428
static void
 
429
wlc_ampdu_agg(struct ampdu_info *ampdu, struct scb *scb, struct sk_buff *p,
 
430
              uint prec)
 
431
{
 
432
        scb_ampdu_t *scb_ampdu;
 
433
        scb_ampdu_tid_ini_t *ini;
 
434
        u8 tid = (u8) (p->priority);
 
435
 
 
436
        scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
 
437
 
 
438
        /* initialize initiator on first packet; sends addba req */
 
439
        ini = SCB_AMPDU_INI(scb_ampdu, tid);
 
440
        if (ini->magic != INI_MAGIC) {
 
441
                ini = wlc_ampdu_init_tid_ini(ampdu, scb_ampdu, tid, false);
 
442
        }
 
443
        return;
 
444
}
 
445
 
 
446
int
 
447
wlc_sendampdu(struct ampdu_info *ampdu, struct wlc_txq_info *qi,
 
448
              struct sk_buff **pdu, int prec)
 
449
{
 
450
        struct wlc_info *wlc;
 
451
        struct sk_buff *p, *pkt[AMPDU_MAX_MPDU];
 
452
        u8 tid, ndelim;
 
453
        int err = 0;
 
454
        u8 preamble_type = WLC_GF_PREAMBLE;
 
455
        u8 fbr_preamble_type = WLC_GF_PREAMBLE;
 
456
        u8 rts_preamble_type = WLC_LONG_PREAMBLE;
 
457
        u8 rts_fbr_preamble_type = WLC_LONG_PREAMBLE;
 
458
 
 
459
        bool rr = true, fbr = false;
 
460
        uint i, count = 0, fifo, seg_cnt = 0;
 
461
        u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0;
 
462
        u32 ampdu_len, maxlen = 0;
 
463
        d11txh_t *txh = NULL;
 
464
        u8 *plcp;
 
465
        struct ieee80211_hdr *h;
 
466
        struct scb *scb;
 
467
        scb_ampdu_t *scb_ampdu;
 
468
        scb_ampdu_tid_ini_t *ini;
 
469
        u8 mcs = 0;
 
470
        bool use_rts = false, use_cts = false;
 
471
        ratespec_t rspec = 0, rspec_fallback = 0;
 
472
        ratespec_t rts_rspec = 0, rts_rspec_fallback = 0;
 
473
        u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
 
474
        struct ieee80211_rts *rts;
 
475
        u8 rr_retry_limit;
 
476
        wlc_fifo_info_t *f;
 
477
        bool fbr_iscck;
 
478
        struct ieee80211_tx_info *tx_info;
 
479
        u16 qlen;
 
480
        struct wiphy *wiphy;
 
481
 
 
482
        wlc = ampdu->wlc;
 
483
        wiphy = wlc->wiphy;
 
484
        p = *pdu;
 
485
 
 
486
        tid = (u8) (p->priority);
 
487
 
 
488
        f = ampdu->fifo_tb + prio2fifo[tid];
 
489
 
 
490
        scb = wlc->pub->global_scb;
 
491
        scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
 
492
        ini = &scb_ampdu->ini[tid];
 
493
 
 
494
        /* Let pressure continue to build ... */
 
495
        qlen = pktq_plen(&qi->q, prec);
 
496
        if (ini->tx_in_transit > 0 && qlen < scb_ampdu->max_pdu) {
 
497
                return -EBUSY;
 
498
        }
 
499
 
 
500
        wlc_ampdu_agg(ampdu, scb, p, tid);
 
501
 
 
502
        if (wlc->block_datafifo) {
 
503
                wiphy_err(wiphy, "%s: Fifo blocked\n", __func__);
 
504
                return -EBUSY;
 
505
        }
 
506
        rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
 
507
        ampdu_len = 0;
 
508
        dma_len = 0;
 
509
        while (p) {
 
510
                struct ieee80211_tx_rate *txrate;
 
511
 
 
512
                tx_info = IEEE80211_SKB_CB(p);
 
513
                txrate = tx_info->status.rates;
 
514
 
 
515
                if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
 
516
                        err = wlc_prep_pdu(wlc, p, &fifo);
 
517
                } else {
 
518
                        wiphy_err(wiphy, "%s: AMPDU flag is off!\n", __func__);
 
519
                        *pdu = NULL;
 
520
                        err = 0;
 
521
                        break;
 
522
                }
 
523
 
 
524
                if (err) {
 
525
                        if (err == -EBUSY) {
 
526
                                wiphy_err(wiphy, "wl%d: wlc_sendampdu: "
 
527
                                          "prep_xdu retry; seq 0x%x\n",
 
528
                                          wlc->pub->unit, seq);
 
529
                                *pdu = p;
 
530
                                break;
 
531
                        }
 
532
 
 
533
                        /* error in the packet; reject it */
 
534
                        wiphy_err(wiphy, "wl%d: wlc_sendampdu: prep_xdu "
 
535
                                  "rejected; seq 0x%x\n", wlc->pub->unit, seq);
 
536
                        *pdu = NULL;
 
537
                        break;
 
538
                }
 
539
 
 
540
                /* pkt is good to be aggregated */
 
541
                txh = (d11txh_t *) p->data;
 
542
                plcp = (u8 *) (txh + 1);
 
543
                h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
 
544
                seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
 
545
                index = TX_SEQ_TO_INDEX(seq);
 
546
 
 
547
                /* check mcl fields and test whether it can be agg'd */
 
548
                mcl = le16_to_cpu(txh->MacTxControlLow);
 
549
                mcl &= ~TXC_AMPDU_MASK;
 
550
                fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3);
 
551
                txh->PreloadSize = 0;   /* always default to 0 */
 
552
 
 
553
                /*  Handle retry limits */
 
554
                if (txrate[0].count <= rr_retry_limit) {
 
555
                        txrate[0].count++;
 
556
                        rr = true;
 
557
                        fbr = false;
 
558
                } else {
 
559
                        fbr = true;
 
560
                        rr = false;
 
561
                        txrate[1].count++;
 
562
                }
 
563
 
 
564
                /* extract the length info */
 
565
                len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
 
566
                    : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
 
567
 
 
568
                /* retrieve null delimiter count */
 
569
                ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
 
570
                seg_cnt += 1;
 
571
 
 
572
                BCMMSG(wlc->wiphy, "wl%d: mpdu %d plcp_len %d\n",
 
573
                        wlc->pub->unit, count, len);
 
574
 
 
575
                /*
 
576
                 * aggregateable mpdu. For ucode/hw agg,
 
577
                 * test whether need to break or change the epoch
 
578
                 */
 
579
                if (count == 0) {
 
580
                        mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
 
581
                        /* refill the bits since might be a retx mpdu */
 
582
                        mcl |= TXC_STARTMSDU;
 
583
                        rts = (struct ieee80211_rts *)&txh->rts_frame;
 
584
 
 
585
                        if (ieee80211_is_rts(rts->frame_control)) {
 
586
                                mcl |= TXC_SENDRTS;
 
587
                                use_rts = true;
 
588
                        }
 
589
                        if (ieee80211_is_cts(rts->frame_control)) {
 
590
                                mcl |= TXC_SENDCTS;
 
591
                                use_cts = true;
 
592
                        }
 
593
                } else {
 
594
                        mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
 
595
                        mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
 
596
                }
 
597
 
 
598
                len = roundup(len, 4);
 
599
                ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
 
600
 
 
601
                dma_len += (u16) bcm_pkttotlen(p);
 
602
 
 
603
                BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d"
 
604
                        " seg_cnt %d null delim %d\n",
 
605
                        wlc->pub->unit, ampdu_len, seg_cnt, ndelim);
 
606
 
 
607
                txh->MacTxControlLow = cpu_to_le16(mcl);
 
608
 
 
609
                /* this packet is added */
 
610
                pkt[count++] = p;
 
611
 
 
612
                /* patch the first MPDU */
 
613
                if (count == 1) {
 
614
                        u8 plcp0, plcp3, is40, sgi;
 
615
                        struct ieee80211_sta *sta;
 
616
 
 
617
                        sta = tx_info->control.sta;
 
618
 
 
619
                        if (rr) {
 
620
                                plcp0 = plcp[0];
 
621
                                plcp3 = plcp[3];
 
622
                        } else {
 
623
                                plcp0 = txh->FragPLCPFallback[0];
 
624
                                plcp3 = txh->FragPLCPFallback[3];
 
625
 
 
626
                        }
 
627
                        is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
 
628
                        sgi = PLCP3_ISSGI(plcp3) ? 1 : 0;
 
629
                        mcs = plcp0 & ~MIMO_PLCP_40MHZ;
 
630
                        maxlen =
 
631
                            min(scb_ampdu->max_rxlen,
 
632
                                ampdu->max_txlen[mcs][is40][sgi]);
 
633
 
 
634
                        /* XXX Fix me to honor real max_rxlen */
 
635
                        /* can fix this as soon as ampdu_action() in mac80211.h
 
636
                         * gets extra u8buf_size par */
 
637
                        maxlen = 64 * 1024;
 
638
 
 
639
                        if (is40)
 
640
                                mimo_ctlchbw =
 
641
                                    CHSPEC_SB_UPPER(WLC_BAND_PI_RADIO_CHANSPEC)
 
642
                                    ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
 
643
 
 
644
                        /* rebuild the rspec and rspec_fallback */
 
645
                        rspec = RSPEC_MIMORATE;
 
646
                        rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
 
647
                        if (plcp[0] & MIMO_PLCP_40MHZ)
 
648
                                rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
 
649
 
 
650
                        if (fbr_iscck)  /* CCK */
 
651
                                rspec_fallback =
 
652
                                    CCK_RSPEC(CCK_PHY2MAC_RATE
 
653
                                              (txh->FragPLCPFallback[0]));
 
654
                        else {  /* MIMO */
 
655
                                rspec_fallback = RSPEC_MIMORATE;
 
656
                                rspec_fallback |=
 
657
                                    txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
 
658
                                if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
 
659
                                        rspec_fallback |=
 
660
                                            (PHY_TXC1_BW_40MHZ <<
 
661
                                             RSPEC_BW_SHIFT);
 
662
                        }
 
663
 
 
664
                        if (use_rts || use_cts) {
 
665
                                rts_rspec =
 
666
                                    wlc_rspec_to_rts_rspec(wlc, rspec, false,
 
667
                                                           mimo_ctlchbw);
 
668
                                rts_rspec_fallback =
 
669
                                    wlc_rspec_to_rts_rspec(wlc, rspec_fallback,
 
670
                                                           false, mimo_ctlchbw);
 
671
                        }
 
672
                }
 
673
 
 
674
                /* if (first mpdu for host agg) */
 
675
                /* test whether to add more */
 
676
                if ((MCS_RATE(mcs, true, false) >= f->dmaxferrate) &&
 
677
                    (count == f->mcs2ampdu_table[mcs])) {
 
678
                        BCMMSG(wlc->wiphy, "wl%d: PR 37644: stopping"
 
679
                                " ampdu at %d for mcs %d\n",
 
680
                                wlc->pub->unit, count, mcs);
 
681
                        break;
 
682
                }
 
683
 
 
684
                if (count == scb_ampdu->max_pdu) {
 
685
                        break;
 
686
                }
 
687
 
 
688
                /* check to see if the next pkt is a candidate for aggregation */
 
689
                p = pktq_ppeek(&qi->q, prec);
 
690
                tx_info = IEEE80211_SKB_CB(p);  /* tx_info must be checked with current p */
 
691
 
 
692
                if (p) {
 
693
                        if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
 
694
                            ((u8) (p->priority) == tid)) {
 
695
 
 
696
                                plen =
 
697
                                    bcm_pkttotlen(p) + AMPDU_MAX_MPDU_OVERHEAD;
 
698
                                plen = max(scb_ampdu->min_len, plen);
 
699
 
 
700
                                if ((plen + ampdu_len) > maxlen) {
 
701
                                        p = NULL;
 
702
                                        wiphy_err(wiphy, "%s: Bogus plen #1\n",
 
703
                                                __func__);
 
704
                                        continue;
 
705
                                }
 
706
 
 
707
                                /* check if there are enough descriptors available */
 
708
                                if (TXAVAIL(wlc, fifo) <= (seg_cnt + 1)) {
 
709
                                        wiphy_err(wiphy, "%s: No fifo space  "
 
710
                                                  "!!\n", __func__);
 
711
                                        p = NULL;
 
712
                                        continue;
 
713
                                }
 
714
                                p = bcm_pktq_pdeq(&qi->q, prec);
 
715
                        } else {
 
716
                                p = NULL;
 
717
                        }
 
718
                }
 
719
        }                       /* end while(p) */
 
720
 
 
721
        ini->tx_in_transit += count;
 
722
 
 
723
        if (count) {
 
724
                /* patch up the last txh */
 
725
                txh = (d11txh_t *) pkt[count - 1]->data;
 
726
                mcl = le16_to_cpu(txh->MacTxControlLow);
 
727
                mcl &= ~TXC_AMPDU_MASK;
 
728
                mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
 
729
                txh->MacTxControlLow = cpu_to_le16(mcl);
 
730
 
 
731
                /* remove the null delimiter after last mpdu */
 
732
                ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
 
733
                txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
 
734
                ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
 
735
 
 
736
                /* remove the pad len from last mpdu */
 
737
                fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
 
738
                len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
 
739
                    : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
 
740
                ampdu_len -= roundup(len, 4) - len;
 
741
 
 
742
                /* patch up the first txh & plcp */
 
743
                txh = (d11txh_t *) pkt[0]->data;
 
744
                plcp = (u8 *) (txh + 1);
 
745
 
 
746
                WLC_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
 
747
                /* mark plcp to indicate ampdu */
 
748
                WLC_SET_MIMO_PLCP_AMPDU(plcp);
 
749
 
 
750
                /* reset the mixed mode header durations */
 
751
                if (txh->MModeLen) {
 
752
                        u16 mmodelen =
 
753
                            wlc_calc_lsig_len(wlc, rspec, ampdu_len);
 
754
                        txh->MModeLen = cpu_to_le16(mmodelen);
 
755
                        preamble_type = WLC_MM_PREAMBLE;
 
756
                }
 
757
                if (txh->MModeFbrLen) {
 
758
                        u16 mmfbrlen =
 
759
                            wlc_calc_lsig_len(wlc, rspec_fallback, ampdu_len);
 
760
                        txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
 
761
                        fbr_preamble_type = WLC_MM_PREAMBLE;
 
762
                }
 
763
 
 
764
                /* set the preload length */
 
765
                if (MCS_RATE(mcs, true, false) >= f->dmaxferrate) {
 
766
                        dma_len = min(dma_len, f->ampdu_pld_size);
 
767
                        txh->PreloadSize = cpu_to_le16(dma_len);
 
768
                } else
 
769
                        txh->PreloadSize = 0;
 
770
 
 
771
                mch = le16_to_cpu(txh->MacTxControlHigh);
 
772
 
 
773
                /* update RTS dur fields */
 
774
                if (use_rts || use_cts) {
 
775
                        u16 durid;
 
776
                        rts = (struct ieee80211_rts *)&txh->rts_frame;
 
777
                        if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
 
778
                            TXC_PREAMBLE_RTS_MAIN_SHORT)
 
779
                                rts_preamble_type = WLC_SHORT_PREAMBLE;
 
780
 
 
781
                        if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
 
782
                            TXC_PREAMBLE_RTS_FB_SHORT)
 
783
                                rts_fbr_preamble_type = WLC_SHORT_PREAMBLE;
 
784
 
 
785
                        durid =
 
786
                            wlc_compute_rtscts_dur(wlc, use_cts, rts_rspec,
 
787
                                                   rspec, rts_preamble_type,
 
788
                                                   preamble_type, ampdu_len,
 
789
                                                   true);
 
790
                        rts->duration = cpu_to_le16(durid);
 
791
                        durid = wlc_compute_rtscts_dur(wlc, use_cts,
 
792
                                                       rts_rspec_fallback,
 
793
                                                       rspec_fallback,
 
794
                                                       rts_fbr_preamble_type,
 
795
                                                       fbr_preamble_type,
 
796
                                                       ampdu_len, true);
 
797
                        txh->RTSDurFallback = cpu_to_le16(durid);
 
798
                        /* set TxFesTimeNormal */
 
799
                        txh->TxFesTimeNormal = rts->duration;
 
800
                        /* set fallback rate version of TxFesTimeNormal */
 
801
                        txh->TxFesTimeFallback = txh->RTSDurFallback;
 
802
                }
 
803
 
 
804
                /* set flag and plcp for fallback rate */
 
805
                if (fbr) {
 
806
                        mch |= TXC_AMPDU_FBR;
 
807
                        txh->MacTxControlHigh = cpu_to_le16(mch);
 
808
                        WLC_SET_MIMO_PLCP_AMPDU(plcp);
 
809
                        WLC_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
 
810
                }
 
811
 
 
812
                BCMMSG(wlc->wiphy, "wl%d: count %d ampdu_len %d\n",
 
813
                        wlc->pub->unit, count, ampdu_len);
 
814
 
 
815
                /* inform rate_sel if it this is a rate probe pkt */
 
816
                frameid = le16_to_cpu(txh->TxFrameID);
 
817
                if (frameid & TXFID_RATE_PROBE_MASK) {
 
818
                        wiphy_err(wiphy, "%s: XXX what to do with "
 
819
                                  "TXFID_RATE_PROBE_MASK!?\n", __func__);
 
820
                }
 
821
                for (i = 0; i < count; i++)
 
822
                        wlc_txfifo(wlc, fifo, pkt[i], i == (count - 1),
 
823
                                   ampdu->txpkt_weight);
 
824
 
 
825
        }
 
826
        /* endif (count) */
 
827
        return err;
 
828
}
 
829
 
 
830
void
 
831
wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
 
832
                     struct sk_buff *p, tx_status_t *txs)
 
833
{
 
834
        scb_ampdu_t *scb_ampdu;
 
835
        struct wlc_info *wlc = ampdu->wlc;
 
836
        scb_ampdu_tid_ini_t *ini;
 
837
        u32 s1 = 0, s2 = 0;
 
838
        struct ieee80211_tx_info *tx_info;
 
839
 
 
840
        tx_info = IEEE80211_SKB_CB(p);
 
841
 
 
842
        /* BMAC_NOTE: For the split driver, second level txstatus comes later
 
843
         * So if the ACK was received then wait for the second level else just
 
844
         * call the first one
 
845
         */
 
846
        if (txs->status & TX_STATUS_ACK_RCV) {
 
847
                u8 status_delay = 0;
 
848
 
 
849
                /* wait till the next 8 bytes of txstatus is available */
 
850
                while (((s1 = R_REG(&wlc->regs->frmtxstatus)) & TXS_V) == 0) {
 
851
                        udelay(1);
 
852
                        status_delay++;
 
853
                        if (status_delay > 10) {
 
854
                                return; /* error condition */
 
855
                        }
 
856
                }
 
857
 
 
858
                s2 = R_REG(&wlc->regs->frmtxstatus2);
 
859
        }
 
860
 
 
861
        if (likely(scb)) {
 
862
                scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
 
863
                ini = SCB_AMPDU_INI(scb_ampdu, p->priority);
 
864
                wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
 
865
        } else {
 
866
                /* loop through all pkts and free */
 
867
                u8 queue = txs->frameid & TXFID_QUEUE_MASK;
 
868
                d11txh_t *txh;
 
869
                u16 mcl;
 
870
                while (p) {
 
871
                        tx_info = IEEE80211_SKB_CB(p);
 
872
                        txh = (d11txh_t *) p->data;
 
873
                        mcl = le16_to_cpu(txh->MacTxControlLow);
 
874
                        bcm_pkt_buf_free_skb(p);
 
875
                        /* break out if last packet of ampdu */
 
876
                        if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
 
877
                            TXC_AMPDU_LAST)
 
878
                                break;
 
879
                        p = GETNEXTTXP(wlc, queue);
 
880
                }
 
881
                wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
 
882
        }
 
883
        wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini);
 
884
}
 
885
 
 
886
static void
 
887
rate_status(struct wlc_info *wlc, struct ieee80211_tx_info *tx_info,
 
888
            tx_status_t *txs, u8 mcs)
 
889
{
 
890
        struct ieee80211_tx_rate *txrate = tx_info->status.rates;
 
891
        int i;
 
892
 
 
893
        /* clear the rest of the rates */
 
894
        for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
 
895
                txrate[i].idx = -1;
 
896
                txrate[i].count = 0;
 
897
        }
 
898
}
 
899
 
 
900
#define SHORTNAME "AMPDU status"
 
901
 
 
902
static void
 
903
wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
 
904
                              struct sk_buff *p, tx_status_t *txs,
 
905
                              u32 s1, u32 s2)
 
906
{
 
907
        scb_ampdu_t *scb_ampdu;
 
908
        struct wlc_info *wlc = ampdu->wlc;
 
909
        scb_ampdu_tid_ini_t *ini;
 
910
        u8 bitmap[8], queue, tid;
 
911
        d11txh_t *txh;
 
912
        u8 *plcp;
 
913
        struct ieee80211_hdr *h;
 
914
        u16 seq, start_seq = 0, bindex, index, mcl;
 
915
        u8 mcs = 0;
 
916
        bool ba_recd = false, ack_recd = false;
 
917
        u8 suc_mpdu = 0, tot_mpdu = 0;
 
918
        uint supr_status;
 
919
        bool update_rate = true, retry = true, tx_error = false;
 
920
        u16 mimoantsel = 0;
 
921
        u8 antselid = 0;
 
922
        u8 retry_limit, rr_retry_limit;
 
923
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
 
924
        struct wiphy *wiphy = wlc->wiphy;
 
925
 
 
926
#ifdef BCMDBG
 
927
        u8 hole[AMPDU_MAX_MPDU];
 
928
        memset(hole, 0, sizeof(hole));
 
929
#endif
 
930
 
 
931
        scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
 
932
        tid = (u8) (p->priority);
 
933
 
 
934
        ini = SCB_AMPDU_INI(scb_ampdu, tid);
 
935
        retry_limit = ampdu->retry_limit_tid[tid];
 
936
        rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
 
937
        memset(bitmap, 0, sizeof(bitmap));
 
938
        queue = txs->frameid & TXFID_QUEUE_MASK;
 
939
        supr_status = txs->status & TX_STATUS_SUPR_MASK;
 
940
 
 
941
        if (txs->status & TX_STATUS_ACK_RCV) {
 
942
                if (TX_STATUS_SUPR_UF == supr_status) {
 
943
                        update_rate = false;
 
944
                }
 
945
 
 
946
                WARN_ON(!(txs->status & TX_STATUS_INTERMEDIATE));
 
947
                start_seq = txs->sequence >> SEQNUM_SHIFT;
 
948
                bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >>
 
949
                    TX_STATUS_BA_BMAP03_SHIFT;
 
950
 
 
951
                WARN_ON(s1 & TX_STATUS_INTERMEDIATE);
 
952
                WARN_ON(!(s1 & TX_STATUS_AMPDU));
 
953
 
 
954
                bitmap[0] |=
 
955
                    (s1 & TX_STATUS_BA_BMAP47_MASK) <<
 
956
                    TX_STATUS_BA_BMAP47_SHIFT;
 
957
                bitmap[1] = (s1 >> 8) & 0xff;
 
958
                bitmap[2] = (s1 >> 16) & 0xff;
 
959
                bitmap[3] = (s1 >> 24) & 0xff;
 
960
 
 
961
                bitmap[4] = s2 & 0xff;
 
962
                bitmap[5] = (s2 >> 8) & 0xff;
 
963
                bitmap[6] = (s2 >> 16) & 0xff;
 
964
                bitmap[7] = (s2 >> 24) & 0xff;
 
965
 
 
966
                ba_recd = true;
 
967
        } else {
 
968
                if (supr_status) {
 
969
                        update_rate = false;
 
970
                        if (supr_status == TX_STATUS_SUPR_BADCH) {
 
971
                                wiphy_err(wiphy, "%s: Pkt tx suppressed, "
 
972
                                          "illegal channel possibly %d\n",
 
973
                                          __func__, CHSPEC_CHANNEL(
 
974
                                          wlc->default_bss->chanspec));
 
975
                        } else {
 
976
                                if (supr_status != TX_STATUS_SUPR_FRAG)
 
977
                                        wiphy_err(wiphy, "%s: wlc_ampdu_dotx"
 
978
                                                  "status:supr_status 0x%x\n",
 
979
                                                 __func__, supr_status);
 
980
                        }
 
981
                        /* no need to retry for badch; will fail again */
 
982
                        if (supr_status == TX_STATUS_SUPR_BADCH ||
 
983
                            supr_status == TX_STATUS_SUPR_EXPTIME) {
 
984
                                retry = false;
 
985
                        } else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
 
986
                                /* TX underflow : try tuning pre-loading or ampdu size */
 
987
                        } else if (supr_status == TX_STATUS_SUPR_FRAG) {
 
988
                                /* if there were underflows, but pre-loading is not active,
 
989
                                   notify rate adaptation.
 
990
                                 */
 
991
                                if (wlc_ffpld_check_txfunfl(wlc, prio2fifo[tid])
 
992
                                    > 0) {
 
993
                                        tx_error = true;
 
994
                                }
 
995
                        }
 
996
                } else if (txs->phyerr) {
 
997
                        update_rate = false;
 
998
                        wiphy_err(wiphy, "wl%d: wlc_ampdu_dotxstatus: tx phy "
 
999
                                  "error (0x%x)\n", wlc->pub->unit,
 
1000
                                  txs->phyerr);
 
1001
 
 
1002
                        if (WL_ERROR_ON()) {
 
1003
                                bcm_prpkt("txpkt (AMPDU)", p);
 
1004
                                wlc_print_txdesc((d11txh_t *) p->data);
 
1005
                        }
 
1006
                        wlc_print_txstatus(txs);
 
1007
                }
 
1008
        }
 
1009
 
 
1010
        /* loop through all pkts and retry if not acked */
 
1011
        while (p) {
 
1012
                tx_info = IEEE80211_SKB_CB(p);
 
1013
                txh = (d11txh_t *) p->data;
 
1014
                mcl = le16_to_cpu(txh->MacTxControlLow);
 
1015
                plcp = (u8 *) (txh + 1);
 
1016
                h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
 
1017
                seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
 
1018
 
 
1019
                if (tot_mpdu == 0) {
 
1020
                        mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
 
1021
                        mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel);
 
1022
                }
 
1023
 
 
1024
                index = TX_SEQ_TO_INDEX(seq);
 
1025
                ack_recd = false;
 
1026
                if (ba_recd) {
 
1027
                        bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
 
1028
                        BCMMSG(wlc->wiphy, "tid %d seq %d,"
 
1029
                                " start_seq %d, bindex %d set %d, index %d\n",
 
1030
                                tid, seq, start_seq, bindex,
 
1031
                                isset(bitmap, bindex), index);
 
1032
                        /* if acked then clear bit and free packet */
 
1033
                        if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
 
1034
                            && isset(bitmap, bindex)) {
 
1035
                                ini->tx_in_transit--;
 
1036
                                ini->txretry[index] = 0;
 
1037
 
 
1038
                                /* ampdu_ack_len: number of acked aggregated frames */
 
1039
                                /* ampdu_len: number of aggregated frames */
 
1040
                                rate_status(wlc, tx_info, txs, mcs);
 
1041
                                tx_info->flags |= IEEE80211_TX_STAT_ACK;
 
1042
                                tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
 
1043
                                tx_info->status.ampdu_ack_len =
 
1044
                                        tx_info->status.ampdu_len = 1;
 
1045
 
 
1046
                                skb_pull(p, D11_PHY_HDR_LEN);
 
1047
                                skb_pull(p, D11_TXH_LEN);
 
1048
 
 
1049
                                ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
 
1050
                                                            p);
 
1051
                                ack_recd = true;
 
1052
                                suc_mpdu++;
 
1053
                        }
 
1054
                }
 
1055
                /* either retransmit or send bar if ack not recd */
 
1056
                if (!ack_recd) {
 
1057
                        struct ieee80211_tx_rate *txrate =
 
1058
                            tx_info->status.rates;
 
1059
                        if (retry && (txrate[0].count < (int)retry_limit)) {
 
1060
                                ini->txretry[index]++;
 
1061
                                ini->tx_in_transit--;
 
1062
                                /* Use high prededence for retransmit to give some punch */
 
1063
                                /* wlc_txq_enq(wlc, scb, p, WLC_PRIO_TO_PREC(tid)); */
 
1064
                                wlc_txq_enq(wlc, scb, p,
 
1065
                                            WLC_PRIO_TO_HI_PREC(tid));
 
1066
                        } else {
 
1067
                                /* Retry timeout */
 
1068
                                ini->tx_in_transit--;
 
1069
                                ieee80211_tx_info_clear_status(tx_info);
 
1070
                                tx_info->status.ampdu_ack_len = 0;
 
1071
                                tx_info->status.ampdu_len = 1;
 
1072
                                tx_info->flags |=
 
1073
                                    IEEE80211_TX_STAT_AMPDU_NO_BACK;
 
1074
                                skb_pull(p, D11_PHY_HDR_LEN);
 
1075
                                skb_pull(p, D11_TXH_LEN);
 
1076
                                wiphy_err(wiphy, "%s: BA Timeout, seq %d, in_"
 
1077
                                        "transit %d\n", SHORTNAME, seq,
 
1078
                                        ini->tx_in_transit);
 
1079
                                ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
 
1080
                                                            p);
 
1081
                        }
 
1082
                }
 
1083
                tot_mpdu++;
 
1084
 
 
1085
                /* break out if last packet of ampdu */
 
1086
                if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
 
1087
                    TXC_AMPDU_LAST)
 
1088
                        break;
 
1089
 
 
1090
                p = GETNEXTTXP(wlc, queue);
 
1091
        }
 
1092
        wlc_send_q(wlc);
 
1093
 
 
1094
        /* update rate state */
 
1095
        antselid = wlc_antsel_antsel2id(wlc->asi, mimoantsel);
 
1096
 
 
1097
        wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
 
1098
}
 
1099
 
 
1100
/* initialize the initiator code for tid */
 
1101
static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
 
1102
                                                   scb_ampdu_t *scb_ampdu,
 
1103
                                                   u8 tid, bool override)
 
1104
{
 
1105
        scb_ampdu_tid_ini_t *ini;
 
1106
 
 
1107
        /* check for per-tid control of ampdu */
 
1108
        if (!ampdu->ini_enable[tid]) {
 
1109
                wiphy_err(ampdu->wlc->wiphy, "%s: Rejecting tid %d\n",
 
1110
                          __func__, tid);
 
1111
                return NULL;
 
1112
        }
 
1113
 
 
1114
        ini = SCB_AMPDU_INI(scb_ampdu, tid);
 
1115
        ini->tid = tid;
 
1116
        ini->scb = scb_ampdu->scb;
 
1117
        ini->magic = INI_MAGIC;
 
1118
        return ini;
 
1119
}
 
1120
 
 
1121
static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on)
 
1122
{
 
1123
        struct wlc_info *wlc = ampdu->wlc;
 
1124
 
 
1125
        wlc->pub->_ampdu = false;
 
1126
 
 
1127
        if (on) {
 
1128
                if (!N_ENAB(wlc->pub)) {
 
1129
                        wiphy_err(ampdu->wlc->wiphy, "wl%d: driver not "
 
1130
                                "nmode enabled\n", wlc->pub->unit);
 
1131
                        return -ENOTSUPP;
 
1132
                }
 
1133
                if (!wlc_ampdu_cap(ampdu)) {
 
1134
                        wiphy_err(ampdu->wlc->wiphy, "wl%d: device not "
 
1135
                                "ampdu capable\n", wlc->pub->unit);
 
1136
                        return -ENOTSUPP;
 
1137
                }
 
1138
                wlc->pub->_ampdu = on;
 
1139
        }
 
1140
 
 
1141
        return 0;
 
1142
}
 
1143
 
 
1144
static bool wlc_ampdu_cap(struct ampdu_info *ampdu)
 
1145
{
 
1146
        if (WLC_PHY_11N_CAP(ampdu->wlc->band))
 
1147
                return true;
 
1148
        else
 
1149
                return false;
 
1150
}
 
1151
 
 
1152
static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
 
1153
{
 
1154
        u32 rate, mcs;
 
1155
 
 
1156
        for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
 
1157
                /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
 
1158
                /* 20MHz, No SGI */
 
1159
                rate = MCS_RATE(mcs, false, false);
 
1160
                ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
 
1161
                /* 40 MHz, No SGI */
 
1162
                rate = MCS_RATE(mcs, true, false);
 
1163
                ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
 
1164
                /* 20MHz, SGI */
 
1165
                rate = MCS_RATE(mcs, false, true);
 
1166
                ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
 
1167
                /* 40 MHz, SGI */
 
1168
                rate = MCS_RATE(mcs, true, true);
 
1169
                ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
 
1170
        }
 
1171
}
 
1172
 
 
1173
void wlc_ampdu_macaddr_upd(struct wlc_info *wlc)
 
1174
{
 
1175
        char template[T_RAM_ACCESS_SZ * 2];
 
1176
 
 
1177
        /* driver needs to write the ta in the template; ta is at offset 16 */
 
1178
        memset(template, 0, sizeof(template));
 
1179
        memcpy(template, wlc->pub->cur_etheraddr, ETH_ALEN);
 
1180
        wlc_write_template_ram(wlc, (T_BA_TPL_BASE + 16), (T_RAM_ACCESS_SZ * 2),
 
1181
                               template);
 
1182
}
 
1183
 
 
1184
bool wlc_aggregatable(struct wlc_info *wlc, u8 tid)
 
1185
{
 
1186
        return wlc->ampdu->ini_enable[tid];
 
1187
}
 
1188
 
 
1189
void wlc_ampdu_shm_upd(struct ampdu_info *ampdu)
 
1190
{
 
1191
        struct wlc_info *wlc = ampdu->wlc;
 
1192
 
 
1193
        /* Extend ucode internal watchdog timer to match larger received frames */
 
1194
        if ((ampdu->rx_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) ==
 
1195
            IEEE80211_HT_MAX_AMPDU_64K) {
 
1196
                wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
 
1197
                wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
 
1198
        } else {
 
1199
                wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
 
1200
                wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);
 
1201
        }
 
1202
}
 
1203
 
 
1204
/*
 
1205
 * callback function that helps flushing ampdu packets from a priority queue
 
1206
 */
 
1207
static bool cb_del_ampdu_pkt(struct sk_buff *mpdu, void *arg_a)
 
1208
{
 
1209
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu);
 
1210
        struct cb_del_ampdu_pars *ampdu_pars =
 
1211
                                 (struct cb_del_ampdu_pars *)arg_a;
 
1212
        bool rc;
 
1213
 
 
1214
        rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false;
 
1215
        rc = rc && (tx_info->control.sta == NULL || ampdu_pars->sta == NULL ||
 
1216
                    tx_info->control.sta == ampdu_pars->sta);
 
1217
        rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid);
 
1218
        return rc;
 
1219
}
 
1220
 
 
1221
/*
 
1222
 * callback function that helps invalidating ampdu packets in a DMA queue
 
1223
 */
 
1224
static void dma_cb_fn_ampdu(void *txi, void *arg_a)
 
1225
{
 
1226
        struct ieee80211_sta *sta = arg_a;
 
1227
        struct ieee80211_tx_info *tx_info = (struct ieee80211_tx_info *)txi;
 
1228
 
 
1229
        if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
 
1230
            (tx_info->control.sta == sta || sta == NULL))
 
1231
                tx_info->control.sta = NULL;
 
1232
}
 
1233
 
 
1234
/*
 
1235
 * When a remote party is no longer available for ampdu communication, any
 
1236
 * pending tx ampdu packets in the driver have to be flushed.
 
1237
 */
 
1238
void wlc_ampdu_flush(struct wlc_info *wlc,
 
1239
                     struct ieee80211_sta *sta, u16 tid)
 
1240
{
 
1241
        struct wlc_txq_info *qi = wlc->pkt_queue;
 
1242
        struct pktq *pq = &qi->q;
 
1243
        int prec;
 
1244
        struct cb_del_ampdu_pars ampdu_pars;
 
1245
 
 
1246
        ampdu_pars.sta = sta;
 
1247
        ampdu_pars.tid = tid;
 
1248
        for (prec = 0; prec < pq->num_prec; prec++) {
 
1249
                bcm_pktq_pflush(pq, prec, true, cb_del_ampdu_pkt,
 
1250
                            (void *)&ampdu_pars);
 
1251
        }
 
1252
        wlc_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu);
 
1253
}