]> git.karo-electronics.de Git - linux-beck.git/blob - drivers/staging/brcm80211/sys/wlc_mac80211.c
cbd0504f450ccd3b428625491545abed857c3b36
[linux-beck.git] / drivers / staging / brcm80211 / sys / wlc_mac80211.c
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
17 #include <wlc_cfg.h>
18 #include <typedefs.h>
19 #include <linux/kernel.h>
20 #include <linuxver.h>
21 #include <bcmdefs.h>
22 #include <osl.h>
23 #include <linux/ctype.h>
24 #include <bcmutils.h>
25 #include <bcmwifi.h>
26 #include <siutils.h>
27 #include <bcmendian.h>
28 #include <proto/wpa.h>
29 #include <pcicfg.h>
30 #include <bcmsrom.h>
31 #include <wlioctl.h>
32 #include <epivers.h>
33 #include <bcmwpa.h>
34 #include <sbhnddma.h>
35 #include <hnddma.h>
36 #include <hndpmu.h>
37 #include <d11.h>
38 #include <wlc_rate.h>
39 #include <wlc_pub.h>
40 #include <wlc_key.h>
41 #include <wlc_bsscfg.h>
42 #include <wlc_channel.h>
43 #include <wlc_mac80211.h>
44 #include <wlc_bmac.h>
45 #include <wlc_scb.h>
46 #include <wlc_phy_hal.h>
47 #include <wlc_phy_shim.h>
48 #include <wlc_antsel.h>
49 #include <wlc_stf.h>
50 #include <wlc_ampdu.h>
51 #include <wlc_event.h>
52 #include <wl_export.h>
53 #ifdef BCMSDIO
54 #include <bcmsdh.h>
55 #else
56 #include "d11ucode_ext.h"
57 #endif
58 #ifdef WLC_HIGH_ONLY
59 #include <bcm_rpc_tp.h>
60 #include <bcm_rpc.h>
61 #include <bcm_xdr.h>
62 #include <wlc_rpc.h>
63 #include <wlc_rpctx.h>
64 #endif                          /* WLC_HIGH_ONLY */
65 #include <wlc_alloc.h>
66 #include <net/mac80211.h>
67
68 #ifdef WLC_HIGH_ONLY
69 #undef R_REG
70 #undef W_REG
71 #define R_REG(osh, r) RPC_READ_REG(osh, r)
72 #define W_REG(osh, r, v) RPC_WRITE_REG(osh, r, v)
73 #endif
74
75 /*
76  * buffer length needed for wlc_format_ssid
77  * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
78  */
79 #define SSID_FMT_BUF_LEN        ((4 * DOT11_MAX_SSID_LEN) + 1)
80
81 #define TIMER_INTERVAL_WATCHDOG 1000    /* watchdog timer, in unit of ms */
82 #define TIMER_INTERVAL_RADIOCHK 800     /* radio monitor timer, in unit of ms */
83
84 #ifndef WLC_MPC_MAX_DELAYCNT
85 #define WLC_MPC_MAX_DELAYCNT    10      /* Max MPC timeout, in unit of watchdog */
86 #endif
87 #define WLC_MPC_MIN_DELAYCNT    1       /* Min MPC timeout, in unit of watchdog */
88 #define WLC_MPC_THRESHOLD       3       /* MPC count threshold level */
89
90 #define BEACON_INTERVAL_DEFAULT 100     /* beacon interval, in unit of 1024TU */
91 #define DTIM_INTERVAL_DEFAULT   3       /* DTIM interval, in unit of beacon interval */
92
93 /* Scale down delays to accommodate QT slow speed */
94 #define BEACON_INTERVAL_DEF_QT  20      /* beacon interval, in unit of 1024TU */
95 #define DTIM_INTERVAL_DEF_QT    1       /* DTIM interval, in unit of beacon interval */
96
97 #define TBTT_ALIGN_LEEWAY_US    100     /* min leeway before first TBTT in us */
98
99 /*
100  * driver maintains internal 'tick'(wlc->pub->now) which increments in 1s OS timer(soft
101  * watchdog) it is not a wall clock and won't increment when driver is in "down" state
102  * this low resolution driver tick can be used for maintenance tasks such as phy
103  * calibration and scb update
104  */
105
106 /* watchdog trigger mode: OSL timer or TBTT */
107 #define WLC_WATCHDOG_TBTT(wlc) \
108         (wlc->stas_associated > 0 && wlc->PM != PM_OFF && wlc->pub->align_wd_tbtt)
109
110 /* To inform the ucode of the last mcast frame posted so that it can clear moredata bit */
111 #define BCMCFID(wlc, fid) wlc_bmac_write_shm((wlc)->hw, M_BCMC_FID, (fid))
112
113 #ifndef WLC_HIGH_ONLY
114 #define WLC_WAR16165(wlc) (BUSTYPE(wlc->pub->sih->bustype) == PCI_BUS && \
115                                 (!AP_ENAB(wlc->pub)) && (wlc->war16165))
116 #else
117 #define WLC_WAR16165(wlc) (FALSE)
118 #endif                          /* WLC_HIGH_ONLY */
119
120 /* debug/trace */
121 uint wl_msg_level =
122 #if defined(BCMDBG)
123     WL_ERROR_VAL;
124 #else
125     0;
126 #endif                          /* BCMDBG */
127
128 /* Find basic rate for a given rate */
129 #define WLC_BASIC_RATE(wlc, rspec)      (IS_MCS(rspec) ? \
130                         (wlc)->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK].leg_ofdm] : \
131                         (wlc)->band->basic_rate[rspec & RSPEC_RATE_MASK])
132
133 #define FRAMETYPE(r, mimoframe) (IS_MCS(r) ? mimoframe  : (IS_CCK(r) ? FT_CCK : FT_OFDM))
134
135 #define RFDISABLE_DEFAULT       10000000        /* rfdisable delay timer 500 ms, runs of ALP clock */
136
137 #define WLC_TEMPSENSE_PERIOD            10      /* 10 second timeout */
138
139 #define SCAN_IN_PROGRESS(x)     0
140
141 #ifdef BCMDBG
142 /* pointer to most recently allocated wl/wlc */
143 static wlc_info_t *wlc_info_dbg = (wlc_info_t *) (NULL);
144 #endif
145
146 /* IOVar table */
147
148 /* Parameter IDs, for use only internally to wlc -- in the wlc_iovars
149  * table and by the wlc_doiovar() function.  No ordering is imposed:
150  * the table is keyed by name, and the function uses a switch.
151  */
152 enum {
153         IOV_MPC = 1,
154         IOV_QTXPOWER,
155         IOV_BCN_LI_BCN,         /* Beacon listen interval in # of beacons */
156         IOV_LAST                /* In case of a need to check max ID number */
157 };
158
159 const bcm_iovar_t wlc_iovars[] = {
160         {"mpc", IOV_MPC, (IOVF_OPEN_ALLOW), IOVT_BOOL, 0},
161         {"qtxpower", IOV_QTXPOWER, (IOVF_WHL | IOVF_OPEN_ALLOW), IOVT_UINT32,
162          0},
163         {"bcn_li_bcn", IOV_BCN_LI_BCN, 0, IOVT_UINT8, 0},
164         {NULL, 0, 0, 0, 0}
165 };
166
167 const u8 prio2fifo[NUMPRIO] = {
168         TX_AC_BE_FIFO,          /* 0    BE      AC_BE   Best Effort */
169         TX_AC_BK_FIFO,          /* 1    BK      AC_BK   Background */
170         TX_AC_BK_FIFO,          /* 2    --      AC_BK   Background */
171         TX_AC_BE_FIFO,          /* 3    EE      AC_BE   Best Effort */
172         TX_AC_VI_FIFO,          /* 4    CL      AC_VI   Video */
173         TX_AC_VI_FIFO,          /* 5    VI      AC_VI   Video */
174         TX_AC_VO_FIFO,          /* 6    VO      AC_VO   Voice */
175         TX_AC_VO_FIFO           /* 7    NC      AC_VO   Voice */
176 };
177
178 /* precedences numbers for wlc queues. These are twice as may levels as
179  * 802.1D priorities.
180  * Odd numbers are used for HI priority traffic at same precedence levels
181  * These constants are used ONLY by wlc_prio2prec_map.  Do not use them elsewhere.
182  */
183 #define _WLC_PREC_NONE          0       /* None = - */
184 #define _WLC_PREC_BK            2       /* BK - Background */
185 #define _WLC_PREC_BE            4       /* BE - Best-effort */
186 #define _WLC_PREC_EE            6       /* EE - Excellent-effort */
187 #define _WLC_PREC_CL            8       /* CL - Controlled Load */
188 #define _WLC_PREC_VI            10      /* Vi - Video */
189 #define _WLC_PREC_VO            12      /* Vo - Voice */
190 #define _WLC_PREC_NC            14      /* NC - Network Control */
191
192 /* 802.1D Priority to precedence queue mapping */
193 const u8 wlc_prio2prec_map[] = {
194         _WLC_PREC_BE,           /* 0 BE - Best-effort */
195         _WLC_PREC_BK,           /* 1 BK - Background */
196         _WLC_PREC_NONE,         /* 2 None = - */
197         _WLC_PREC_EE,           /* 3 EE - Excellent-effort */
198         _WLC_PREC_CL,           /* 4 CL - Controlled Load */
199         _WLC_PREC_VI,           /* 5 Vi - Video */
200         _WLC_PREC_VO,           /* 6 Vo - Voice */
201         _WLC_PREC_NC,           /* 7 NC - Network Control */
202 };
203
204 /* Sanity check for tx_prec_map and fifo synchup
205  * Either there are some packets pending for the fifo, else if fifo is empty then
206  * all the corresponding precmap bits should be set
207  */
208 #define WLC_TX_FIFO_CHECK(wlc, fifo) (TXPKTPENDGET((wlc), (fifo)) ||    \
209         (TXPKTPENDGET((wlc), (fifo)) == 0 && \
210         ((wlc)->tx_prec_map & (wlc)->fifo2prec_map[(fifo)]) == \
211         (wlc)->fifo2prec_map[(fifo)]))
212
213 /* TX FIFO number to WME/802.1E Access Category */
214 const u8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE };
215
216 /* WME/802.1E Access Category to TX FIFO number */
217 static const u8 wme_ac2fifo[] = { 1, 0, 2, 3 };
218
219 static bool in_send_q = FALSE;
220
221 /* Shared memory location index for various AC params */
222 #define wme_shmemacindex(ac)    wme_ac2fifo[ac]
223
224 #ifdef BCMDBG
225 static const char *fifo_names[] = {
226         "AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" };
227 const char *aci_names[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
228 #endif
229
230 static const u8 acbitmap2maxprio[] = {
231         PRIO_8021D_BE, PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_BK,
232         PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI,
233         PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO,
234         PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO
235 };
236
237 /* currently the best mechanism for determining SIFS is the band in use */
238 #define SIFS(band) ((band)->bandtype == WLC_BAND_5G ? APHY_SIFS_TIME : BPHY_SIFS_TIME);
239
240 /* value for # replay counters currently supported */
241 #define WLC_REPLAY_CNTRS_VALUE  WPA_CAP_16_REPLAY_CNTRS
242
243 /* local prototypes */
244 extern void wlc_txq_enq(void *ctx, struct scb *scb, void *sdu, uint prec);
245 static u16 BCMFASTPATH wlc_d11hdrs_mac80211(wlc_info_t *wlc,
246                                                struct ieee80211_hw *hw, void *p,
247                                                struct scb *scb, uint frag,
248                                                uint nfrags, uint queue,
249                                                uint next_frag_len,
250                                                wsec_key_t *key,
251                                                ratespec_t rspec_override);
252 bool wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw);
253 void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend);
254 static void wlc_bss_default_init(wlc_info_t *wlc);
255 static void wlc_ucode_mac_upd(wlc_info_t *wlc);
256 static ratespec_t mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band,
257                                          u32 int_val);
258 static void wlc_tx_prec_map_init(wlc_info_t *wlc);
259 static void wlc_watchdog(void *arg);
260 static void wlc_watchdog_by_timer(void *arg);
261 static int wlc_set_rateset(wlc_info_t *wlc, wlc_rateset_t *rs_arg);
262 static int wlc_iovar_rangecheck(wlc_info_t *wlc, u32 val,
263                                 const bcm_iovar_t *vi);
264 static u8 wlc_local_constraint_qdbm(wlc_info_t *wlc);
265
266 /* send and receive */
267 static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, osl_t *osh);
268 static void wlc_txq_free(wlc_info_t *wlc, osl_t *osh, wlc_txq_info_t *qi);
269 static void wlc_txflowcontrol_signal(wlc_info_t *wlc, wlc_txq_info_t *qi,
270                                      bool on, int prio);
271 static void wlc_txflowcontrol_reset(wlc_info_t *wlc);
272 static u16 wlc_compute_airtime(wlc_info_t *wlc, ratespec_t rspec,
273                                   uint length);
274 static void wlc_compute_cck_plcp(ratespec_t rate, uint length, u8 *plcp);
275 static void wlc_compute_ofdm_plcp(ratespec_t rate, uint length, u8 *plcp);
276 static void wlc_compute_mimo_plcp(ratespec_t rate, uint length, u8 *plcp);
277 static u16 wlc_compute_frame_dur(wlc_info_t *wlc, ratespec_t rate,
278                                     u8 preamble_type, uint next_frag_len);
279 static void wlc_recvctl(wlc_info_t *wlc, osl_t *osh, d11rxhdr_t *rxh,
280                         void *p);
281 static uint wlc_calc_frame_len(wlc_info_t *wlc, ratespec_t rate,
282                                u8 preamble_type, uint dur);
283 static uint wlc_calc_ack_time(wlc_info_t *wlc, ratespec_t rate,
284                               u8 preamble_type);
285 static uint wlc_calc_cts_time(wlc_info_t *wlc, ratespec_t rate,
286                               u8 preamble_type);
287 /* interrupt, up/down, band */
288 static void wlc_setband(wlc_info_t *wlc, uint bandunit);
289 static chanspec_t wlc_init_chanspec(wlc_info_t *wlc);
290 static void wlc_bandinit_ordered(wlc_info_t *wlc, chanspec_t chanspec);
291 static void wlc_bsinit(wlc_info_t *wlc);
292 static int wlc_duty_cycle_set(wlc_info_t *wlc, int duty_cycle, bool isOFDM,
293                               bool writeToShm);
294 static void wlc_radio_hwdisable_upd(wlc_info_t *wlc);
295 static bool wlc_radio_monitor_start(wlc_info_t *wlc);
296 static void wlc_radio_timer(void *arg);
297 static void wlc_radio_enable(wlc_info_t *wlc);
298 static void wlc_radio_upd(wlc_info_t *wlc);
299
300 /* scan, association, BSS */
301 static uint wlc_calc_ba_time(wlc_info_t *wlc, ratespec_t rate,
302                              u8 preamble_type);
303 static void wlc_update_mimo_band_bwcap(wlc_info_t *wlc, u8 bwcap);
304 static void wlc_ht_update_sgi_rx(wlc_info_t *wlc, int val);
305 void wlc_ht_mimops_cap_update(wlc_info_t *wlc, u8 mimops_mode);
306 static void wlc_ht_update_ldpc(wlc_info_t *wlc, s8 val);
307 static void wlc_war16165(wlc_info_t *wlc, bool tx);
308
309 static void wlc_process_eventq(void *arg);
310 static void wlc_wme_retries_write(wlc_info_t *wlc);
311 static bool wlc_attach_stf_ant_init(wlc_info_t *wlc);
312 static uint wlc_attach_module(wlc_info_t *wlc);
313 static void wlc_detach_module(wlc_info_t *wlc);
314 static void wlc_timers_deinit(wlc_info_t *wlc);
315 static void wlc_down_led_upd(wlc_info_t *wlc);
316 static uint wlc_down_del_timer(wlc_info_t *wlc);
317 static void wlc_ofdm_rateset_war(wlc_info_t *wlc);
318 static int _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len,
319                       struct wlc_if *wlcif);
320
321 #if defined(BCMDBG)
322 void wlc_get_rcmta(wlc_info_t *wlc, int idx, struct ether_addr *addr)
323 {
324         d11regs_t *regs = wlc->regs;
325         u32 v32;
326         osl_t *osh;
327
328         WL_TRACE(("wl%d: %s\n", WLCWLUNIT(wlc), __func__));
329
330         ASSERT(wlc->pub->corerev > 4);
331
332         osh = wlc->osh;
333
334         W_REG(osh, &regs->objaddr, (OBJADDR_RCMTA_SEL | (idx * 2)));
335         (void)R_REG(osh, &regs->objaddr);
336         v32 = R_REG(osh, &regs->objdata);
337         addr->octet[0] = (u8) v32;
338         addr->octet[1] = (u8) (v32 >> 8);
339         addr->octet[2] = (u8) (v32 >> 16);
340         addr->octet[3] = (u8) (v32 >> 24);
341         W_REG(osh, &regs->objaddr, (OBJADDR_RCMTA_SEL | ((idx * 2) + 1)));
342         (void)R_REG(osh, &regs->objaddr);
343         v32 = R_REG(osh, (volatile u16 *)(uintptr) & regs->objdata);
344         addr->octet[4] = (u8) v32;
345         addr->octet[5] = (u8) (v32 >> 8);
346 }
347 #endif                          /* defined(BCMDBG) */
348
349 /* keep the chip awake if needed */
350 bool wlc_stay_awake(wlc_info_t *wlc)
351 {
352         return TRUE;
353 }
354
355 /* conditions under which the PM bit should be set in outgoing frames and STAY_AWAKE is meaningful
356  */
357 bool wlc_ps_allowed(wlc_info_t *wlc)
358 {
359         int idx;
360         wlc_bsscfg_t *cfg;
361
362         /* disallow PS when one of the following global conditions meets */
363         if (!wlc->pub->associated || !wlc->PMenabled || wlc->PM_override)
364                 return FALSE;
365
366         /* disallow PS when one of these meets when not scanning */
367         if (!wlc->PMblocked) {
368                 if (AP_ACTIVE(wlc) || wlc->monitor)
369                         return FALSE;
370         }
371
372         FOREACH_AS_STA(wlc, idx, cfg) {
373                 /* disallow PS when one of the following bsscfg specific conditions meets */
374                 if (!cfg->BSS || !WLC_PORTOPEN(cfg))
375                         return FALSE;
376
377                 if (!cfg->dtim_programmed)
378                         return FALSE;
379         }
380
381         return TRUE;
382 }
383
384 void wlc_reset(wlc_info_t *wlc)
385 {
386         WL_TRACE(("wl%d: wlc_reset\n", wlc->pub->unit));
387
388         wlc->check_for_unaligned_tbtt = FALSE;
389
390         /* slurp up hw mac counters before core reset */
391         if (WLC_UPDATE_STATS(wlc)) {
392                 wlc_statsupd(wlc);
393
394                 /* reset our snapshot of macstat counters */
395                 bzero((char *)wlc->core->macstat_snapshot, sizeof(macstat_t));
396         }
397
398         wlc_bmac_reset(wlc->hw);
399         wlc_ampdu_reset(wlc->ampdu);
400         wlc->txretried = 0;
401
402 #ifdef WLC_HIGH_ONLY
403         /* Need to set a flag(to be cleared asynchronously by BMAC driver with high call)
404          *  in order to prevent wlc_rpctx_txreclaim() from screwing wlc_rpctx_getnexttxp(),
405          *  which could be invoked by already QUEUED high call(s) from BMAC driver before
406          *  wlc_bmac_reset() finishes.
407          * It's not needed before in monolithic driver model because d11core interrupts would
408          *  have been cleared instantly in wlc_bmac_reset() and no txstatus interrupt
409          *  will come to driver to fetch those flushed dma pkt pointers.
410          */
411         wlc->reset_bmac_pending = TRUE;
412
413         wlc_rpctx_txreclaim(wlc->rpctx);
414
415         wlc_stf_phy_txant_upd(wlc);
416         wlc_phy_ant_rxdiv_set(wlc->band->pi, wlc->stf->ant_rx_ovr);
417 #endif
418 }
419
420 void wlc_fatal_error(wlc_info_t *wlc)
421 {
422         WL_ERROR(("wl%d: fatal error, reinitializing\n", wlc->pub->unit));
423         wl_init(wlc->wl);
424 }
425
426 /* Return the channel the driver should initialize during wlc_init.
427  * the channel may have to be changed from the currently configured channel
428  * if other configurations are in conflict (bandlocked, 11n mode disabled,
429  * invalid channel for current country, etc.)
430  */
431 static chanspec_t wlc_init_chanspec(wlc_info_t *wlc)
432 {
433         chanspec_t chanspec =
434             1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE |
435             WL_CHANSPEC_BAND_2G;
436
437         /* make sure the channel is on the supported band if we are band-restricted */
438         if (wlc->bandlocked || NBANDS(wlc) == 1) {
439                 ASSERT(CHSPEC_WLCBANDUNIT(chanspec) == wlc->band->bandunit);
440         }
441         ASSERT(wlc_valid_chanspec_db(wlc->cmi, chanspec));
442         return chanspec;
443 }
444
445 struct scb global_scb;
446
447 static void wlc_init_scb(wlc_info_t *wlc, struct scb *scb)
448 {
449         int i;
450         scb->flags = SCB_WMECAP | SCB_HTCAP;
451         for (i = 0; i < NUMPRIO; i++)
452                 scb->seqnum[i] = 0;
453 }
454
455 void wlc_init(wlc_info_t *wlc)
456 {
457         d11regs_t *regs;
458         chanspec_t chanspec;
459         int i;
460         wlc_bsscfg_t *bsscfg;
461         bool mute = FALSE;
462
463         WL_TRACE(("wl%d: wlc_init\n", wlc->pub->unit));
464
465         regs = wlc->regs;
466
467         /* This will happen if a big-hammer was executed. In that case, we want to go back
468          * to the channel that we were on and not new channel
469          */
470         if (wlc->pub->associated)
471                 chanspec = wlc->home_chanspec;
472         else
473                 chanspec = wlc_init_chanspec(wlc);
474
475         wlc_bmac_init(wlc->hw, chanspec, mute);
476
477         wlc->seckeys = wlc_bmac_read_shm(wlc->hw, M_SECRXKEYS_PTR) * 2;
478         if (D11REV_GE(wlc->pub->corerev, 15) && (wlc->machwcap & MCAP_TKIPMIC))
479                 wlc->tkmickeys =
480                     wlc_bmac_read_shm(wlc->hw, M_TKMICKEYS_PTR) * 2;
481
482         /* update beacon listen interval */
483         wlc_bcn_li_upd(wlc);
484         wlc->bcn_wait_prd =
485             (u8) (wlc_bmac_read_shm(wlc->hw, M_NOSLPZNATDTIM) >> 10);
486         ASSERT(wlc->bcn_wait_prd > 0);
487
488         /* the world is new again, so is our reported rate */
489         wlc_reprate_init(wlc);
490
491         /* write ethernet address to core */
492         FOREACH_BSS(wlc, i, bsscfg) {
493                 wlc_set_mac(bsscfg);
494                 wlc_set_bssid(bsscfg);
495         }
496
497         /* Update tsf_cfprep if associated and up */
498         if (wlc->pub->associated) {
499                 FOREACH_BSS(wlc, i, bsscfg) {
500                         if (bsscfg->up) {
501                                 u32 bi;
502
503                                 /* get beacon period from bsscfg and convert to uS */
504                                 bi = bsscfg->current_bss->beacon_period << 10;
505                                 /* update the tsf_cfprep register */
506                                 /* since init path would reset to default value */
507                                 W_REG(wlc->osh, &regs->tsf_cfprep,
508                                       (bi << CFPREP_CBI_SHIFT));
509
510                                 /* Update maccontrol PM related bits */
511                                 wlc_set_ps_ctrl(wlc);
512
513                                 break;
514                         }
515                 }
516         }
517
518         wlc_key_hw_init_all(wlc);
519
520         wlc_bandinit_ordered(wlc, chanspec);
521
522         wlc_init_scb(wlc, &global_scb);
523
524         /* init probe response timeout */
525         wlc_write_shm(wlc, M_PRS_MAXTIME, wlc->prb_resp_timeout);
526
527         /* init max burst txop (framebursting) */
528         wlc_write_shm(wlc, M_MBURST_TXOP,
529                       (wlc->
530                        _rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP));
531
532         /* initialize maximum allowed duty cycle */
533         wlc_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, TRUE, TRUE);
534         wlc_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, FALSE, TRUE);
535
536         /* Update some shared memory locations related to max AMPDU size allowed to received */
537         wlc_ampdu_shm_upd(wlc->ampdu);
538
539         /* band-specific inits */
540         wlc_bsinit(wlc);
541
542         /* Enable EDCF mode (while the MAC is suspended) */
543         if (EDCF_ENAB(wlc->pub)) {
544                 OR_REG(wlc->osh, &regs->ifs_ctl, IFS_USEEDCF);
545                 wlc_edcf_setparams(wlc->cfg, FALSE);
546         }
547
548         /* Init precedence maps for empty FIFOs */
549         wlc_tx_prec_map_init(wlc);
550
551         /* read the ucode version if we have not yet done so */
552         if (wlc->ucode_rev == 0) {
553                 wlc->ucode_rev =
554                     wlc_read_shm(wlc, M_BOM_REV_MAJOR) << NBITS(u16);
555                 wlc->ucode_rev |= wlc_read_shm(wlc, M_BOM_REV_MINOR);
556         }
557
558         /* ..now really unleash hell (allow the MAC out of suspend) */
559         wlc_enable_mac(wlc);
560
561         /* clear tx flow control */
562         wlc_txflowcontrol_reset(wlc);
563
564         /* clear tx data fifo suspends */
565         wlc->tx_suspended = FALSE;
566
567         /* enable the RF Disable Delay timer */
568         if (D11REV_GE(wlc->pub->corerev, 10))
569                 W_REG(wlc->osh, &wlc->regs->rfdisabledly, RFDISABLE_DEFAULT);
570
571         /* initialize mpc delay */
572         wlc->mpc_delay_off = wlc->mpc_dlycnt = WLC_MPC_MIN_DELAYCNT;
573
574         /*
575          * Initialize WME parameters; if they haven't been set by some other
576          * mechanism (IOVar, etc) then read them from the hardware.
577          */
578         if (WLC_WME_RETRY_SHORT_GET(wlc, 0) == 0) {     /* Unintialized; read from HW */
579                 int ac;
580
581                 ASSERT(wlc->clk);
582                 for (ac = 0; ac < AC_COUNT; ac++) {
583                         wlc->wme_retries[ac] =
584                             wlc_read_shm(wlc, M_AC_TXLMT_ADDR(ac));
585                 }
586         }
587 }
588
589 void wlc_mac_bcn_promisc_change(wlc_info_t *wlc, bool promisc)
590 {
591         wlc->bcnmisc_monitor = promisc;
592         wlc_mac_bcn_promisc(wlc);
593 }
594
595 void wlc_mac_bcn_promisc(wlc_info_t *wlc)
596 {
597         if ((AP_ENAB(wlc->pub) && (N_ENAB(wlc->pub) || wlc->band->gmode)) ||
598             wlc->bcnmisc_ibss || wlc->bcnmisc_scan || wlc->bcnmisc_monitor)
599                 wlc_mctrl(wlc, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC);
600         else
601                 wlc_mctrl(wlc, MCTL_BCNS_PROMISC, 0);
602 }
603
604 /* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */
605 void wlc_mac_promisc(wlc_info_t *wlc)
606 {
607         u32 promisc_bits = 0;
608
609         /* promiscuous mode just sets MCTL_PROMISC
610          * Note: APs get all BSS traffic without the need to set the MCTL_PROMISC bit
611          * since all BSS data traffic is directed at the AP
612          */
613         if (PROMISC_ENAB(wlc->pub) && !AP_ENAB(wlc->pub) && !wlc->wet)
614                 promisc_bits |= MCTL_PROMISC;
615
616         /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL
617          * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is
618          * handled in wlc_mac_bcn_promisc()
619          */
620         if (MONITOR_ENAB(wlc))
621                 promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL;
622
623         wlc_mctrl(wlc, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits);
624 }
625
626 /* check if hps and wake states of sw and hw are in sync */
627 bool wlc_ps_check(wlc_info_t *wlc)
628 {
629         bool res = TRUE;
630         bool hps, wake;
631         bool wake_ok;
632
633         if (!AP_ACTIVE(wlc)) {
634                 volatile u32 tmp;
635                 tmp = R_REG(wlc->osh, &wlc->regs->maccontrol);
636
637                 /* If deviceremoved is detected, then don't take any action as this can be called
638                  * in any context. Assume that caller will take care of the condition. This is just
639                  * to avoid assert
640                  */
641                 if (tmp == 0xffffffff) {
642                         WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit,
643                                   __func__));
644                         return DEVICEREMOVED(wlc);
645                 }
646
647                 hps = PS_ALLOWED(wlc);
648
649                 if (hps != ((tmp & MCTL_HPS) != 0)) {
650                         int idx;
651                         wlc_bsscfg_t *cfg;
652                         WL_ERROR(("wl%d: hps not sync, sw %d, maccontrol 0x%x\n", wlc->pub->unit, hps, tmp));
653                         FOREACH_BSS(wlc, idx, cfg) {
654                                 if (!BSSCFG_STA(cfg))
655                                         continue;
656                         }
657
658                         res = FALSE;
659                 }
660 #ifdef WLC_LOW
661                 /* For a monolithic build the wake check can be exact since it looks at wake
662                  * override bits. The MCTL_WAKE bit should match the 'wake' value.
663                  */
664                 wake = STAY_AWAKE(wlc) || wlc->hw->wake_override;
665                 wake_ok = (wake == ((tmp & MCTL_WAKE) != 0));
666 #else
667                 /* For a split build we will not have access to any wake overrides from the low
668                  * level. The check can only make sure the MCTL_WAKE bit is on if the high
669                  * level 'wake' value is true. If the high level 'wake' is false, the MCTL_WAKE
670                  * may be either true or false due to the low level override.
671                  */
672                 wake = STAY_AWAKE(wlc);
673                 wake_ok = (wake && ((tmp & MCTL_WAKE) != 0)) || !wake;
674 #endif
675                 if (hps && !wake_ok) {
676                         WL_ERROR(("wl%d: wake not sync, sw %d maccontrol 0x%x\n", wlc->pub->unit, wake, tmp));
677                         res = FALSE;
678                 }
679         }
680         ASSERT(res);
681         return res;
682 }
683
684 /* push sw hps and wake state through hardware */
685 void wlc_set_ps_ctrl(wlc_info_t *wlc)
686 {
687         u32 v1, v2;
688         bool hps, wake;
689         bool awake_before;
690
691         hps = PS_ALLOWED(wlc);
692         wake = hps ? (STAY_AWAKE(wlc)) : TRUE;
693
694         WL_TRACE(("wl%d: wlc_set_ps_ctrl: hps %d wake %d\n", wlc->pub->unit,
695                   hps, wake));
696
697         v1 = R_REG(wlc->osh, &wlc->regs->maccontrol);
698         v2 = 0;
699         if (hps)
700                 v2 |= MCTL_HPS;
701         if (wake)
702                 v2 |= MCTL_WAKE;
703
704         wlc_mctrl(wlc, MCTL_WAKE | MCTL_HPS, v2);
705
706         awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));
707
708         if (wake && !awake_before)
709                 wlc_bmac_wait_for_wake(wlc->hw);
710
711 }
712
713 /*
714  * Write this BSS config's MAC address to core.
715  * Updates RXE match engine.
716  */
717 int wlc_set_mac(wlc_bsscfg_t *cfg)
718 {
719         int err = 0;
720         wlc_info_t *wlc = cfg->wlc;
721
722         if (cfg == wlc->cfg) {
723                 /* enter the MAC addr into the RXE match registers */
724                 wlc_set_addrmatch(wlc, RCM_MAC_OFFSET, &cfg->cur_etheraddr);
725         }
726
727         wlc_ampdu_macaddr_upd(wlc);
728
729         return err;
730 }
731
732 /* Write the BSS config's BSSID address to core (set_bssid in d11procs.tcl).
733  * Updates RXE match engine.
734  */
735 void wlc_set_bssid(wlc_bsscfg_t *cfg)
736 {
737         wlc_info_t *wlc = cfg->wlc;
738
739         /* if primary config, we need to update BSSID in RXE match registers */
740         if (cfg == wlc->cfg) {
741                 wlc_set_addrmatch(wlc, RCM_BSSID_OFFSET, &cfg->BSSID);
742         }
743 #ifdef SUPPORT_HWKEYS
744         else if (BSSCFG_STA(cfg) && cfg->BSS) {
745                 wlc_rcmta_add_bssid(wlc, cfg);
746         }
747 #endif
748 }
749
750 /*
751  * Suspend the the MAC and update the slot timing
752  * for standard 11b/g (20us slots) or shortslot 11g (9us slots).
753  */
754 void wlc_switch_shortslot(wlc_info_t *wlc, bool shortslot)
755 {
756         int idx;
757         wlc_bsscfg_t *cfg;
758
759         ASSERT(wlc->band->gmode);
760
761         /* use the override if it is set */
762         if (wlc->shortslot_override != WLC_SHORTSLOT_AUTO)
763                 shortslot = (wlc->shortslot_override == WLC_SHORTSLOT_ON);
764
765         if (wlc->shortslot == shortslot)
766                 return;
767
768         wlc->shortslot = shortslot;
769
770         /* update the capability based on current shortslot mode */
771         FOREACH_BSS(wlc, idx, cfg) {
772                 if (!cfg->associated)
773                         continue;
774                 cfg->current_bss->capability &= ~DOT11_CAP_SHORTSLOT;
775                 if (wlc->shortslot)
776                         cfg->current_bss->capability |= DOT11_CAP_SHORTSLOT;
777         }
778
779         wlc_bmac_set_shortslot(wlc->hw, shortslot);
780 }
781
782 static u8 wlc_local_constraint_qdbm(wlc_info_t *wlc)
783 {
784         u8 local;
785         s16 local_max;
786
787         local = WLC_TXPWR_MAX;
788         if (wlc->pub->associated &&
789             (wf_chspec_ctlchan(wlc->chanspec) ==
790              wf_chspec_ctlchan(wlc->home_chanspec))) {
791
792                 /* get the local power constraint if we are on the AP's
793                  * channel [802.11h, 7.3.2.13]
794                  */
795                 /* Clamp the value between 0 and WLC_TXPWR_MAX w/o overflowing the target */
796                 local_max =
797                     (wlc->txpwr_local_max -
798                      wlc->txpwr_local_constraint) * WLC_TXPWR_DB_FACTOR;
799                 if (local_max > 0 && local_max < WLC_TXPWR_MAX)
800                         return (u8) local_max;
801                 if (local_max < 0)
802                         return 0;
803         }
804
805         return local;
806 }
807
808 /* propagate home chanspec to all bsscfgs in case bsscfg->current_bss->chanspec is referenced */
809 void wlc_set_home_chanspec(wlc_info_t *wlc, chanspec_t chanspec)
810 {
811         if (wlc->home_chanspec != chanspec) {
812                 int idx;
813                 wlc_bsscfg_t *cfg;
814
815                 wlc->home_chanspec = chanspec;
816
817                 FOREACH_BSS(wlc, idx, cfg) {
818                         if (!cfg->associated)
819                                 continue;
820                         cfg->target_bss->chanspec = chanspec;
821                         cfg->current_bss->chanspec = chanspec;
822                 }
823
824         }
825 }
826
827 static void wlc_set_phy_chanspec(wlc_info_t *wlc, chanspec_t chanspec)
828 {
829         /* Save our copy of the chanspec */
830         wlc->chanspec = chanspec;
831
832         /* Set the chanspec and power limits for this locale after computing
833          * any 11h local tx power constraints.
834          */
835         wlc_channel_set_chanspec(wlc->cmi, chanspec,
836                                  wlc_local_constraint_qdbm(wlc));
837
838         if (wlc->stf->ss_algosel_auto)
839                 wlc_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel,
840                                             chanspec);
841
842         wlc_stf_ss_update(wlc, wlc->band);
843
844 }
845
846 void wlc_set_chanspec(wlc_info_t *wlc, chanspec_t chanspec)
847 {
848         uint bandunit;
849         bool switchband = FALSE;
850         chanspec_t old_chanspec = wlc->chanspec;
851
852         if (!wlc_valid_chanspec_db(wlc->cmi, chanspec)) {
853                 WL_ERROR(("wl%d: %s: Bad channel %d\n",
854                           wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec)));
855                 ASSERT(wlc_valid_chanspec_db(wlc->cmi, chanspec));
856                 return;
857         }
858
859         /* Switch bands if necessary */
860         if (NBANDS(wlc) > 1) {
861                 bandunit = CHSPEC_WLCBANDUNIT(chanspec);
862                 if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) {
863                         switchband = TRUE;
864                         if (wlc->bandlocked) {
865                                 WL_ERROR(("wl%d: %s: chspec %d band is locked!\n", wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec)));
866                                 return;
867                         }
868                         /* BMAC_NOTE: should the setband call come after the wlc_bmac_chanspec() ?
869                          * if the setband updates (wlc_bsinit) use low level calls to inspect and
870                          * set state, the state inspected may be from the wrong band, or the
871                          * following wlc_bmac_set_chanspec() may undo the work.
872                          */
873                         wlc_setband(wlc, bandunit);
874                 }
875         }
876
877         ASSERT(N_ENAB(wlc->pub) || !CHSPEC_IS40(chanspec));
878
879         /* sync up phy/radio chanspec */
880         wlc_set_phy_chanspec(wlc, chanspec);
881
882         /* init antenna selection */
883         if (CHSPEC_WLC_BW(old_chanspec) != CHSPEC_WLC_BW(chanspec)) {
884                 if (WLANTSEL_ENAB(wlc))
885                         wlc_antsel_init(wlc->asi);
886
887                 /* Fix the hardware rateset based on bw.
888                  * Mainly add MCS32 for 40Mhz, remove MCS 32 for 20Mhz
889                  */
890                 wlc_rateset_bw_mcs_filter(&wlc->band->hw_rateset,
891                                           wlc->band->
892                                           mimo_cap_40 ? CHSPEC_WLC_BW(chanspec)
893                                           : 0);
894         }
895
896         /* update some mac configuration since chanspec changed */
897         wlc_ucode_mac_upd(wlc);
898 }
899
900 #if defined(BCMDBG)
901 static int wlc_get_current_txpwr(wlc_info_t *wlc, void *pwr, uint len)
902 {
903         txpwr_limits_t txpwr;
904         tx_power_t power;
905         tx_power_legacy_t *old_power = NULL;
906         int r, c;
907         uint qdbm;
908         bool override;
909
910         if (len == sizeof(tx_power_legacy_t))
911                 old_power = (tx_power_legacy_t *) pwr;
912         else if (len < sizeof(tx_power_t))
913                 return BCME_BUFTOOSHORT;
914
915         bzero(&power, sizeof(tx_power_t));
916
917         power.chanspec = WLC_BAND_PI_RADIO_CHANSPEC;
918         if (wlc->pub->associated)
919                 power.local_chanspec = wlc->home_chanspec;
920
921         /* Return the user target tx power limits for the various rates.  Note  wlc_phy.c's
922          * public interface only implements getting and setting a single value for all of
923          * rates, so we need to fill the array ourselves.
924          */
925         wlc_phy_txpower_get(wlc->band->pi, &qdbm, &override);
926         for (r = 0; r < WL_TX_POWER_RATES; r++) {
927                 power.user_limit[r] = (u8) qdbm;
928         }
929
930         power.local_max = wlc->txpwr_local_max * WLC_TXPWR_DB_FACTOR;
931         power.local_constraint =
932             wlc->txpwr_local_constraint * WLC_TXPWR_DB_FACTOR;
933
934         power.antgain[0] = wlc->bandstate[BAND_2G_INDEX]->antgain;
935         power.antgain[1] = wlc->bandstate[BAND_5G_INDEX]->antgain;
936
937         wlc_channel_reg_limits(wlc->cmi, power.chanspec, &txpwr);
938
939 #if WL_TX_POWER_CCK_NUM != WLC_NUM_RATES_CCK
940 #error "WL_TX_POWER_CCK_NUM != WLC_NUM_RATES_CCK"
941 #endif
942
943         /* CCK tx power limits */
944         for (c = 0, r = WL_TX_POWER_CCK_FIRST; c < WL_TX_POWER_CCK_NUM;
945              c++, r++)
946                 power.reg_limit[r] = txpwr.cck[c];
947
948 #if WL_TX_POWER_OFDM_NUM != WLC_NUM_RATES_OFDM
949 #error "WL_TX_POWER_OFDM_NUM != WLC_NUM_RATES_OFDM"
950 #endif
951
952         /* 20 MHz OFDM SISO tx power limits */
953         for (c = 0, r = WL_TX_POWER_OFDM_FIRST; c < WL_TX_POWER_OFDM_NUM;
954              c++, r++)
955                 power.reg_limit[r] = txpwr.ofdm[c];
956
957         if (WLC_PHY_11N_CAP(wlc->band)) {
958
959                 /* 20 MHz OFDM CDD tx power limits */
960                 for (c = 0, r = WL_TX_POWER_OFDM20_CDD_FIRST;
961                      c < WL_TX_POWER_OFDM_NUM; c++, r++)
962                         power.reg_limit[r] = txpwr.ofdm_cdd[c];
963
964                 /* 40 MHz OFDM SISO tx power limits */
965                 for (c = 0, r = WL_TX_POWER_OFDM40_SISO_FIRST;
966                      c < WL_TX_POWER_OFDM_NUM; c++, r++)
967                         power.reg_limit[r] = txpwr.ofdm_40_siso[c];
968
969                 /* 40 MHz OFDM CDD tx power limits */
970                 for (c = 0, r = WL_TX_POWER_OFDM40_CDD_FIRST;
971                      c < WL_TX_POWER_OFDM_NUM; c++, r++)
972                         power.reg_limit[r] = txpwr.ofdm_40_cdd[c];
973
974 #if WL_TX_POWER_MCS_1_STREAM_NUM != WLC_NUM_RATES_MCS_1_STREAM
975 #error "WL_TX_POWER_MCS_1_STREAM_NUM != WLC_NUM_RATES_MCS_1_STREAM"
976 #endif
977
978                 /* 20MHz MCS0-7 SISO tx power limits */
979                 for (c = 0, r = WL_TX_POWER_MCS20_SISO_FIRST;
980                      c < WLC_NUM_RATES_MCS_1_STREAM; c++, r++)
981                         power.reg_limit[r] = txpwr.mcs_20_siso[c];
982
983                 /* 20MHz MCS0-7 CDD tx power limits */
984                 for (c = 0, r = WL_TX_POWER_MCS20_CDD_FIRST;
985                      c < WLC_NUM_RATES_MCS_1_STREAM; c++, r++)
986                         power.reg_limit[r] = txpwr.mcs_20_cdd[c];
987
988                 /* 20MHz MCS0-7 STBC tx power limits */
989                 for (c = 0, r = WL_TX_POWER_MCS20_STBC_FIRST;
990                      c < WLC_NUM_RATES_MCS_1_STREAM; c++, r++)
991                         power.reg_limit[r] = txpwr.mcs_20_stbc[c];
992
993                 /* 40MHz MCS0-7 SISO tx power limits */
994                 for (c = 0, r = WL_TX_POWER_MCS40_SISO_FIRST;
995                      c < WLC_NUM_RATES_MCS_1_STREAM; c++, r++)
996                         power.reg_limit[r] = txpwr.mcs_40_siso[c];
997
998                 /* 40MHz MCS0-7 CDD tx power limits */
999                 for (c = 0, r = WL_TX_POWER_MCS40_CDD_FIRST;
1000                      c < WLC_NUM_RATES_MCS_1_STREAM; c++, r++)
1001                         power.reg_limit[r] = txpwr.mcs_40_cdd[c];
1002
1003                 /* 40MHz MCS0-7 STBC tx power limits */
1004                 for (c = 0, r = WL_TX_POWER_MCS40_STBC_FIRST;
1005                      c < WLC_NUM_RATES_MCS_1_STREAM; c++, r++)
1006                         power.reg_limit[r] = txpwr.mcs_40_stbc[c];
1007
1008 #if WL_TX_POWER_MCS_2_STREAM_NUM != WLC_NUM_RATES_MCS_2_STREAM
1009 #error "WL_TX_POWER_MCS_2_STREAM_NUM != WLC_NUM_RATES_MCS_2_STREAM"
1010 #endif
1011
1012                 /* 20MHz MCS8-15 SDM tx power limits */
1013                 for (c = 0, r = WL_TX_POWER_MCS20_SDM_FIRST;
1014                      c < WLC_NUM_RATES_MCS_2_STREAM; c++, r++)
1015                         power.reg_limit[r] = txpwr.mcs_20_mimo[c];
1016
1017                 /* 40MHz MCS8-15 SDM tx power limits */
1018                 for (c = 0, r = WL_TX_POWER_MCS40_SDM_FIRST;
1019                      c < WLC_NUM_RATES_MCS_2_STREAM; c++, r++)
1020                         power.reg_limit[r] = txpwr.mcs_40_mimo[c];
1021
1022                 /* MCS 32 */
1023                 power.reg_limit[WL_TX_POWER_MCS_32] = txpwr.mcs32;
1024         }
1025
1026         wlc_phy_txpower_get_current(wlc->band->pi, &power,
1027                                     CHSPEC_CHANNEL(power.chanspec));
1028
1029         /* copy the tx_power_t struct to the return buffer,
1030          * or convert to a tx_power_legacy_t struct
1031          */
1032         if (!old_power) {
1033                 bcopy(&power, pwr, sizeof(tx_power_t));
1034         } else {
1035                 int band_idx = CHSPEC_IS2G(power.chanspec) ? 0 : 1;
1036
1037                 bzero(old_power, sizeof(tx_power_legacy_t));
1038
1039                 old_power->txpwr_local_max = power.local_max;
1040                 old_power->txpwr_local_constraint = power.local_constraint;
1041                 if (CHSPEC_IS2G(power.chanspec)) {
1042                         old_power->txpwr_chan_reg_max = txpwr.cck[0];
1043                         old_power->txpwr_est_Pout[band_idx] =
1044                             power.est_Pout_cck;
1045                         old_power->txpwr_est_Pout_gofdm = power.est_Pout[0];
1046                 } else {
1047                         old_power->txpwr_chan_reg_max = txpwr.ofdm[0];
1048                         old_power->txpwr_est_Pout[band_idx] = power.est_Pout[0];
1049                 }
1050                 old_power->txpwr_antgain[0] = power.antgain[0];
1051                 old_power->txpwr_antgain[1] = power.antgain[1];
1052
1053                 for (r = 0; r < NUM_PWRCTRL_RATES; r++) {
1054                         old_power->txpwr_band_max[r] = power.user_limit[r];
1055                         old_power->txpwr_limit[r] = power.reg_limit[r];
1056                         old_power->txpwr_target[band_idx][r] = power.target[r];
1057                         if (CHSPEC_IS2G(power.chanspec))
1058                                 old_power->txpwr_bphy_cck_max[r] =
1059                                     power.board_limit[r];
1060                         else
1061                                 old_power->txpwr_aphy_max[r] =
1062                                     power.board_limit[r];
1063                 }
1064         }
1065
1066         return 0;
1067 }
1068 #endif                          /* defined(BCMDBG) */
1069
1070 static u32 wlc_watchdog_backup_bi(wlc_info_t *wlc)
1071 {
1072         u32 bi;
1073         bi = 2 * wlc->cfg->current_bss->dtim_period *
1074             wlc->cfg->current_bss->beacon_period;
1075         if (wlc->bcn_li_dtim)
1076                 bi *= wlc->bcn_li_dtim;
1077         else if (wlc->bcn_li_bcn)
1078                 /* recalculate bi based on bcn_li_bcn */
1079                 bi = 2 * wlc->bcn_li_bcn * wlc->cfg->current_bss->beacon_period;
1080
1081         if (bi < 2 * TIMER_INTERVAL_WATCHDOG)
1082                 bi = 2 * TIMER_INTERVAL_WATCHDOG;
1083         return bi;
1084 }
1085
1086 /* Change to run the watchdog either from a periodic timer or from tbtt handler.
1087  * Call watchdog from tbtt handler if tbtt is TRUE, watchdog timer otherwise.
1088  */
1089 void wlc_watchdog_upd(wlc_info_t *wlc, bool tbtt)
1090 {
1091         /* make sure changing watchdog driver is allowed */
1092         if (!wlc->pub->up || !wlc->pub->align_wd_tbtt)
1093                 return;
1094         if (!tbtt && wlc->WDarmed) {
1095                 wl_del_timer(wlc->wl, wlc->wdtimer);
1096                 wlc->WDarmed = FALSE;
1097         }
1098
1099         /* stop watchdog timer and use tbtt interrupt to drive watchdog */
1100         if (tbtt && wlc->WDarmed) {
1101                 wl_del_timer(wlc->wl, wlc->wdtimer);
1102                 wlc->WDarmed = FALSE;
1103                 wlc->WDlast = OSL_SYSUPTIME();
1104         }
1105         /* arm watchdog timer and drive the watchdog there */
1106         else if (!tbtt && !wlc->WDarmed) {
1107                 wl_add_timer(wlc->wl, wlc->wdtimer, TIMER_INTERVAL_WATCHDOG,
1108                              TRUE);
1109                 wlc->WDarmed = TRUE;
1110         }
1111         if (tbtt && !wlc->WDarmed) {
1112                 wl_add_timer(wlc->wl, wlc->wdtimer, wlc_watchdog_backup_bi(wlc),
1113                              TRUE);
1114                 wlc->WDarmed = TRUE;
1115         }
1116 }
1117
1118 ratespec_t wlc_lowest_basic_rspec(wlc_info_t *wlc, wlc_rateset_t *rs)
1119 {
1120         ratespec_t lowest_basic_rspec;
1121         uint i;
1122
1123         /* Use the lowest basic rate */
1124         lowest_basic_rspec = rs->rates[0] & RATE_MASK;
1125         for (i = 0; i < rs->count; i++) {
1126                 if (rs->rates[i] & WLC_RATE_FLAG) {
1127                         lowest_basic_rspec = rs->rates[i] & RATE_MASK;
1128                         break;
1129                 }
1130         }
1131 #if NCONF
1132         /* pick siso/cdd as default for OFDM (note no basic rate MCSs are supported yet) */
1133         if (IS_OFDM(lowest_basic_rspec)) {
1134                 lowest_basic_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
1135         }
1136 #endif
1137
1138         return lowest_basic_rspec;
1139 }
1140
1141 /* This function changes the phytxctl for beacon based on current beacon ratespec AND txant
1142  * setting as per this table:
1143  *  ratespec     CCK            ant = wlc->stf->txant
1144  *              OFDM            ant = 3
1145  */
1146 void wlc_beacon_phytxctl_txant_upd(wlc_info_t *wlc, ratespec_t bcn_rspec)
1147 {
1148         u16 phyctl;
1149         u16 phytxant = wlc->stf->phytxant;
1150         u16 mask = PHY_TXC_ANT_MASK;
1151
1152         /* for non-siso rates or default setting, use the available chains */
1153         if (WLC_PHY_11N_CAP(wlc->band)) {
1154                 phytxant = wlc_stf_phytxchain_sel(wlc, bcn_rspec);
1155         }
1156
1157         phyctl = wlc_read_shm(wlc, M_BCN_PCTLWD);
1158         phyctl = (phyctl & ~mask) | phytxant;
1159         wlc_write_shm(wlc, M_BCN_PCTLWD, phyctl);
1160 }
1161
1162 /* centralized protection config change function to simplify debugging, no consistency checking
1163  * this should be called only on changes to avoid overhead in periodic function
1164 */
1165 void wlc_protection_upd(wlc_info_t *wlc, uint idx, int val)
1166 {
1167         WL_TRACE(("wlc_protection_upd: idx %d, val %d\n", idx, val));
1168
1169         switch (idx) {
1170         case WLC_PROT_G_SPEC:
1171                 wlc->protection->_g = (bool) val;
1172                 break;
1173         case WLC_PROT_G_OVR:
1174                 wlc->protection->g_override = (s8) val;
1175                 break;
1176         case WLC_PROT_G_USER:
1177                 wlc->protection->gmode_user = (u8) val;
1178                 break;
1179         case WLC_PROT_OVERLAP:
1180                 wlc->protection->overlap = (s8) val;
1181                 break;
1182         case WLC_PROT_N_USER:
1183                 wlc->protection->nmode_user = (s8) val;
1184                 break;
1185         case WLC_PROT_N_CFG:
1186                 wlc->protection->n_cfg = (s8) val;
1187                 break;
1188         case WLC_PROT_N_CFG_OVR:
1189                 wlc->protection->n_cfg_override = (s8) val;
1190                 break;
1191         case WLC_PROT_N_NONGF:
1192                 wlc->protection->nongf = (bool) val;
1193                 break;
1194         case WLC_PROT_N_NONGF_OVR:
1195                 wlc->protection->nongf_override = (s8) val;
1196                 break;
1197         case WLC_PROT_N_PAM_OVR:
1198                 wlc->protection->n_pam_override = (s8) val;
1199                 break;
1200         case WLC_PROT_N_OBSS:
1201                 wlc->protection->n_obss = (bool) val;
1202                 break;
1203
1204         default:
1205                 ASSERT(0);
1206                 break;
1207         }
1208
1209 }
1210
1211 static void wlc_ht_update_sgi_rx(wlc_info_t *wlc, int val)
1212 {
1213         wlc->ht_cap.cap &= ~(HT_CAP_SHORT_GI_20 | HT_CAP_SHORT_GI_40);
1214         wlc->ht_cap.cap |= (val & WLC_N_SGI_20) ? HT_CAP_SHORT_GI_20 : 0;
1215         wlc->ht_cap.cap |= (val & WLC_N_SGI_40) ? HT_CAP_SHORT_GI_40 : 0;
1216
1217         if (wlc->pub->up) {
1218                 wlc_update_beacon(wlc);
1219                 wlc_update_probe_resp(wlc, TRUE);
1220         }
1221 }
1222
1223 static void wlc_ht_update_ldpc(wlc_info_t *wlc, s8 val)
1224 {
1225         wlc->stf->ldpc = val;
1226
1227         wlc->ht_cap.cap &= ~HT_CAP_LDPC_CODING;
1228         if (wlc->stf->ldpc != OFF)
1229                 wlc->ht_cap.cap |= HT_CAP_LDPC_CODING;
1230
1231         if (wlc->pub->up) {
1232                 wlc_update_beacon(wlc);
1233                 wlc_update_probe_resp(wlc, TRUE);
1234                 wlc_phy_ldpc_override_set(wlc->band->pi, (val ? TRUE : FALSE));
1235         }
1236 }
1237
1238 /*
1239  * ucode, hwmac update
1240  *    Channel dependent updates for ucode and hw
1241  */
1242 static void wlc_ucode_mac_upd(wlc_info_t *wlc)
1243 {
1244         /* enable or disable any active IBSSs depending on whether or not
1245          * we are on the home channel
1246          */
1247         if (wlc->home_chanspec == WLC_BAND_PI_RADIO_CHANSPEC) {
1248                 if (wlc->pub->associated) {
1249                         /* BMAC_NOTE: This is something that should be fixed in ucode inits.
1250                          * I think that the ucode inits set up the bcn templates and shm values
1251                          * with a bogus beacon. This should not be done in the inits. If ucode needs
1252                          * to set up a beacon for testing, the test routines should write it down,
1253                          * not expect the inits to populate a bogus beacon.
1254                          */
1255                         if (WLC_PHY_11N_CAP(wlc->band)) {
1256                                 wlc_write_shm(wlc, M_BCN_TXTSF_OFFSET,
1257                                               wlc->band->bcntsfoff);
1258                         }
1259                 }
1260         } else {
1261                 /* disable an active IBSS if we are not on the home channel */
1262         }
1263
1264         /* update the various promisc bits */
1265         wlc_mac_bcn_promisc(wlc);
1266         wlc_mac_promisc(wlc);
1267 }
1268
1269 static void wlc_bandinit_ordered(wlc_info_t *wlc, chanspec_t chanspec)
1270 {
1271         wlc_rateset_t default_rateset;
1272         uint parkband;
1273         uint i, band_order[2];
1274
1275         WL_TRACE(("wl%d: wlc_bandinit_ordered\n", wlc->pub->unit));
1276         /*
1277          * We might have been bandlocked during down and the chip power-cycled (hibernate).
1278          * figure out the right band to park on
1279          */
1280         if (wlc->bandlocked || NBANDS(wlc) == 1) {
1281                 ASSERT(CHSPEC_WLCBANDUNIT(chanspec) == wlc->band->bandunit);
1282
1283                 parkband = wlc->band->bandunit; /* updated in wlc_bandlock() */
1284                 band_order[0] = band_order[1] = parkband;
1285         } else {
1286                 /* park on the band of the specified chanspec */
1287                 parkband = CHSPEC_WLCBANDUNIT(chanspec);
1288
1289                 /* order so that parkband initialize last */
1290                 band_order[0] = parkband ^ 1;
1291                 band_order[1] = parkband;
1292         }
1293
1294         /* make each band operational, software state init */
1295         for (i = 0; i < NBANDS(wlc); i++) {
1296                 uint j = band_order[i];
1297
1298                 wlc->band = wlc->bandstate[j];
1299
1300                 wlc_default_rateset(wlc, &default_rateset);
1301
1302                 /* fill in hw_rate */
1303                 wlc_rateset_filter(&default_rateset, &wlc->band->hw_rateset,
1304                                    FALSE, WLC_RATES_CCK_OFDM, RATE_MASK,
1305                                    (bool) N_ENAB(wlc->pub));
1306
1307                 /* init basic rate lookup */
1308                 wlc_rate_lookup_init(wlc, &default_rateset);
1309         }
1310
1311         /* sync up phy/radio chanspec */
1312         wlc_set_phy_chanspec(wlc, chanspec);
1313 }
1314
1315 /* band-specific init */
1316 static void WLBANDINITFN(wlc_bsinit) (wlc_info_t *wlc)
1317 {
1318         WL_TRACE(("wl%d: wlc_bsinit: bandunit %d\n", wlc->pub->unit,
1319                   wlc->band->bandunit));
1320
1321         /* write ucode ACK/CTS rate table */
1322         wlc_set_ratetable(wlc);
1323
1324         /* update some band specific mac configuration */
1325         wlc_ucode_mac_upd(wlc);
1326
1327         /* init antenna selection */
1328         if (WLANTSEL_ENAB(wlc))
1329                 wlc_antsel_init(wlc->asi);
1330
1331 }
1332
1333 /* switch to and initialize new band */
1334 static void WLBANDINITFN(wlc_setband) (wlc_info_t *wlc, uint bandunit)
1335 {
1336         int idx;
1337         wlc_bsscfg_t *cfg;
1338
1339         ASSERT(NBANDS(wlc) > 1);
1340         ASSERT(!wlc->bandlocked);
1341         ASSERT(bandunit != wlc->band->bandunit || wlc->bandinit_pending);
1342
1343         wlc->band = wlc->bandstate[bandunit];
1344
1345         if (!wlc->pub->up)
1346                 return;
1347
1348         /* wait for at least one beacon before entering sleeping state */
1349         wlc->PMawakebcn = TRUE;
1350         FOREACH_AS_STA(wlc, idx, cfg)
1351             cfg->PMawakebcn = TRUE;
1352         wlc_set_ps_ctrl(wlc);
1353
1354         /* band-specific initializations */
1355         wlc_bsinit(wlc);
1356 }
1357
1358 /* Initialize a WME Parameter Info Element with default STA parameters from WMM Spec, Table 12 */
1359 void wlc_wme_initparams_sta(wlc_info_t *wlc, wme_param_ie_t *pe)
1360 {
1361         static const wme_param_ie_t stadef = {
1362                 WME_OUI,
1363                 WME_TYPE,
1364                 WME_SUBTYPE_PARAM_IE,
1365                 WME_VER,
1366                 0,
1367                 0,
1368                 {
1369                  {EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA,
1370                   HTOL16(EDCF_AC_BE_TXOP_STA)},
1371                  {EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA,
1372                   HTOL16(EDCF_AC_BK_TXOP_STA)},
1373                  {EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA,
1374                   HTOL16(EDCF_AC_VI_TXOP_STA)},
1375                  {EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA,
1376                   HTOL16(EDCF_AC_VO_TXOP_STA)}
1377                  }
1378         };
1379
1380         ASSERT(sizeof(*pe) == WME_PARAM_IE_LEN);
1381         memcpy(pe, &stadef, sizeof(*pe));
1382 }
1383
1384 void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend)
1385 {
1386         int i;
1387         shm_acparams_t acp_shm;
1388         u16 *shm_entry;
1389         struct ieee80211_tx_queue_params *params = arg;
1390
1391         ASSERT(wlc);
1392
1393         /* Only apply params if the core is out of reset and has clocks */
1394         if (!wlc->clk) {
1395                 WL_ERROR(("wl%d: %s : no-clock\n", wlc->pub->unit, __func__));
1396                 return;
1397         }
1398
1399         /*
1400          * AP uses AC params from wme_param_ie_ap.
1401          * AP advertises AC params from wme_param_ie.
1402          * STA uses AC params from wme_param_ie.
1403          */
1404
1405         wlc->wme_admctl = 0;
1406
1407         do {
1408                 bzero((char *)&acp_shm, sizeof(shm_acparams_t));
1409                 /* find out which ac this set of params applies to */
1410                 ASSERT(aci < AC_COUNT);
1411                 /* set the admission control policy for this AC */
1412                 /* wlc->wme_admctl |= 1 << aci; *//* should be set ??  seems like off by default */
1413
1414                 /* fill in shm ac params struct */
1415                 acp_shm.txop = ltoh16(params->txop);
1416                 /* convert from units of 32us to us for ucode */
1417                 wlc->edcf_txop[aci & 0x3] = acp_shm.txop =
1418                     EDCF_TXOP2USEC(acp_shm.txop);
1419                 acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK);
1420
1421                 if (aci == AC_VI && acp_shm.txop == 0
1422                     && acp_shm.aifs < EDCF_AIFSN_MAX)
1423                         acp_shm.aifs++;
1424
1425                 if (acp_shm.aifs < EDCF_AIFSN_MIN
1426                     || acp_shm.aifs > EDCF_AIFSN_MAX) {
1427                         WL_ERROR(("wl%d: wlc_edcf_setparams: bad aifs %d\n",
1428                                   wlc->pub->unit, acp_shm.aifs));
1429                         continue;
1430                 }
1431
1432                 acp_shm.cwmin = params->cw_min;
1433                 acp_shm.cwmax = params->cw_max;
1434                 acp_shm.cwcur = acp_shm.cwmin;
1435                 acp_shm.bslots =
1436                     R_REG(wlc->osh, &wlc->regs->tsf_random) & acp_shm.cwcur;
1437                 acp_shm.reggap = acp_shm.bslots + acp_shm.aifs;
1438                 /* Indicate the new params to the ucode */
1439                 acp_shm.status = wlc_read_shm(wlc, (M_EDCF_QINFO +
1440                                                     wme_shmemacindex(aci) *
1441                                                     M_EDCF_QLEN +
1442                                                     M_EDCF_STATUS_OFF));
1443                 acp_shm.status |= WME_STATUS_NEWAC;
1444
1445                 /* Fill in shm acparam table */
1446                 shm_entry = (u16 *) &acp_shm;
1447                 for (i = 0; i < (int)sizeof(shm_acparams_t); i += 2)
1448                         wlc_write_shm(wlc,
1449                                       M_EDCF_QINFO +
1450                                       wme_shmemacindex(aci) * M_EDCF_QLEN + i,
1451                                       *shm_entry++);
1452
1453         } while (0);
1454
1455         if (suspend)
1456                 wlc_suspend_mac_and_wait(wlc);
1457
1458         if (suspend)
1459                 wlc_enable_mac(wlc);
1460
1461 }
1462
1463 void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend)
1464 {
1465         wlc_info_t *wlc = cfg->wlc;
1466         uint aci, i, j;
1467         edcf_acparam_t *edcf_acp;
1468         shm_acparams_t acp_shm;
1469         u16 *shm_entry;
1470
1471         ASSERT(cfg);
1472         ASSERT(wlc);
1473
1474         /* Only apply params if the core is out of reset and has clocks */
1475         if (!wlc->clk)
1476                 return;
1477
1478         /*
1479          * AP uses AC params from wme_param_ie_ap.
1480          * AP advertises AC params from wme_param_ie.
1481          * STA uses AC params from wme_param_ie.
1482          */
1483
1484         edcf_acp = (edcf_acparam_t *) &wlc->wme_param_ie.acparam[0];
1485
1486         wlc->wme_admctl = 0;
1487
1488         for (i = 0; i < AC_COUNT; i++, edcf_acp++) {
1489                 bzero((char *)&acp_shm, sizeof(shm_acparams_t));
1490                 /* find out which ac this set of params applies to */
1491                 aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;
1492                 ASSERT(aci < AC_COUNT);
1493                 /* set the admission control policy for this AC */
1494                 if (edcf_acp->ACI & EDCF_ACM_MASK) {
1495                         wlc->wme_admctl |= 1 << aci;
1496                 }
1497
1498                 /* fill in shm ac params struct */
1499                 acp_shm.txop = ltoh16(edcf_acp->TXOP);
1500                 /* convert from units of 32us to us for ucode */
1501                 wlc->edcf_txop[aci] = acp_shm.txop =
1502                     EDCF_TXOP2USEC(acp_shm.txop);
1503                 acp_shm.aifs = (edcf_acp->ACI & EDCF_AIFSN_MASK);
1504
1505                 if (aci == AC_VI && acp_shm.txop == 0
1506                     && acp_shm.aifs < EDCF_AIFSN_MAX)
1507                         acp_shm.aifs++;
1508
1509                 if (acp_shm.aifs < EDCF_AIFSN_MIN
1510                     || acp_shm.aifs > EDCF_AIFSN_MAX) {
1511                         WL_ERROR(("wl%d: wlc_edcf_setparams: bad aifs %d\n",
1512                                   wlc->pub->unit, acp_shm.aifs));
1513                         continue;
1514                 }
1515
1516                 /* CWmin = 2^(ECWmin) - 1 */
1517                 acp_shm.cwmin = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK);
1518                 /* CWmax = 2^(ECWmax) - 1 */
1519                 acp_shm.cwmax = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK)
1520                                             >> EDCF_ECWMAX_SHIFT);
1521                 acp_shm.cwcur = acp_shm.cwmin;
1522                 acp_shm.bslots =
1523                     R_REG(wlc->osh, &wlc->regs->tsf_random) & acp_shm.cwcur;
1524                 acp_shm.reggap = acp_shm.bslots + acp_shm.aifs;
1525                 /* Indicate the new params to the ucode */
1526                 acp_shm.status = wlc_read_shm(wlc, (M_EDCF_QINFO +
1527                                                     wme_shmemacindex(aci) *
1528                                                     M_EDCF_QLEN +
1529                                                     M_EDCF_STATUS_OFF));
1530                 acp_shm.status |= WME_STATUS_NEWAC;
1531
1532                 /* Fill in shm acparam table */
1533                 shm_entry = (u16 *) &acp_shm;
1534                 for (j = 0; j < (int)sizeof(shm_acparams_t); j += 2)
1535                         wlc_write_shm(wlc,
1536                                       M_EDCF_QINFO +
1537                                       wme_shmemacindex(aci) * M_EDCF_QLEN + j,
1538                                       *shm_entry++);
1539         }
1540
1541         if (suspend)
1542                 wlc_suspend_mac_and_wait(wlc);
1543
1544         if (AP_ENAB(wlc->pub) && WME_ENAB(wlc->pub)) {
1545                 wlc_update_beacon(wlc);
1546                 wlc_update_probe_resp(wlc, FALSE);
1547         }
1548
1549         if (suspend)
1550                 wlc_enable_mac(wlc);
1551
1552 }
1553
1554 bool wlc_timers_init(wlc_info_t *wlc, int unit)
1555 {
1556         wlc->wdtimer = wl_init_timer(wlc->wl, wlc_watchdog_by_timer,
1557                 wlc, "watchdog");
1558         if (!wlc->wdtimer) {
1559                 WL_ERROR(("wl%d:  wl_init_timer for wdtimer failed\n", unit));
1560                 goto fail;
1561         }
1562
1563         wlc->radio_timer = wl_init_timer(wlc->wl, wlc_radio_timer,
1564                 wlc, "radio");
1565         if (!wlc->radio_timer) {
1566                 WL_ERROR(("wl%d:  wl_init_timer for radio_timer failed\n",
1567                           unit));
1568                 goto fail;
1569         }
1570
1571         return TRUE;
1572
1573  fail:
1574         return FALSE;
1575 }
1576
1577 /*
1578  * Initialize wlc_info default values ...
1579  * may get overrides later in this function
1580  */
1581 void wlc_info_init(wlc_info_t *wlc, int unit)
1582 {
1583         int i;
1584         /* Assume the device is there until proven otherwise */
1585         wlc->device_present = TRUE;
1586
1587         /* set default power output percentage to 100 percent */
1588         wlc->txpwr_percent = 100;
1589
1590         /* Save our copy of the chanspec */
1591         wlc->chanspec = CH20MHZ_CHSPEC(1);
1592
1593         /* initialize CCK preamble mode to unassociated state */
1594         wlc->shortpreamble = FALSE;
1595
1596         wlc->legacy_probe = TRUE;
1597
1598         /* various 802.11g modes */
1599         wlc->shortslot = FALSE;
1600         wlc->shortslot_override = WLC_SHORTSLOT_AUTO;
1601
1602         wlc->barker_overlap_control = TRUE;
1603         wlc->barker_preamble = WLC_BARKER_SHORT_ALLOWED;
1604         wlc->txburst_limit_override = AUTO;
1605
1606         wlc_protection_upd(wlc, WLC_PROT_G_OVR, WLC_PROTECTION_AUTO);
1607         wlc_protection_upd(wlc, WLC_PROT_G_SPEC, FALSE);
1608
1609         wlc_protection_upd(wlc, WLC_PROT_N_CFG_OVR, WLC_PROTECTION_AUTO);
1610         wlc_protection_upd(wlc, WLC_PROT_N_CFG, WLC_N_PROTECTION_OFF);
1611         wlc_protection_upd(wlc, WLC_PROT_N_NONGF_OVR, WLC_PROTECTION_AUTO);
1612         wlc_protection_upd(wlc, WLC_PROT_N_NONGF, FALSE);
1613         wlc_protection_upd(wlc, WLC_PROT_N_PAM_OVR, AUTO);
1614
1615         wlc_protection_upd(wlc, WLC_PROT_OVERLAP, WLC_PROTECTION_CTL_OVERLAP);
1616
1617         /* 802.11g draft 4.0 NonERP elt advertisement */
1618         wlc->include_legacy_erp = TRUE;
1619
1620         wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF;
1621         wlc->stf->txant = ANT_TX_DEF;
1622
1623         wlc->prb_resp_timeout = WLC_PRB_RESP_TIMEOUT;
1624
1625         wlc->usr_fragthresh = DOT11_DEFAULT_FRAG_LEN;
1626         for (i = 0; i < NFIFO; i++)
1627                 wlc->fragthresh[i] = DOT11_DEFAULT_FRAG_LEN;
1628         wlc->RTSThresh = DOT11_DEFAULT_RTS_LEN;
1629
1630         /* default rate fallback retry limits */
1631         wlc->SFBL = RETRY_SHORT_FB;
1632         wlc->LFBL = RETRY_LONG_FB;
1633
1634         /* default mac retry limits */
1635         wlc->SRL = RETRY_SHORT_DEF;
1636         wlc->LRL = RETRY_LONG_DEF;
1637
1638         /* init PM state */
1639         wlc->PM = PM_OFF;       /* User's setting of PM mode through IOCTL */
1640         wlc->PM_override = FALSE;       /* Prevents from going to PM if our AP is 'ill' */
1641         wlc->PMenabled = FALSE; /* Current PM state */
1642         wlc->PMpending = FALSE; /* Tracks whether STA indicated PM in the last attempt */
1643         wlc->PMblocked = FALSE; /* To allow blocking going into PM during RM and scans */
1644
1645         /* In WMM Auto mode, PM is allowed if association is a UAPSD association */
1646         wlc->WME_PM_blocked = FALSE;
1647
1648         /* Init wme queuing method */
1649         wlc->wme_prec_queuing = FALSE;
1650
1651         /* Overrides for the core to stay awake under zillion conditions Look for STAY_AWAKE */
1652         wlc->wake = FALSE;
1653         /* Are we waiting for a response to PS-Poll that we sent */
1654         wlc->PSpoll = FALSE;
1655
1656         /* APSD defaults */
1657         wlc->wme_apsd = TRUE;
1658         wlc->apsd_sta_usp = FALSE;
1659         wlc->apsd_trigger_timeout = 0;  /* disable the trigger timer */
1660         wlc->apsd_trigger_ac = AC_BITMAP_ALL;
1661
1662         /* Set flag to indicate that hw keys should be used when available. */
1663         wlc->wsec_swkeys = FALSE;
1664
1665         /* init the 4 static WEP default keys */
1666         for (i = 0; i < WSEC_MAX_DEFAULT_KEYS; i++) {
1667                 wlc->wsec_keys[i] = wlc->wsec_def_keys[i];
1668                 wlc->wsec_keys[i]->idx = (u8) i;
1669         }
1670
1671         wlc->_regulatory_domain = FALSE;        /* 802.11d */
1672
1673         /* WME QoS mode is Auto by default */
1674         wlc->pub->_wme = AUTO;
1675
1676 #ifdef BCMSDIODEV_ENABLED
1677         wlc->pub->_priofc = TRUE;       /* enable priority flow control for sdio dongle */
1678 #endif
1679
1680         wlc->pub->_ampdu = AMPDU_AGG_HOST;
1681         wlc->pub->bcmerror = 0;
1682         wlc->ibss_allowed = TRUE;
1683         wlc->ibss_coalesce_allowed = TRUE;
1684         wlc->pub->_coex = ON;
1685
1686         /* intialize mpc delay */
1687         wlc->mpc_delay_off = wlc->mpc_dlycnt = WLC_MPC_MIN_DELAYCNT;
1688
1689         wlc->pr80838_war = TRUE;
1690 }
1691
1692 static bool wlc_state_bmac_sync(wlc_info_t *wlc)
1693 {
1694         wlc_bmac_state_t state_bmac;
1695
1696         if (wlc_bmac_state_get(wlc->hw, &state_bmac) != 0)
1697                 return FALSE;
1698
1699         wlc->machwcap = state_bmac.machwcap;
1700         wlc_protection_upd(wlc, WLC_PROT_N_PAM_OVR,
1701                            (s8) state_bmac.preamble_ovr);
1702
1703         return TRUE;
1704 }
1705
1706 static uint wlc_attach_module(wlc_info_t *wlc)
1707 {
1708         uint err = 0;
1709         uint unit;
1710         unit = wlc->pub->unit;
1711
1712         wlc->asi = wlc_antsel_attach(wlc, wlc->osh, wlc->pub, wlc->hw);
1713         if (wlc->asi == NULL) {
1714                 WL_ERROR(("wl%d: wlc_attach: wlc_antsel_attach failed\n",
1715                           unit));
1716                 err = 44;
1717                 goto fail;
1718         }
1719
1720         wlc->ampdu = wlc_ampdu_attach(wlc);
1721         if (wlc->ampdu == NULL) {
1722                 WL_ERROR(("wl%d: wlc_attach: wlc_ampdu_attach failed\n", unit));
1723                 err = 50;
1724                 goto fail;
1725         }
1726
1727         /* Initialize event queue; needed before following calls */
1728         wlc->eventq =
1729             wlc_eventq_attach(wlc->pub, wlc, wlc->wl, wlc_process_eventq);
1730         if (wlc->eventq == NULL) {
1731                 WL_ERROR(("wl%d: wlc_attach: wlc_eventq_attachfailed\n", unit));
1732                 err = 57;
1733                 goto fail;
1734         }
1735
1736         if ((wlc_stf_attach(wlc) != 0)) {
1737                 WL_ERROR(("wl%d: wlc_attach: wlc_stf_attach failed\n", unit));
1738                 err = 68;
1739                 goto fail;
1740         }
1741  fail:
1742         return err;
1743 }
1744
1745 wlc_pub_t *wlc_pub(void *wlc)
1746 {
1747         return ((wlc_info_t *) wlc)->pub;
1748 }
1749
1750 #define CHIP_SUPPORTS_11N(wlc)  1
1751
1752 /*
1753  * The common driver entry routine. Error codes should be unique
1754  */
1755 void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
1756                  osl_t *osh, void *regsva, uint bustype, void *btparam,
1757                  uint *perr)
1758 {
1759         wlc_info_t *wlc;
1760         uint err = 0;
1761         uint j;
1762         wlc_pub_t *pub;
1763         wlc_txq_info_t *qi;
1764         uint n_disabled;
1765
1766         WL_NONE(("wl%d: %s: vendor 0x%x device 0x%x\n", unit, __func__, vendor,
1767                  device));
1768
1769         ASSERT(WSEC_MAX_RCMTA_KEYS <= WSEC_MAX_KEYS);
1770         ASSERT(WSEC_MAX_DEFAULT_KEYS == WLC_DEFAULT_KEYS);
1771
1772         /* some code depends on packed structures */
1773         ASSERT(sizeof(struct ether_addr) == ETHER_ADDR_LEN);
1774         ASSERT(sizeof(struct ether_header) == ETHER_HDR_LEN);
1775         ASSERT(sizeof(d11regs_t) == SI_CORE_SIZE);
1776         ASSERT(sizeof(ofdm_phy_hdr_t) == D11_PHY_HDR_LEN);
1777         ASSERT(sizeof(cck_phy_hdr_t) == D11_PHY_HDR_LEN);
1778         ASSERT(sizeof(d11txh_t) == D11_TXH_LEN);
1779         ASSERT(sizeof(d11rxhdr_t) == RXHDR_LEN);
1780         ASSERT(sizeof(struct dot11_header) == DOT11_A4_HDR_LEN);
1781         ASSERT(sizeof(struct dot11_rts_frame) == DOT11_RTS_LEN);
1782         ASSERT(sizeof(struct dot11_management_header) == DOT11_MGMT_HDR_LEN);
1783         ASSERT(sizeof(struct dot11_bcn_prb) == DOT11_BCN_PRB_LEN);
1784         ASSERT(sizeof(tx_status_t) == TXSTATUS_LEN);
1785         ASSERT(sizeof(ht_cap_ie_t) == HT_CAP_IE_LEN);
1786         ASSERT(offsetof(wl_scan_params_t, channel_list) ==
1787                WL_SCAN_PARAMS_FIXED_SIZE);
1788         ASSERT(IS_ALIGNED(offsetof(wsec_key_t, data), sizeof(u32)));
1789         ASSERT(ISPOWEROF2(MA_WINDOW_SZ));
1790
1791         ASSERT(sizeof(wlc_d11rxhdr_t) <= WL_HWRXOFF);
1792
1793         /*
1794          * Number of replay counters value used in WPA IE must match # rxivs
1795          * supported in wsec_key_t struct. See 802.11i/D3.0 sect. 7.3.2.17
1796          * 'RSN Information Element' figure 8 for this mapping.
1797          */
1798         ASSERT((WPA_CAP_16_REPLAY_CNTRS == WLC_REPLAY_CNTRS_VALUE
1799                 && 16 == WLC_NUMRXIVS)
1800                || (WPA_CAP_4_REPLAY_CNTRS == WLC_REPLAY_CNTRS_VALUE
1801                    && 4 == WLC_NUMRXIVS));
1802
1803         /* allocate wlc_info_t state and its substructures */
1804         wlc = (wlc_info_t *) wlc_attach_malloc(osh, unit, &err, device);
1805         if (wlc == NULL)
1806                 goto fail;
1807         wlc->osh = osh;
1808         pub = wlc->pub;
1809
1810 #if defined(BCMDBG)
1811         wlc_info_dbg = wlc;
1812 #endif
1813
1814         wlc->band = wlc->bandstate[0];
1815         wlc->core = wlc->corestate;
1816         wlc->wl = wl;
1817         pub->unit = unit;
1818         pub->osh = osh;
1819         wlc->btparam = btparam;
1820         pub->_piomode = piomode;
1821         wlc->bandinit_pending = FALSE;
1822         /* By default restrict TKIP associations from 11n STA's */
1823         wlc->ht_wsec_restriction = WLC_HT_TKIP_RESTRICT;
1824
1825         /* populate wlc_info_t with default values  */
1826         wlc_info_init(wlc, unit);
1827
1828         /* update sta/ap related parameters */
1829         wlc_ap_upd(wlc);
1830
1831         /* 11n_disable nvram */
1832         n_disabled = getintvar(pub->vars, "11n_disable");
1833
1834         /* register a module (to handle iovars) */
1835         wlc_module_register(wlc->pub, wlc_iovars, "wlc_iovars", wlc,
1836                             wlc_doiovar, NULL, NULL);
1837
1838         /* low level attach steps(all hw accesses go inside, no more in rest of the attach) */
1839         err = wlc_bmac_attach(wlc, vendor, device, unit, piomode, osh, regsva,
1840                               bustype, btparam);
1841         if (err)
1842                 goto fail;
1843
1844         /* for some states, due to different info pointer(e,g, wlc, wlc_hw) or master/slave split,
1845          * HIGH driver(both monolithic and HIGH_ONLY) needs to sync states FROM BMAC portion driver
1846          */
1847         if (!wlc_state_bmac_sync(wlc)) {
1848                 err = 20;
1849                 goto fail;
1850         }
1851
1852         pub->phy_11ncapable = WLC_PHY_11N_CAP(wlc->band);
1853
1854         /* propagate *vars* from BMAC driver to high driver */
1855         wlc_bmac_copyfrom_vars(wlc->hw, &pub->vars, &wlc->vars_size);
1856
1857 #ifdef WLC_HIGH_ONLY
1858         WL_TRACE(("nvram : vars %p , vars_size %d\n", pub->vars,
1859                   wlc->vars_size));
1860 #endif
1861
1862         /* set maximum allowed duty cycle */
1863         wlc->tx_duty_cycle_ofdm =
1864             (u16) getintvar(pub->vars, "tx_duty_cycle_ofdm");
1865         wlc->tx_duty_cycle_cck =
1866             (u16) getintvar(pub->vars, "tx_duty_cycle_cck");
1867
1868         wlc_stf_phy_chain_calc(wlc);
1869
1870         /* txchain 1: txant 0, txchain 2: txant 1 */
1871         if (WLCISNPHY(wlc->band) && (wlc->stf->txstreams == 1))
1872                 wlc->stf->txant = wlc->stf->hw_txchain - 1;
1873
1874         /* push to BMAC driver */
1875         wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain,
1876                                wlc->stf->hw_rxchain);
1877
1878 #ifdef WLC_LOW
1879         /* pull up some info resulting from the low attach */
1880         {
1881                 int i;
1882                 for (i = 0; i < NFIFO; i++)
1883                         wlc->core->txavail[i] = wlc->hw->txavail[i];
1884         }
1885 #endif                          /* WLC_LOW */
1886
1887         wlc_bmac_hw_etheraddr(wlc->hw, &wlc->perm_etheraddr);
1888
1889         bcopy((char *)&wlc->perm_etheraddr, (char *)&pub->cur_etheraddr,
1890               ETHER_ADDR_LEN);
1891
1892         for (j = 0; j < NBANDS(wlc); j++) {
1893                 /* Use band 1 for single band 11a */
1894                 if (IS_SINGLEBAND_5G(wlc->deviceid))
1895                         j = BAND_5G_INDEX;
1896
1897                 wlc->band = wlc->bandstate[j];
1898
1899                 if (!wlc_attach_stf_ant_init(wlc)) {
1900                         err = 24;
1901                         goto fail;
1902                 }
1903
1904                 /* default contention windows size limits */
1905                 wlc->band->CWmin = APHY_CWMIN;
1906                 wlc->band->CWmax = PHY_CWMAX;
1907
1908                 /* init gmode value */
1909                 if (BAND_2G(wlc->band->bandtype)) {
1910                         wlc->band->gmode = GMODE_AUTO;
1911                         wlc_protection_upd(wlc, WLC_PROT_G_USER,
1912                                            wlc->band->gmode);
1913                 }
1914
1915                 /* init _n_enab supported mode */
1916                 if (WLC_PHY_11N_CAP(wlc->band) && CHIP_SUPPORTS_11N(wlc)) {
1917                         if (n_disabled & WLFEATURE_DISABLE_11N) {
1918                                 pub->_n_enab = OFF;
1919                                 wlc_protection_upd(wlc, WLC_PROT_N_USER, OFF);
1920                         } else {
1921                                 pub->_n_enab = SUPPORT_11N;
1922                                 wlc_protection_upd(wlc, WLC_PROT_N_USER,
1923                                                    ((pub->_n_enab ==
1924                                                      SUPPORT_11N) ? WL_11N_2x2 :
1925                                                     WL_11N_3x3));
1926                         }
1927                 }
1928
1929                 /* init per-band default rateset, depend on band->gmode */
1930                 wlc_default_rateset(wlc, &wlc->band->defrateset);
1931
1932                 /* fill in hw_rateset (used early by WLC_SET_RATESET) */
1933                 wlc_rateset_filter(&wlc->band->defrateset,
1934                                    &wlc->band->hw_rateset, FALSE,
1935                                    WLC_RATES_CCK_OFDM, RATE_MASK,
1936                                    (bool) N_ENAB(wlc->pub));
1937         }
1938
1939         /* update antenna config due to wlc->stf->txant/txchain/ant_rx_ovr change */
1940         wlc_stf_phy_txant_upd(wlc);
1941
1942         /* attach each modules */
1943         err = wlc_attach_module(wlc);
1944         if (err != 0)
1945                 goto fail;
1946
1947         if (!wlc_timers_init(wlc, unit)) {
1948                 WL_ERROR(("wl%d: %s: wlc_init_timer failed\n", unit, __func__));
1949                 err = 32;
1950                 goto fail;
1951         }
1952
1953         /* depend on rateset, gmode */
1954         wlc->cmi = wlc_channel_mgr_attach(wlc);
1955         if (!wlc->cmi) {
1956                 WL_ERROR(("wl%d: %s: wlc_channel_mgr_attach failed\n", unit,
1957                           __func__));
1958                 err = 33;
1959                 goto fail;
1960         }
1961
1962         /* init default when all parameters are ready, i.e. ->rateset */
1963         wlc_bss_default_init(wlc);
1964
1965         /*
1966          * Complete the wlc default state initializations..
1967          */
1968
1969         /* allocate our initial queue */
1970         qi = wlc_txq_alloc(wlc, osh);
1971         if (qi == NULL) {
1972                 WL_ERROR(("wl%d: %s: failed to malloc tx queue\n", unit,
1973                           __func__));
1974                 err = 100;
1975                 goto fail;
1976         }
1977         wlc->active_queue = qi;
1978
1979         wlc->bsscfg[0] = wlc->cfg;
1980         wlc->cfg->_idx = 0;
1981         wlc->cfg->wlc = wlc;
1982         pub->txmaxpkts = MAXTXPKTS;
1983
1984         WLCNTSET(pub->_cnt->version, WL_CNT_T_VERSION);
1985         WLCNTSET(pub->_cnt->length, sizeof(wl_cnt_t));
1986
1987         WLCNTSET(pub->_wme_cnt->version, WL_WME_CNT_VERSION);
1988         WLCNTSET(pub->_wme_cnt->length, sizeof(wl_wme_cnt_t));
1989
1990         wlc_wme_initparams_sta(wlc, &wlc->wme_param_ie);
1991
1992         wlc->mimoft = FT_HT;
1993         wlc->ht_cap.cap = HT_CAP;
1994         if (HT_ENAB(wlc->pub))
1995                 wlc->stf->ldpc = AUTO;
1996
1997         wlc->mimo_40txbw = AUTO;
1998         wlc->ofdm_40txbw = AUTO;
1999         wlc->cck_40txbw = AUTO;
2000         wlc_update_mimo_band_bwcap(wlc, WLC_N_BW_20IN2G_40IN5G);
2001
2002         /* Enable setting the RIFS Mode bit by default in HT Info IE */
2003         wlc->rifs_advert = AUTO;
2004
2005         /* Set default values of SGI */
2006         if (WLC_SGI_CAP_PHY(wlc)) {
2007                 wlc_ht_update_sgi_rx(wlc, (WLC_N_SGI_20 | WLC_N_SGI_40));
2008                 wlc->sgi_tx = AUTO;
2009         } else if (WLCISSSLPNPHY(wlc->band)) {
2010                 wlc_ht_update_sgi_rx(wlc, (WLC_N_SGI_20 | WLC_N_SGI_40));
2011                 wlc->sgi_tx = AUTO;
2012         } else {
2013                 wlc_ht_update_sgi_rx(wlc, 0);
2014                 wlc->sgi_tx = OFF;
2015         }
2016
2017         /* *******nvram 11n config overrides Start ********* */
2018
2019         /* apply the sgi override from nvram conf */
2020         if (n_disabled & WLFEATURE_DISABLE_11N_SGI_TX)
2021                 wlc->sgi_tx = OFF;
2022
2023         if (n_disabled & WLFEATURE_DISABLE_11N_SGI_RX)
2024                 wlc_ht_update_sgi_rx(wlc, 0);
2025
2026         /* apply the stbc override from nvram conf */
2027         if (n_disabled & WLFEATURE_DISABLE_11N_STBC_TX) {
2028                 wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = OFF;
2029                 wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = OFF;
2030                 wlc->ht_cap.cap &= ~HT_CAP_TX_STBC;
2031         }
2032         if (n_disabled & WLFEATURE_DISABLE_11N_STBC_RX)
2033                 wlc_stf_stbc_rx_set(wlc, HT_CAP_RX_STBC_NO);
2034
2035         /* apply the GF override from nvram conf */
2036         if (n_disabled & WLFEATURE_DISABLE_11N_GF)
2037                 wlc->ht_cap.cap &= ~HT_CAP_GF;
2038
2039         /* initialize radio_mpc_disable according to wlc->mpc */
2040         wlc_radio_mpc_upd(wlc);
2041
2042         if (WLANTSEL_ENAB(wlc)) {
2043                 if ((CHIPID(wlc->pub->sih->chip)) == BCM43235_CHIP_ID) {
2044                         if ((getintvar(wlc->pub->vars, "aa2g") == 7) ||
2045                             (getintvar(wlc->pub->vars, "aa5g") == 7)) {
2046                                 wlc_bmac_antsel_set(wlc->hw, 1);
2047                         }
2048                 } else {
2049                         wlc_bmac_antsel_set(wlc->hw, wlc->asi->antsel_avail);
2050                 }
2051         }
2052
2053         if (perr)
2054                 *perr = 0;
2055
2056         return (void *)wlc;
2057
2058  fail:
2059         WL_ERROR(("wl%d: %s: failed with err %d\n", unit, __func__, err));
2060         if (wlc)
2061                 wlc_detach(wlc);
2062
2063         if (perr)
2064                 *perr = err;
2065         return NULL;
2066 }
2067
2068 static void wlc_attach_antgain_init(wlc_info_t *wlc)
2069 {
2070         uint unit;
2071         unit = wlc->pub->unit;
2072
2073         if ((wlc->band->antgain == -1) && (wlc->pub->sromrev == 1)) {
2074                 /* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */
2075                 wlc->band->antgain = 8;
2076         } else if (wlc->band->antgain == -1) {
2077                 WL_ERROR(("wl%d: %s: Invalid antennas available in srom, using 2dB\n", unit, __func__));
2078                 wlc->band->antgain = 8;
2079         } else {
2080                 s8 gain, fract;
2081                 /* Older sroms specified gain in whole dbm only.  In order
2082                  * be able to specify qdbm granularity and remain backward compatible
2083                  * the whole dbms are now encoded in only low 6 bits and remaining qdbms
2084                  * are encoded in the hi 2 bits. 6 bit signed number ranges from
2085                  * -32 - 31. Examples: 0x1 = 1 db,
2086                  * 0xc1 = 1.75 db (1 + 3 quarters),
2087                  * 0x3f = -1 (-1 + 0 quarters),
2088                  * 0x7f = -.75 (-1 in low 6 bits + 1 quarters in hi 2 bits) = -3 qdbm.
2089                  * 0xbf = -.50 (-1 in low 6 bits + 2 quarters in hi 2 bits) = -2 qdbm.
2090                  */
2091                 gain = wlc->band->antgain & 0x3f;
2092                 gain <<= 2;     /* Sign extend */
2093                 gain >>= 2;
2094                 fract = (wlc->band->antgain & 0xc0) >> 6;
2095                 wlc->band->antgain = 4 * gain + fract;
2096         }
2097 }
2098
2099 static bool wlc_attach_stf_ant_init(wlc_info_t *wlc)
2100 {
2101         int aa;
2102         uint unit;
2103         char *vars;
2104         int bandtype;
2105
2106         unit = wlc->pub->unit;
2107         vars = wlc->pub->vars;
2108         bandtype = wlc->band->bandtype;
2109
2110         /* get antennas available */
2111         aa = (s8) getintvar(vars, (BAND_5G(bandtype) ? "aa5g" : "aa2g"));
2112         if (aa == 0)
2113                 aa = (s8) getintvar(vars,
2114                                       (BAND_5G(bandtype) ? "aa1" : "aa0"));
2115         if ((aa < 1) || (aa > 15)) {
2116                 WL_ERROR(("wl%d: %s: Invalid antennas available in srom (0x%x), using 3.\n", unit, __func__, aa));
2117                 aa = 3;
2118         }
2119
2120         /* reset the defaults if we have a single antenna */
2121         if (aa == 1) {
2122                 wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_0;
2123                 wlc->stf->txant = ANT_TX_FORCE_0;
2124         } else if (aa == 2) {
2125                 wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_1;
2126                 wlc->stf->txant = ANT_TX_FORCE_1;
2127         } else {
2128         }
2129
2130         /* Compute Antenna Gain */
2131         wlc->band->antgain =
2132             (s8) getintvar(vars, (BAND_5G(bandtype) ? "ag1" : "ag0"));
2133         wlc_attach_antgain_init(wlc);
2134
2135         return TRUE;
2136 }
2137
2138 #ifdef WLC_HIGH_ONLY
2139 /* HIGH_ONLY bmac_attach, which sync over LOW_ONLY bmac_attach states */
2140 int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
2141                     bool piomode, osl_t *osh, void *regsva, uint bustype,
2142                     void *btparam)
2143 {
2144         wlc_bmac_revinfo_t revinfo;
2145         uint idx = 0;
2146         rpc_info_t *rpc = (rpc_info_t *) btparam;
2147
2148         ASSERT(bustype == RPC_BUS);
2149
2150         /* install the rpc handle in the various state structures used by stub RPC functions */
2151         wlc->rpc = rpc;
2152         wlc->hw->rpc = rpc;
2153         wlc->hw->osh = osh;
2154
2155         wlc->regs = 0;
2156
2157         wlc->rpctx = wlc_rpctx_attach(wlc->pub, wlc);
2158         if (wlc->rpctx == NULL)
2159                 return -1;
2160
2161         /*
2162          * FIFO 0
2163          * TX: TX_AC_BK_FIFO (TX AC Background data packets)
2164          */
2165         /* Always initialized */
2166         ASSERT(NRPCTXBUFPOST <= NTXD);
2167         wlc_rpctx_fifoinit(wlc->rpctx, TX_DATA_FIFO, NRPCTXBUFPOST);
2168         wlc_rpctx_fifoinit(wlc->rpctx, TX_CTL_FIFO, NRPCTXBUFPOST);
2169         wlc_rpctx_fifoinit(wlc->rpctx, TX_BCMC_FIFO, NRPCTXBUFPOST);
2170
2171         /* VI and BK inited only if WME */
2172         if (WME_ENAB(wlc->pub)) {
2173                 wlc_rpctx_fifoinit(wlc->rpctx, TX_AC_BK_FIFO, NRPCTXBUFPOST);
2174                 wlc_rpctx_fifoinit(wlc->rpctx, TX_AC_VI_FIFO, NRPCTXBUFPOST);
2175         }
2176
2177         /* Allocate SB handle */
2178         wlc->pub->sih = osl_malloc(wlc->osh, sizeof(si_t));
2179         if (!wlc->pub->sih)
2180                 return -1;
2181         bzero(wlc->pub->sih, sizeof(si_t));
2182
2183         /* sync up revinfo with BMAC */
2184         bzero(&revinfo, sizeof(wlc_bmac_revinfo_t));
2185         if (wlc_bmac_revinfo_get(wlc->hw, &revinfo) != 0)
2186                 return -1;
2187         wlc->vendorid = (u16) revinfo.vendorid;
2188         wlc->deviceid = (u16) revinfo.deviceid;
2189
2190         wlc->pub->boardrev = (u16) revinfo.boardrev;
2191         wlc->pub->corerev = revinfo.corerev;
2192         wlc->pub->sromrev = (u8) revinfo.sromrev;
2193         wlc->pub->sih->chiprev = revinfo.chiprev;
2194         wlc->pub->sih->chip = revinfo.chip;
2195         wlc->pub->sih->chippkg = revinfo.chippkg;
2196         wlc->pub->sih->boardtype = revinfo.boardtype;
2197         wlc->pub->sih->boardvendor = revinfo.boardvendor;
2198         wlc->pub->sih->bustype = revinfo.bustype;
2199         wlc->pub->sih->buscoretype = revinfo.buscoretype;
2200         wlc->pub->sih->buscorerev = revinfo.buscorerev;
2201         wlc->pub->sih->issim = (bool) revinfo.issim;
2202         wlc->pub->sih->rpc = rpc;
2203
2204         if (revinfo.nbands == 0 || revinfo.nbands > 2)
2205                 return -1;
2206         wlc->pub->_nbands = revinfo.nbands;
2207
2208         for (idx = 0; idx < wlc->pub->_nbands; idx++) {
2209                 uint bandunit, bandtype;        /* To access bandstate */
2210                 wlc_phy_t *pi = osl_malloc(wlc->osh, sizeof(wlc_phy_t));
2211
2212                 if (!pi)
2213                         return -1;
2214                 bzero(pi, sizeof(wlc_phy_t));
2215                 pi->rpc = rpc;
2216
2217                 bandunit = revinfo.band[idx].bandunit;
2218                 bandtype = revinfo.band[idx].bandtype;
2219                 wlc->bandstate[bandunit]->radiorev =
2220                     (u8) revinfo.band[idx].radiorev;
2221                 wlc->bandstate[bandunit]->phytype =
2222                     (u16) revinfo.band[idx].phytype;
2223                 wlc->bandstate[bandunit]->phyrev =
2224                     (u16) revinfo.band[idx].phyrev;
2225                 wlc->bandstate[bandunit]->radioid =
2226                     (u16) revinfo.band[idx].radioid;
2227                 wlc->bandstate[bandunit]->abgphy_encore =
2228                     revinfo.band[idx].abgphy_encore;
2229
2230                 wlc->bandstate[bandunit]->pi = pi;
2231                 wlc->bandstate[bandunit]->bandunit = bandunit;
2232                 wlc->bandstate[bandunit]->bandtype = bandtype;
2233         }
2234
2235         /* misc stuff */
2236
2237         return 0;
2238 }
2239
2240 /* Free the convenience handles */
2241 int wlc_bmac_detach(wlc_info_t *wlc)
2242 {
2243         uint idx;
2244
2245         if (wlc->pub->sih) {
2246                 osl_mfree(wlc->osh, (void *)wlc->pub->sih, sizeof(si_t));
2247                 wlc->pub->sih = NULL;
2248         }
2249
2250         for (idx = 0; idx < MAXBANDS; idx++)
2251                 if (wlc->bandstate[idx]->pi) {
2252                         osl_mfree(wlc->osh, wlc->bandstate[idx]->pi,
2253                                   sizeof(wlc_phy_t));
2254                         wlc->bandstate[idx]->pi = NULL;
2255                 }
2256
2257         if (wlc->rpctx) {
2258                 wlc_rpctx_detach(wlc->rpctx);
2259                 wlc->rpctx = NULL;
2260         }
2261
2262         return 0;
2263
2264 }
2265
2266 #endif                          /* WLC_HIGH_ONLY */
2267
2268 static void wlc_timers_deinit(wlc_info_t *wlc)
2269 {
2270         /* free timer state */
2271         if (wlc->wdtimer) {
2272                 wl_free_timer(wlc->wl, wlc->wdtimer);
2273                 wlc->wdtimer = NULL;
2274         }
2275         if (wlc->radio_timer) {
2276                 wl_free_timer(wlc->wl, wlc->radio_timer);
2277                 wlc->radio_timer = NULL;
2278         }
2279 }
2280
2281 static void wlc_detach_module(wlc_info_t *wlc)
2282 {
2283         if (wlc->asi) {
2284                 wlc_antsel_detach(wlc->asi);
2285                 wlc->asi = NULL;
2286         }
2287
2288         if (wlc->ampdu) {
2289                 wlc_ampdu_detach(wlc->ampdu);
2290                 wlc->ampdu = NULL;
2291         }
2292
2293         wlc_stf_detach(wlc);
2294 }
2295
2296 /*
2297  * Return a count of the number of driver callbacks still pending.
2298  *
2299  * General policy is that wlc_detach can only dealloc/free software states. It can NOT
2300  *  touch hardware registers since the d11core may be in reset and clock may not be available.
2301  *    One exception is sb register access, which is possible if crystal is turned on
2302  * After "down" state, driver should avoid software timer with the exception of radio_monitor.
2303  */
2304 uint wlc_detach(wlc_info_t *wlc)
2305 {
2306         uint i;
2307         uint callbacks = 0;
2308
2309         if (wlc == NULL)
2310                 return 0;
2311
2312         WL_TRACE(("wl%d: %s\n", wlc->pub->unit, __func__));
2313
2314         ASSERT(!wlc->pub->up);
2315
2316         callbacks += wlc_bmac_detach(wlc);
2317
2318         /* delete software timers */
2319         if (!wlc_radio_monitor_stop(wlc))
2320                 callbacks++;
2321
2322         if (wlc->eventq) {
2323                 wlc_eventq_detach(wlc->eventq);
2324                 wlc->eventq = NULL;
2325         }
2326
2327         wlc_channel_mgr_detach(wlc->cmi);
2328
2329         wlc_timers_deinit(wlc);
2330
2331         wlc_detach_module(wlc);
2332
2333         /* free other state */
2334
2335 #ifdef WLC_HIGH_ONLY
2336         /* High-Only driver has an allocated copy of vars, monolithic just
2337          * references the wlc->hw->vars which is freed in wlc_bmac_detach()
2338          */
2339         if (wlc->pub->vars) {
2340                 osl_mfree(wlc->osh, wlc->pub->vars, wlc->vars_size);
2341                 wlc->pub->vars = NULL;
2342         }
2343 #endif
2344
2345 #ifdef BCMDBG
2346         if (wlc->country_ie_override) {
2347                 osl_mfree(wlc->osh, wlc->country_ie_override,
2348                           wlc->country_ie_override->len + TLV_HDR_LEN);
2349                 wlc->country_ie_override = NULL;
2350         }
2351 #endif                          /* BCMDBG */
2352
2353         {
2354                 /* free dumpcb list */
2355                 dumpcb_t *prev, *ptr;
2356                 prev = ptr = wlc->dumpcb_head;
2357                 while (ptr) {
2358                         ptr = prev->next;
2359                         osl_mfree(wlc->osh, prev, sizeof(dumpcb_t));
2360                         prev = ptr;
2361                 }
2362                 wlc->dumpcb_head = NULL;
2363         }
2364
2365         /* Detach from iovar manager */
2366         wlc_module_unregister(wlc->pub, "wlc_iovars", wlc);
2367
2368         /*
2369            if (wlc->ap) {
2370            wlc_ap_detach(wlc->ap);
2371            wlc->ap = NULL;
2372            }
2373          */
2374
2375         while (wlc->tx_queues != NULL) {
2376                 wlc_txq_free(wlc, wlc->osh, wlc->tx_queues);
2377         }
2378
2379         /*
2380          * consistency check: wlc_module_register/wlc_module_unregister calls
2381          * should match therefore nothing should be left here.
2382          */
2383         for (i = 0; i < WLC_MAXMODULES; i++)
2384                 ASSERT(wlc->modulecb[i].name[0] == '\0');
2385
2386         wlc_detach_mfree(wlc, wlc->osh);
2387         return callbacks;
2388 }
2389
2390 /* update state that depends on the current value of "ap" */
2391 void wlc_ap_upd(wlc_info_t *wlc)
2392 {
2393         if (AP_ENAB(wlc->pub))
2394                 wlc->PLCPHdr_override = WLC_PLCP_AUTO;  /* AP: short not allowed, but not enforced */
2395         else
2396                 wlc->PLCPHdr_override = WLC_PLCP_SHORT; /* STA-BSS; short capable */
2397
2398         /* disable vlan_mode on AP since some legacy STAs cannot rx tagged pkts */
2399         wlc->vlan_mode = AP_ENAB(wlc->pub) ? OFF : AUTO;
2400
2401         /* fixup mpc */
2402         wlc->mpc = TRUE;
2403 }
2404
2405 /* read hwdisable state and propagate to wlc flag */
2406 static void wlc_radio_hwdisable_upd(wlc_info_t *wlc)
2407 {
2408         if (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO || wlc->pub->hw_off)
2409                 return;
2410
2411         if (wlc_bmac_radio_read_hwdisabled(wlc->hw)) {
2412                 mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
2413         } else {
2414                 mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
2415         }
2416 }
2417
2418 /* return TRUE if Minimum Power Consumption should be entered, FALSE otherwise */
2419 bool wlc_is_non_delay_mpc(wlc_info_t *wlc)
2420 {
2421         return FALSE;
2422 }
2423
2424 bool wlc_ismpc(wlc_info_t *wlc)
2425 {
2426         return (wlc->mpc_delay_off == 0) && (wlc_is_non_delay_mpc(wlc));
2427 }
2428
2429 void wlc_radio_mpc_upd(wlc_info_t *wlc)
2430 {
2431         bool mpc_radio, radio_state;
2432
2433         /*
2434          * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled
2435          * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio
2436          * monitor also when WL_RADIO_MPC_DISABLE is the only reason that
2437          * the radio is going down.
2438          */
2439         if (!wlc->mpc) {
2440                 if (!wlc->pub->radio_disabled)
2441                         return;
2442                 mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
2443                 wlc_radio_upd(wlc);
2444                 if (!wlc->pub->radio_disabled)
2445                         wlc_radio_monitor_stop(wlc);
2446                 return;
2447         }
2448
2449         /*
2450          * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in wlc->pub->radio_disabled
2451          * to go ON, always call radio_upd synchronously
2452          * to go OFF, postpone radio_upd to later when context is safe(e.g. watchdog)
2453          */
2454         radio_state =
2455             (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF :
2456              ON);
2457         mpc_radio = (wlc_ismpc(wlc) == TRUE) ? OFF : ON;
2458
2459         if (radio_state == ON && mpc_radio == OFF)
2460                 wlc->mpc_delay_off = wlc->mpc_dlycnt;
2461         else if (radio_state == OFF && mpc_radio == ON) {
2462                 mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
2463                 wlc_radio_upd(wlc);
2464                 if (wlc->mpc_offcnt < WLC_MPC_THRESHOLD) {
2465                         wlc->mpc_dlycnt = WLC_MPC_MAX_DELAYCNT;
2466                 } else
2467                         wlc->mpc_dlycnt = WLC_MPC_MIN_DELAYCNT;
2468                 wlc->mpc_dur += OSL_SYSUPTIME() - wlc->mpc_laston_ts;
2469         }
2470         /* Below logic is meant to capture the transition from mpc off to mpc on for reasons
2471          * other than wlc->mpc_delay_off keeping the mpc off. In that case reset
2472          * wlc->mpc_delay_off to wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off
2473          */
2474         if ((wlc->prev_non_delay_mpc == FALSE) &&
2475             (wlc_is_non_delay_mpc(wlc) == TRUE) && wlc->mpc_delay_off) {
2476                 wlc->mpc_delay_off = wlc->mpc_dlycnt;
2477         }
2478         wlc->prev_non_delay_mpc = wlc_is_non_delay_mpc(wlc);
2479 }
2480
2481 /*
2482  * centralized radio disable/enable function,
2483  * invoke radio enable/disable after updating hwradio status
2484  */
2485 static void wlc_radio_upd(wlc_info_t *wlc)
2486 {
2487         if (wlc->pub->radio_disabled)
2488                 wlc_radio_disable(wlc);
2489         else
2490                 wlc_radio_enable(wlc);
2491 }
2492
2493 /* maintain LED behavior in down state */
2494 static void wlc_down_led_upd(wlc_info_t *wlc)
2495 {
2496         ASSERT(!wlc->pub->up);
2497
2498         /* maintain LEDs while in down state, turn on sbclk if not available yet */
2499         /* turn on sbclk if necessary */
2500         if (!AP_ENAB(wlc->pub)) {
2501                 wlc_pllreq(wlc, TRUE, WLC_PLLREQ_FLIP);
2502
2503                 wlc_pllreq(wlc, FALSE, WLC_PLLREQ_FLIP);
2504         }
2505 }
2506
2507 void wlc_radio_disable(wlc_info_t *wlc)
2508 {
2509         if (!wlc->pub->up) {
2510                 wlc_down_led_upd(wlc);
2511                 return;
2512         }
2513
2514         wlc_radio_monitor_start(wlc);
2515         wl_down(wlc->wl);
2516 }
2517
2518 static void wlc_radio_enable(wlc_info_t *wlc)
2519 {
2520         if (wlc->pub->up)
2521                 return;
2522
2523         if (DEVICEREMOVED(wlc))
2524                 return;
2525
2526         if (!wlc->down_override) {      /* imposed by wl down/out ioctl */
2527                 wl_up(wlc->wl);
2528         }
2529 }
2530
2531 /* periodical query hw radio button while driver is "down" */
2532 static void wlc_radio_timer(void *arg)
2533 {
2534         wlc_info_t *wlc = (wlc_info_t *) arg;
2535
2536         if (DEVICEREMOVED(wlc)) {
2537                 WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit, __func__));
2538                 wl_down(wlc->wl);
2539                 return;
2540         }
2541
2542         /* cap mpc off count */
2543         if (wlc->mpc_offcnt < WLC_MPC_MAX_DELAYCNT)
2544                 wlc->mpc_offcnt++;
2545
2546         /* validate all the reasons driver could be down and running this radio_timer */
2547         ASSERT(wlc->pub->radio_disabled || wlc->down_override);
2548         wlc_radio_hwdisable_upd(wlc);
2549         wlc_radio_upd(wlc);
2550 }
2551
2552 static bool wlc_radio_monitor_start(wlc_info_t *wlc)
2553 {
2554         /* Don't start the timer if HWRADIO feature is disabled */
2555         if (wlc->radio_monitor || (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO))
2556                 return TRUE;
2557
2558         wlc->radio_monitor = TRUE;
2559         wlc_pllreq(wlc, TRUE, WLC_PLLREQ_RADIO_MON);
2560         wl_add_timer(wlc->wl, wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, TRUE);
2561         return TRUE;
2562 }
2563
2564 bool wlc_radio_monitor_stop(wlc_info_t *wlc)
2565 {
2566         if (!wlc->radio_monitor)
2567                 return TRUE;
2568
2569         ASSERT((wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO) !=
2570                WL_SWFL_NOHWRADIO);
2571
2572         wlc->radio_monitor = FALSE;
2573         wlc_pllreq(wlc, FALSE, WLC_PLLREQ_RADIO_MON);
2574         return wl_del_timer(wlc->wl, wlc->radio_timer);
2575 }
2576
2577 /* bring the driver down, but don't reset hardware */
2578 void wlc_out(wlc_info_t *wlc)
2579 {
2580         wlc_bmac_set_noreset(wlc->hw, TRUE);
2581         wlc_radio_upd(wlc);
2582         wl_down(wlc->wl);
2583         wlc_bmac_set_noreset(wlc->hw, FALSE);
2584
2585         /* core clk is TRUE in BMAC driver due to noreset, need to mirror it in HIGH */
2586         wlc->clk = TRUE;
2587
2588         /* This will make sure that when 'up' is done
2589          * after 'out' it'll restore hardware (especially gpios)
2590          */
2591         wlc->pub->hw_up = FALSE;
2592 }
2593
2594 #if defined(BCMDBG)
2595 /* Verify the sanity of wlc->tx_prec_map. This can be done only by making sure that
2596  * if there is no packet pending for the FIFO, then the corresponding prec bits should be set
2597  * in prec_map. Of course, ignore this rule when block_datafifo is set
2598  */
2599 static bool wlc_tx_prec_map_verify(wlc_info_t *wlc)
2600 {
2601         /* For non-WME, both fifos have overlapping prec_map. So it's an error only if both
2602          * fail the check.
2603          */
2604         if (!EDCF_ENAB(wlc->pub)) {
2605                 if (!(WLC_TX_FIFO_CHECK(wlc, TX_DATA_FIFO) ||
2606                       WLC_TX_FIFO_CHECK(wlc, TX_CTL_FIFO)))
2607                         return FALSE;
2608                 else
2609                         return TRUE;
2610         }
2611
2612         return WLC_TX_FIFO_CHECK(wlc, TX_AC_BK_FIFO)
2613                 && WLC_TX_FIFO_CHECK(wlc, TX_AC_BE_FIFO)
2614                 && WLC_TX_FIFO_CHECK(wlc, TX_AC_VI_FIFO)
2615                 && WLC_TX_FIFO_CHECK(wlc, TX_AC_VO_FIFO);
2616 }
2617 #endif                          /* BCMDBG */
2618
2619 static void wlc_watchdog_by_timer(void *arg)
2620 {
2621         wlc_info_t *wlc = (wlc_info_t *) arg;
2622         wlc_watchdog(arg);
2623         if (WLC_WATCHDOG_TBTT(wlc)) {
2624                 /* set to normal osl watchdog period */
2625                 wl_del_timer(wlc->wl, wlc->wdtimer);
2626                 wl_add_timer(wlc->wl, wlc->wdtimer, TIMER_INTERVAL_WATCHDOG,
2627                              TRUE);
2628         }
2629 }
2630
2631 /* common watchdog code */
2632 static void wlc_watchdog(void *arg)
2633 {
2634         wlc_info_t *wlc = (wlc_info_t *) arg;
2635         int i;
2636         wlc_bsscfg_t *cfg;
2637
2638         WL_TRACE(("wl%d: wlc_watchdog\n", wlc->pub->unit));
2639
2640         if (!wlc->pub->up)
2641                 return;
2642
2643         if (DEVICEREMOVED(wlc)) {
2644                 WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit, __func__));
2645                 wl_down(wlc->wl);
2646                 return;
2647         }
2648
2649         /* increment second count */
2650         wlc->pub->now++;
2651
2652         /* delay radio disable */
2653         if (wlc->mpc_delay_off) {
2654                 if (--wlc->mpc_delay_off == 0) {
2655                         mboolset(wlc->pub->radio_disabled,
2656                                  WL_RADIO_MPC_DISABLE);
2657                         if (wlc->mpc && wlc_ismpc(wlc))
2658                                 wlc->mpc_offcnt = 0;
2659                         wlc->mpc_laston_ts = OSL_SYSUPTIME();
2660                 }
2661         }
2662
2663         /* mpc sync */
2664         wlc_radio_mpc_upd(wlc);
2665         /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */
2666         wlc_radio_hwdisable_upd(wlc);
2667         wlc_radio_upd(wlc);
2668         /* if ismpc, driver should be in down state if up/down is allowed */
2669         if (wlc->mpc && wlc_ismpc(wlc))
2670                 ASSERT(!wlc->pub->up);
2671         /* if radio is disable, driver may be down, quit here */
2672         if (wlc->pub->radio_disabled)
2673                 return;
2674
2675 #ifdef WLC_LOW
2676         wlc_bmac_watchdog(wlc);
2677 #endif
2678 #ifdef WLC_HIGH_ONLY
2679         /* maintenance */
2680         wlc_bmac_rpc_watchdog(wlc);
2681 #endif
2682
2683         /* occasionally sample mac stat counters to detect 16-bit counter wrap */
2684         if ((WLC_UPDATE_STATS(wlc))
2685             && (!(wlc->pub->now % SW_TIMER_MAC_STAT_UPD)))
2686                 wlc_statsupd(wlc);
2687
2688         /* Manage TKIP countermeasures timers */
2689         FOREACH_BSS(wlc, i, cfg) {
2690                 if (cfg->tk_cm_dt) {
2691                         cfg->tk_cm_dt--;
2692                 }
2693                 if (cfg->tk_cm_bt) {
2694                         cfg->tk_cm_bt--;
2695                 }
2696         }
2697
2698         /* Call any registered watchdog handlers */
2699         for (i = 0; i < WLC_MAXMODULES; i++) {
2700                 if (wlc->modulecb[i].watchdog_fn)
2701                         wlc->modulecb[i].watchdog_fn(wlc->modulecb[i].hdl);
2702         }
2703
2704         if (WLCISNPHY(wlc->band) && !wlc->pub->tempsense_disable &&
2705             ((wlc->pub->now - wlc->tempsense_lasttime) >=
2706              WLC_TEMPSENSE_PERIOD)) {
2707                 wlc->tempsense_lasttime = wlc->pub->now;
2708                 wlc_tempsense_upd(wlc);
2709         }
2710 #ifdef WLC_LOW
2711         /* BMAC_NOTE: for HIGH_ONLY driver, this seems being called after RPC bus failed */
2712         ASSERT(wlc_bmac_taclear(wlc->hw, TRUE));
2713 #endif
2714
2715         /* Verify that tx_prec_map and fifos are in sync to avoid lock ups */
2716         ASSERT(wlc_tx_prec_map_verify(wlc));
2717
2718         ASSERT(wlc_ps_check(wlc));
2719 }
2720
2721 /* make interface operational */
2722 int wlc_up(wlc_info_t *wlc)
2723 {
2724         WL_TRACE(("wl%d: %s:\n", wlc->pub->unit, __func__));
2725
2726         /* HW is turned off so don't try to access it */
2727         if (wlc->pub->hw_off || DEVICEREMOVED(wlc))
2728                 return BCME_RADIOOFF;
2729
2730         if (!wlc->pub->hw_up) {
2731                 wlc_bmac_hw_up(wlc->hw);
2732                 wlc->pub->hw_up = TRUE;
2733         }
2734
2735         if ((wlc->pub->boardflags & BFL_FEM)
2736             && (CHIPID(wlc->pub->sih->chip) == BCM4313_CHIP_ID)) {
2737                 if (wlc->pub->boardrev >= 0x1250
2738                     && (wlc->pub->boardflags & BFL_FEM_BT)) {
2739                         wlc_mhf(wlc, MHF5, MHF5_4313_GPIOCTRL,
2740                                 MHF5_4313_GPIOCTRL, WLC_BAND_ALL);
2741                 } else {
2742                         wlc_mhf(wlc, MHF4, MHF4_EXTPA_ENABLE, MHF4_EXTPA_ENABLE,
2743                                 WLC_BAND_ALL);
2744                 }
2745         }
2746
2747         /*
2748          * Need to read the hwradio status here to cover the case where the system
2749          * is loaded with the hw radio disabled. We do not want to bring the driver up in this case.
2750          * if radio is disabled, abort up, lower power, start radio timer and return 0(for NDIS)
2751          * don't call radio_update to avoid looping wlc_up.
2752          *
2753          * wlc_bmac_up_prep() returns either 0 or BCME_RADIOOFF only
2754          */
2755         if (!wlc->pub->radio_disabled) {
2756                 int status = wlc_bmac_up_prep(wlc->hw);
2757                 if (status == BCME_RADIOOFF) {
2758                         if (!mboolisset
2759                             (wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE)) {
2760                                 int idx;
2761                                 wlc_bsscfg_t *bsscfg;
2762                                 mboolset(wlc->pub->radio_disabled,
2763                                          WL_RADIO_HW_DISABLE);
2764
2765                                 FOREACH_BSS(wlc, idx, bsscfg) {
2766                                         if (!BSSCFG_STA(bsscfg)
2767                                             || !bsscfg->enable || !bsscfg->BSS)
2768                                                 continue;
2769                                         WL_ERROR(("wl%d.%d: wlc_up: rfdisable -> " "wlc_bsscfg_disable()\n", wlc->pub->unit, idx));
2770                                 }
2771                         }
2772                 } else
2773                         ASSERT(!status);
2774         }
2775
2776         if (wlc->pub->radio_disabled) {
2777                 wlc_radio_monitor_start(wlc);
2778                 return 0;
2779         }
2780
2781         /* wlc_bmac_up_prep has done wlc_corereset(). so clk is on, set it */
2782         wlc->clk = TRUE;
2783
2784         wlc_radio_monitor_stop(wlc);
2785
2786         /* Set EDCF hostflags */
2787         if (EDCF_ENAB(wlc->pub)) {
2788                 wlc_mhf(wlc, MHF1, MHF1_EDCF, MHF1_EDCF, WLC_BAND_ALL);
2789         } else {
2790                 wlc_mhf(wlc, MHF1, MHF1_EDCF, 0, WLC_BAND_ALL);
2791         }
2792
2793         if (WLC_WAR16165(wlc))
2794                 wlc_mhf(wlc, MHF2, MHF2_PCISLOWCLKWAR, MHF2_PCISLOWCLKWAR,
2795                         WLC_BAND_ALL);
2796
2797         wl_init(wlc->wl);
2798         wlc->pub->up = TRUE;
2799
2800         if (wlc->bandinit_pending) {
2801                 wlc_suspend_mac_and_wait(wlc);
2802                 wlc_set_chanspec(wlc, wlc->default_bss->chanspec);
2803                 wlc->bandinit_pending = FALSE;
2804                 wlc_enable_mac(wlc);
2805         }
2806
2807         wlc_bmac_up_finish(wlc->hw);
2808
2809         /* other software states up after ISR is running */
2810         /* start APs that were to be brought up but are not up  yet */
2811         /* if (AP_ENAB(wlc->pub)) wlc_restart_ap(wlc->ap); */
2812
2813         /* Program the TX wme params with the current settings */
2814         wlc_wme_retries_write(wlc);
2815
2816         /* start one second watchdog timer */
2817         ASSERT(!wlc->WDarmed);
2818         wl_add_timer(wlc->wl, wlc->wdtimer, TIMER_INTERVAL_WATCHDOG, TRUE);
2819         wlc->WDarmed = TRUE;
2820
2821         /* ensure antenna config is up to date */
2822         wlc_stf_phy_txant_upd(wlc);
2823         /* ensure LDPC config is in sync */
2824         wlc_ht_update_ldpc(wlc, wlc->stf->ldpc);
2825
2826         return 0;
2827 }
2828
2829 /* Initialize the base precedence map for dequeueing from txq based on WME settings */
2830 static void wlc_tx_prec_map_init(wlc_info_t *wlc)
2831 {
2832         wlc->tx_prec_map = WLC_PREC_BMP_ALL;
2833         bzero(wlc->fifo2prec_map, sizeof(u16) * NFIFO);
2834
2835         /* For non-WME, both fifos have overlapping MAXPRIO. So just disable all precedences
2836          * if either is full.
2837          */
2838         if (!EDCF_ENAB(wlc->pub)) {
2839                 wlc->fifo2prec_map[TX_DATA_FIFO] = WLC_PREC_BMP_ALL;
2840                 wlc->fifo2prec_map[TX_CTL_FIFO] = WLC_PREC_BMP_ALL;
2841         } else {
2842                 wlc->fifo2prec_map[TX_AC_BK_FIFO] = WLC_PREC_BMP_AC_BK;
2843                 wlc->fifo2prec_map[TX_AC_BE_FIFO] = WLC_PREC_BMP_AC_BE;
2844                 wlc->fifo2prec_map[TX_AC_VI_FIFO] = WLC_PREC_BMP_AC_VI;
2845                 wlc->fifo2prec_map[TX_AC_VO_FIFO] = WLC_PREC_BMP_AC_VO;
2846         }
2847 }
2848
2849 static uint wlc_down_del_timer(wlc_info_t *wlc)
2850 {
2851         uint callbacks = 0;
2852
2853         return callbacks;
2854 }
2855
2856 /*
2857  * Mark the interface nonoperational, stop the software mechanisms,
2858  * disable the hardware, free any transient buffer state.
2859  * Return a count of the number of driver callbacks still pending.
2860  */
2861 uint wlc_down(wlc_info_t *wlc)
2862 {
2863
2864         uint callbacks = 0;
2865         int i;
2866         bool dev_gone = FALSE;
2867         wlc_txq_info_t *qi;
2868
2869         WL_TRACE(("wl%d: %s:\n", wlc->pub->unit, __func__));
2870
2871         /* check if we are already in the going down path */
2872         if (wlc->going_down) {
2873                 WL_ERROR(("wl%d: %s: Driver going down so return\n",
2874                           wlc->pub->unit, __func__));
2875                 return 0;
2876         }
2877         if (!wlc->pub->up)
2878                 return callbacks;
2879
2880         /* in between, mpc could try to bring down again.. */
2881         wlc->going_down = TRUE;
2882
2883         callbacks += wlc_bmac_down_prep(wlc->hw);
2884
2885         dev_gone = DEVICEREMOVED(wlc);
2886
2887         /* Call any registered down handlers */
2888         for (i = 0; i < WLC_MAXMODULES; i++) {
2889                 if (wlc->modulecb[i].down_fn)
2890                         callbacks +=
2891                             wlc->modulecb[i].down_fn(wlc->modulecb[i].hdl);
2892         }
2893
2894         /* cancel the watchdog timer */
2895         if (wlc->WDarmed) {
2896                 if (!wl_del_timer(wlc->wl, wlc->wdtimer))
2897                         callbacks++;
2898                 wlc->WDarmed = FALSE;
2899         }
2900         /* cancel all other timers */
2901         callbacks += wlc_down_del_timer(wlc);
2902
2903         /* interrupt must have been blocked */
2904         ASSERT((wlc->macintmask == 0) || !wlc->pub->up);
2905
2906         wlc->pub->up = FALSE;
2907
2908         wlc_phy_mute_upd(wlc->band->pi, FALSE, PHY_MUTE_ALL);
2909
2910         /* clear txq flow control */
2911         wlc_txflowcontrol_reset(wlc);
2912
2913         /* flush tx queues */
2914         for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) {
2915                 pktq_flush(wlc->osh, &qi->q, TRUE, NULL, 0);
2916                 ASSERT(pktq_empty(&qi->q));
2917         }
2918
2919         /* flush event queue.
2920          * Should be the last thing done after all the events are generated
2921          * Just delivers the events synchronously instead of waiting for a timer
2922          */
2923         callbacks += wlc_eventq_down(wlc->eventq);
2924
2925         callbacks += wlc_bmac_down_finish(wlc->hw);
2926
2927         /* wlc_bmac_down_finish has done wlc_coredisable(). so clk is off */
2928         wlc->clk = FALSE;
2929
2930 #ifdef WLC_HIGH_ONLY
2931         wlc_rpctx_txreclaim(wlc->rpctx);
2932 #endif
2933
2934         /* Verify all packets are flushed from the driver */
2935         if (PKTALLOCED(wlc->osh) != 0) {
2936                 WL_ERROR(("%d packets not freed at wlc_down!!!!!!\n",
2937                           PKTALLOCED(wlc->osh)));
2938         }
2939 #ifdef BCMDBG
2940         /* Since all the packets should have been freed,
2941          * all callbacks should have been called
2942          */
2943         for (i = 1; i <= wlc->pub->tunables->maxpktcb; i++)
2944                 ASSERT(wlc->pkt_callback[i].fn == NULL);
2945 #endif
2946         wlc->going_down = FALSE;
2947         return callbacks;
2948 }
2949
2950 /* Set the current gmode configuration */
2951 int wlc_set_gmode(wlc_info_t *wlc, u8 gmode, bool config)
2952 {
2953         int ret = 0;
2954         uint i;
2955         wlc_rateset_t rs;
2956         /* Default to 54g Auto */
2957         s8 shortslot = WLC_SHORTSLOT_AUTO;      /* Advertise and use shortslot (-1/0/1 Auto/Off/On) */
2958         bool shortslot_restrict = FALSE;        /* Restrict association to stations that support shortslot
2959                                                  */
2960         bool ignore_bcns = TRUE;        /* Ignore legacy beacons on the same channel */
2961         bool ofdm_basic = FALSE;        /* Make 6, 12, and 24 basic rates */
2962         int preamble = WLC_PLCP_LONG;   /* Advertise and use short preambles (-1/0/1 Auto/Off/On) */
2963         bool preamble_restrict = FALSE; /* Restrict association to stations that support short
2964                                          * preambles
2965                                          */
2966         wlcband_t *band;
2967
2968         /* if N-support is enabled, allow Gmode set as long as requested
2969          * Gmode is not GMODE_LEGACY_B
2970          */
2971         if (N_ENAB(wlc->pub) && gmode == GMODE_LEGACY_B)
2972                 return BCME_UNSUPPORTED;
2973
2974         /* verify that we are dealing with 2G band and grab the band pointer */
2975         if (wlc->band->bandtype == WLC_BAND_2G)
2976                 band = wlc->band;
2977         else if ((NBANDS(wlc) > 1) &&
2978                  (wlc->bandstate[OTHERBANDUNIT(wlc)]->bandtype == WLC_BAND_2G))
2979                 band = wlc->bandstate[OTHERBANDUNIT(wlc)];
2980         else
2981                 return BCME_BADBAND;
2982
2983         /* Legacy or bust when no OFDM is supported by regulatory */
2984         if ((wlc_channel_locale_flags_in_band(wlc->cmi, band->bandunit) &
2985              WLC_NO_OFDM) && (gmode != GMODE_LEGACY_B))
2986                 return BCME_RANGE;
2987
2988         /* update configuration value */
2989         if (config == TRUE)
2990                 wlc_protection_upd(wlc, WLC_PROT_G_USER, gmode);
2991
2992         /* Clear supported rates filter */
2993         bzero(&wlc->sup_rates_override, sizeof(wlc_rateset_t));
2994
2995         /* Clear rateset override */
2996         bzero(&rs, sizeof(wlc_rateset_t));
2997
2998         switch (gmode) {
2999         case GMODE_LEGACY_B:
3000                 shortslot = WLC_SHORTSLOT_OFF;
3001                 wlc_rateset_copy(&gphy_legacy_rates, &rs);
3002
3003                 break;
3004
3005         case GMODE_LRS:
3006                 if (AP_ENAB(wlc->pub))
3007                         wlc_rateset_copy(&cck_rates, &wlc->sup_rates_override);
3008                 break;
3009
3010         case GMODE_AUTO:
3011                 /* Accept defaults */
3012                 break;
3013
3014         case GMODE_ONLY:
3015                 ofdm_basic = TRUE;
3016                 preamble = WLC_PLCP_SHORT;
3017                 preamble_restrict = TRUE;
3018                 break;
3019
3020         case GMODE_PERFORMANCE:
3021                 if (AP_ENAB(wlc->pub))  /* Put all rates into the Supported Rates element */
3022                         wlc_rateset_copy(&cck_ofdm_rates,
3023                                          &wlc->sup_rates_override);
3024
3025                 shortslot = WLC_SHORTSLOT_ON;
3026                 shortslot_restrict = TRUE;
3027                 ofdm_basic = TRUE;
3028                 preamble = WLC_PLCP_SHORT;
3029                 preamble_restrict = TRUE;
3030                 break;
3031
3032         default:
3033                 /* Error */
3034                 WL_ERROR(("wl%d: %s: invalid gmode %d\n", wlc->pub->unit,
3035                           __func__, gmode));
3036                 return BCME_UNSUPPORTED;
3037         }
3038
3039         /*
3040          * If we are switching to gmode == GMODE_LEGACY_B,
3041          * clean up rate info that may refer to OFDM rates.
3042          */
3043         if ((gmode == GMODE_LEGACY_B) && (band->gmode != GMODE_LEGACY_B)) {
3044                 band->gmode = gmode;
3045                 if (band->rspec_override && !IS_CCK(band->rspec_override)) {
3046                         band->rspec_override = 0;
3047                         wlc_reprate_init(wlc);
3048                 }
3049                 if (band->mrspec_override && !IS_CCK(band->mrspec_override)) {
3050                         band->mrspec_override = 0;
3051                 }
3052         }
3053
3054         band->gmode = gmode;
3055
3056         wlc->ignore_bcns = ignore_bcns;
3057
3058         wlc->shortslot_override = shortslot;
3059
3060         if (AP_ENAB(wlc->pub)) {
3061                 /* wlc->ap->shortslot_restrict = shortslot_restrict; */
3062                 wlc->PLCPHdr_override =
3063                     (preamble !=
3064                      WLC_PLCP_LONG) ? WLC_PLCP_SHORT : WLC_PLCP_AUTO;
3065         }
3066
3067         if ((AP_ENAB(wlc->pub) && preamble != WLC_PLCP_LONG)
3068             || preamble == WLC_PLCP_SHORT)
3069                 wlc->default_bss->capability |= DOT11_CAP_SHORT;
3070         else
3071                 wlc->default_bss->capability &= ~DOT11_CAP_SHORT;
3072
3073         /* Update shortslot capability bit for AP and IBSS */
3074         if ((AP_ENAB(wlc->pub) && shortslot == WLC_SHORTSLOT_AUTO) ||
3075             shortslot == WLC_SHORTSLOT_ON)
3076                 wlc->default_bss->capability |= DOT11_CAP_SHORTSLOT;
3077         else
3078                 wlc->default_bss->capability &= ~DOT11_CAP_SHORTSLOT;
3079
3080         /* Use the default 11g rateset */
3081         if (!rs.count)
3082                 wlc_rateset_copy(&cck_ofdm_rates, &rs);
3083
3084         if (ofdm_basic) {
3085                 for (i = 0; i < rs.count; i++) {
3086                         if (rs.rates[i] == WLC_RATE_6M
3087                             || rs.rates[i] == WLC_RATE_12M
3088                             || rs.rates[i] == WLC_RATE_24M)
3089                                 rs.rates[i] |= WLC_RATE_FLAG;
3090                 }
3091         }
3092
3093         /* Set default bss rateset */
3094         wlc->default_bss->rateset.count = rs.count;
3095         bcopy((char *)rs.rates, (char *)wlc->default_bss->rateset.rates,
3096               sizeof(wlc->default_bss->rateset.rates));
3097
3098         return ret;
3099 }
3100
3101 static int wlc_nmode_validate(wlc_info_t *wlc, s32 nmode)
3102 {
3103         int err = 0;
3104
3105         switch (nmode) {
3106
3107         case OFF:
3108                 break;
3109
3110         case AUTO:
3111         case WL_11N_2x2:
3112         case WL_11N_3x3:
3113                 if (!(WLC_PHY_11N_CAP(wlc->band)))
3114                         err = BCME_BADBAND;
3115                 break;
3116
3117         default:
3118                 err = BCME_RANGE;
3119                 break;
3120         }
3121
3122         return err;
3123 }
3124
3125 int wlc_set_nmode(wlc_info_t *wlc, s32 nmode)
3126 {
3127         uint i;
3128         int err;
3129
3130         err = wlc_nmode_validate(wlc, nmode);
3131         ASSERT(err == 0);
3132         if (err)
3133                 return err;
3134
3135         switch (nmode) {
3136         case OFF:
3137                 wlc->pub->_n_enab = OFF;
3138                 wlc->default_bss->flags &= ~WLC_BSS_HT;
3139                 /* delete the mcs rates from the default and hw ratesets */
3140                 wlc_rateset_mcs_clear(&wlc->default_bss->rateset);
3141                 for (i = 0; i < NBANDS(wlc); i++) {
3142                         memset(wlc->bandstate[i]->hw_rateset.mcs, 0,
3143                                MCSSET_LEN);
3144                         if (IS_MCS(wlc->band->rspec_override)) {
3145                                 wlc->bandstate[i]->rspec_override = 0;
3146                                 wlc_reprate_init(wlc);
3147                         }
3148                         if (IS_MCS(wlc->band->mrspec_override))
3149                                 wlc->bandstate[i]->mrspec_override = 0;
3150                 }
3151                 break;
3152
3153         case AUTO:
3154                 if (wlc->stf->txstreams == WL_11N_3x3)
3155                         nmode = WL_11N_3x3;
3156                 else
3157                         nmode = WL_11N_2x2;
3158         case WL_11N_2x2:
3159         case WL_11N_3x3:
3160                 ASSERT(WLC_PHY_11N_CAP(wlc->band));
3161                 /* force GMODE_AUTO if NMODE is ON */
3162                 wlc_set_gmode(wlc, GMODE_AUTO, TRUE);
3163                 if (nmode == WL_11N_3x3)
3164                         wlc->pub->_n_enab = SUPPORT_HT;
3165                 else
3166                         wlc->pub->_n_enab = SUPPORT_11N;
3167                 wlc->default_bss->flags |= WLC_BSS_HT;
3168                 /* add the mcs rates to the default and hw ratesets */
3169                 wlc_rateset_mcs_build(&wlc->default_bss->rateset,
3170                                       wlc->stf->txstreams);
3171                 for (i = 0; i < NBANDS(wlc); i++)
3172                         memcpy(wlc->bandstate[i]->hw_rateset.mcs,
3173                                wlc->default_bss->rateset.mcs, MCSSET_LEN);
3174                 break;
3175
3176         default:
3177                 ASSERT(0);
3178                 break;
3179         }
3180
3181         return err;
3182 }
3183
3184 static int wlc_set_rateset(wlc_info_t *wlc, wlc_rateset_t *rs_arg)
3185 {
3186         wlc_rateset_t rs, new;
3187         uint bandunit;
3188
3189         bcopy((char *)rs_arg, (char *)&rs, sizeof(wlc_rateset_t));
3190
3191         /* check for bad count value */
3192         if ((rs.count == 0) || (rs.count > WLC_NUMRATES))
3193                 return BCME_BADRATESET;
3194
3195         /* try the current band */
3196         bandunit = wlc->band->bandunit;
3197         bcopy((char *)&rs, (char *)&new, sizeof(wlc_rateset_t));
3198         if (wlc_rate_hwrs_filter_sort_validate
3199             (&new, &wlc->bandstate[bandunit]->hw_rateset, TRUE,
3200              wlc->stf->txstreams))
3201                 goto good;
3202
3203         /* try the other band */
3204         if (IS_MBAND_UNLOCKED(wlc)) {
3205                 bandunit = OTHERBANDUNIT(wlc);
3206                 bcopy((char *)&rs, (char *)&new, sizeof(wlc_rateset_t));
3207                 if (wlc_rate_hwrs_filter_sort_validate(&new,
3208                                                        &wlc->
3209                                                        bandstate[bandunit]->
3210                                                        hw_rateset, TRUE,
3211                                                        wlc->stf->txstreams))
3212                         goto good;
3213         }
3214
3215         return BCME_ERROR;
3216
3217  good:
3218         /* apply new rateset */
3219         bcopy((char *)&new, (char *)&wlc->default_bss->rateset,
3220               sizeof(wlc_rateset_t));
3221         bcopy((char *)&new, (char *)&wlc->bandstate[bandunit]->defrateset,
3222               sizeof(wlc_rateset_t));
3223         return 0;
3224 }
3225
3226 /* simplified integer set interface for common ioctl handler */
3227 int wlc_set(wlc_info_t *wlc, int cmd, int arg)
3228 {
3229         return wlc_ioctl(wlc, cmd, (void *)&arg, sizeof(arg), NULL);
3230 }
3231
3232 /* simplified integer get interface for common ioctl handler */
3233 int wlc_get(wlc_info_t *wlc, int cmd, int *arg)
3234 {
3235         return wlc_ioctl(wlc, cmd, arg, sizeof(int), NULL);
3236 }
3237
3238 static void wlc_ofdm_rateset_war(wlc_info_t *wlc)
3239 {
3240         u8 r;
3241         bool war = FALSE;
3242
3243         if (wlc->cfg->associated)
3244                 r = wlc->cfg->current_bss->rateset.rates[0];
3245         else
3246                 r = wlc->default_bss->rateset.rates[0];
3247
3248         wlc_phy_ofdm_rateset_war(wlc->band->pi, war);
3249
3250         return;
3251 }
3252
3253 int
3254 wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
3255 {
3256         return _wlc_ioctl(wlc, cmd, arg, len, wlcif);
3257 }
3258
3259 /* common ioctl handler. return: 0=ok, -1=error, positive=particular error */
3260 static int
3261 _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
3262 {
3263         int val, *pval;
3264         bool bool_val;
3265         int bcmerror;
3266         d11regs_t *regs;
3267         uint i;
3268         struct scb *nextscb;
3269         bool ta_ok;
3270         uint band;
3271         rw_reg_t *r;
3272         wlc_bsscfg_t *bsscfg;
3273         osl_t *osh;
3274         wlc_bss_info_t *current_bss;
3275
3276         /* update bsscfg pointer */
3277         bsscfg = NULL;          /* XXX: Hack bsscfg to be size one and use this globally */
3278         current_bss = NULL;
3279
3280         /* initialize the following to get rid of compiler warning */
3281         nextscb = NULL;
3282         ta_ok = FALSE;
3283         band = 0;
3284         r = NULL;
3285
3286         /* If the device is turned off, then it's not "removed" */
3287         if (!wlc->pub->hw_off && DEVICEREMOVED(wlc)) {
3288                 WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit, __func__));
3289                 wl_down(wlc->wl);
3290                 return BCME_ERROR;
3291         }
3292
3293         ASSERT(!(wlc->pub->hw_off && wlc->pub->up));
3294
3295         /* default argument is generic integer */
3296         pval = arg ? (int *)arg:NULL;
3297
3298         /* This will prevent the misaligned access */
3299         if (pval && (u32) len >= sizeof(val))
3300                 bcopy(pval, &val, sizeof(val));
3301         else
3302                 val = 0;
3303
3304         /* bool conversion to avoid duplication below */
3305         bool_val = val != 0;
3306
3307         if (cmd != WLC_SET_CHANNEL)
3308                 WL_NONE(("WLC_IOCTL: cmd %d val 0x%x (%d) len %d\n", cmd,
3309                          (uint) val, val, len));
3310
3311         bcmerror = 0;
3312         regs = wlc->regs;
3313         osh = wlc->osh;
3314
3315         /* A few commands don't need any arguments; all the others do. */
3316         switch (cmd) {
3317         case WLC_UP:
3318         case WLC_OUT:
3319         case WLC_DOWN:
3320         case WLC_DISASSOC:
3321         case WLC_RESTART:
3322         case WLC_REBOOT:
3323         case WLC_START_CHANNEL_QA:
3324         case WLC_INIT:
3325                 break;
3326
3327         default:
3328                 if ((arg == NULL) || (len <= 0)) {
3329                         WL_ERROR(("wl%d: %s: Command %d needs arguments\n",
3330                                   wlc->pub->unit, __func__, cmd));
3331                         bcmerror = BCME_BADARG;
3332                         goto done;
3333                 }
3334         }
3335
3336         switch (cmd) {
3337
3338 #if defined(BCMDBG)
3339         case WLC_GET_MSGLEVEL:
3340                 *pval = wl_msg_level;
3341                 break;
3342
3343         case WLC_SET_MSGLEVEL:
3344                 wl_msg_level = val;
3345                 break;
3346 #endif
3347
3348         case WLC_GET_INSTANCE:
3349                 *pval = wlc->pub->unit;
3350                 break;
3351
3352         case WLC_GET_CHANNEL:{
3353                         channel_info_t *ci = (channel_info_t *) arg;
3354
3355                         ASSERT(len > (int)sizeof(ci));
3356
3357                         ci->hw_channel =
3358                             CHSPEC_CHANNEL(WLC_BAND_PI_RADIO_CHANSPEC);
3359                         ci->target_channel =
3360                             CHSPEC_CHANNEL(wlc->default_bss->chanspec);
3361                         ci->scan_channel = 0;
3362
3363                         break;
3364                 }
3365
3366         case WLC_SET_CHANNEL:{
3367                         chanspec_t chspec = CH20MHZ_CHSPEC(val);
3368
3369                         if (val < 0 || val > MAXCHANNEL) {
3370                                 bcmerror = BCME_OUTOFRANGECHAN;
3371                                 break;
3372                         }
3373
3374                         if (!wlc_valid_chanspec_db(wlc->cmi, chspec)) {
3375                                 bcmerror = BCME_BADCHAN;
3376                                 break;
3377                         }
3378
3379                         if (!wlc->pub->up && IS_MBAND_UNLOCKED(wlc)) {
3380                                 if (wlc->band->bandunit !=
3381                                     CHSPEC_WLCBANDUNIT(chspec))
3382                                         wlc->bandinit_pending = TRUE;
3383                                 else
3384                                         wlc->bandinit_pending = FALSE;
3385                         }
3386
3387                         wlc->default_bss->chanspec = chspec;
3388                         /* wlc_BSSinit() will sanitize the rateset before using it.. */
3389                         if (wlc->pub->up && !wlc->pub->associated &&
3390                             (WLC_BAND_PI_RADIO_CHANSPEC != chspec)) {
3391                                 wlc_set_home_chanspec(wlc, chspec);
3392                                 wlc_suspend_mac_and_wait(wlc);
3393                                 wlc_set_chanspec(wlc, chspec);
3394                                 wlc_enable_mac(wlc);
3395                         }
3396 #ifdef WLC_HIGH_ONLY
3397                         /* delay for channel change */
3398                         msleep(50);
3399 #endif
3400                         break;
3401                 }
3402
3403 #if defined(BCMDBG)
3404         case WLC_GET_UCFLAGS:
3405                 if (!wlc->pub->up) {
3406                         bcmerror = BCME_NOTUP;
3407                         break;
3408                 }
3409
3410                 /* optional band is stored in the second integer of incoming buffer */
3411                 band =
3412                     (len <
3413                      (int)(2 * sizeof(int))) ? WLC_BAND_AUTO : ((int *)arg)[1];
3414
3415                 /* bcmerror checking */
3416                 bcmerror = wlc_iocregchk(wlc, band);
3417                 if (bcmerror)
3418                         break;
3419
3420                 if (val >= MHFMAX) {
3421                         bcmerror = BCME_RANGE;
3422                         break;
3423                 }
3424
3425                 *pval = wlc_bmac_mhf_get(wlc->hw, (u8) val, WLC_BAND_AUTO);
3426                 break;
3427
3428         case WLC_SET_UCFLAGS:
3429                 if (!wlc->pub->up) {
3430                         bcmerror = BCME_NOTUP;
3431                         break;
3432                 }
3433
3434                 /* optional band is stored in the second integer of incoming buffer */
3435                 band =
3436                     (len <
3437                      (int)(2 * sizeof(int))) ? WLC_BAND_AUTO : ((int *)arg)[1];
3438
3439                 /* bcmerror checking */
3440                 bcmerror = wlc_iocregchk(wlc, band);
3441                 if (bcmerror)
3442                         break;
3443
3444                 i = (u16) val;
3445                 if (i >= MHFMAX) {
3446                         bcmerror = BCME_RANGE;
3447                         break;
3448                 }
3449
3450                 wlc_mhf(wlc, (u8) i, 0xffff, (u16) (val >> NBITS(u16)),
3451                         WLC_BAND_AUTO);
3452                 break;
3453
3454         case WLC_GET_SHMEM:
3455                 ta_ok = TRUE;
3456
3457                 /* optional band is stored in the second integer of incoming buffer */
3458                 band =
3459                     (len <
3460                      (int)(2 * sizeof(int))) ? WLC_BAND_AUTO : ((int *)arg)[1];
3461
3462                 /* bcmerror checking */
3463                 bcmerror = wlc_iocregchk(wlc, band);
3464                 if (bcmerror)
3465                         break;
3466
3467                 if (val & 1) {
3468                         bcmerror = BCME_BADADDR;
3469                         break;
3470                 }
3471
3472                 *pval = wlc_read_shm(wlc, (u16) val);
3473                 break;
3474
3475         case WLC_SET_SHMEM:
3476                 ta_ok = TRUE;
3477
3478                 /* optional band is stored in the second integer of incoming buffer */
3479                 band =
3480                     (len <
3481                      (int)(2 * sizeof(int))) ? WLC_BAND_AUTO : ((int *)arg)[1];
3482
3483                 /* bcmerror checking */
3484                 bcmerror = wlc_iocregchk(wlc, band);
3485                 if (bcmerror)
3486                         break;
3487
3488                 if (val & 1) {
3489                         bcmerror = BCME_BADADDR;
3490                         break;
3491                 }
3492
3493                 wlc_write_shm(wlc, (u16) val,
3494                               (u16) (val >> NBITS(u16)));
3495                 break;
3496
3497         case WLC_R_REG: /* MAC registers */
3498                 ta_ok = TRUE;
3499                 r = (rw_reg_t *) arg;
3500                 band = WLC_BAND_AUTO;
3501
3502                 if (len < (int)(sizeof(rw_reg_t) - sizeof(uint))) {
3503                         bcmerror = BCME_BUFTOOSHORT;
3504                         break;
3505                 }
3506
3507                 if (len >= (int)sizeof(rw_reg_t))
3508                         band = r->band;
3509
3510                 /* bcmerror checking */
3511                 bcmerror = wlc_iocregchk(wlc, band);
3512                 if (bcmerror)
3513                         break;
3514
3515                 if ((r->byteoff + r->size) > sizeof(d11regs_t)) {
3516                         bcmerror = BCME_BADADDR;
3517                         break;
3518                 }
3519                 if (r->size == sizeof(u32))
3520                         r->val =
3521                             R_REG(osh,
3522                                   (u32 *) ((unsigned char *) (uintptr) regs +
3523                                               r->byteoff));
3524                 else if (r->size == sizeof(u16))
3525                         r->val =
3526                             R_REG(osh,
3527                                   (u16 *) ((unsigned char *) (uintptr) regs +
3528                                               r->byteoff));
3529                 else
3530                         bcmerror = BCME_BADADDR;
3531                 break;
3532
3533         case WLC_W_REG:
3534                 ta_ok = TRUE;
3535                 r = (rw_reg_t *) arg;
3536                 band = WLC_BAND_AUTO;
3537
3538                 if (len < (int)(sizeof(rw_reg_t) - sizeof(uint))) {
3539                         bcmerror = BCME_BUFTOOSHORT;
3540                         break;
3541                 }
3542
3543                 if (len >= (int)sizeof(rw_reg_t))
3544                         band = r->band;
3545
3546                 /* bcmerror checking */
3547                 bcmerror = wlc_iocregchk(wlc, band);
3548                 if (bcmerror)
3549                         break;
3550
3551                 if (r->byteoff + r->size > sizeof(d11regs_t)) {
3552                         bcmerror = BCME_BADADDR;
3553                         break;
3554                 }
3555                 if (r->size == sizeof(u32))
3556                         W_REG(osh,
3557                               (u32 *) ((unsigned char *) (uintptr) regs +
3558                                           r->byteoff), r->val);
3559                 else if (r->size == sizeof(u16))
3560                         W_REG(osh,
3561                               (u16 *) ((unsigned char *) (uintptr) regs +
3562                                           r->byteoff), r->val);
3563                 else
3564                         bcmerror = BCME_BADADDR;
3565                 break;
3566 #endif                          /* BCMDBG */
3567
3568         case WLC_GET_TXANT:
3569                 *pval = wlc->stf->txant;
3570                 break;
3571
3572         case WLC_SET_TXANT:
3573                 bcmerror = wlc_stf_ant_txant_validate(wlc, (s8) val);
3574                 if (bcmerror < 0)
3575                         break;
3576
3577                 wlc->stf->txant = (s8) val;
3578
3579                 /* if down, we are done */
3580                 if (!wlc->pub->up)
3581                         break;
3582
3583                 wlc_suspend_mac_and_wait(wlc);
3584
3585                 wlc_stf_phy_txant_upd(wlc);
3586                 wlc_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec);
3587
3588                 wlc_enable_mac(wlc);
3589
3590                 break;
3591
3592         case WLC_GET_ANTDIV:{
3593                         u8 phy_antdiv;
3594
3595                         /* return configured value if core is down */
3596                         if (!wlc->pub->up) {
3597                                 *pval = wlc->stf->ant_rx_ovr;
3598
3599                         } else {
3600                                 if (wlc_phy_ant_rxdiv_get
3601                                     (wlc->band->pi, &phy_antdiv))
3602                                         *pval = (int)phy_antdiv;
3603                                 else
3604                                         *pval = (int)wlc->stf->ant_rx_ovr;
3605                         }
3606
3607                         break;
3608                 }
3609         case WLC_SET_ANTDIV:
3610                 /* values are -1=driver default, 0=force0, 1=force1, 2=start1, 3=start0 */
3611                 if ((val < -1) || (val > 3)) {
3612                         bcmerror = BCME_RANGE;
3613                         break;
3614                 }
3615
3616                 if (val == -1)
3617                         val = ANT_RX_DIV_DEF;
3618
3619                 wlc->stf->ant_rx_ovr = (u8) val;
3620                 wlc_phy_ant_rxdiv_set(wlc->band->pi, (u8) val);
3621                 break;
3622
3623         case WLC_GET_RX_ANT:{   /* get latest used rx antenna */
3624                         u16 rxstatus;
3625
3626                         if (!wlc->pub->up) {
3627                                 bcmerror = BCME_NOTUP;
3628                                 break;
3629                         }
3630
3631                         rxstatus = R_REG(wlc->osh, &wlc->regs->phyrxstatus0);
3632                         if (rxstatus == 0xdead || rxstatus == (u16) -1) {
3633                                 bcmerror = BCME_ERROR;
3634                                 break;
3635                         }
3636                         *pval = (rxstatus & PRXS0_RXANT_UPSUBBAND) ? 1 : 0;
3637                         break;
3638                 }
3639
3640 #if defined(BCMDBG)
3641         case WLC_GET_UCANTDIV:
3642                 if (!wlc->clk) {
3643                         bcmerror = BCME_NOCLK;
3644                         break;
3645                 }
3646
3647                 *pval =
3648                     (wlc_bmac_mhf_get(wlc->hw, MHF1, WLC_BAND_AUTO) &
3649                      MHF1_ANTDIV);
3650                 break;
3651
3652         case WLC_SET_UCANTDIV:{
3653                         if (!wlc->pub->up) {
3654                                 bcmerror = BCME_NOTUP;
3655                                 break;
3656                         }
3657
3658                         /* if multiband, band must be locked */
3659                         if (IS_MBAND_UNLOCKED(wlc)) {
3660                                 bcmerror = BCME_NOTBANDLOCKED;
3661                                 break;
3662                         }
3663
3664                         /* 4322 supports antdiv in phy, no need to set it to ucode */
3665                         if (WLCISNPHY(wlc->band)
3666                             && D11REV_IS(wlc->pub->corerev, 16)) {
3667                                 WL_ERROR(("wl%d: can't set ucantdiv for 4322\n",
3668                                           wlc->pub->unit));
3669                                 bcmerror = BCME_UNSUPPORTED;
3670                         } else
3671                                 wlc_mhf(wlc, MHF1, MHF1_ANTDIV,
3672                                         (val ? MHF1_ANTDIV : 0), WLC_BAND_AUTO);
3673                         break;
3674                 }
3675 #endif                          /* defined(BCMDBG) */
3676
3677         case WLC_GET_SRL:
3678                 *pval = wlc->SRL;
3679                 break;
3680
3681         case WLC_SET_SRL:
3682                 if (val >= 1 && val <= RETRY_SHORT_MAX) {
3683                         int ac;
3684                         wlc->SRL = (u16) val;
3685
3686                         wlc_bmac_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
3687
3688                         for (ac = 0; ac < AC_COUNT; ac++) {
3689                                 WLC_WME_RETRY_SHORT_SET(wlc, ac, wlc->SRL);
3690                         }
3691                         wlc_wme_retries_write(wlc);
3692                 } else
3693                         bcmerror = BCME_RANGE;
3694                 break;
3695
3696         case WLC_GET_LRL:
3697                 *pval = wlc->LRL;
3698                 break;
3699
3700         case WLC_SET_LRL:
3701                 if (val >= 1 && val <= 255) {
3702                         int ac;
3703                         wlc->LRL = (u16) val;
3704
3705                         wlc_bmac_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
3706
3707                         for (ac = 0; ac < AC_COUNT; ac++) {
3708                                 WLC_WME_RETRY_LONG_SET(wlc, ac, wlc->LRL);
3709                         }
3710                         wlc_wme_retries_write(wlc);
3711                 } else
3712                         bcmerror = BCME_RANGE;
3713                 break;
3714
3715         case WLC_GET_CWMIN:
3716                 *pval = wlc->band->CWmin;
3717                 break;
3718
3719         case WLC_SET_CWMIN:
3720                 if (!wlc->clk) {
3721                         bcmerror = BCME_NOCLK;
3722                         break;
3723                 }
3724
3725                 if (val >= 1 && val <= 255) {
3726                         wlc_set_cwmin(wlc, (u16) val);
3727                 } else
3728                         bcmerror = BCME_RANGE;
3729                 break;
3730
3731         case WLC_GET_CWMAX:
3732                 *pval = wlc->band->CWmax;
3733                 break;
3734
3735         case WLC_SET_CWMAX:
3736                 if (!wlc->clk) {
3737                         bcmerror = BCME_NOCLK;
3738                         break;
3739                 }
3740
3741                 if (val >= 255 && val <= 2047) {
3742                         wlc_set_cwmax(wlc, (u16) val);
3743                 } else
3744                         bcmerror = BCME_RANGE;
3745                 break;
3746
3747         case WLC_GET_RADIO:     /* use mask if don't want to expose some internal bits */
3748                 *pval = wlc->pub->radio_disabled;
3749                 break;
3750
3751         case WLC_SET_RADIO:{    /* 32 bits input, higher 16 bits are mask, lower 16 bits are value to
3752                                  * set
3753                                  */
3754                         u16 radiomask, radioval;
3755                         uint validbits =
3756                             WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE;
3757                         mbool new = 0;
3758
3759                         radiomask = (val & 0xffff0000) >> 16;
3760                         radioval = val & 0x0000ffff;
3761
3762                         if ((radiomask == 0) || (radiomask & ~validbits)
3763                             || (radioval & ~validbits)
3764                             || ((radioval & ~radiomask) != 0)) {
3765                                 WL_ERROR(("SET_RADIO with wrong bits 0x%x\n",
3766                                           val));
3767                                 bcmerror = BCME_RANGE;
3768                                 break;
3769                         }
3770
3771                         new =
3772                             (wlc->pub->radio_disabled & ~radiomask) | radioval;
3773                         wlc->pub->radio_disabled = new;
3774
3775                         wlc_radio_hwdisable_upd(wlc);
3776                         wlc_radio_upd(wlc);
3777                         break;
3778                 }
3779
3780         case WLC_GET_PHYTYPE:
3781                 *pval = WLC_PHYTYPE(wlc->band->phytype);
3782                 break;
3783
3784 #if defined(BCMDBG)
3785         case WLC_GET_KEY:
3786                 if ((val >= 0) && (val < WLC_MAX_WSEC_KEYS(wlc))) {
3787                         wl_wsec_key_t key;
3788
3789                         wsec_key_t *src_key = wlc->wsec_keys[val];
3790
3791                         if (len < (int)sizeof(key)) {
3792                                 bcmerror = BCME_BUFTOOSHORT;
3793                                 break;
3794                         }
3795
3796                         bzero((char *)&key, sizeof(key));
3797                         if (src_key) {
3798                                 key.index = src_key->id;
3799                                 key.len = src_key->len;
3800                                 bcopy(src_key->data, key.data, key.len);
3801                                 key.algo = src_key->algo;
3802                                 if (WSEC_SOFTKEY(wlc, src_key, bsscfg))
3803                                         key.flags |= WL_SOFT_KEY;
3804                                 if (src_key->flags & WSEC_PRIMARY_KEY)
3805                                         key.flags |= WL_PRIMARY_KEY;
3806
3807                                 bcopy(src_key->ea.octet, key.ea.octet,
3808                                       ETHER_ADDR_LEN);
3809                         }
3810
3811                         bcopy((char *)&key, arg, sizeof(key));
3812                 } else
3813                         bcmerror = BCME_BADKEYIDX;
3814                 break;
3815 #endif                          /* defined(BCMDBG) */
3816
3817         case WLC_SET_KEY:
3818                 bcmerror =
3819                     wlc_iovar_op(wlc, "wsec_key", NULL, 0, arg, len, IOV_SET,
3820                                  wlcif);
3821                 break;
3822
3823         case WLC_GET_KEY_SEQ:{
3824                         wsec_key_t *key;
3825
3826                         if (len < DOT11_WPA_KEY_RSC_LEN) {
3827                                 bcmerror = BCME_BUFTOOSHORT;
3828                                 break;
3829                         }
3830
3831                         /* Return the key's tx iv as an EAPOL sequence counter.
3832                          * This will be used to supply the RSC value to a supplicant.
3833                          * The format is 8 bytes, with least significant in seq[0].
3834                          */
3835
3836                         key = WSEC_KEY(wlc, val);
3837                         if ((val >= 0) && (val < WLC_MAX_WSEC_KEYS(wlc)) &&
3838                                 (key != NULL)) {
3839                                 u8 seq[DOT11_WPA_KEY_RSC_LEN];
3840                                 u16 lo;
3841                                 u32 hi;
3842                                 /* group keys in WPA-NONE (IBSS only, AES and TKIP) use a global TXIV */
3843                                 if ((bsscfg->WPA_auth & WPA_AUTH_NONE)
3844                                     && ETHER_ISNULLADDR(&key->ea)) {
3845                                         lo = bsscfg->wpa_none_txiv.lo;
3846                                         hi = bsscfg->wpa_none_txiv.hi;
3847                                 } else {
3848                                         lo = key->txiv.lo;
3849                                         hi = key->txiv.hi;
3850                                 }
3851
3852                                 /* format the buffer, low to high */
3853                                 seq[0] = lo & 0xff;
3854                                 seq[1] = (lo >> 8) & 0xff;
3855                                 seq[2] = hi & 0xff;
3856                                 seq[3] = (hi >> 8) & 0xff;
3857                                 seq[4] = (hi >> 16) & 0xff;
3858                                 seq[5] = (hi >> 24) & 0xff;
3859                                 seq[6] = 0;
3860                                 seq[7] = 0;
3861
3862                                 bcopy((char *)seq, arg, sizeof(seq));
3863                         } else {
3864                                 bcmerror = BCME_BADKEYIDX;
3865                         }
3866                         break;
3867                 }
3868
3869         case WLC_GET_CURR_RATESET:{
3870                         wl_rateset_t *ret_rs = (wl_rateset_t *) arg;
3871                         wlc_rateset_t *rs;
3872
3873                         if (bsscfg->associated)
3874                                 rs = &current_bss->rateset;
3875                         else
3876                                 rs = &wlc->default_bss->rateset;
3877
3878                         if (len < (int)(rs->count + sizeof(rs->count))) {
3879                                 bcmerror = BCME_BUFTOOSHORT;
3880                                 break;
3881                         }
3882
3883                         /* Copy only legacy rateset section */
3884                         ret_rs->count = rs->count;
3885                         bcopy(&rs->rates, &ret_rs->rates, rs->count);
3886                         break;
3887                 }
3888
3889         case WLC_GET_RATESET:{
3890                         wlc_rateset_t rs;
3891                         wl_rateset_t *ret_rs = (wl_rateset_t *) arg;
3892
3893                         bzero(&rs, sizeof(wlc_rateset_t));
3894                         wlc_default_rateset(wlc, (wlc_rateset_t *) &rs);
3895
3896                         if (len < (int)(rs.count + sizeof(rs.count))) {
3897                                 bcmerror = BCME_BUFTOOSHORT;
3898                                 break;
3899                         }
3900
3901                         /* Copy only legacy rateset section */
3902                         ret_rs->count = rs.count;
3903                         bcopy(&rs.rates, &ret_rs->rates, rs.count);
3904                         break;
3905                 }
3906
3907         case WLC_SET_RATESET:{
3908                         wlc_rateset_t rs;
3909                         wl_rateset_t *in_rs = (wl_rateset_t *) arg;
3910
3911                         if (len < (int)(in_rs->count + sizeof(in_rs->count))) {
3912                                 bcmerror = BCME_BUFTOOSHORT;
3913                                 break;
3914                         }
3915
3916                         if (in_rs->count > WLC_NUMRATES) {
3917                                 bcmerror = BCME_BUFTOOLONG;
3918                                 break;
3919                         }
3920
3921                         bzero(&rs, sizeof(wlc_rateset_t));
3922
3923                         /* Copy only legacy rateset section */
3924                         rs.count = in_rs->count;
3925                         bcopy(&in_rs->rates, &rs.rates, rs.count);
3926
3927                         /* merge rateset coming in with the current mcsset */
3928                         if (N_ENAB(wlc->pub)) {
3929                                 if (bsscfg->associated)
3930                                         bcopy(&current_bss->rateset.mcs[0],
3931                                               rs.mcs, MCSSET_LEN);
3932                                 else
3933                                         bcopy(&wlc->default_bss->rateset.mcs[0],
3934                                               rs.mcs, MCSSET_LEN);
3935                         }
3936
3937                         bcmerror = wlc_set_rateset(wlc, &rs);
3938
3939                         if (!bcmerror)
3940                                 wlc_ofdm_rateset_war(wlc);
3941
3942                         break;
3943                 }
3944
3945         case WLC_GET_BCNPRD:
3946                 if (BSSCFG_STA(bsscfg) && bsscfg->BSS && bsscfg->associated)
3947                         *pval = current_bss->beacon_period;
3948                 else
3949                         *pval = wlc->default_bss->beacon_period;
3950                 break;
3951
3952         case WLC_SET_BCNPRD:
3953                 /* range [1, 0xffff] */
3954                 if (val >= DOT11_MIN_BEACON_PERIOD
3955                     && val <= DOT11_MAX_BEACON_PERIOD) {
3956                         wlc->default_bss->beacon_period = (u16) val;
3957                 } else
3958                         bcmerror = BCME_RANGE;
3959                 break;
3960
3961         case WLC_GET_DTIMPRD:
3962                 if (BSSCFG_STA(bsscfg) && bsscfg->BSS && bsscfg->associated)
3963                         *pval = current_bss->dtim_period;
3964                 else
3965                         *pval = wlc->default_bss->dtim_period;
3966                 break;
3967
3968         case WLC_SET_DTIMPRD:
3969                 /* range [1, 0xff] */
3970                 if (val >= DOT11_MIN_DTIM_PERIOD
3971                     && val <= DOT11_MAX_DTIM_PERIOD) {
3972                         wlc->default_bss->dtim_period = (u8) val;
3973                 } else
3974                         bcmerror = BCME_RANGE;
3975                 break;
3976
3977 #ifdef SUPPORT_PS
3978         case WLC_GET_PM:
3979                 *pval = wlc->PM;
3980                 break;
3981
3982         case WLC_SET_PM:
3983                 if ((val >= PM_OFF) && (val <= PM_MAX)) {
3984                         wlc->PM = (u8) val;
3985                         if (wlc->pub->up) {
3986                         }
3987                         /* Change watchdog driver to align watchdog with tbtt if possible */
3988                         wlc_watchdog_upd(wlc, PS_ALLOWED(wlc));
3989                 } else
3990                         bcmerror = BCME_ERROR;
3991                 break;
3992 #endif                          /* SUPPORT_PS */
3993
3994 #ifdef SUPPORT_PS
3995 #ifdef BCMDBG
3996         case WLC_GET_WAKE:
3997                 if (AP_ENAB(wlc->pub)) {
3998                         bcmerror = BCME_NOTSTA;
3999                         break;
4000                 }
4001                 *pval = wlc->wake;
4002                 break;
4003
4004         case WLC_SET_WAKE:
4005                 if (AP_ENAB(wlc->pub)) {
4006                         bcmerror = BCME_NOTSTA;
4007                         break;
4008                 }
4009
4010                 wlc->wake = val ? TRUE : FALSE;
4011
4012                 /* if down, we're done */
4013                 if (!wlc->pub->up)
4014                         break;
4015
4016                 /* apply to the mac */
4017                 wlc_set_ps_ctrl(wlc);
4018                 break;
4019 #endif                          /* BCMDBG */
4020 #endif                          /* SUPPORT_PS */
4021
4022         case WLC_GET_REVINFO:
4023                 bcmerror = wlc_get_revision_info(wlc, arg, (uint) len);
4024                 break;
4025
4026         case WLC_GET_AP:
4027                 *pval = (int)AP_ENAB(wlc->pub);
4028                 break;
4029
4030         case WLC_GET_ATIM:
4031                 if (bsscfg->associated)
4032                         *pval = (int)current_bss->atim_window;
4033                 else
4034                         *pval = (int)wlc->default_bss->atim_window;
4035                 break;
4036
4037         case WLC_SET_ATIM:
4038                 wlc->default_bss->atim_window = (u32) val;
4039                 break;
4040
4041         case WLC_GET_PKTCNTS:{
4042                         get_pktcnt_t *pktcnt = (get_pktcnt_t *) pval;
4043                         if (WLC_UPDATE_STATS(wlc))
4044                                 wlc_statsupd(wlc);
4045                         pktcnt->rx_good_pkt = WLCNTVAL(wlc->pub->_cnt->rxframe);
4046                         pktcnt->rx_bad_pkt = WLCNTVAL(wlc->pub->_cnt->rxerror);
4047                         pktcnt->tx_good_pkt =
4048                             WLCNTVAL(wlc->pub->_cnt->txfrmsnt);
4049                         pktcnt->tx_bad_pkt =
4050                             WLCNTVAL(wlc->pub->_cnt->txerror) +
4051                             WLCNTVAL(wlc->pub->_cnt->txfail);
4052                         if (len >= (int)sizeof(get_pktcnt_t)) {
4053                                 /* Be backward compatible - only if buffer is large enough  */
4054                                 pktcnt->rx_ocast_good_pkt =
4055                                     WLCNTVAL(wlc->pub->_cnt->rxmfrmocast);
4056                         }
4057                         break;
4058                 }
4059
4060 #ifdef SUPPORT_HWKEY
4061         case WLC_GET_WSEC:
4062                 bcmerror =
4063                     wlc_iovar_op(wlc, "wsec", NULL, 0, arg, len, IOV_GET,
4064                                  wlcif);
4065                 break;
4066
4067         case WLC_SET_WSEC:
4068                 bcmerror =
4069                     wlc_iovar_op(wlc, "wsec", NULL, 0, arg, len, IOV_SET,
4070                                  wlcif);
4071                 break;
4072
4073         case WLC_GET_WPA_AUTH:
4074                 *pval = (int)bsscfg->WPA_auth;
4075                 break;
4076
4077         case WLC_SET_WPA_AUTH:
4078                 /* change of WPA_Auth modifies the PS_ALLOWED state */
4079                 if (BSSCFG_STA(bsscfg)) {
4080                         bsscfg->WPA_auth = (u16) val;
4081                 } else
4082                         bsscfg->WPA_auth = (u16) val;
4083                 break;
4084 #endif                          /* SUPPORT_HWKEY */
4085
4086         case WLC_GET_BANDLIST:
4087                 /* count of number of bands, followed by each band type */
4088                 *pval++ = NBANDS(wlc);
4089                 *pval++ = wlc->band->bandtype;
4090                 if (NBANDS(wlc) > 1)
4091                         *pval++ = wlc->bandstate[OTHERBANDUNIT(wlc)]->bandtype;
4092                 break;
4093
4094         case WLC_GET_BAND:
4095                 *pval = wlc->bandlocked ? wlc->band->bandtype : WLC_BAND_AUTO;
4096                 break;
4097
4098         case WLC_GET_PHYLIST:
4099                 {
4100                         unsigned char *cp = arg;
4101                         if (len < 3) {
4102                                 bcmerror = BCME_BUFTOOSHORT;
4103                                 break;
4104                         }
4105
4106                         if (WLCISNPHY(wlc->band)) {
4107                                 *cp++ = 'n';
4108                         } else if (WLCISLCNPHY(wlc->band)) {
4109                                 *cp++ = 'c';
4110                         } else if (WLCISSSLPNPHY(wlc->band)) {
4111                                 *cp++ = 's';
4112                         }
4113                         *cp = '\0';
4114                         break;
4115                 }
4116
4117         case WLC_GET_SHORTSLOT:
4118                 *pval = wlc->shortslot;
4119                 break;
4120
4121         case WLC_GET_SHORTSLOT_OVERRIDE:
4122                 *pval = wlc->shortslot_override;
4123                 break;
4124
4125         case WLC_SET_SHORTSLOT_OVERRIDE:
4126                 if ((val != WLC_SHORTSLOT_AUTO) &&
4127                     (val != WLC_SHORTSLOT_OFF) && (val != WLC_SHORTSLOT_ON)) {
4128                         bcmerror = BCME_RANGE;
4129                         break;
4130                 }
4131
4132                 wlc->shortslot_override = (s8) val;
4133
4134                 /* shortslot is an 11g feature, so no more work if we are
4135                  * currently on the 5G band
4136                  */
4137                 if (BAND_5G(wlc->band->bandtype))
4138                         break;
4139
4140                 if (wlc->pub->up && wlc->pub->associated) {
4141                         /* let watchdog or beacon processing update shortslot */
4142                 } else if (wlc->pub->up) {
4143                         /* unassociated shortslot is off */
4144                         wlc_switch_shortslot(wlc, FALSE);
4145                 } else {
4146                         /* driver is down, so just update the wlc_info value */
4147                         if (wlc->shortslot_override == WLC_SHORTSLOT_AUTO) {
4148                                 wlc->shortslot = FALSE;
4149                         } else {
4150                                 wlc->shortslot =
4151                                     (wlc->shortslot_override ==
4152                                      WLC_SHORTSLOT_ON);
4153                         }
4154                 }
4155
4156                 break;
4157
4158         case WLC_GET_LEGACY_ERP:
4159                 *pval = wlc->include_legacy_erp;
4160                 break;
4161
4162         case WLC_SET_LEGACY_ERP:
4163                 if (wlc->include_legacy_erp == bool_val)
4164                         break;
4165
4166                 wlc->include_legacy_erp = bool_val;
4167
4168                 if (AP_ENAB(wlc->pub) && wlc->clk) {
4169                         wlc_update_beacon(wlc);
4170                         wlc_update_probe_resp(wlc, TRUE);
4171                 }
4172                 break;
4173
4174         case WLC_GET_GMODE:
4175                 if (wlc->band->bandtype == WLC_BAND_2G)
4176                         *pval = wlc->band->gmode;
4177                 else if (NBANDS(wlc) > 1)
4178                         *pval = wlc->bandstate[OTHERBANDUNIT(wlc)]->gmode;
4179                 break;
4180
4181         case WLC_SET_GMODE:
4182                 if (!wlc->pub->associated)
4183                         bcmerror = wlc_set_gmode(wlc, (u8) val, TRUE);
4184                 else {
4185                         bcmerror = BCME_ASSOCIATED;
4186                         break;
4187                 }
4188                 break;
4189
4190         case WLC_GET_GMODE_PROTECTION:
4191                 *pval = wlc->protection->_g;
4192                 break;
4193
4194         case WLC_GET_PROTECTION_CONTROL:
4195                 *pval = wlc->protection->overlap;
4196                 break;
4197
4198         case WLC_SET_PROTECTION_CONTROL:
4199                 if ((val != WLC_PROTECTION_CTL_OFF) &&
4200                     (val != WLC_PROTECTION_CTL_LOCAL) &&
4201                     (val != WLC_PROTECTION_CTL_OVERLAP)) {
4202                         bcmerror = BCME_RANGE;
4203                         break;
4204                 }
4205
4206                 wlc_protection_upd(wlc, WLC_PROT_OVERLAP, (s8) val);
4207
4208                 /* Current g_protection will sync up to the specified control alg in watchdog
4209                  * if the driver is up and associated.
4210                  * If the driver is down or not associated, the control setting has no effect.
4211                  */
4212                 break;
4213
4214         case WLC_GET_GMODE_PROTECTION_OVERRIDE:
4215                 *pval = wlc->protection->g_override;
4216                 break;
4217
4218         case WLC_SET_GMODE_PROTECTION_OVERRIDE:
4219                 if ((val != WLC_PROTECTION_AUTO) &&
4220                     (val != WLC_PROTECTION_OFF) && (val != WLC_PROTECTION_ON)) {
4221                         bcmerror = BCME_RANGE;
4222                         break;
4223                 }
4224
4225                 wlc_protection_upd(wlc, WLC_PROT_G_OVR, (s8) val);
4226
4227                 break;
4228
4229         case WLC_SET_SUP_RATESET_OVERRIDE:{
4230                         wlc_rateset_t rs, new;
4231
4232                         /* copyin */
4233                         if (len < (int)sizeof(wlc_rateset_t)) {
4234                                 bcmerror = BCME_BUFTOOSHORT;
4235                                 break;
4236                         }
4237                         bcopy((char *)arg, (char *)&rs, sizeof(wlc_rateset_t));
4238
4239                         /* check for bad count value */
4240                         if (rs.count > WLC_NUMRATES) {
4241                                 bcmerror = BCME_BADRATESET;     /* invalid rateset */
4242                                 break;
4243                         }
4244
4245                         /* this command is only appropriate for gmode operation */
4246                         if (!(wlc->band->gmode ||
4247                               ((NBANDS(wlc) > 1)
4248                                && wlc->bandstate[OTHERBANDUNIT(wlc)]->gmode))) {
4249                                 bcmerror = BCME_BADBAND;        /* gmode only command when not in gmode */
4250                                 break;
4251                         }
4252
4253                         /* check for an empty rateset to clear the override */
4254                         if (rs.count == 0) {
4255                                 bzero(&wlc->sup_rates_override,
4256                                       sizeof(wlc_rateset_t));
4257                                 break;
4258                         }
4259
4260                         /* validate rateset by comparing pre and post sorted against 11g hw rates */
4261                         wlc_rateset_filter(&rs, &new, FALSE, WLC_RATES_CCK_OFDM,
4262                                            RATE_MASK, BSS_N_ENAB(wlc, bsscfg));
4263                         wlc_rate_hwrs_filter_sort_validate(&new,
4264                                                            &cck_ofdm_rates,
4265                                                            FALSE,
4266                                                            wlc->stf->txstreams);
4267                         if (rs.count != new.count) {
4268                                 bcmerror = BCME_BADRATESET;     /* invalid rateset */
4269                                 break;
4270                         }
4271
4272                         /* apply new rateset to the override */
4273                         bcopy((char *)&new, (char *)&wlc->sup_rates_override,
4274                               sizeof(wlc_rateset_t));
4275
4276                         /* update bcn and probe resp if needed */
4277                         if (wlc->pub->up && AP_ENAB(wlc->pub)
4278                             && wlc->pub->associated) {
4279                                 wlc_update_beacon(wlc);
4280                                 wlc_update_probe_resp(wlc, TRUE);
4281                         }
4282                         break;
4283                 }
4284
4285         case WLC_GET_SUP_RATESET_OVERRIDE:
4286                 /* this command is only appropriate for gmode operation */
4287                 if (!(wlc->band->gmode ||
4288                       ((NBANDS(wlc) > 1)
4289                        && wlc->bandstate[OTHERBANDUNIT(wlc)]->gmode))) {
4290                         bcmerror = BCME_BADBAND;        /* gmode only command when not in gmode */
4291                         break;
4292                 }
4293                 if (len < (int)sizeof(wlc_rateset_t)) {
4294                         bcmerror = BCME_BUFTOOSHORT;
4295                         break;
4296                 }
4297                 bcopy((char *)&wlc->sup_rates_override, (char *)arg,
4298                       sizeof(wlc_rateset_t));
4299
4300                 break;
4301
4302         case WLC_GET_PRB_RESP_TIMEOUT:
4303                 *pval = wlc->prb_resp_timeout;
4304                 break;
4305
4306         case WLC_SET_PRB_RESP_TIMEOUT:
4307                 if (wlc->pub->up) {
4308                         bcmerror = BCME_NOTDOWN;
4309                         break;
4310                 }
4311                 if (val < 0 || val >= 0xFFFF) {
4312                         bcmerror = BCME_RANGE;  /* bad value */
4313                         break;
4314                 }
4315                 wlc->prb_resp_timeout = (u16) val;
4316                 break;
4317
4318         case WLC_GET_KEY_PRIMARY:{
4319                         wsec_key_t *key;
4320
4321                         /* treat the 'val' parm as the key id */
4322                         key = WSEC_BSS_DEFAULT_KEY(bsscfg);
4323                         if (key != NULL) {
4324                                 *pval = key->id == val ? TRUE : FALSE;
4325                         } else {
4326                                 bcmerror = BCME_BADKEYIDX;
4327                         }
4328                         break;
4329                 }
4330
4331         case WLC_SET_KEY_PRIMARY:{
4332                         wsec_key_t *key, *old_key;
4333
4334                         bcmerror = BCME_BADKEYIDX;
4335
4336                         /* treat the 'val' parm as the key id */
4337                         for (i = 0; i < WSEC_MAX_DEFAULT_KEYS; i++) {
4338                                 key = bsscfg->bss_def_keys[i];
4339                                 if (key != NULL && key->id == val) {
4340                                         old_key = WSEC_BSS_DEFAULT_KEY(bsscfg);
4341                                         if (old_key != NULL)
4342                                                 old_key->flags &=
4343                                                     ~WSEC_PRIMARY_KEY;
4344                                         key->flags |= WSEC_PRIMARY_KEY;
4345                                         bsscfg->wsec_index = i;
4346                                         bcmerror = BCME_OK;
4347                                 }
4348                         }
4349                         break;
4350                 }
4351
4352 #ifdef BCMDBG
4353         case WLC_INIT:
4354                 wl_init(wlc->wl);
4355                 break;
4356 #endif
4357
4358         case WLC_SET_VAR:
4359         case WLC_GET_VAR:{
4360                         char *name;
4361                         /* validate the name value */
4362                         name = (char *)arg;
4363                         for (i = 0; i < (uint) len && *name != '\0';
4364                              i++, name++)
4365                                 ;
4366
4367                         if (i == (uint) len) {
4368                                 bcmerror = BCME_BUFTOOSHORT;
4369                                 break;
4370                         }
4371                         i++;    /* include the null in the string length */
4372
4373                         if (cmd == WLC_GET_VAR) {
4374                                 bcmerror =
4375                                     wlc_iovar_op(wlc, arg,
4376                                                  (void *)((s8 *) arg + i),
4377                                                  len - i, arg, len, IOV_GET,
4378                                                  wlcif);
4379                         } else
4380                                 bcmerror =
4381                                     wlc_iovar_op(wlc, arg, NULL, 0,
4382                                                  (void *)((s8 *) arg + i),
4383                                                  len - i, IOV_SET, wlcif);
4384
4385                         break;
4386                 }
4387
4388         case WLC_SET_WSEC_PMK:
4389                 bcmerror = BCME_UNSUPPORTED;
4390                 break;
4391
4392 #if defined(BCMDBG)
4393         case WLC_CURRENT_PWR:
4394                 if (!wlc->pub->up)
4395                         bcmerror = BCME_NOTUP;
4396                 else
4397                         bcmerror = wlc_get_current_txpwr(wlc, arg, len);
4398                 break;
4399 #endif
4400
4401         case WLC_LAST:
4402                 WL_ERROR(("%s: WLC_LAST\n", __func__));
4403         }
4404  done:
4405
4406         if (bcmerror) {
4407                 if (VALID_BCMERROR(bcmerror))
4408                         wlc->pub->bcmerror = bcmerror;
4409                 else {
4410                         bcmerror = 0;
4411                 }
4412
4413         }
4414 #ifdef WLC_LOW
4415         /* BMAC_NOTE: for HIGH_ONLY driver, this seems being called after RPC bus failed */
4416         /* In hw_off condition, IOCTLs that reach here are deemed safe but taclear would
4417          * certainly result in getting -1 for register reads. So skip ta_clear altogether
4418          */
4419         if (!(wlc->pub->hw_off))
4420                 ASSERT(wlc_bmac_taclear(wlc->hw, ta_ok) || !ta_ok);
4421 #endif
4422
4423         return bcmerror;
4424 }
4425
4426 #if defined(BCMDBG)
4427 /* consolidated register access ioctl error checking */
4428 int wlc_iocregchk(wlc_info_t *wlc, uint band)
4429 {
4430         /* if band is specified, it must be the current band */
4431         if ((band != WLC_BAND_AUTO) && (band != (uint) wlc->band->bandtype))
4432                 return BCME_BADBAND;
4433
4434         /* if multiband and band is not specified, band must be locked */
4435         if ((band == WLC_BAND_AUTO) && IS_MBAND_UNLOCKED(wlc))
4436                 return BCME_NOTBANDLOCKED;
4437
4438         /* must have core clocks */
4439         if (!wlc->clk)
4440                 return BCME_NOCLK;
4441
4442         return 0;
4443 }
4444 #endif                          /* defined(BCMDBG) */
4445
4446 #if defined(BCMDBG)
4447 /* For some ioctls, make sure that the pi pointer matches the current phy */
4448 int wlc_iocpichk(wlc_info_t *wlc, uint phytype)
4449 {
4450         if (wlc->band->phytype != phytype)
4451                 return BCME_BADBAND;
4452         return 0;
4453 }
4454 #endif
4455
4456 /* Look up the given var name in the given table */
4457 static const bcm_iovar_t *wlc_iovar_lookup(const bcm_iovar_t *table,
4458                                            const char *name)
4459 {
4460         const bcm_iovar_t *vi;
4461         const char *lookup_name;
4462
4463         /* skip any ':' delimited option prefixes */
4464         lookup_name = strrchr(name, ':');
4465         if (lookup_name != NULL)
4466                 lookup_name++;
4467         else
4468                 lookup_name = name;
4469
4470         ASSERT(table != NULL);
4471
4472         for (vi = table; vi->name; vi++) {
4473                 if (!strcmp(vi->name, lookup_name))
4474                         return vi;
4475         }
4476         /* ran to end of table */
4477
4478         return NULL;            /* var name not found */
4479 }
4480
4481 /* simplified integer get interface for common WLC_GET_VAR ioctl handler */
4482 int wlc_iovar_getint(wlc_info_t *wlc, const char *name, int *arg)
4483 {
4484         return wlc_iovar_op(wlc, name, NULL, 0, arg, sizeof(s32), IOV_GET,
4485                             NULL);
4486 }
4487
4488 /* simplified integer set interface for common WLC_SET_VAR ioctl handler */
4489 int wlc_iovar_setint(wlc_info_t *wlc, const char *name, int arg)
4490 {
4491         return wlc_iovar_op(wlc, name, NULL, 0, (void *)&arg, sizeof(arg),
4492                             IOV_SET, NULL);
4493 }
4494
4495 /* simplified s8 get interface for common WLC_GET_VAR ioctl handler */
4496 int wlc_iovar_gets8(wlc_info_t *wlc, const char *name, s8 *arg)
4497 {
4498         int iovar_int;
4499         int err;
4500
4501         err =
4502             wlc_iovar_op(wlc, name, NULL, 0, &iovar_int, sizeof(iovar_int),
4503                          IOV_GET, NULL);
4504         if (!err)
4505                 *arg = (s8) iovar_int;
4506
4507         return err;
4508 }
4509
4510 /*
4511  * register iovar table, watchdog and down handlers.
4512  * calling function must keep 'iovars' until wlc_module_unregister is called.
4513  * 'iovar' must have the last entry's name field being NULL as terminator.
4514  */
4515 int wlc_module_register(wlc_pub_t *pub, const bcm_iovar_t *iovars,
4516                         const char *name, void *hdl, iovar_fn_t i_fn,
4517                         watchdog_fn_t w_fn, down_fn_t d_fn)
4518 {
4519         wlc_info_t *wlc = (wlc_info_t *) pub->wlc;
4520         int i;
4521
4522         ASSERT(name != NULL);
4523         ASSERT(i_fn != NULL || w_fn != NULL || d_fn != NULL);
4524
4525         /* find an empty entry and just add, no duplication check! */
4526         for (i = 0; i < WLC_MAXMODULES; i++) {
4527                 if (wlc->modulecb[i].name[0] == '\0') {
4528                         strncpy(wlc->modulecb[i].name, name,
4529                                 sizeof(wlc->modulecb[i].name) - 1);
4530                         wlc->modulecb[i].iovars = iovars;
4531                         wlc->modulecb[i].hdl = hdl;
4532                         wlc->modulecb[i].iovar_fn = i_fn;
4533                         wlc->modulecb[i].watchdog_fn = w_fn;
4534                         wlc->modulecb[i].down_fn = d_fn;
4535                         return 0;
4536                 }
4537         }
4538
4539         /* it is time to increase the capacity */
4540         ASSERT(i < WLC_MAXMODULES);
4541         return BCME_NORESOURCE;
4542 }
4543
4544 /* unregister module callbacks */
4545 int wlc_module_unregister(wlc_pub_t *pub, const char *name, void *hdl)
4546 {
4547         wlc_info_t *wlc = (wlc_info_t *) pub->wlc;
4548         int i;
4549
4550         if (wlc == NULL)
4551                 return BCME_NOTFOUND;
4552
4553         ASSERT(name != NULL);
4554
4555         for (i = 0; i < WLC_MAXMODULES; i++) {
4556                 if (!strcmp(wlc->modulecb[i].name, name) &&
4557                     (wlc->modulecb[i].hdl == hdl)) {
4558                         bzero(&wlc->modulecb[i], sizeof(modulecb_t));
4559                         return 0;
4560                 }
4561         }
4562
4563         /* table not found! */
4564         return BCME_NOTFOUND;
4565 }
4566
4567 /* Write WME tunable parameters for retransmit/max rate from wlc struct to ucode */
4568 static void wlc_wme_retries_write(wlc_info_t *wlc)
4569 {
4570         int ac;
4571
4572         /* Need clock to do this */
4573         if (!wlc->clk)
4574                 return;
4575
4576         for (ac = 0; ac < AC_COUNT; ac++) {
4577                 wlc_write_shm(wlc, M_AC_TXLMT_ADDR(ac), wlc->wme_retries[ac]);
4578         }
4579 }
4580
4581 /* Get or set an iovar.  The params/p_len pair specifies any additional
4582  * qualifying parameters (e.g. an "element index") for a get, while the
4583  * arg/len pair is the buffer for the value to be set or retrieved.
4584  * Operation (get/set) is specified by the last argument.
4585  * interface context provided by wlcif
4586  *
4587  * All pointers may point into the same buffer.
4588  */
4589 int
4590 wlc_iovar_op(wlc_info_t *wlc, const char *name,
4591              void *params, int p_len, void *arg, int len,
4592              bool set, struct wlc_if *wlcif)
4593 {
4594         int err = 0;
4595         int val_size;
4596         const bcm_iovar_t *vi = NULL;
4597         u32 actionid;
4598         int i;
4599
4600         ASSERT(name != NULL);
4601
4602         ASSERT(len >= 0);
4603
4604         /* Get MUST have return space */
4605         ASSERT(set || (arg && len));
4606
4607         ASSERT(!(wlc->pub->hw_off && wlc->pub->up));
4608
4609         /* Set does NOT take qualifiers */
4610         ASSERT(!set || (!params && !p_len));
4611
4612         if (!set && (len == sizeof(int)) &&
4613             !(IS_ALIGNED((uintptr) (arg), (uint) sizeof(int)))) {
4614                 WL_ERROR(("wl%d: %s unaligned get ptr for %s\n",
4615                           wlc->pub->unit, __func__, name));
4616                 ASSERT(0);
4617         }
4618
4619         /* find the given iovar name */
4620         for (i = 0; i < WLC_MAXMODULES; i++) {
4621                 if (!wlc->modulecb[i].iovars)
4622                         continue;
4623                 vi = wlc_iovar_lookup(wlc->modulecb[i].iovars, name);
4624                 if (vi)
4625                         break;
4626         }
4627         /* iovar name not found */
4628         if (i >= WLC_MAXMODULES) {
4629                 err = BCME_UNSUPPORTED;
4630 #ifdef WLC_HIGH_ONLY
4631                 err =
4632                     bcmsdh_iovar_op(wlc->btparam, name, params, p_len, arg, len,
4633                                     set);
4634 #endif
4635                 goto exit;
4636         }
4637
4638         /* set up 'params' pointer in case this is a set command so that
4639          * the convenience int and bool code can be common to set and get
4640          */
4641         if (params == NULL) {
4642                 params = arg;
4643                 p_len = len;
4644         }
4645
4646         if (vi->type == IOVT_VOID)
4647                 val_size = 0;
4648         else if (vi->type == IOVT_BUFFER)
4649                 val_size = len;
4650         else
4651                 /* all other types are integer sized */
4652                 val_size = sizeof(int);
4653
4654         actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4655
4656         /* Do the actual parameter implementation */
4657         err = wlc->modulecb[i].iovar_fn(wlc->modulecb[i].hdl, vi, actionid,
4658                                         name, params, p_len, arg, len, val_size,
4659                                         wlcif);
4660
4661  exit:
4662         return err;
4663 }
4664
4665 int
4666 wlc_iovar_check(wlc_pub_t *pub, const bcm_iovar_t *vi, void *arg, int len,
4667                 bool set)
4668 {
4669         wlc_info_t *wlc = (wlc_info_t *) pub->wlc;
4670         int err = 0;
4671         s32 int_val = 0;
4672
4673         /* check generic condition flags */
4674         if (set) {
4675                 if (((vi->flags & IOVF_SET_DOWN) && wlc->pub->up) ||
4676                     ((vi->flags & IOVF_SET_UP) && !wlc->pub->up)) {
4677                         err = (wlc->pub->up ? BCME_NOTDOWN : BCME_NOTUP);
4678                 } else if ((vi->flags & IOVF_SET_BAND)
4679                            && IS_MBAND_UNLOCKED(wlc)) {
4680                         err = BCME_NOTBANDLOCKED;
4681                 } else if ((vi->flags & IOVF_SET_CLK) && !wlc->clk) {
4682                         err = BCME_NOCLK;
4683                 }
4684         } else {
4685                 if (((vi->flags & IOVF_GET_DOWN) && wlc->pub->up) ||
4686                     ((vi->flags & IOVF_GET_UP) && !wlc->pub->up)) {
4687                         err = (wlc->pub->up ? BCME_NOTDOWN : BCME_NOTUP);
4688                 } else if ((vi->flags & IOVF_GET_BAND)
4689                            && IS_MBAND_UNLOCKED(wlc)) {
4690                         err = BCME_NOTBANDLOCKED;
4691                 } else if ((vi->flags & IOVF_GET_CLK) && !wlc->clk) {
4692                         err = BCME_NOCLK;
4693                 }
4694         }
4695
4696         if (err)
4697                 goto exit;
4698
4699         /* length check on io buf */
4700         err = bcm_iovar_lencheck(vi, arg, len, set);
4701         if (err)
4702                 goto exit;
4703
4704         /* On set, check value ranges for integer types */
4705         if (set) {
4706                 switch (vi->type) {
4707                 case IOVT_BOOL:
4708                 case IOVT_INT8:
4709                 case IOVT_INT16:
4710                 case IOVT_INT32:
4711                 case IOVT_UINT8:
4712                 case IOVT_UINT16:
4713                 case IOVT_UINT32:
4714                         bcopy(arg, &int_val, sizeof(int));
4715                         err = wlc_iovar_rangecheck(wlc, int_val, vi);
4716                         break;
4717                 }
4718         }
4719  exit:
4720         return err;
4721 }
4722
4723 /* handler for iovar table wlc_iovars */
4724 /*
4725  * IMPLEMENTATION NOTE: In order to avoid checking for get/set in each
4726  * iovar case, the switch statement maps the iovar id into separate get
4727  * and set values.  If you add a new iovar to the switch you MUST use
4728  * IOV_GVAL and/or IOV_SVAL in the case labels to avoid conflict with
4729  * another case.
4730  * Please use params for additional qualifying parameters.
4731  */
4732 int
4733 wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid,
4734             const char *name, void *params, uint p_len, void *arg, int len,
4735             int val_size, struct wlc_if *wlcif)
4736 {
4737         wlc_info_t *wlc = hdl;
4738         wlc_bsscfg_t *bsscfg;
4739         int err = 0;
4740         s32 int_val = 0;
4741         s32 int_val2 = 0;
4742         s32 *ret_int_ptr;
4743         bool bool_val;
4744         bool bool_val2;
4745         wlc_bss_info_t *current_bss;
4746
4747         WL_TRACE(("wl%d: %s\n", wlc->pub->unit, __func__));
4748
4749         bsscfg = NULL;
4750         current_bss = NULL;
4751
4752         err = wlc_iovar_check(wlc->pub, vi, arg, len, IOV_ISSET(actionid));
4753         if (err != 0)
4754                 return err;
4755
4756         /* convenience int and bool vals for first 8 bytes of buffer */
4757         if (p_len >= (int)sizeof(int_val))
4758                 bcopy(params, &int_val, sizeof(int_val));
4759
4760         if (p_len >= (int)sizeof(int_val) * 2)
4761                 bcopy((void *)((uintptr) params + sizeof(int_val)), &int_val2,
4762                       sizeof(int_val));
4763
4764         /* convenience int ptr for 4-byte gets (requires int aligned arg) */
4765         ret_int_ptr = (s32 *) arg;
4766
4767         bool_val = (int_val != 0) ? TRUE : FALSE;
4768         bool_val2 = (int_val2 != 0) ? TRUE : FALSE;
4769
4770         WL_TRACE(("wl%d: %s: id %d\n", wlc->pub->unit, __func__,
4771                   IOV_ID(actionid)));
4772         /* Do the actual parameter implementation */
4773         switch (actionid) {
4774
4775         case IOV_GVAL(IOV_QTXPOWER):{
4776                         uint qdbm;
4777                         bool override;
4778
4779                         err = wlc_phy_txpower_get(wlc->band->pi, &qdbm,
4780                                 &override);
4781                         if (err != BCME_OK)
4782                                 return err;
4783
4784                         /* Return qdbm units */
4785                         *ret_int_ptr =
4786                             qdbm | (override ? WL_TXPWR_OVERRIDE : 0);
4787                         break;
4788                 }
4789
4790                 /* As long as override is false, this only sets the *user* targets.
4791                    User can twiddle this all he wants with no harm.
4792                    wlc_phy_txpower_set() explicitly sets override to false if
4793                    not internal or test.
4794                  */
4795         case IOV_SVAL(IOV_QTXPOWER):{
4796                         u8 qdbm;
4797                         bool override;
4798
4799                         /* Remove override bit and clip to max qdbm value */
4800                         qdbm = (u8)min_t(u32, (int_val & ~WL_TXPWR_OVERRIDE), 0xff);
4801                         /* Extract override setting */
4802                         override = (int_val & WL_TXPWR_OVERRIDE) ? TRUE : FALSE;
4803                         err =
4804                             wlc_phy_txpower_set(wlc->band->pi, qdbm, override);
4805                         break;
4806                 }
4807
4808         case IOV_GVAL(IOV_MPC):
4809                 *ret_int_ptr = (s32) wlc->mpc;
4810                 break;
4811
4812         case IOV_SVAL(IOV_MPC):
4813                 wlc->mpc = bool_val;
4814                 wlc_radio_mpc_upd(wlc);
4815
4816                 break;
4817
4818         case IOV_GVAL(IOV_BCN_LI_BCN):
4819                 *ret_int_ptr = wlc->bcn_li_bcn;
4820                 break;
4821
4822         case IOV_SVAL(IOV_BCN_LI_BCN):
4823                 wlc->bcn_li_bcn = (u8) int_val;
4824                 if (wlc->pub->up)
4825                         wlc_bcn_li_upd(wlc);
4826                 break;
4827
4828         default:
4829                 WL_ERROR(("wl%d: %s: unsupported\n", wlc->pub->unit, __func__));
4830                 err = BCME_UNSUPPORTED;
4831                 break;
4832         }
4833
4834         goto exit;              /* avoid unused label warning */
4835
4836  exit:
4837         return err;
4838 }
4839
4840 static int
4841 wlc_iovar_rangecheck(wlc_info_t *wlc, u32 val, const bcm_iovar_t *vi)
4842 {
4843         int err = 0;
4844         u32 min_val = 0;
4845         u32 max_val = 0;
4846
4847         /* Only ranged integers are checked */
4848         switch (vi->type) {
4849         case IOVT_INT32:
4850                 max_val |= 0x7fffffff;
4851                 /* fall through */
4852         case IOVT_INT16:
4853                 max_val |= 0x00007fff;
4854                 /* fall through */
4855         case IOVT_INT8:
4856                 max_val |= 0x0000007f;
4857                 min_val = ~max_val;
4858                 if (vi->flags & IOVF_NTRL)
4859                         min_val = 1;
4860                 else if (vi->flags & IOVF_WHL)
4861                         min_val = 0;
4862                 /* Signed values are checked against max_val and min_val */
4863                 if ((s32) val < (s32) min_val
4864                     || (s32) val > (s32) max_val)
4865                         err = BCME_RANGE;
4866                 break;
4867
4868         case IOVT_UINT32:
4869                 max_val |= 0xffffffff;
4870                 /* fall through */
4871         case IOVT_UINT16:
4872                 max_val |= 0x0000ffff;
4873                 /* fall through */
4874         case IOVT_UINT8:
4875                 max_val |= 0x000000ff;
4876                 if (vi->flags & IOVF_NTRL)
4877                         min_val = 1;
4878                 if ((val < min_val) || (val > max_val))
4879                         err = BCME_RANGE;
4880                 break;
4881         }
4882
4883         return err;
4884 }
4885
4886 #ifdef BCMDBG
4887 static const char *supr_reason[] = {
4888         "None", "PMQ Entry", "Flush request",
4889         "Previous frag failure", "Channel mismatch",
4890         "Lifetime Expiry", "Underflow"
4891 };
4892
4893 static void wlc_print_txs_status(u16 s)
4894 {
4895         printf("[15:12]  %d  frame attempts\n", (s & TX_STATUS_FRM_RTX_MASK) >>
4896                TX_STATUS_FRM_RTX_SHIFT);
4897         printf(" [11:8]  %d  rts attempts\n", (s & TX_STATUS_RTS_RTX_MASK) >>
4898                TX_STATUS_RTS_RTX_SHIFT);
4899         printf("    [7]  %d  PM mode indicated\n",
4900                ((s & TX_STATUS_PMINDCTD) ? 1 : 0));
4901         printf("    [6]  %d  intermediate status\n",
4902                ((s & TX_STATUS_INTERMEDIATE) ? 1 : 0));
4903         printf("    [5]  %d  AMPDU\n", (s & TX_STATUS_AMPDU) ? 1 : 0);
4904         printf("  [4:2]  %d  Frame Suppressed Reason (%s)\n",
4905                ((s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT),
4906                supr_reason[(s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT]);
4907         printf("    [1]  %d  acked\n", ((s & TX_STATUS_ACK_RCV) ? 1 : 0));
4908 }
4909 #endif                          /* BCMDBG */
4910
4911 void wlc_print_txstatus(tx_status_t *txs)
4912 {
4913 #if defined(BCMDBG)
4914         u16 s = txs->status;
4915         u16 ackphyrxsh = txs->ackphyrxsh;
4916
4917         printf("\ntxpkt (MPDU) Complete\n");
4918
4919         printf("FrameID: %04x   ", txs->frameid);
4920         printf("TxStatus: %04x", s);
4921         printf("\n");
4922 #ifdef BCMDBG
4923         wlc_print_txs_status(s);
4924 #endif
4925         printf("LastTxTime: %04x ", txs->lasttxtime);
4926         printf("Seq: %04x ", txs->sequence);
4927         printf("PHYTxStatus: %04x ", txs->phyerr);
4928         printf("RxAckRSSI: %04x ",
4929                (ackphyrxsh & PRXS1_JSSI_MASK) >> PRXS1_JSSI_SHIFT);
4930         printf("RxAckSQ: %04x", (ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT);
4931         printf("\n");
4932 #endif                          /* defined(BCMDBG) */
4933 }
4934
4935 #define MACSTATUPD(name) \
4936         wlc_ctrupd_cache(macstats.name, &wlc->core->macstat_snapshot->name, &wlc->pub->_cnt->name)
4937
4938 void wlc_statsupd(wlc_info_t *wlc)
4939 {
4940         int i;
4941 #ifdef BCMDBG
4942         u16 delta;
4943         u16 rxf0ovfl;
4944         u16 txfunfl[NFIFO];
4945 #endif                          /* BCMDBG */
4946
4947         /* if driver down, make no sense to update stats */
4948         if (!wlc->pub->up)
4949                 return;
4950
4951 #ifdef BCMDBG
4952         /* save last rx fifo 0 overflow count */
4953         rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl;
4954
4955         /* save last tx fifo  underflow count */
4956         for (i = 0; i < NFIFO; i++)
4957                 txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i];
4958 #endif                          /* BCMDBG */
4959
4960 #ifdef BCMDBG
4961         /* check for rx fifo 0 overflow */
4962         delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
4963         if (delta)
4964                 WL_ERROR(("wl%d: %u rx fifo 0 overflows!\n", wlc->pub->unit,
4965                           delta));
4966
4967         /* check for tx fifo underflows */
4968         for (i = 0; i < NFIFO; i++) {
4969                 delta =
4970                     (u16) (wlc->core->macstat_snapshot->txfunfl[i] -
4971                               txfunfl[i]);
4972                 if (delta)
4973                         WL_ERROR(("wl%d: %u tx fifo %d underflows!\n",
4974                                   wlc->pub->unit, delta, i));
4975         }
4976 #endif                          /* BCMDBG */
4977
4978         /* dot11 counter update */
4979
4980         WLCNTSET(wlc->pub->_cnt->txrts,
4981                  (wlc->pub->_cnt->rxctsucast -
4982                   wlc->pub->_cnt->d11cnt_txrts_off));
4983         WLCNTSET(wlc->pub->_cnt->rxcrc,
4984                  (wlc->pub->_cnt->rxbadfcs - wlc->pub->_cnt->d11cnt_rxcrc_off));
4985         WLCNTSET(wlc->pub->_cnt->txnocts,
4986                  ((wlc->pub->_cnt->txrtsfrm - wlc->pub->_cnt->rxctsucast) -
4987                   wlc->pub->_cnt->d11cnt_txnocts_off));
4988
4989         /* merge counters from dma module */
4990         for (i = 0; i < NFIFO; i++) {
4991                 if (wlc->hw->di[i]) {
4992                         WLCNTADD(wlc->pub->_cnt->txnobuf,
4993                                  (wlc->hw->di[i])->txnobuf);
4994                         WLCNTADD(wlc->pub->_cnt->rxnobuf,
4995                                  (wlc->hw->di[i])->rxnobuf);
4996                         WLCNTADD(wlc->pub->_cnt->rxgiant,
4997                                  (wlc->hw->di[i])->rxgiants);
4998                         dma_counterreset(wlc->hw->di[i]);
4999                 }
5000         }
5001
5002         /*
5003          * Aggregate transmit and receive errors that probably resulted
5004          * in the loss of a frame are computed on the fly.
5005          */
5006         WLCNTSET(wlc->pub->_cnt->txerror,
5007                  wlc->pub->_cnt->txnobuf + wlc->pub->_cnt->txnoassoc +
5008                  wlc->pub->_cnt->txuflo + wlc->pub->_cnt->txrunt +
5009                  wlc->pub->_cnt->dmade + wlc->pub->_cnt->dmada +
5010                  wlc->pub->_cnt->dmape);
5011         WLCNTSET(wlc->pub->_cnt->rxerror,
5012                  wlc->pub->_cnt->rxoflo + wlc->pub->_cnt->rxnobuf +
5013                  wlc->pub->_cnt->rxfragerr + wlc->pub->_cnt->rxrunt +
5014                  wlc->pub->_cnt->rxgiant + wlc->pub->_cnt->rxnoscb +
5015                  wlc->pub->_cnt->rxbadsrcmac);
5016         for (i = 0; i < NFIFO; i++)
5017                 WLCNTADD(wlc->pub->_cnt->rxerror, wlc->pub->_cnt->rxuflo[i]);
5018 }
5019
5020 bool wlc_chipmatch(u16 vendor, u16 device)
5021 {
5022         if (vendor != VENDOR_BROADCOM) {
5023                 WL_ERROR(("wlc_chipmatch: unknown vendor id %04x\n", vendor));
5024                 return FALSE;
5025         }
5026
5027         if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID))
5028                 return TRUE;
5029
5030         if (device == BCM4313_D11N2G_ID)
5031                 return TRUE;
5032         if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID))
5033                 return TRUE;
5034
5035         WL_ERROR(("wlc_chipmatch: unknown device id %04x\n", device));
5036         return FALSE;
5037 }
5038
5039 #if defined(BCMDBG)
5040 void wlc_print_txdesc(d11txh_t *txh)
5041 {
5042         u16 mtcl = ltoh16(txh->MacTxControlLow);
5043         u16 mtch = ltoh16(txh->MacTxControlHigh);
5044         u16 mfc = ltoh16(txh->MacFrameControl);
5045         u16 tfest = ltoh16(txh->TxFesTimeNormal);
5046         u16 ptcw = ltoh16(txh->PhyTxControlWord);
5047         u16 ptcw_1 = ltoh16(txh->PhyTxControlWord_1);
5048         u16 ptcw_1_Fbr = ltoh16(txh->PhyTxControlWord_1_Fbr);
5049         u16 ptcw_1_Rts = ltoh16(txh->PhyTxControlWord_1_Rts);
5050         u16 ptcw_1_FbrRts = ltoh16(txh->PhyTxControlWord_1_FbrRts);
5051         u16 mainrates = ltoh16(txh->MainRates);
5052         u16 xtraft = ltoh16(txh->XtraFrameTypes);
5053         u8 *iv = txh->IV;
5054         u8 *ra = txh->TxFrameRA;
5055         u16 tfestfb = ltoh16(txh->TxFesTimeFallback);
5056         u8 *rtspfb = txh->RTSPLCPFallback;
5057         u16 rtsdfb = ltoh16(txh->RTSDurFallback);
5058         u8 *fragpfb = txh->FragPLCPFallback;
5059         u16 fragdfb = ltoh16(txh->FragDurFallback);
5060         u16 mmodelen = ltoh16(txh->MModeLen);
5061         u16 mmodefbrlen = ltoh16(txh->MModeFbrLen);
5062         u16 tfid = ltoh16(txh->TxFrameID);
5063         u16 txs = ltoh16(txh->TxStatus);
5064         u16 mnmpdu = ltoh16(txh->MaxNMpdus);
5065         u16 mabyte = ltoh16(txh->MaxABytes_MRT);
5066         u16 mabyte_f = ltoh16(txh->MaxABytes_FBR);
5067         u16 mmbyte = ltoh16(txh->MinMBytes);
5068
5069         u8 *rtsph = txh->RTSPhyHeader;
5070         struct dot11_rts_frame rts = txh->rts_frame;
5071         char hexbuf[256];
5072
5073         /* add plcp header along with txh descriptor */
5074         prhex("Raw TxDesc + plcp header", (unsigned char *) txh, sizeof(d11txh_t) + 48);
5075
5076         printf("TxCtlLow: %04x ", mtcl);
5077         printf("TxCtlHigh: %04x ", mtch);
5078         printf("FC: %04x ", mfc);
5079         printf("FES Time: %04x\n", tfest);
5080         printf("PhyCtl: %04x%s ", ptcw,
5081                (ptcw & PHY_TXC_SHORT_HDR) ? " short" : "");
5082         printf("PhyCtl_1: %04x ", ptcw_1);
5083         printf("PhyCtl_1_Fbr: %04x\n", ptcw_1_Fbr);
5084         printf("PhyCtl_1_Rts: %04x ", ptcw_1_Rts);
5085         printf("PhyCtl_1_Fbr_Rts: %04x\n", ptcw_1_FbrRts);
5086         printf("MainRates: %04x ", mainrates);
5087         printf("XtraFrameTypes: %04x ", xtraft);
5088         printf("\n");
5089
5090         bcm_format_hex(hexbuf, iv, sizeof(txh->IV));
5091         printf("SecIV:       %s\n", hexbuf);
5092         bcm_format_hex(hexbuf, ra, sizeof(txh->TxFrameRA));
5093         printf("RA:          %s\n", hexbuf);
5094
5095         printf("Fb FES Time: %04x ", tfestfb);
5096         bcm_format_hex(hexbuf, rtspfb, sizeof(txh->RTSPLCPFallback));
5097         printf("RTS PLCP: %s ", hexbuf);
5098         printf("RTS DUR: %04x ", rtsdfb);
5099         bcm_format_hex(hexbuf, fragpfb, sizeof(txh->FragPLCPFallback));
5100         printf("PLCP: %s ", hexbuf);
5101         printf("DUR: %04x", fragdfb);
5102         printf("\n");
5103
5104         printf("MModeLen: %04x ", mmodelen);
5105         printf("MModeFbrLen: %04x\n", mmodefbrlen);
5106
5107         printf("FrameID:     %04x\n", tfid);
5108         printf("TxStatus:    %04x\n", txs);
5109
5110         printf("MaxNumMpdu:  %04x\n", mnmpdu);
5111         printf("MaxAggbyte:  %04x\n", mabyte);
5112         printf("MaxAggbyte_fb:  %04x\n", mabyte_f);
5113         printf("MinByte:     %04x\n", mmbyte);
5114
5115         bcm_format_hex(hexbuf, rtsph, sizeof(txh->RTSPhyHeader));
5116         printf("RTS PLCP: %s ", hexbuf);
5117         bcm_format_hex(hexbuf, (u8 *) &rts, sizeof(txh->rts_frame));
5118         printf("RTS Frame: %s", hexbuf);
5119         printf("\n");
5120
5121 }
5122 #endif                          /* defined(BCMDBG) */
5123
5124 #if defined(BCMDBG)
5125 void wlc_print_rxh(d11rxhdr_t *rxh)
5126 {
5127         u16 len = rxh->RxFrameSize;
5128         u16 phystatus_0 = rxh->PhyRxStatus_0;
5129         u16 phystatus_1 = rxh->PhyRxStatus_1;
5130         u16 phystatus_2 = rxh->PhyRxStatus_2;
5131         u16 phystatus_3 = rxh->PhyRxStatus_3;
5132         u16 macstatus1 = rxh->RxStatus1;
5133         u16 macstatus2 = rxh->RxStatus2;
5134         char flagstr[64];
5135         char lenbuf[20];
5136         static const bcm_bit_desc_t macstat_flags[] = {
5137                 {RXS_FCSERR, "FCSErr"},
5138                 {RXS_RESPFRAMETX, "Reply"},
5139                 {RXS_PBPRES, "PADDING"},
5140                 {RXS_DECATMPT, "DeCr"},
5141                 {RXS_DECERR, "DeCrErr"},
5142                 {RXS_BCNSENT, "Bcn"},
5143                 {0, NULL}
5144         };
5145
5146         prhex("Raw RxDesc", (unsigned char *) rxh, sizeof(d11rxhdr_t));
5147
5148         bcm_format_flags(macstat_flags, macstatus1, flagstr, 64);
5149
5150         snprintf(lenbuf, sizeof(lenbuf), "0x%x", len);
5151
5152         printf("RxFrameSize:     %6s (%d)%s\n", lenbuf, len,
5153                (rxh->PhyRxStatus_0 & PRXS0_SHORTH) ? " short preamble" : "");
5154         printf("RxPHYStatus:     %04x %04x %04x %04x\n",
5155                phystatus_0, phystatus_1, phystatus_2, phystatus_3);
5156         printf("RxMACStatus:     %x %s\n", macstatus1, flagstr);
5157         printf("RXMACaggtype: %x\n", (macstatus2 & RXS_AGGTYPE_MASK));
5158         printf("RxTSFTime:       %04x\n", rxh->RxTSFTime);
5159 }
5160 #endif                          /* defined(BCMDBG) */
5161
5162 #if defined(BCMDBG)
5163 int wlc_format_ssid(char *buf, const unsigned char ssid[], uint ssid_len)
5164 {
5165         uint i, c;
5166         char *p = buf;
5167         char *endp = buf + SSID_FMT_BUF_LEN;
5168
5169         if (ssid_len > DOT11_MAX_SSID_LEN)
5170                 ssid_len = DOT11_MAX_SSID_LEN;
5171
5172         for (i = 0; i < ssid_len; i++) {
5173                 c = (uint) ssid[i];
5174                 if (c == '\\') {
5175                         *p++ = '\\';
5176                         *p++ = '\\';
5177                 } else if (isprint((unsigned char) c)) {
5178                         *p++ = (char)c;
5179                 } else {
5180                         p += snprintf(p, (endp - p), "\\x%02X", c);
5181                 }
5182         }
5183         *p = '\0';
5184         ASSERT(p < endp);
5185
5186         return (int)(p - buf);
5187 }
5188 #endif                          /* defined(BCMDBG) */
5189
5190 u16 wlc_rate_shm_offset(wlc_info_t *wlc, u8 rate)
5191 {
5192         return wlc_bmac_rate_shm_offset(wlc->hw, rate);
5193 }
5194
5195 /* Callback for device removed */
5196 #if defined(WLC_HIGH_ONLY)
5197 void wlc_device_removed(void *arg)
5198 {
5199         wlc_info_t *wlc = (wlc_info_t *) arg;
5200
5201         wlc->device_present = FALSE;
5202 }
5203 #endif                          /* WLC_HIGH_ONLY */
5204
5205 /*
5206  * Attempts to queue a packet onto a multiple-precedence queue,
5207  * if necessary evicting a lower precedence packet from the queue.
5208  *
5209  * 'prec' is the precedence number that has already been mapped
5210  * from the packet priority.
5211  *
5212  * Returns TRUE if packet consumed (queued), FALSE if not.
5213  */
5214 bool BCMFASTPATH
5215 wlc_prec_enq(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec)
5216 {
5217         return wlc_prec_enq_head(wlc, q, pkt, prec, FALSE);
5218 }
5219
5220 bool BCMFASTPATH
5221 wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec,
5222                   bool head)
5223 {
5224         void *p;
5225         int eprec = -1;         /* precedence to evict from */
5226
5227         /* Determine precedence from which to evict packet, if any */
5228         if (pktq_pfull(q, prec))
5229                 eprec = prec;
5230         else if (pktq_full(q)) {
5231                 p = pktq_peek_tail(q, &eprec);
5232                 ASSERT(p != NULL);
5233                 if (eprec > prec) {
5234                         WL_ERROR(("%s: Failing: eprec %d > prec %d\n", __func__,
5235                                   eprec, prec));
5236                         return FALSE;
5237                 }
5238         }
5239
5240         /* Evict if needed */
5241         if (eprec >= 0) {
5242                 bool discard_oldest;
5243
5244                 /* Detect queueing to unconfigured precedence */
5245                 ASSERT(!pktq_pempty(q, eprec));
5246
5247                 discard_oldest = AC_BITMAP_TST(wlc->wme_dp, eprec);
5248
5249                 /* Refuse newer packet unless configured to discard oldest */
5250                 if (eprec == prec && !discard_oldest) {
5251                         WL_ERROR(("%s: No where to go, prec == %d\n", __func__,
5252                                   prec));
5253                         return FALSE;
5254                 }
5255
5256                 /* Evict packet according to discard policy */
5257                 p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q,
5258                                                                           eprec);
5259                 ASSERT(p != NULL);
5260
5261                 /* Increment wme stats */
5262                 if (WME_ENAB(wlc->pub)) {
5263                         WLCNTINCR(wlc->pub->_wme_cnt->
5264                                   tx_failed[WME_PRIO2AC(PKTPRIO(p))].packets);
5265                         WLCNTADD(wlc->pub->_wme_cnt->
5266                                  tx_failed[WME_PRIO2AC(PKTPRIO(p))].bytes,
5267                                  pkttotlen(wlc->osh, p));
5268                 }
5269
5270                 ASSERT(0);
5271                 PKTFREE(wlc->osh, p, TRUE);
5272                 WLCNTINCR(wlc->pub->_cnt->txnobuf);
5273         }
5274
5275         /* Enqueue */
5276         if (head)
5277                 p = pktq_penq_head(q, prec, pkt);
5278         else
5279                 p = pktq_penq(q, prec, pkt);
5280         ASSERT(p != NULL);
5281
5282         return TRUE;
5283 }
5284
5285 void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, void *sdu, uint prec)
5286 {
5287         wlc_info_t *wlc = (wlc_info_t *) ctx;
5288         wlc_txq_info_t *qi = wlc->active_queue; /* Check me */
5289         struct pktq *q = &qi->q;
5290         int prio;
5291
5292         prio = PKTPRIO(sdu);
5293
5294         ASSERT(pktq_max(q) >= wlc->pub->tunables->datahiwat);
5295
5296         if (!wlc_prec_enq(wlc, q, sdu, prec)) {
5297                 if (!EDCF_ENAB(wlc->pub)
5298                     || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL))
5299                         WL_ERROR(("wl%d: wlc_txq_enq: txq overflow\n",
5300                                   wlc->pub->unit));
5301
5302                 /* ASSERT(9 == 8); *//* XXX we might hit this condtion in case packet flooding from mac80211 stack */
5303                 PKTFREE(wlc->osh, sdu, TRUE);
5304                 WLCNTINCR(wlc->pub->_cnt->txnobuf);
5305         }
5306
5307         /* Check if flow control needs to be turned on after enqueuing the packet
5308          *   Don't turn on flow control if EDCF is enabled. Driver would make the decision on what
5309          *   to drop instead of relying on stack to make the right decision
5310          */
5311         if (!EDCF_ENAB(wlc->pub)
5312             || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL)) {
5313                 if (pktq_len(q) >= wlc->pub->tunables->datahiwat) {
5314                         wlc_txflowcontrol(wlc, qi, ON, ALLPRIO);
5315                 }
5316         } else if (wlc->pub->_priofc) {
5317                 if (pktq_plen(q, wlc_prio2prec_map[prio]) >=
5318                     wlc->pub->tunables->datahiwat) {
5319                         wlc_txflowcontrol(wlc, qi, ON, prio);
5320                 }
5321         }
5322 }
5323
5324 bool BCMFASTPATH
5325 wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw)
5326 {
5327         u8 prio;
5328         uint fifo;
5329         void *pkt;
5330         struct scb *scb = &global_scb;
5331         struct dot11_header *d11_header = (struct dot11_header *)PKTDATA(sdu);
5332         u16 type, fc;
5333
5334         ASSERT(sdu);
5335
5336         fc = ltoh16(d11_header->fc);
5337         type = FC_TYPE(fc);
5338
5339         /* 802.11 standard requires management traffic to go at highest priority */
5340         prio = (type == FC_TYPE_DATA ? PKTPRIO(sdu) : MAXPRIO);
5341         fifo = prio2fifo[prio];
5342
5343         ASSERT((uint) PKTHEADROOM(sdu) >= TXOFF);
5344         ASSERT(!PKTSHARED(sdu));
5345         ASSERT(!PKTNEXT(sdu));
5346         ASSERT(!PKTLINK(sdu));
5347         ASSERT(fifo < NFIFO);
5348
5349         pkt = sdu;
5350         if (unlikely
5351             (wlc_d11hdrs_mac80211(wlc, hw, pkt, scb, 0, 1, fifo, 0, NULL, 0)))
5352                 return -EINVAL;
5353         wlc_txq_enq(wlc, scb, pkt, WLC_PRIO_TO_PREC(prio));
5354         wlc_send_q(wlc, wlc->active_queue);
5355
5356         WLCNTINCR(wlc->pub->_cnt->ieee_tx);
5357         return 0;
5358 }
5359
5360 void BCMFASTPATH wlc_send_q(wlc_info_t *wlc, wlc_txq_info_t *qi)
5361 {
5362         void *pkt[DOT11_MAXNUMFRAGS];
5363         int prec;
5364         u16 prec_map;
5365         int err = 0, i, count;
5366         uint fifo;
5367         struct pktq *q = &qi->q;
5368         struct ieee80211_tx_info *tx_info;
5369
5370         /* only do work for the active queue */
5371         if (qi != wlc->active_queue)
5372                 return;
5373
5374         if (in_send_q)
5375                 return;
5376         else
5377                 in_send_q = TRUE;
5378
5379         prec_map = wlc->tx_prec_map;
5380
5381         /* Send all the enq'd pkts that we can.
5382          * Dequeue packets with precedence with empty HW fifo only
5383          */
5384         while (prec_map && (pkt[0] = pktq_mdeq(q, prec_map, &prec))) {
5385                 tx_info = IEEE80211_SKB_CB(pkt[0]);
5386                 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
5387                         err = wlc_sendampdu(wlc->ampdu, qi, pkt, prec);
5388                 } else {
5389                         count = 1;
5390                         err = wlc_prep_pdu(wlc, pkt[0], &fifo);
5391                         if (!err) {
5392                                 for (i = 0; i < count; i++) {
5393                                         wlc_txfifo(wlc, fifo, pkt[i], TRUE, 1);
5394                                 }
5395                         }
5396                 }
5397
5398                 if (err == BCME_BUSY) {
5399                         pktq_penq_head(q, prec, pkt[0]);
5400                         /* If send failed due to any other reason than a change in
5401                          * HW FIFO condition, quit. Otherwise, read the new prec_map!
5402                          */
5403                         if (prec_map == wlc->tx_prec_map)
5404                                 break;
5405                         prec_map = wlc->tx_prec_map;
5406                 }
5407         }
5408
5409         /* Check if flow control needs to be turned off after sending the packet */
5410         if (!EDCF_ENAB(wlc->pub)
5411             || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL)) {
5412                 if (wlc_txflowcontrol_prio_isset(wlc, qi, ALLPRIO)
5413                     && (pktq_len(q) < wlc->pub->tunables->datahiwat / 2)) {
5414                         wlc_txflowcontrol(wlc, qi, OFF, ALLPRIO);
5415                 }
5416         } else if (wlc->pub->_priofc) {
5417                 int prio;
5418                 for (prio = MAXPRIO; prio >= 0; prio--) {
5419                         if (wlc_txflowcontrol_prio_isset(wlc, qi, prio) &&
5420                             (pktq_plen(q, wlc_prio2prec_map[prio]) <
5421                              wlc->pub->tunables->datahiwat / 2)) {
5422                                 wlc_txflowcontrol(wlc, qi, OFF, prio);
5423                         }
5424                 }
5425         }
5426         in_send_q = FALSE;
5427 }
5428
5429 /*
5430  * bcmc_fid_generate:
5431  * Generate frame ID for a BCMC packet.  The frag field is not used
5432  * for MC frames so is used as part of the sequence number.
5433  */
5434 static inline u16
5435 bcmc_fid_generate(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg, d11txh_t *txh)
5436 {
5437         u16 frameid;
5438
5439         frameid = ltoh16(txh->TxFrameID) & ~(TXFID_SEQ_MASK | TXFID_QUEUE_MASK);
5440         frameid |=
5441             (((wlc->
5442                mc_fid_counter++) << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
5443             TX_BCMC_FIFO;
5444
5445         return frameid;
5446 }
5447
5448 void BCMFASTPATH
5449 wlc_txfifo(wlc_info_t *wlc, uint fifo, void *p, bool commit, s8 txpktpend)
5450 {
5451         u16 frameid = INVALIDFID;
5452         d11txh_t *txh;
5453
5454         ASSERT(fifo < NFIFO);
5455         txh = (d11txh_t *) PKTDATA(p);
5456
5457         /* When a BC/MC frame is being committed to the BCMC fifo via DMA (NOT PIO), update
5458          * ucode or BSS info as appropriate.
5459          */
5460         if (fifo == TX_BCMC_FIFO) {
5461                 frameid = ltoh16(txh->TxFrameID);
5462
5463         }
5464
5465         if (WLC_WAR16165(wlc))
5466                 wlc_war16165(wlc, TRUE);
5467
5468 #ifdef WLC_HIGH_ONLY
5469         if (RPCTX_ENAB(wlc->pub)) {
5470                 (void)wlc_rpctx_tx(wlc->rpctx, fifo, p, commit, frameid,
5471                                    txpktpend);
5472                 return;
5473         }
5474 #else
5475
5476         /* Bump up pending count for if not using rpc. If rpc is used, this will be handled
5477          * in wlc_bmac_txfifo()
5478          */
5479         if (commit) {
5480                 TXPKTPENDINC(wlc, fifo, txpktpend);
5481                 WL_TRACE(("wlc_txfifo, pktpend inc %d to %d\n", txpktpend,
5482                           TXPKTPENDGET(wlc, fifo)));
5483         }
5484
5485         /* Commit BCMC sequence number in the SHM frame ID location */
5486         if (frameid != INVALIDFID)
5487                 BCMCFID(wlc, frameid);
5488
5489         if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0) {
5490                 WL_ERROR(("wlc_txfifo: fatal, toss frames !!!\n"));
5491         }
5492 #endif                          /* WLC_HIGH_ONLY */
5493 }
5494
5495 static u16
5496 wlc_compute_airtime(wlc_info_t *wlc, ratespec_t rspec, uint length)
5497 {
5498         u16 usec = 0;
5499         uint mac_rate = RSPEC2RATE(rspec);
5500         uint nsyms;
5501
5502         if (IS_MCS(rspec)) {
5503                 /* not supported yet */
5504                 ASSERT(0);
5505         } else if (IS_OFDM(rspec)) {
5506                 /* nsyms = Ceiling(Nbits / (Nbits/sym))
5507                  *
5508                  * Nbits = length * 8
5509                  * Nbits/sym = Mbps * 4 = mac_rate * 2
5510                  */
5511                 nsyms = CEIL((length * 8), (mac_rate * 2));
5512
5513                 /* usec = symbols * usec/symbol */
5514                 usec = (u16) (nsyms * APHY_SYMBOL_TIME);
5515                 return usec;
5516         } else {
5517                 switch (mac_rate) {
5518                 case WLC_RATE_1M:
5519                         usec = length << 3;
5520                         break;
5521                 case WLC_RATE_2M:
5522                         usec = length << 2;
5523                         break;
5524                 case WLC_RATE_5M5:
5525                         usec = (length << 4) / 11;
5526                         break;
5527                 case WLC_RATE_11M:
5528                         usec = (length << 3) / 11;
5529                         break;
5530                 default:
5531                         WL_ERROR(("wl%d: wlc_compute_airtime: unsupported rspec 0x%x\n", wlc->pub->unit, rspec));
5532                         ASSERT((const char *)"Bad phy_rate" == NULL);
5533                         break;
5534                 }
5535         }
5536
5537         return usec;
5538 }
5539
5540 void BCMFASTPATH
5541 wlc_compute_plcp(wlc_info_t *wlc, ratespec_t rspec, uint length, u8 *plcp)
5542 {
5543         if (IS_MCS(rspec)) {
5544                 wlc_compute_mimo_plcp(rspec, length, plcp);
5545         } else if (IS_OFDM(rspec)) {
5546                 wlc_compute_ofdm_plcp(rspec, length, plcp);
5547         } else {
5548                 wlc_compute_cck_plcp(rspec, length, plcp);
5549         }
5550         return;
5551 }
5552
5553 /* Rate: 802.11 rate code, length: PSDU length in octets */
5554 static void wlc_compute_mimo_plcp(ratespec_t rspec, uint length, u8 *plcp)
5555 {
5556         u8 mcs = (u8) (rspec & RSPEC_RATE_MASK);
5557         ASSERT(IS_MCS(rspec));
5558         plcp[0] = mcs;
5559         if (RSPEC_IS40MHZ(rspec) || (mcs == 32))
5560                 plcp[0] |= MIMO_PLCP_40MHZ;
5561         WLC_SET_MIMO_PLCP_LEN(plcp, length);
5562         plcp[3] = RSPEC_MIMOPLCP3(rspec);       /* rspec already holds this byte */
5563         plcp[3] |= 0x7;         /* set smoothing, not sounding ppdu & reserved */
5564         plcp[4] = 0;            /* number of extension spatial streams bit 0 & 1 */
5565         plcp[5] = 0;
5566 }
5567
5568 /* Rate: 802.11 rate code, length: PSDU length in octets */
5569 static void BCMFASTPATH
5570 wlc_compute_ofdm_plcp(ratespec_t rspec, u32 length, u8 *plcp)
5571 {
5572         u8 rate_signal;
5573         u32 tmp = 0;
5574         int rate = RSPEC2RATE(rspec);
5575
5576         ASSERT(IS_OFDM(rspec));
5577
5578         /* encode rate per 802.11a-1999 sec 17.3.4.1, with lsb transmitted first */
5579         rate_signal = rate_info[rate] & RATE_MASK;
5580         ASSERT(rate_signal != 0);
5581
5582         bzero(plcp, D11_PHY_HDR_LEN);
5583         D11A_PHY_HDR_SRATE((ofdm_phy_hdr_t *) plcp, rate_signal);
5584
5585         tmp = (length & 0xfff) << 5;
5586         plcp[2] |= (tmp >> 16) & 0xff;
5587         plcp[1] |= (tmp >> 8) & 0xff;
5588         plcp[0] |= tmp & 0xff;
5589
5590         return;
5591 }
5592
5593 /*
5594  * Compute PLCP, but only requires actual rate and length of pkt.
5595  * Rate is given in the driver standard multiple of 500 kbps.
5596  * le is set for 11 Mbps rate if necessary.
5597  * Broken out for PRQ.
5598  */
5599
5600 static void wlc_cck_plcp_set(int rate_500, uint length, u8 *plcp)
5601 {
5602         u16 usec = 0;
5603         u8 le = 0;
5604
5605         switch (rate_500) {
5606         case WLC_RATE_1M:
5607                 usec = length << 3;
5608                 break;
5609         case WLC_RATE_2M:
5610                 usec = length << 2;
5611                 break;
5612         case WLC_RATE_5M5:
5613                 usec = (length << 4) / 11;
5614                 if ((length << 4) - (usec * 11) > 0)
5615                         usec++;
5616                 break;
5617         case WLC_RATE_11M:
5618                 usec = (length << 3) / 11;
5619                 if ((length << 3) - (usec * 11) > 0) {
5620                         usec++;
5621                         if ((usec * 11) - (length << 3) >= 8)
5622                                 le = D11B_PLCP_SIGNAL_LE;
5623                 }
5624                 break;
5625
5626         default:
5627                 WL_ERROR(("wlc_cck_plcp_set: unsupported rate %d\n", rate_500));
5628                 rate_500 = WLC_RATE_1M;
5629                 usec = length << 3;
5630                 break;
5631         }
5632         /* PLCP signal byte */
5633         plcp[0] = rate_500 * 5; /* r (500kbps) * 5 == r (100kbps) */
5634         /* PLCP service byte */
5635         plcp[1] = (u8) (le | D11B_PLCP_SIGNAL_LOCKED);
5636         /* PLCP length u16, little endian */
5637         plcp[2] = usec & 0xff;
5638         plcp[3] = (usec >> 8) & 0xff;
5639         /* PLCP CRC16 */
5640         plcp[4] = 0;
5641         plcp[5] = 0;
5642 }
5643
5644 /* Rate: 802.11 rate code, length: PSDU length in octets */
5645 static void wlc_compute_cck_plcp(ratespec_t rspec, uint length, u8 *plcp)
5646 {
5647         int rate = RSPEC2RATE(rspec);
5648
5649         ASSERT(IS_CCK(rspec));
5650
5651         wlc_cck_plcp_set(rate, length, plcp);
5652 }
5653
5654 /* wlc_compute_frame_dur()
5655  *
5656  * Calculate the 802.11 MAC header DUR field for MPDU
5657  * DUR for a single frame = 1 SIFS + 1 ACK
5658  * DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time
5659  *
5660  * rate                 MPDU rate in unit of 500kbps
5661  * next_frag_len        next MPDU length in bytes
5662  * preamble_type        use short/GF or long/MM PLCP header
5663  */
5664 static u16 BCMFASTPATH
5665 wlc_compute_frame_dur(wlc_info_t *wlc, ratespec_t rate, u8 preamble_type,
5666                       uint next_frag_len)
5667 {
5668         u16 dur, sifs;
5669
5670         sifs = SIFS(wlc->band);
5671
5672         dur = sifs;
5673         dur += (u16) wlc_calc_ack_time(wlc, rate, preamble_type);
5674
5675         if (next_frag_len) {
5676                 /* Double the current DUR to get 2 SIFS + 2 ACKs */
5677                 dur *= 2;
5678                 /* add another SIFS and the frag time */
5679                 dur += sifs;
5680                 dur +=
5681                     (u16) wlc_calc_frame_time(wlc, rate, preamble_type,
5682                                                  next_frag_len);
5683         }
5684         return dur;
5685 }
5686
5687 /* wlc_compute_rtscts_dur()
5688  *
5689  * Calculate the 802.11 MAC header DUR field for an RTS or CTS frame
5690  * DUR for normal RTS/CTS w/ frame = 3 SIFS + 1 CTS + next frame time + 1 ACK
5691  * DUR for CTS-TO-SELF w/ frame    = 2 SIFS         + next frame time + 1 ACK
5692  *
5693  * cts                  cts-to-self or rts/cts
5694  * rts_rate             rts or cts rate in unit of 500kbps
5695  * rate                 next MPDU rate in unit of 500kbps
5696  * frame_len            next MPDU frame length in bytes
5697  */
5698 u16 BCMFASTPATH
5699 wlc_compute_rtscts_dur(wlc_info_t *wlc, bool cts_only, ratespec_t rts_rate,
5700                        ratespec_t frame_rate, u8 rts_preamble_type,
5701                        u8 frame_preamble_type, uint frame_len, bool ba)
5702 {
5703         u16 dur, sifs;
5704
5705         sifs = SIFS(wlc->band);
5706
5707         if (!cts_only) {        /* RTS/CTS */
5708                 dur = 3 * sifs;
5709                 dur +=
5710                     (u16) wlc_calc_cts_time(wlc, rts_rate,
5711                                                rts_preamble_type);
5712         } else {                /* CTS-TO-SELF */
5713                 dur = 2 * sifs;
5714         }
5715
5716         dur +=
5717             (u16) wlc_calc_frame_time(wlc, frame_rate, frame_preamble_type,
5718                                          frame_len);
5719         if (ba)
5720                 dur +=
5721                     (u16) wlc_calc_ba_time(wlc, frame_rate,
5722                                               WLC_SHORT_PREAMBLE);
5723         else
5724                 dur +=
5725                     (u16) wlc_calc_ack_time(wlc, frame_rate,
5726                                                frame_preamble_type);
5727         return dur;
5728 }
5729
5730 static bool wlc_phy_rspec_check(wlc_info_t *wlc, u16 bw, ratespec_t rspec)
5731 {
5732         if (IS_MCS(rspec)) {
5733                 uint mcs = rspec & RSPEC_RATE_MASK;
5734
5735                 if (mcs < 8) {
5736                         ASSERT(RSPEC_STF(rspec) < PHY_TXC1_MODE_SDM);
5737                 } else if ((mcs >= 8) && (mcs <= 23)) {
5738                         ASSERT(RSPEC_STF(rspec) == PHY_TXC1_MODE_SDM);
5739                 } else if (mcs == 32) {
5740                         ASSERT(RSPEC_STF(rspec) < PHY_TXC1_MODE_SDM);
5741                         ASSERT(bw == PHY_TXC1_BW_40MHZ_DUP);
5742                 }
5743         } else if (IS_OFDM(rspec)) {
5744                 ASSERT(RSPEC_STF(rspec) < PHY_TXC1_MODE_STBC);
5745         } else {
5746                 ASSERT(IS_CCK(rspec));
5747
5748                 ASSERT((bw == PHY_TXC1_BW_20MHZ)
5749                        || (bw == PHY_TXC1_BW_20MHZ_UP));
5750                 ASSERT(RSPEC_STF(rspec) == PHY_TXC1_MODE_SISO);
5751         }
5752
5753         return TRUE;
5754 }
5755
5756 u16 BCMFASTPATH wlc_phytxctl1_calc(wlc_info_t *wlc, ratespec_t rspec)
5757 {
5758         u16 phyctl1 = 0;
5759         u16 bw;
5760
5761         if (WLCISLCNPHY(wlc->band)) {
5762                 bw = PHY_TXC1_BW_20MHZ;
5763         } else {
5764                 bw = RSPEC_GET_BW(rspec);
5765                 /* 10Mhz is not supported yet */
5766                 if (bw < PHY_TXC1_BW_20MHZ) {
5767                         WL_ERROR(("wlc_phytxctl1_calc: bw %d is not supported yet, set to 20L\n", bw));
5768                         bw = PHY_TXC1_BW_20MHZ;
5769                 }
5770
5771                 wlc_phy_rspec_check(wlc, bw, rspec);
5772         }
5773
5774         if (IS_MCS(rspec)) {
5775                 uint mcs = rspec & RSPEC_RATE_MASK;
5776
5777                 /* bw, stf, coding-type is part of RSPEC_PHYTXBYTE2 returns */
5778                 phyctl1 = RSPEC_PHYTXBYTE2(rspec);
5779                 /* set the upper byte of phyctl1 */
5780                 phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8);
5781         } else if (IS_CCK(rspec) && !WLCISLCNPHY(wlc->band)
5782                    && !WLCISSSLPNPHY(wlc->band)) {
5783                 /* In CCK mode LPPHY overloads OFDM Modulation bits with CCK Data Rate */
5784                 /* Eventually MIMOPHY would also be converted to this format */
5785                 /* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */
5786                 phyctl1 = (bw | (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT));
5787         } else {                /* legacy OFDM/CCK */
5788                 s16 phycfg;
5789                 /* get the phyctl byte from rate phycfg table */
5790                 phycfg = wlc_rate_legacy_phyctl(RSPEC2RATE(rspec));
5791                 if (phycfg == -1) {
5792                         WL_ERROR(("wlc_phytxctl1_calc: wrong legacy OFDM/CCK rate\n"));
5793                         ASSERT(0);
5794                         phycfg = 0;
5795                 }
5796                 /* set the upper byte of phyctl1 */
5797                 phyctl1 =
5798                     (bw | (phycfg << 8) |
5799                      (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT));
5800         }
5801
5802 #ifdef BCMDBG
5803         /* phy clock must support 40Mhz if tx descriptor uses it */
5804         if ((phyctl1 & PHY_TXC1_BW_MASK) >= PHY_TXC1_BW_40MHZ) {
5805                 ASSERT(CHSPEC_WLC_BW(wlc->chanspec) == WLC_40_MHZ);
5806 #ifndef WLC_HIGH_ONLY
5807                 ASSERT(wlc->chanspec == wlc_phy_chanspec_get(wlc->band->pi));
5808 #endif
5809         }
5810 #endif                          /* BCMDBG */
5811         return phyctl1;
5812 }
5813
5814 ratespec_t BCMFASTPATH
5815 wlc_rspec_to_rts_rspec(wlc_info_t *wlc, ratespec_t rspec, bool use_rspec,
5816                        u16 mimo_ctlchbw)
5817 {
5818         ratespec_t rts_rspec = 0;
5819
5820         if (use_rspec) {
5821                 /* use frame rate as rts rate */
5822                 rts_rspec = rspec;
5823
5824         } else if (wlc->band->gmode && wlc->protection->_g && !IS_CCK(rspec)) {
5825                 /* Use 11Mbps as the g protection RTS target rate and fallback.
5826                  * Use the WLC_BASIC_RATE() lookup to find the best basic rate under the
5827                  * target in case 11 Mbps is not Basic.
5828                  * 6 and 9 Mbps are not usually selected by rate selection, but even
5829                  * if the OFDM rate we are protecting is 6 or 9 Mbps, 11 is more robust.
5830                  */
5831                 rts_rspec = WLC_BASIC_RATE(wlc, WLC_RATE_11M);
5832         } else {
5833                 /* calculate RTS rate and fallback rate based on the frame rate
5834                  * RTS must be sent at a basic rate since it is a
5835                  * control frame, sec 9.6 of 802.11 spec
5836                  */
5837                 rts_rspec = WLC_BASIC_RATE(wlc, rspec);
5838         }
5839
5840         if (WLC_PHY_11N_CAP(wlc->band)) {
5841                 /* set rts txbw to correct side band */
5842                 rts_rspec &= ~RSPEC_BW_MASK;
5843
5844                 /* if rspec/rspec_fallback is 40MHz, then send RTS on both 20MHz channel
5845                  * (DUP), otherwise send RTS on control channel
5846                  */
5847                 if (RSPEC_IS40MHZ(rspec) && !IS_CCK(rts_rspec))
5848                         rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT);
5849                 else
5850                         rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
5851
5852                 /* pick siso/cdd as default for ofdm */
5853                 if (IS_OFDM(rts_rspec)) {
5854                         rts_rspec &= ~RSPEC_STF_MASK;
5855                         rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
5856                 }
5857         }
5858         return rts_rspec;
5859 }
5860
5861 /*
5862  * Add d11txh_t, cck_phy_hdr_t.
5863  *
5864  * 'p' data must start with 802.11 MAC header
5865  * 'p' must allow enough bytes of local headers to be "pushed" onto the packet
5866  *
5867  * headroom == D11_PHY_HDR_LEN + D11_TXH_LEN (D11_TXH_LEN is now 104 bytes)
5868  *
5869  */
5870 static u16 BCMFASTPATH
5871 wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
5872                      void *p, struct scb *scb, uint frag,
5873                      uint nfrags, uint queue, uint next_frag_len,
5874                      wsec_key_t *key, ratespec_t rspec_override)
5875 {
5876         struct dot11_header *h;
5877         d11txh_t *txh;
5878         u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN];
5879         osl_t *osh;
5880         int len, phylen, rts_phylen;
5881         u16 fc, type, frameid, mch, phyctl, xfts, mainrates;
5882         u16 seq = 0, mcl = 0, status = 0;
5883         ratespec_t rspec[2] = { WLC_RATE_1M, WLC_RATE_1M }, rts_rspec[2] = {
5884         WLC_RATE_1M, WLC_RATE_1M};
5885         bool use_rts = FALSE;
5886         bool use_cts = FALSE;
5887         bool use_rifs = FALSE;
5888         bool short_preamble[2] = { FALSE, FALSE };
5889         u8 preamble_type[2] = { WLC_LONG_PREAMBLE, WLC_LONG_PREAMBLE };
5890         u8 rts_preamble_type[2] = { WLC_LONG_PREAMBLE, WLC_LONG_PREAMBLE };
5891         u8 *rts_plcp, rts_plcp_fallback[D11_PHY_HDR_LEN];
5892         struct dot11_rts_frame *rts = NULL;
5893         bool qos;
5894         uint ac;
5895         u32 rate_val[2];
5896         bool hwtkmic = FALSE;
5897         u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
5898 #ifdef WLANTSEL
5899 #define ANTCFG_NONE 0xFF
5900         u8 antcfg = ANTCFG_NONE;
5901         u8 fbantcfg = ANTCFG_NONE;
5902 #endif
5903         uint phyctl1_stf = 0;
5904         u16 durid = 0;
5905         struct ieee80211_tx_rate *txrate[2];
5906         int k;
5907         struct ieee80211_tx_info *tx_info;
5908         bool is_mcs[2];
5909         u16 mimo_txbw;
5910         u8 mimo_preamble_type;
5911
5912         frameid = 0;
5913
5914         ASSERT(queue < NFIFO);
5915
5916         osh = wlc->osh;
5917
5918         /* locate 802.11 MAC header */
5919         h = (struct dot11_header *)PKTDATA(p);
5920         fc = ltoh16(h->fc);
5921         type = FC_TYPE(fc);
5922
5923         qos = (type == FC_TYPE_DATA && FC_SUBTYPE_ANY_QOS(FC_SUBTYPE(fc)));
5924
5925         /* compute length of frame in bytes for use in PLCP computations */
5926         len = pkttotlen(osh, p);
5927         phylen = len + DOT11_FCS_LEN;
5928
5929         /* If WEP enabled, add room in phylen for the additional bytes of
5930          * ICV which MAC generates.  We do NOT add the additional bytes to
5931          * the packet itself, thus phylen = packet length + ICV_LEN + FCS_LEN
5932          * in this case
5933          */
5934         if (key) {
5935                 phylen += key->icv_len;
5936         }
5937
5938         /* Get tx_info */
5939         tx_info = IEEE80211_SKB_CB(p);
5940         ASSERT(tx_info);
5941
5942         /* add PLCP */
5943         plcp = PKTPUSH(p, D11_PHY_HDR_LEN);
5944
5945         /* add Broadcom tx descriptor header */
5946         txh = (d11txh_t *) PKTPUSH(p, D11_TXH_LEN);
5947         bzero((char *)txh, D11_TXH_LEN);
5948
5949         /* setup frameid */
5950         if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
5951                 /* non-AP STA should never use BCMC queue */
5952                 ASSERT(queue != TX_BCMC_FIFO);
5953                 if (queue == TX_BCMC_FIFO) {
5954                         WL_ERROR(("wl%d: %s: ASSERT queue == TX_BCMC!\n",
5955                                   WLCWLUNIT(wlc), __func__));
5956                         frameid = bcmc_fid_generate(wlc, NULL, txh);
5957                 } else {
5958                         /* Increment the counter for first fragment */
5959                         if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) {
5960                                 SCB_SEQNUM(scb, PKTPRIO(p))++;
5961                         }
5962
5963                         /* extract fragment number from frame first */
5964                         seq = ltoh16(seq) & FRAGNUM_MASK;
5965                         seq |= (SCB_SEQNUM(scb, PKTPRIO(p)) << SEQNUM_SHIFT);
5966                         h->seq = htol16(seq);
5967
5968                         frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
5969                             (queue & TXFID_QUEUE_MASK);
5970                 }
5971         }
5972         frameid |= queue & TXFID_QUEUE_MASK;
5973
5974         /* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */
5975         if (SCB_PS(scb) || ((fc & FC_KIND_MASK) == FC_BEACON))
5976                 mcl |= TXC_IGNOREPMQ;
5977
5978         ASSERT(hw->max_rates <= IEEE80211_TX_MAX_RATES);
5979         ASSERT(hw->max_rates == 2);
5980
5981         txrate[0] = tx_info->control.rates;
5982         txrate[1] = txrate[0] + 1;
5983
5984         ASSERT(txrate[0]->idx >= 0);
5985         /* if rate control algorithm didn't give us a fallback rate, use the primary rate */
5986         if (txrate[1]->idx < 0) {
5987                 txrate[1] = txrate[0];
5988         }
5989 #ifdef WLC_HIGH_ONLY
5990         /* Double protection , just in case */
5991         if (txrate[0]->idx > HIGHEST_SINGLE_STREAM_MCS)
5992                 txrate[0]->idx = HIGHEST_SINGLE_STREAM_MCS;
5993         if (txrate[1]->idx > HIGHEST_SINGLE_STREAM_MCS)
5994                 txrate[1]->idx = HIGHEST_SINGLE_STREAM_MCS;
5995 #endif
5996
5997         for (k = 0; k < hw->max_rates; k++) {
5998                 is_mcs[k] =
5999                     txrate[k]->flags & IEEE80211_TX_RC_MCS ? TRUE : FALSE;
6000                 if (!is_mcs[k]) {
6001                         ASSERT(!(tx_info->flags & IEEE80211_TX_CTL_AMPDU));
6002                         if ((txrate[k]->idx >= 0)
6003                             && (txrate[k]->idx <
6004                                 hw->wiphy->bands[tx_info->band]->n_bitrates)) {
6005                                 rate_val[k] =
6006                                     hw->wiphy->bands[tx_info->band]->
6007                                     bitrates[txrate[k]->idx].hw_value;
6008                                 short_preamble[k] =
6009                                     txrate[k]->
6010                                     flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ?
6011                                     TRUE : FALSE;
6012                         } else {
6013                                 ASSERT((txrate[k]->idx >= 0) &&
6014                                        (txrate[k]->idx <
6015                                         hw->wiphy->bands[tx_info->band]->
6016                                         n_bitrates));
6017                                 rate_val[k] = WLC_RATE_1M;
6018                         }
6019                 } else {
6020                         rate_val[k] = txrate[k]->idx;
6021                 }
6022                 /* Currently only support same setting for primay and fallback rates.
6023                  * Unify flags for each rate into a single value for the frame
6024                  */
6025                 use_rts |=
6026                     txrate[k]->
6027                     flags & IEEE80211_TX_RC_USE_RTS_CTS ? TRUE : FALSE;
6028                 use_cts |=
6029                     txrate[k]->
6030                     flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? TRUE : FALSE;
6031
6032                 if (is_mcs[k])
6033                         rate_val[k] |= NRATE_MCS_INUSE;
6034
6035                 rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band, rate_val[k]);
6036
6037                 /* (1) RATE: determine and validate primary rate and fallback rates */
6038                 if (!RSPEC_ACTIVE(rspec[k])) {
6039                         ASSERT(RSPEC_ACTIVE(rspec[k]));
6040                         rspec[k] = WLC_RATE_1M;
6041                 } else {
6042                         if (WLANTSEL_ENAB(wlc) && !ETHER_ISMULTI(&h->a1)) {
6043                                 /* set tx antenna config */
6044                                 wlc_antsel_antcfg_get(wlc->asi, FALSE, FALSE, 0,
6045                                                       0, &antcfg, &fbantcfg);
6046                         }
6047                 }
6048         }
6049
6050         phyctl1_stf = wlc->stf->ss_opmode;
6051
6052         if (N_ENAB(wlc->pub)) {
6053                 for (k = 0; k < hw->max_rates; k++) {
6054                         /* apply siso/cdd to single stream mcs's or ofdm if rspec is auto selected */
6055                         if (((IS_MCS(rspec[k]) &&
6056                               IS_SINGLE_STREAM(rspec[k] & RSPEC_RATE_MASK)) ||
6057                              IS_OFDM(rspec[k]))
6058                             && ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY)
6059                                 || !(rspec[k] & RSPEC_OVERRIDE))) {
6060                                 rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK);
6061
6062                                 /* For SISO MCS use STBC if possible */
6063                                 if (IS_MCS(rspec[k])
6064                                     && WLC_STF_SS_STBC_TX(wlc, scb)) {
6065                                         u8 stc;
6066
6067                                         ASSERT(WLC_STBC_CAP_PHY(wlc));
6068                                         stc = 1;        /* Nss for single stream is always 1 */
6069                                         rspec[k] |=
6070                                             (PHY_TXC1_MODE_STBC <<
6071                                              RSPEC_STF_SHIFT) | (stc <<
6072                                                                  RSPEC_STC_SHIFT);
6073                                 } else
6074                                         rspec[k] |=
6075                                             (phyctl1_stf << RSPEC_STF_SHIFT);
6076                         }
6077
6078                         /* Is the phy configured to use 40MHZ frames? If so then pick the desired txbw */
6079                         if (CHSPEC_WLC_BW(wlc->chanspec) == WLC_40_MHZ) {
6080                                 /* default txbw is 20in40 SB */
6081                                 mimo_ctlchbw = mimo_txbw =
6082                                     CHSPEC_SB_UPPER(WLC_BAND_PI_RADIO_CHANSPEC)
6083                                     ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
6084
6085                                 if (IS_MCS(rspec[k])) {
6086                                         /* mcs 32 must be 40b/w DUP */
6087                                         if ((rspec[k] & RSPEC_RATE_MASK) == 32) {
6088                                                 mimo_txbw =
6089                                                     PHY_TXC1_BW_40MHZ_DUP;
6090                                                 /* use override */
6091                                         } else if (wlc->mimo_40txbw != AUTO)
6092                                                 mimo_txbw = wlc->mimo_40txbw;
6093                                         /* else check if dst is using 40 Mhz */
6094                                         else if (scb->flags & SCB_IS40)
6095                                                 mimo_txbw = PHY_TXC1_BW_40MHZ;
6096                                 } else if (IS_OFDM(rspec[k])) {
6097                                         if (wlc->ofdm_40txbw != AUTO)
6098                                                 mimo_txbw = wlc->ofdm_40txbw;
6099                                 } else {
6100                                         ASSERT(IS_CCK(rspec[k]));
6101                                         if (wlc->cck_40txbw != AUTO)
6102                                                 mimo_txbw = wlc->cck_40txbw;
6103                                 }
6104                         } else {
6105                                 /* mcs32 is 40 b/w only.
6106                                  * This is possible for probe packets on a STA during SCAN
6107                                  */
6108                                 if ((rspec[k] & RSPEC_RATE_MASK) == 32) {
6109                                         /* mcs 0 */
6110                                         rspec[k] = RSPEC_MIMORATE;
6111                                 }
6112                                 mimo_txbw = PHY_TXC1_BW_20MHZ;
6113                         }
6114
6115                         /* Set channel width */
6116                         rspec[k] &= ~RSPEC_BW_MASK;
6117                         if ((k == 0) || ((k > 0) && IS_MCS(rspec[k])))
6118                                 rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT);
6119                         else
6120                                 rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
6121
6122                         /* Set Short GI */
6123 #ifdef NOSGIYET
6124                         if (IS_MCS(rspec[k])
6125                             && (txrate[k]->flags & IEEE80211_TX_RC_SHORT_GI))
6126                                 rspec[k] |= RSPEC_SHORT_GI;
6127                         else if (!(txrate[k]->flags & IEEE80211_TX_RC_SHORT_GI))
6128                                 rspec[k] &= ~RSPEC_SHORT_GI;
6129 #else
6130                         rspec[k] &= ~RSPEC_SHORT_GI;
6131 #endif
6132
6133                         mimo_preamble_type = WLC_MM_PREAMBLE;
6134                         if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD)
6135                                 mimo_preamble_type = WLC_GF_PREAMBLE;
6136
6137                         if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
6138                             && (!IS_MCS(rspec[k]))) {
6139                                 WL_ERROR(("wl%d: %s: IEEE80211_TX_RC_MCS != IS_MCS(rspec)\n", WLCWLUNIT(wlc), __func__));
6140                                 ASSERT(0 && "Rate mismatch");
6141                         }
6142
6143                         if (IS_MCS(rspec[k])) {
6144                                 preamble_type[k] = mimo_preamble_type;
6145
6146                                 /* if SGI is selected, then forced mm for single stream */
6147                                 if ((rspec[k] & RSPEC_SHORT_GI)
6148                                     && IS_SINGLE_STREAM(rspec[k] &
6149                                                         RSPEC_RATE_MASK)) {
6150                                         preamble_type[k] = WLC_MM_PREAMBLE;
6151                                 }
6152                         }
6153
6154                         /* mimo bw field MUST now be valid in the rspec (it affects duration calculations) */
6155                         ASSERT(VALID_RATE_DBG(wlc, rspec[0]));
6156
6157                         /* should be better conditionalized */
6158                         if (!IS_MCS(rspec[0])
6159                             && (tx_info->control.rates[0].
6160                                 flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE))
6161                                 preamble_type[k] = WLC_SHORT_PREAMBLE;
6162
6163                         ASSERT(!IS_MCS(rspec[0])
6164                                || WLC_IS_MIMO_PREAMBLE(preamble_type[k]));
6165                 }
6166         } else {
6167                 for (k = 0; k < hw->max_rates; k++) {
6168                         /* Set ctrlchbw as 20Mhz */
6169                         ASSERT(!IS_MCS(rspec[k]));
6170                         rspec[k] &= ~RSPEC_BW_MASK;
6171                         rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT);
6172
6173                         /* for nphy, stf of ofdm frames must follow policies */
6174                         if (WLCISNPHY(wlc->band) && IS_OFDM(rspec[k])) {
6175                                 rspec[k] &= ~RSPEC_STF_MASK;
6176                                 rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT;
6177                         }
6178                 }
6179         }
6180
6181         /* Reset these for use with AMPDU's */
6182         txrate[0]->count = 0;
6183         txrate[1]->count = 0;
6184
6185         /* (3) PLCP: determine PLCP header and MAC duration, fill d11txh_t */
6186         wlc_compute_plcp(wlc, rspec[0], phylen, plcp);
6187         wlc_compute_plcp(wlc, rspec[1], phylen, plcp_fallback);
6188         bcopy(plcp_fallback, (char *)&txh->FragPLCPFallback,
6189               sizeof(txh->FragPLCPFallback));
6190
6191         /* Length field now put in CCK FBR CRC field */
6192         if (IS_CCK(rspec[1])) {
6193                 txh->FragPLCPFallback[4] = phylen & 0xff;
6194                 txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8;
6195         }
6196
6197         /* MIMO-RATE: need validation ?? */
6198         mainrates =
6199             IS_OFDM(rspec[0]) ? D11A_PHY_HDR_GRATE((ofdm_phy_hdr_t *) plcp) :
6200             plcp[0];
6201
6202         /* DUR field for main rate */
6203         if ((fc != FC_PS_POLL) && !ETHER_ISMULTI(&h->a1) && !use_rifs) {
6204                 durid =
6205                     wlc_compute_frame_dur(wlc, rspec[0], preamble_type[0],
6206                                           next_frag_len);
6207                 h->durid = htol16(durid);
6208         } else if (use_rifs) {
6209                 /* NAV protect to end of next max packet size */
6210                 durid =
6211                     (u16) wlc_calc_frame_time(wlc, rspec[0],
6212                                                  preamble_type[0],
6213                                                  DOT11_MAX_FRAG_LEN);
6214                 durid += RIFS_11N_TIME;
6215                 h->durid = htol16(durid);
6216         }
6217
6218         /* DUR field for fallback rate */
6219         if (fc == FC_PS_POLL)
6220                 txh->FragDurFallback = h->durid;
6221         else if (ETHER_ISMULTI(&h->a1) || use_rifs)
6222                 txh->FragDurFallback = 0;
6223         else {
6224                 durid = wlc_compute_frame_dur(wlc, rspec[1],
6225                                               preamble_type[1], next_frag_len);
6226                 txh->FragDurFallback = htol16(durid);
6227         }
6228
6229         /* (4) MAC-HDR: MacTxControlLow */
6230         if (frag == 0)
6231                 mcl |= TXC_STARTMSDU;
6232
6233         if (!ETHER_ISMULTI(&h->a1))
6234                 mcl |= TXC_IMMEDACK;
6235
6236         if (BAND_5G(wlc->band->bandtype))
6237                 mcl |= TXC_FREQBAND_5G;
6238
6239         if (CHSPEC_IS40(WLC_BAND_PI_RADIO_CHANSPEC))
6240                 mcl |= TXC_BW_40;
6241
6242         /* set AMIC bit if using hardware TKIP MIC */
6243         if (hwtkmic)
6244                 mcl |= TXC_AMIC;
6245
6246         txh->MacTxControlLow = htol16(mcl);
6247
6248         /* MacTxControlHigh */
6249         mch = 0;
6250
6251         /* Set fallback rate preamble type */
6252         if ((preamble_type[1] == WLC_SHORT_PREAMBLE) ||
6253             (preamble_type[1] == WLC_GF_PREAMBLE)) {
6254                 ASSERT((preamble_type[1] == WLC_GF_PREAMBLE) ||
6255                        (!IS_MCS(rspec[1])));
6256                 if (RSPEC2RATE(rspec[1]) != WLC_RATE_1M)
6257                         mch |= TXC_PREAMBLE_DATA_FB_SHORT;
6258         }
6259
6260         /* MacFrameControl */
6261         bcopy((char *)&h->fc, (char *)&txh->MacFrameControl, sizeof(u16));
6262
6263         txh->TxFesTimeNormal = htol16(0);
6264
6265         txh->TxFesTimeFallback = htol16(0);
6266
6267         /* TxFrameRA */
6268         bcopy((char *)&h->a1, (char *)&txh->TxFrameRA, ETHER_ADDR_LEN);
6269
6270         /* TxFrameID */
6271         txh->TxFrameID = htol16(frameid);
6272
6273         /* TxStatus, Note the case of recreating the first frag of a suppressed frame
6274          * then we may need to reset the retry cnt's via the status reg
6275          */
6276         txh->TxStatus = htol16(status);
6277
6278         if (D11REV_GE(wlc->pub->corerev, 16)) {
6279                 /* extra fields for ucode AMPDU aggregation, the new fields are added to
6280                  * the END of previous structure so that it's compatible in driver.
6281                  * In old rev ucode, these fields should be ignored
6282                  */
6283                 txh->MaxNMpdus = htol16(0);
6284                 txh->MaxABytes_MRT = htol16(0);
6285                 txh->MaxABytes_FBR = htol16(0);
6286                 txh->MinMBytes = htol16(0);
6287         }
6288
6289         /* (5) RTS/CTS: determine RTS/CTS PLCP header and MAC duration, furnish d11txh_t */
6290         /* RTS PLCP header and RTS frame */
6291         if (use_rts || use_cts) {
6292                 if (use_rts && use_cts)
6293                         use_cts = FALSE;
6294
6295                 for (k = 0; k < 2; k++) {
6296                         rts_rspec[k] = wlc_rspec_to_rts_rspec(wlc, rspec[k],
6297                                                               FALSE,
6298                                                               mimo_ctlchbw);
6299                 }
6300
6301                 if (!IS_OFDM(rts_rspec[0]) &&
6302                     !((RSPEC2RATE(rts_rspec[0]) == WLC_RATE_1M) ||
6303                       (wlc->PLCPHdr_override == WLC_PLCP_LONG))) {
6304                         rts_preamble_type[0] = WLC_SHORT_PREAMBLE;
6305                         mch |= TXC_PREAMBLE_RTS_MAIN_SHORT;
6306                 }
6307
6308                 if (!IS_OFDM(rts_rspec[1]) &&
6309                     !((RSPEC2RATE(rts_rspec[1]) == WLC_RATE_1M) ||
6310                       (wlc->PLCPHdr_override == WLC_PLCP_LONG))) {
6311                         rts_preamble_type[1] = WLC_SHORT_PREAMBLE;
6312                         mch |= TXC_PREAMBLE_RTS_FB_SHORT;
6313                 }
6314
6315                 /* RTS/CTS additions to MacTxControlLow */
6316                 if (use_cts) {
6317                         txh->MacTxControlLow |= htol16(TXC_SENDCTS);
6318                 } else {
6319                         txh->MacTxControlLow |= htol16(TXC_SENDRTS);
6320                         txh->MacTxControlLow |= htol16(TXC_LONGFRAME);
6321                 }
6322
6323                 /* RTS PLCP header */
6324                 ASSERT(IS_ALIGNED((uintptr) txh->RTSPhyHeader, sizeof(u16)));
6325                 rts_plcp = txh->RTSPhyHeader;
6326                 if (use_cts)
6327                         rts_phylen = DOT11_CTS_LEN + DOT11_FCS_LEN;
6328                 else
6329                         rts_phylen = DOT11_RTS_LEN + DOT11_FCS_LEN;
6330
6331                 wlc_compute_plcp(wlc, rts_rspec[0], rts_phylen, rts_plcp);
6332
6333                 /* fallback rate version of RTS PLCP header */
6334                 wlc_compute_plcp(wlc, rts_rspec[1], rts_phylen,
6335                                  rts_plcp_fallback);
6336                 bcopy(rts_plcp_fallback, (char *)&txh->RTSPLCPFallback,
6337                       sizeof(txh->RTSPLCPFallback));
6338
6339                 /* RTS frame fields... */
6340                 rts = (struct dot11_rts_frame *)&txh->rts_frame;
6341
6342                 durid = wlc_compute_rtscts_dur(wlc, use_cts, rts_rspec[0],
6343                                                rspec[0], rts_preamble_type[0],
6344                                                preamble_type[0], phylen, FALSE);
6345                 rts->durid = htol16(durid);
6346                 /* fallback rate version of RTS DUR field */
6347                 durid = wlc_compute_rtscts_dur(wlc, use_cts,
6348                                                rts_rspec[1], rspec[1],
6349                                                rts_preamble_type[1],
6350                                                preamble_type[1], phylen, FALSE);
6351                 txh->RTSDurFallback = htol16(durid);
6352
6353                 if (use_cts) {
6354                         rts->fc = htol16(FC_CTS);
6355                         bcopy((char *)&h->a2, (char *)&rts->ra, ETHER_ADDR_LEN);
6356                 } else {
6357                         rts->fc = htol16((u16) FC_RTS);
6358                         bcopy((char *)&h->a1, (char *)&rts->ra,
6359                               2 * ETHER_ADDR_LEN);
6360                 }
6361
6362                 /* mainrate
6363                  *    low 8 bits: main frag rate/mcs,
6364                  *    high 8 bits: rts/cts rate/mcs
6365                  */
6366                 mainrates |= (IS_OFDM(rts_rspec[0]) ?
6367                               D11A_PHY_HDR_GRATE((ofdm_phy_hdr_t *) rts_plcp) :
6368                               rts_plcp[0]) << 8;
6369         } else {
6370                 bzero((char *)txh->RTSPhyHeader, D11_PHY_HDR_LEN);
6371                 bzero((char *)&txh->rts_frame, sizeof(struct dot11_rts_frame));
6372                 bzero((char *)txh->RTSPLCPFallback,
6373                       sizeof(txh->RTSPLCPFallback));
6374                 txh->RTSDurFallback = 0;
6375         }
6376
6377 #ifdef SUPPORT_40MHZ
6378         /* add null delimiter count */
6379         if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && IS_MCS(rspec)) {
6380                 txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] =
6381                     wlc_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen);
6382         }
6383 #endif
6384
6385         /* Now that RTS/RTS FB preamble types are updated, write the final value */
6386         txh->MacTxControlHigh = htol16(mch);
6387
6388         /* MainRates (both the rts and frag plcp rates have been calculated now) */
6389         txh->MainRates = htol16(mainrates);
6390
6391         /* XtraFrameTypes */
6392         xfts = FRAMETYPE(rspec[1], wlc->mimoft);
6393         xfts |= (FRAMETYPE(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);
6394         xfts |= (FRAMETYPE(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);
6395         xfts |=
6396             CHSPEC_CHANNEL(WLC_BAND_PI_RADIO_CHANSPEC) << XFTS_CHANNEL_SHIFT;
6397         txh->XtraFrameTypes = htol16(xfts);
6398
6399         /* PhyTxControlWord */
6400         phyctl = FRAMETYPE(rspec[0], wlc->mimoft);
6401         if ((preamble_type[0] == WLC_SHORT_PREAMBLE) ||
6402             (preamble_type[0] == WLC_GF_PREAMBLE)) {
6403                 ASSERT((preamble_type[0] == WLC_GF_PREAMBLE)
6404                        || !IS_MCS(rspec[0]));
6405                 if (RSPEC2RATE(rspec[0]) != WLC_RATE_1M)
6406                         phyctl |= PHY_TXC_SHORT_HDR;
6407                 WLCNTINCR(wlc->pub->_cnt->txprshort);
6408         }
6409
6410         /* phytxant is properly bit shifted */
6411         phyctl |= wlc_stf_d11hdrs_phyctl_txant(wlc, rspec[0]);
6412         txh->PhyTxControlWord = htol16(phyctl);
6413
6414         /* PhyTxControlWord_1 */
6415         if (WLC_PHY_11N_CAP(wlc->band)) {
6416                 u16 phyctl1 = 0;
6417
6418                 phyctl1 = wlc_phytxctl1_calc(wlc, rspec[0]);
6419                 txh->PhyTxControlWord_1 = htol16(phyctl1);
6420                 phyctl1 = wlc_phytxctl1_calc(wlc, rspec[1]);
6421                 txh->PhyTxControlWord_1_Fbr = htol16(phyctl1);
6422
6423                 if (use_rts || use_cts) {
6424                         phyctl1 = wlc_phytxctl1_calc(wlc, rts_rspec[0]);
6425                         txh->PhyTxControlWord_1_Rts = htol16(phyctl1);
6426                         phyctl1 = wlc_phytxctl1_calc(wlc, rts_rspec[1]);
6427                         txh->PhyTxControlWord_1_FbrRts = htol16(phyctl1);
6428                 }
6429
6430                 /*
6431                  * For mcs frames, if mixedmode(overloaded with long preamble) is going to be set,
6432                  * fill in non-zero MModeLen and/or MModeFbrLen
6433                  *  it will be unnecessary if they are separated
6434                  */
6435                 if (IS_MCS(rspec[0]) && (preamble_type[0] == WLC_MM_PREAMBLE)) {
6436                         u16 mmodelen =
6437                             wlc_calc_lsig_len(wlc, rspec[0], phylen);
6438                         txh->MModeLen = htol16(mmodelen);
6439                 }
6440
6441                 if (IS_MCS(rspec[1]) && (preamble_type[1] == WLC_MM_PREAMBLE)) {
6442                         u16 mmodefbrlen =
6443                             wlc_calc_lsig_len(wlc, rspec[1], phylen);
6444                         txh->MModeFbrLen = htol16(mmodefbrlen);
6445                 }
6446         }
6447
6448         if (IS_MCS(rspec[0]))
6449                 ASSERT(IS_MCS(rspec[1]));
6450
6451         ASSERT(!IS_MCS(rspec[0]) ||
6452                ((preamble_type[0] == WLC_MM_PREAMBLE) == (txh->MModeLen != 0)));
6453         ASSERT(!IS_MCS(rspec[1]) ||
6454                ((preamble_type[1] == WLC_MM_PREAMBLE) ==
6455                 (txh->MModeFbrLen != 0)));
6456
6457         ac = wme_fifo2ac[queue];
6458         if (SCB_WME(scb) && qos && wlc->edcf_txop[ac]) {
6459                 uint frag_dur, dur, dur_fallback;
6460
6461                 ASSERT(!ETHER_ISMULTI(&h->a1));
6462
6463                 /* WME: Update TXOP threshold */
6464                 if ((!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) && (frag == 0)) {
6465                         frag_dur =
6466                             wlc_calc_frame_time(wlc, rspec[0], preamble_type[0],
6467                                                 phylen);
6468
6469                         if (rts) {
6470                                 /* 1 RTS or CTS-to-self frame */
6471                                 dur =
6472                                     wlc_calc_cts_time(wlc, rts_rspec[0],
6473                                                       rts_preamble_type[0]);
6474                                 dur_fallback =
6475                                     wlc_calc_cts_time(wlc, rts_rspec[1],
6476                                                       rts_preamble_type[1]);
6477                                 /* (SIFS + CTS) + SIFS + frame + SIFS + ACK */
6478                                 dur += ltoh16(rts->durid);
6479                                 dur_fallback += ltoh16(txh->RTSDurFallback);
6480                         } else if (use_rifs) {
6481                                 dur = frag_dur;
6482                                 dur_fallback = 0;
6483                         } else {
6484                                 /* frame + SIFS + ACK */
6485                                 dur = frag_dur;
6486                                 dur +=
6487                                     wlc_compute_frame_dur(wlc, rspec[0],
6488                                                           preamble_type[0], 0);
6489
6490                                 dur_fallback =
6491                                     wlc_calc_frame_time(wlc, rspec[1],
6492                                                         preamble_type[1],
6493                                                         phylen);
6494                                 dur_fallback +=
6495                                     wlc_compute_frame_dur(wlc, rspec[1],
6496                                                           preamble_type[1], 0);
6497                         }
6498                         /* NEED to set TxFesTimeNormal (hard) */
6499                         txh->TxFesTimeNormal = htol16((u16) dur);
6500                         /* NEED to set fallback rate version of TxFesTimeNormal (hard) */
6501                         txh->TxFesTimeFallback = htol16((u16) dur_fallback);
6502
6503                         /* update txop byte threshold (txop minus intraframe overhead) */
6504                         if (wlc->edcf_txop[ac] >= (dur - frag_dur)) {
6505                                 {
6506                                         uint newfragthresh;
6507
6508                                         newfragthresh =
6509                                             wlc_calc_frame_len(wlc, rspec[0],
6510                                                                preamble_type[0],
6511                                                                (wlc->
6512                                                                 edcf_txop[ac] -
6513                                                                 (dur -
6514                                                                  frag_dur)));
6515                                         /* range bound the fragthreshold */
6516                                         if (newfragthresh < DOT11_MIN_FRAG_LEN)
6517                                                 newfragthresh =
6518                                                     DOT11_MIN_FRAG_LEN;
6519                                         else if (newfragthresh >
6520                                                  wlc->usr_fragthresh)
6521                                                 newfragthresh =
6522                                                     wlc->usr_fragthresh;
6523                                         /* update the fragthresh and do txc update */
6524                                         if (wlc->fragthresh[queue] !=
6525                                             (u16) newfragthresh) {
6526                                                 wlc->fragthresh[queue] =
6527                                                     (u16) newfragthresh;
6528                                         }
6529                                 }
6530                         } else
6531                                 WL_ERROR(("wl%d: %s txop invalid for rate %d\n",
6532                                           wlc->pub->unit, fifo_names[queue],
6533                                           RSPEC2RATE(rspec[0])));
6534
6535                         if (dur > wlc->edcf_txop[ac])
6536                                 WL_ERROR(("wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n", wlc->pub->unit, __func__, fifo_names[queue], phylen, wlc->fragthresh[queue], dur, wlc->edcf_txop[ac]));
6537                 }
6538         }
6539
6540         return 0;
6541 }
6542
6543 void wlc_tbtt(wlc_info_t *wlc, d11regs_t *regs)
6544 {
6545         wlc_bsscfg_t *cfg = wlc->cfg;
6546
6547         WLCNTINCR(wlc->pub->_cnt->tbtt);
6548
6549         if (BSSCFG_STA(cfg)) {
6550                 /* run watchdog here if the watchdog timer is not armed */
6551                 if (WLC_WATCHDOG_TBTT(wlc)) {
6552                         u32 cur, delta;
6553                         if (wlc->WDarmed) {
6554                                 wl_del_timer(wlc->wl, wlc->wdtimer);
6555                                 wlc->WDarmed = FALSE;
6556                         }
6557
6558                         cur = OSL_SYSUPTIME();
6559                         delta = cur > wlc->WDlast ? cur - wlc->WDlast :
6560                             (u32) ~0 - wlc->WDlast + cur + 1;
6561                         if (delta >= TIMER_INTERVAL_WATCHDOG) {
6562                                 wlc_watchdog((void *)wlc);
6563                                 wlc->WDlast = cur;
6564                         }
6565
6566                         wl_add_timer(wlc->wl, wlc->wdtimer,
6567                                      wlc_watchdog_backup_bi(wlc), TRUE);
6568                         wlc->WDarmed = TRUE;
6569                 }
6570         }
6571
6572         if (!cfg->BSS) {
6573                 /* DirFrmQ is now valid...defer setting until end of ATIM window */
6574                 wlc->qvalid |= MCMD_DIRFRMQVAL;
6575         }
6576 }
6577
6578 /* GP timer is a freerunning 32 bit counter, decrements at 1 us rate */
6579 void wlc_hwtimer_gptimer_set(wlc_info_t *wlc, uint us)
6580 {
6581         ASSERT(wlc->pub->corerev >= 3); /* no gptimer in earlier revs */
6582         W_REG(wlc->osh, &wlc->regs->gptimer, us);
6583 }
6584
6585 void wlc_hwtimer_gptimer_abort(wlc_info_t *wlc)
6586 {
6587         ASSERT(wlc->pub->corerev >= 3);
6588         W_REG(wlc->osh, &wlc->regs->gptimer, 0);
6589 }
6590
6591 static void wlc_hwtimer_gptimer_cb(wlc_info_t *wlc)
6592 {
6593         /* when interrupt is generated, the counter is loaded with last value
6594          * written and continue to decrement. So it has to be cleaned first
6595          */
6596         W_REG(wlc->osh, &wlc->regs->gptimer, 0);
6597 }
6598
6599 /*
6600  * This fn has all the high level dpc processing from wlc_dpc.
6601  * POLICY: no macinstatus change, no bounding loop.
6602  *         All dpc bounding should be handled in BMAC dpc, like txstatus and rxint
6603  */
6604 void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus)
6605 {
6606         d11regs_t *regs = wlc->regs;
6607 #ifdef BCMDBG
6608         char flagstr[128];
6609         static const bcm_bit_desc_t int_flags[] = {
6610                 {MI_MACSSPNDD, "MACSSPNDD"},
6611                 {MI_BCNTPL, "BCNTPL"},
6612                 {MI_TBTT, "TBTT"},
6613                 {MI_BCNSUCCESS, "BCNSUCCESS"},
6614                 {MI_BCNCANCLD, "BCNCANCLD"},
6615                 {MI_ATIMWINEND, "ATIMWINEND"},
6616                 {MI_PMQ, "PMQ"},
6617                 {MI_NSPECGEN_0, "NSPECGEN_0"},
6618                 {MI_NSPECGEN_1, "NSPECGEN_1"},
6619                 {MI_MACTXERR, "MACTXERR"},
6620                 {MI_NSPECGEN_3, "NSPECGEN_3"},
6621                 {MI_PHYTXERR, "PHYTXERR"},
6622                 {MI_PME, "PME"},
6623                 {MI_GP0, "GP0"},
6624                 {MI_GP1, "GP1"},
6625                 {MI_DMAINT, "DMAINT"},
6626                 {MI_TXSTOP, "TXSTOP"},
6627                 {MI_CCA, "CCA"},
6628                 {MI_BG_NOISE, "BG_NOISE"},
6629                 {MI_DTIM_TBTT, "DTIM_TBTT"},
6630                 {MI_PRQ, "PRQ"},
6631                 {MI_PWRUP, "PWRUP"},
6632                 {MI_RFDISABLE, "RFDISABLE"},
6633                 {MI_TFS, "TFS"},
6634                 {MI_PHYCHANGED, "PHYCHANGED"},
6635                 {MI_TO, "TO"},
6636                 {0, NULL}
6637         };
6638
6639         if (macintstatus & ~(MI_TBTT | MI_TXSTOP)) {
6640                 bcm_format_flags(int_flags, macintstatus, flagstr,
6641                                  sizeof(flagstr));
6642                 WL_TRACE(("wl%d: macintstatus 0x%x %s\n", wlc->pub->unit,
6643                           macintstatus, flagstr));
6644         }
6645 #endif                          /* BCMDBG */
6646
6647         if (macintstatus & MI_PRQ) {
6648                 /* Process probe request FIFO */
6649                 ASSERT(0 && "PRQ Interrupt in non-MBSS");
6650         }
6651
6652         /* TBTT indication */
6653         /* ucode only gives either TBTT or DTIM_TBTT, not both */
6654         if (macintstatus & (MI_TBTT | MI_DTIM_TBTT))
6655                 wlc_tbtt(wlc, regs);
6656
6657         if (macintstatus & MI_GP0) {
6658                 WL_ERROR(("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n", wlc->pub->unit, wlc->pub->now));
6659
6660                 printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
6661                             __func__, CHIPID(wlc->pub->sih->chip),
6662                             CHIPREV(wlc->pub->sih->chiprev));
6663
6664                 WLCNTINCR(wlc->pub->_cnt->psmwds);
6665
6666                 /* big hammer */
6667                 wl_init(wlc->wl);
6668         }
6669
6670         /* gptimer timeout */
6671         if (macintstatus & MI_TO) {
6672                 wlc_hwtimer_gptimer_cb(wlc);
6673         }
6674
6675         if (macintstatus & MI_RFDISABLE) {
6676                 WL_ERROR(("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n", wlc->pub->unit, R_REG(wlc->osh, &regs->phydebug) & PDBG_RFD));
6677                 /* delay the cleanup to wl_down in IBSS case */
6678                 if ((R_REG(wlc->osh, &regs->phydebug) & PDBG_RFD)) {
6679                         int idx;
6680                         wlc_bsscfg_t *bsscfg;
6681                         FOREACH_BSS(wlc, idx, bsscfg) {
6682                                 if (!BSSCFG_STA(bsscfg) || !bsscfg->enable
6683                                     || !bsscfg->BSS)
6684                                         continue;
6685                                 WL_ERROR(("wl%d: wlc_dpc: rfdisable -> wlc_bsscfg_disable()\n", wlc->pub->unit));
6686                         }
6687                 }
6688         }
6689
6690         /* send any enq'd tx packets. Just makes sure to jump start tx */
6691         if (!pktq_empty(&wlc->active_queue->q))
6692                 wlc_send_q(wlc, wlc->active_queue);
6693
6694 #ifndef WLC_HIGH_ONLY
6695         ASSERT(wlc_ps_check(wlc));
6696 #endif
6697 }
6698
6699 static void *wlc_15420war(wlc_info_t *wlc, uint queue)
6700 {
6701         hnddma_t *di;
6702         void *p;
6703
6704         ASSERT(queue < NFIFO);
6705
6706         if ((D11REV_IS(wlc->pub->corerev, 4))
6707             || (D11REV_GT(wlc->pub->corerev, 6)))
6708                 return NULL;
6709
6710         di = wlc->hw->di[queue];
6711         ASSERT(di != NULL);
6712
6713         /* get next packet, ignoring XmtStatus.Curr */
6714         p = dma_getnexttxp(di, HNDDMA_RANGE_ALL);
6715
6716         /* sw block tx dma */
6717         dma_txblock(di);
6718
6719         /* if tx ring is now empty, reset and re-init the tx dma channel */
6720         if (dma_txactive(wlc->hw->di[queue]) == 0) {
6721                 WLCNTINCR(wlc->pub->_cnt->txdmawar);
6722                 if (!dma_txreset(di))
6723                         WL_ERROR(("wl%d: %s: dma_txreset[%d]: cannot stop dma\n", wlc->pub->unit, __func__, queue));
6724                 dma_txinit(di);
6725         }
6726         return p;
6727 }
6728
6729 static void wlc_war16165(wlc_info_t *wlc, bool tx)
6730 {
6731         if (tx) {
6732                 /* the post-increment is used in STAY_AWAKE macro */
6733                 if (wlc->txpend16165war++ == 0)
6734                         wlc_set_ps_ctrl(wlc);
6735         } else {
6736                 wlc->txpend16165war--;
6737                 if (wlc->txpend16165war == 0)
6738                         wlc_set_ps_ctrl(wlc);
6739         }
6740 }
6741
6742 /* process an individual tx_status_t */
6743 /* WLC_HIGH_API */
6744 bool BCMFASTPATH
6745 wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2)
6746 {
6747         void *p;
6748         uint queue;
6749         d11txh_t *txh;
6750         struct scb *scb = NULL;
6751         bool free_pdu;
6752         osl_t *osh;
6753         int tx_rts, tx_frame_count, tx_rts_count;
6754         uint totlen, supr_status;
6755         bool lastframe;
6756         struct dot11_header *h;
6757         u16 fc;
6758         u16 mcl;
6759         struct ieee80211_tx_info *tx_info;
6760         struct ieee80211_tx_rate *txrate;
6761         int i;
6762
6763         (void)(frm_tx2);        /* Compiler reference to avoid unused variable warning */
6764
6765         /* discard intermediate indications for ucode with one legitimate case:
6766          *   e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, but the subsequent
6767          *   tx of DATA failed. so it will start rts/cts from the beginning (resetting the rts
6768          *   transmission count)
6769          */
6770         if (!(txs->status & TX_STATUS_AMPDU)
6771             && (txs->status & TX_STATUS_INTERMEDIATE)) {
6772                 WLCNTADD(wlc->pub->_cnt->txnoack,
6773                          ((txs->
6774                            status & TX_STATUS_FRM_RTX_MASK) >>
6775                           TX_STATUS_FRM_RTX_SHIFT));
6776                 WL_ERROR(("%s: INTERMEDIATE but not AMPDU\n", __func__));
6777                 return FALSE;
6778         }
6779
6780         osh = wlc->osh;
6781         queue = txs->frameid & TXFID_QUEUE_MASK;
6782         ASSERT(queue < NFIFO);
6783         if (queue >= NFIFO) {
6784                 p = NULL;
6785                 goto fatal;
6786         }
6787
6788         p = GETNEXTTXP(wlc, queue);
6789         if (WLC_WAR16165(wlc))
6790                 wlc_war16165(wlc, FALSE);
6791         if (p == NULL)
6792                 p = wlc_15420war(wlc, queue);
6793         ASSERT(p != NULL);
6794         if (p == NULL)
6795                 goto fatal;
6796
6797         txh = (d11txh_t *) PKTDATA(p);
6798         mcl = ltoh16(txh->MacTxControlLow);
6799
6800         if (txs->phyerr) {
6801                 WL_ERROR(("phyerr 0x%x, rate 0x%x\n", txs->phyerr,
6802                           txh->MainRates));
6803                 wlc_print_txdesc(txh);
6804                 wlc_print_txstatus(txs);
6805         }
6806
6807         ASSERT(txs->frameid == htol16(txh->TxFrameID));
6808         if (txs->frameid != htol16(txh->TxFrameID))
6809                 goto fatal;
6810
6811         tx_info = IEEE80211_SKB_CB(p);
6812         h = (struct dot11_header *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
6813         fc = ltoh16(h->fc);
6814
6815         scb = (struct scb *)tx_info->control.sta->drv_priv;
6816
6817         if (N_ENAB(wlc->pub)) {
6818                 u8 *plcp = (u8 *) (txh + 1);
6819                 if (PLCP3_ISSGI(plcp[3]))
6820                         WLCNTINCR(wlc->pub->_cnt->txmpdu_sgi);
6821                 if (PLCP3_ISSTBC(plcp[3]))
6822                         WLCNTINCR(wlc->pub->_cnt->txmpdu_stbc);
6823         }
6824
6825         if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
6826                 ASSERT((mcl & TXC_AMPDU_MASK) != TXC_AMPDU_NONE);
6827                 wlc_ampdu_dotxstatus(wlc->ampdu, scb, p, txs);
6828                 return FALSE;
6829         }
6830
6831         supr_status = txs->status & TX_STATUS_SUPR_MASK;
6832         if (supr_status == TX_STATUS_SUPR_BADCH)
6833                 WL_NONE(("%s: Pkt tx suppressed, possibly channel %d\n",
6834                          __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec)));
6835
6836         tx_rts = htol16(txh->MacTxControlLow) & TXC_SENDRTS;
6837         tx_frame_count =
6838             (txs->status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT;
6839         tx_rts_count =
6840             (txs->status & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT;
6841
6842         lastframe = (fc & FC_MOREFRAG) == 0;
6843
6844         if (!lastframe) {
6845                 WL_ERROR(("Not last frame!\n"));
6846         } else {
6847                 u16 sfbl, lfbl;
6848                 ieee80211_tx_info_clear_status(tx_info);
6849                 if (queue < AC_COUNT) {
6850                         sfbl = WLC_WME_RETRY_SFB_GET(wlc, wme_fifo2ac[queue]);
6851                         lfbl = WLC_WME_RETRY_LFB_GET(wlc, wme_fifo2ac[queue]);
6852                 } else {
6853                         sfbl = wlc->SFBL;
6854                         lfbl = wlc->LFBL;
6855                 }
6856
6857                 txrate = tx_info->status.rates;
6858                 /* FIXME: this should use a combination of sfbl, lfbl depending on frame length and RTS setting */
6859                 if ((tx_frame_count > sfbl) && (txrate[1].idx >= 0)) {
6860                         /* rate selection requested a fallback rate and we used it */
6861                         txrate->count = lfbl;
6862                         txrate[1].count = tx_frame_count - lfbl;
6863                 } else {
6864                         /* rate selection did not request fallback rate, or we didn't need it */
6865                         txrate->count = tx_frame_count;
6866                         /* rc80211_minstrel.c:minstrel_tx_status() expects unused rates to be marked with idx = -1 */
6867                         txrate[1].idx = -1;
6868                         txrate[1].count = 0;
6869                 }
6870
6871                 /* clear the rest of the rates */
6872                 for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
6873                         txrate[i].idx = -1;
6874                         txrate[i].count = 0;
6875                 }
6876
6877                 if (txs->status & TX_STATUS_ACK_RCV)
6878                         tx_info->flags |= IEEE80211_TX_STAT_ACK;
6879         }
6880
6881         totlen = pkttotlen(osh, p);
6882         free_pdu = TRUE;
6883
6884         wlc_txfifo_complete(wlc, queue, 1);
6885
6886         if (lastframe) {
6887                 PKTSETNEXT(p, NULL);
6888                 PKTSETLINK(p, NULL);
6889                 wlc->txretried = 0;
6890                 /* remove PLCP & Broadcom tx descriptor header */
6891                 PKTPULL(p, D11_PHY_HDR_LEN);
6892                 PKTPULL(p, D11_TXH_LEN);
6893                 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p);
6894                 WLCNTINCR(wlc->pub->_cnt->ieee_tx_status);
6895         } else {
6896                 WL_ERROR(("%s: Not last frame => not calling tx_status\n",
6897                           __func__));
6898         }
6899
6900         return FALSE;
6901
6902  fatal:
6903         ASSERT(0);
6904         if (p)
6905                 PKTFREE(osh, p, TRUE);
6906
6907 #ifdef WLC_HIGH_ONLY
6908         /* If this is a split driver, do the big-hammer here.
6909          * If this is a monolithic driver, wlc_bmac.c:wlc_dpc() will do the big-hammer.
6910          */
6911         wl_init(wlc->wl);
6912 #endif
6913         return TRUE;
6914
6915 }
6916
6917 void BCMFASTPATH
6918 wlc_txfifo_complete(wlc_info_t *wlc, uint fifo, s8 txpktpend)
6919 {
6920         TXPKTPENDDEC(wlc, fifo, txpktpend);
6921         WL_TRACE(("wlc_txfifo_complete, pktpend dec %d to %d\n", txpktpend,
6922                   TXPKTPENDGET(wlc, fifo)));
6923
6924         /* There is more room; mark precedences related to this FIFO sendable */
6925         WLC_TX_FIFO_ENAB(wlc, fifo);
6926         ASSERT(TXPKTPENDGET(wlc, fifo) >= 0);
6927
6928         if (!TXPKTPENDTOT(wlc)) {
6929                 if (wlc->block_datafifo & DATA_BLOCK_TX_SUPR)
6930                         wlc_bsscfg_tx_check(wlc);
6931         }
6932
6933         /* Clear MHF2_TXBCMC_NOW flag if BCMC fifo has drained */
6934         if (AP_ENAB(wlc->pub) &&
6935             wlc->bcmcfifo_drain && !TXPKTPENDGET(wlc, TX_BCMC_FIFO)) {
6936                 wlc->bcmcfifo_drain = FALSE;
6937                 wlc_mhf(wlc, MHF2, MHF2_TXBCMC_NOW, 0, WLC_BAND_AUTO);
6938         }
6939
6940         /* figure out which bsscfg is being worked on... */
6941 }
6942
6943 /* Given the beacon interval in kus, and a 64 bit TSF in us,
6944  * return the offset (in us) of the TSF from the last TBTT
6945  */
6946 u32 wlc_calc_tbtt_offset(u32 bp, u32 tsf_h, u32 tsf_l)
6947 {
6948         u32 k, btklo, btkhi, offset;
6949
6950         /* TBTT is always an even multiple of the beacon_interval,
6951          * so the TBTT less than or equal to the beacon timestamp is
6952          * the beacon timestamp minus the beacon timestamp modulo
6953          * the beacon interval.
6954          *
6955          * TBTT = BT - (BT % BIu)
6956          *      = (BTk - (BTk % BP)) * 2^10
6957          *
6958          * BT = beacon timestamp (usec, 64bits)
6959          * BTk = beacon timestamp (Kusec, 54bits)
6960          * BP = beacon interval (Kusec, 16bits)
6961          * BIu = BP * 2^10 = beacon interval (usec, 26bits)
6962          *
6963          * To keep the calculations in u32s, the modulo operation
6964          * on the high part of BT needs to be done in parts using the
6965          * relations:
6966          * X*Y mod Z = ((X mod Z) * (Y mod Z)) mod Z
6967          * and
6968          * (X + Y) mod Z = ((X mod Z) + (Y mod Z)) mod Z
6969          *
6970          * So, if BTk[n] = u16 n [0,3] of BTk.
6971          * BTk % BP = SUM((BTk[n] * 2^16n) % BP , 0<=n<4) % BP
6972          * and the SUM term can be broken down:
6973          * (BTk[n] *     2^16n)    % BP
6974          * (BTk[n] * (2^16n % BP)) % BP
6975          *
6976          * Create a set of power of 2 mod BP constants:
6977          * K[n] = 2^(16n) % BP
6978          *      = (K[n-1] * 2^16) % BP
6979          * K[2] = 2^32 % BP = ((2^16 % BP) * 2^16) % BP
6980          *
6981          * BTk % BP = BTk[0-1] % BP +
6982          *            (BTk[2] * K[2]) % BP +
6983          *            (BTk[3] * K[3]) % BP
6984          *
6985          * Since K[n] < 2^16 and BTk[n] is < 2^16, then BTk[n] * K[n] < 2^32
6986          */
6987
6988         /* BTk = BT >> 10, btklo = BTk[0-3], bkthi = BTk[4-6] */
6989         btklo = (tsf_h << 22) | (tsf_l >> 10);
6990         btkhi = tsf_h >> 10;
6991
6992         /* offset = BTk % BP */
6993         offset = btklo % bp;
6994
6995         /* K[2] = ((2^16 % BP) * 2^16) % BP */
6996         k = (u32) (1 << 16) % bp;
6997         k = (u32) (k * 1 << 16) % (u32) bp;
6998
6999         /* offset += (BTk[2] * K[2]) % BP */
7000         offset += ((btkhi & 0xffff) * k) % bp;
7001
7002         /* BTk[3] */
7003         btkhi = btkhi >> 16;
7004
7005         /* k[3] = (K[2] * 2^16) % BP */
7006         k = (k << 16) % bp;
7007
7008         /* offset += (BTk[3] * K[3]) % BP */
7009         offset += ((btkhi & 0xffff) * k) % bp;
7010
7011         offset = offset % bp;
7012
7013         /* convert offset from kus to us by shifting up 10 bits and
7014          * add in the low 10 bits of tsf that we ignored
7015          */
7016         offset = (offset << 10) + (tsf_l & 0x3FF);
7017
7018         return offset;
7019 }
7020
7021 /* Update beacon listen interval in shared memory */
7022 void wlc_bcn_li_upd(wlc_info_t *wlc)
7023 {
7024         if (AP_ENAB(wlc->pub))
7025                 return;
7026
7027         /* wake up every DTIM is the default */
7028         if (wlc->bcn_li_dtim == 1)
7029                 wlc_write_shm(wlc, M_BCN_LI, 0);
7030         else
7031                 wlc_write_shm(wlc, M_BCN_LI,
7032                               (wlc->bcn_li_dtim << 8) | wlc->bcn_li_bcn);
7033 }
7034
7035 static void
7036 prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, void *p,
7037                      struct ieee80211_rx_status *rx_status)
7038 {
7039         u32 tsf_l, tsf_h;
7040         wlc_d11rxhdr_t *wlc_rxh = (wlc_d11rxhdr_t *) rxh;
7041         int preamble;
7042         int channel;
7043         ratespec_t rspec;
7044         unsigned char *plcp;
7045
7046         wlc_read_tsf(wlc, &tsf_l, &tsf_h);      /* mactime */
7047         rx_status->mactime = tsf_h;
7048         rx_status->mactime <<= 32;
7049         rx_status->mactime |= tsf_l;
7050         rx_status->flag |= RX_FLAG_TSFT;
7051
7052         channel = WLC_CHAN_CHANNEL(rxh->RxChan);
7053
7054         /* XXX  Channel/badn needs to be filtered against whether we are single/dual band card */
7055         if (channel > 14) {
7056                 rx_status->band = IEEE80211_BAND_5GHZ;
7057                 rx_status->freq = wf_channel2mhz(channel, WF_CHAN_FACTOR_5_G);
7058         } else {
7059                 rx_status->band = IEEE80211_BAND_2GHZ;
7060                 rx_status->freq = wf_channel2mhz(channel, WF_CHAN_FACTOR_2_4_G);
7061         }
7062
7063         rx_status->signal = wlc_rxh->rssi;      /* signal */
7064
7065         /* noise */
7066         /* qual */
7067         rx_status->antenna = (rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0;      /* ant */
7068
7069         plcp = PKTDATA(p);
7070
7071         rspec = wlc_compute_rspec(rxh, plcp);
7072         if (IS_MCS(rspec)) {
7073                 rx_status->rate_idx = rspec & RSPEC_RATE_MASK;
7074                 rx_status->flag |= RX_FLAG_HT;
7075                 if (RSPEC_IS40MHZ(rspec))
7076                         rx_status->flag |= RX_FLAG_40MHZ;
7077         } else {
7078                 switch (RSPEC2RATE(rspec)) {
7079                 case WLC_RATE_1M:
7080                         rx_status->rate_idx = 0;
7081                         break;
7082                 case WLC_RATE_2M:
7083                         rx_status->rate_idx = 1;
7084                         break;
7085                 case WLC_RATE_5M5:
7086                         rx_status->rate_idx = 2;
7087                         break;
7088                 case WLC_RATE_11M:
7089                         rx_status->rate_idx = 3;
7090                         break;
7091                 case WLC_RATE_6M:
7092                         rx_status->rate_idx = 4;
7093                         break;
7094                 case WLC_RATE_9M:
7095                         rx_status->rate_idx = 5;
7096                         break;
7097                 case WLC_RATE_12M:
7098                         rx_status->rate_idx = 6;
7099                         break;
7100                 case WLC_RATE_18M:
7101                         rx_status->rate_idx = 7;
7102                         break;
7103                 case WLC_RATE_24M:
7104                         rx_status->rate_idx = 8;
7105                         break;
7106                 case WLC_RATE_36M:
7107                         rx_status->rate_idx = 9;
7108                         break;
7109                 case WLC_RATE_48M:
7110                         rx_status->rate_idx = 10;
7111                         break;
7112                 case WLC_RATE_54M:
7113                         rx_status->rate_idx = 11;
7114                         break;
7115                 default:
7116                         WL_ERROR(("%s: Unknown rate\n", __func__));
7117                 }
7118
7119                 /* Determine short preamble and rate_idx */
7120                 preamble = 0;
7121                 if (IS_CCK(rspec)) {
7122                         if (rxh->PhyRxStatus_0 & PRXS0_SHORTH)
7123                                 WL_ERROR(("Short CCK\n"));
7124                         rx_status->flag |= RX_FLAG_SHORTPRE;
7125                 } else if (IS_OFDM(rspec)) {
7126                         rx_status->flag |= RX_FLAG_SHORTPRE;
7127                 } else {
7128                         WL_ERROR(("%s: Unknown modulation\n", __func__));
7129                 }
7130         }
7131
7132         if (PLCP3_ISSGI(plcp[3]))
7133                 rx_status->flag |= RX_FLAG_SHORT_GI;
7134
7135         if (rxh->RxStatus1 & RXS_DECERR) {
7136                 rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC;
7137                 WL_ERROR(("%s:  RX_FLAG_FAILED_PLCP_CRC\n", __func__));
7138         }
7139         if (rxh->RxStatus1 & RXS_FCSERR) {
7140                 rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
7141                 WL_ERROR(("%s:  RX_FLAG_FAILED_FCS_CRC\n", __func__));
7142         }
7143 }
7144
7145 static void
7146 wlc_recvctl(wlc_info_t *wlc, osl_t *osh, d11rxhdr_t *rxh, void *p)
7147 {
7148         int len_mpdu;
7149         struct ieee80211_rx_status rx_status;
7150 #if defined(BCMDBG)
7151         struct sk_buff *skb = p;
7152 #endif                          /* BCMDBG */
7153         /* Todo:
7154          * Cache plcp for first MPDU of AMPD and use chacched version for INTERMEDIATE.
7155          * Test for INTERMEDIATE  like so:
7156          * if (!(plcp[0] | plcp[1] | plcp[2]))
7157          */
7158
7159         memset(&rx_status, 0, sizeof(rx_status));
7160         prep_mac80211_status(wlc, rxh, p, &rx_status);
7161
7162         /* mac header+body length, exclude CRC and plcp header */
7163         len_mpdu = PKTLEN(p) - D11_PHY_HDR_LEN - DOT11_FCS_LEN;
7164         PKTPULL(p, D11_PHY_HDR_LEN);
7165         PKTSETLEN(p, len_mpdu);
7166
7167         ASSERT(!PKTNEXT(p));
7168         ASSERT(!PKTLINK(p));
7169
7170         ASSERT(IS_ALIGNED((uintptr) skb->data, 2));
7171
7172         memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status));
7173         ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p);
7174
7175         WLCNTINCR(wlc->pub->_cnt->ieee_rx);
7176         PKTUNALLOC(osh);
7177         return;
7178 }
7179
7180 void wlc_bss_list_free(wlc_info_t *wlc, wlc_bss_list_t *bss_list)
7181 {
7182         uint index;
7183         wlc_bss_info_t *bi;
7184
7185         if (!bss_list) {
7186                 WL_ERROR(("%s: Attempting to free NULL list\n", __func__));
7187                 return;
7188         }
7189         /* inspect all BSS descriptor */
7190         for (index = 0; index < bss_list->count; index++) {
7191                 bi = bss_list->ptrs[index];
7192                 if (bi) {
7193                         if (bi->bcn_prb) {
7194                                 osl_mfree(wlc->osh, bi->bcn_prb,
7195                                           bi->bcn_prb_len);
7196                         }
7197                         osl_mfree(wlc->osh, bi, sizeof(wlc_bss_info_t));
7198                         bss_list->ptrs[index] = NULL;
7199                 }
7200         }
7201         bss_list->count = 0;
7202 }
7203
7204 /* Process received frames */
7205 /*
7206  * Return TRUE if more frames need to be processed. FALSE otherwise.
7207  * Param 'bound' indicates max. # frames to process before break out.
7208  */
7209 /* WLC_HIGH_API */
7210 void BCMFASTPATH wlc_recv(wlc_info_t *wlc, void *p)
7211 {
7212         d11rxhdr_t *rxh;
7213         struct dot11_header *h;
7214         osl_t *osh;
7215         u16 fc;
7216         uint len;
7217         bool is_amsdu;
7218
7219         WL_TRACE(("wl%d: wlc_recv\n", wlc->pub->unit));
7220
7221         osh = wlc->osh;
7222
7223         /* frame starts with rxhdr */
7224         rxh = (d11rxhdr_t *) PKTDATA(p);
7225
7226         /* strip off rxhdr */
7227         PKTPULL(p, wlc->hwrxoff);
7228
7229         /* fixup rx header endianness */
7230         ltoh16_buf((void *)rxh, sizeof(d11rxhdr_t));
7231
7232         /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
7233         if (rxh->RxStatus1 & RXS_PBPRES) {
7234                 if (PKTLEN(p) < 2) {
7235                         WLCNTINCR(wlc->pub->_cnt->rxrunt);
7236                         WL_ERROR(("wl%d: wlc_recv: rcvd runt of len %d\n",
7237                                   wlc->pub->unit, PKTLEN(p)));
7238                         goto toss;
7239                 }
7240                 PKTPULL(p, 2);
7241         }
7242
7243         h = (struct dot11_header *)(PKTDATA(p) + D11_PHY_HDR_LEN);
7244         len = PKTLEN(p);
7245
7246         if (rxh->RxStatus1 & RXS_FCSERR) {
7247                 if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) {
7248                         WL_ERROR(("FCSERR while scanning******* - tossing\n"));
7249                         goto toss;
7250                 } else {
7251                         WL_ERROR(("RCSERR!!!\n"));
7252                         goto toss;
7253                 }
7254         }
7255
7256         /* check received pkt has at least frame control field */
7257         if (len >= D11_PHY_HDR_LEN + sizeof(h->fc)) {
7258                 fc = ltoh16(h->fc);
7259         } else {
7260                 WLCNTINCR(wlc->pub->_cnt->rxrunt);
7261                 goto toss;
7262         }
7263
7264         is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK;
7265
7266         /* explicitly test bad src address to avoid sending bad deauth */
7267         if (!is_amsdu) {
7268                 /* CTS and ACK CTL frames are w/o a2 */
7269                 if (FC_TYPE(fc) == FC_TYPE_DATA || FC_TYPE(fc) == FC_TYPE_MNG) {
7270                         if ((ETHER_ISNULLADDR(&h->a2) || ETHER_ISMULTI(&h->a2))) {
7271                                 WL_ERROR(("wl%d: %s: dropping a frame with "
7272                                         "invalid src mac address, a2: %pM\n",
7273                                         wlc->pub->unit, __func__, &h->a2));
7274                                 WLCNTINCR(wlc->pub->_cnt->rxbadsrcmac);
7275                                 goto toss;
7276                         }
7277                         WLCNTINCR(wlc->pub->_cnt->rxfrag);
7278                 }
7279         }
7280
7281         /* due to sheer numbers, toss out probe reqs for now */
7282         if (FC_TYPE(fc) == FC_TYPE_MNG) {
7283                 if ((fc & FC_KIND_MASK) == FC_PROBE_REQ)
7284                         goto toss;
7285         }
7286
7287         if (is_amsdu) {
7288                 WL_ERROR(("%s: is_amsdu causing toss\n", __func__));
7289                 goto toss;
7290         }
7291
7292         wlc_recvctl(wlc, osh, rxh, p);
7293         return;
7294
7295  toss:
7296         PKTFREE(osh, p, FALSE);
7297 }
7298
7299 /* calculate frame duration for Mixed-mode L-SIG spoofing, return
7300  * number of bytes goes in the length field
7301  *
7302  * Formula given by HT PHY Spec v 1.13
7303  *   len = 3(nsyms + nstream + 3) - 3
7304  */
7305 u16 BCMFASTPATH
7306 wlc_calc_lsig_len(wlc_info_t *wlc, ratespec_t ratespec, uint mac_len)
7307 {
7308         uint nsyms, len = 0, kNdps;
7309
7310         WL_TRACE(("wl%d: wlc_calc_lsig_len: rate %d, len%d\n", wlc->pub->unit,
7311                   RSPEC2RATE(ratespec), mac_len));
7312
7313         if (IS_MCS(ratespec)) {
7314                 uint mcs = ratespec & RSPEC_RATE_MASK;
7315                 /* MCS_TXS(mcs) returns num tx streams - 1 */
7316                 int tot_streams = (MCS_TXS(mcs) + 1) + RSPEC_STC(ratespec);
7317
7318                 ASSERT(WLC_PHY_11N_CAP(wlc->band));
7319                 /* the payload duration calculation matches that of regular ofdm */
7320                 /* 1000Ndbps = kbps * 4 */
7321                 kNdps =
7322                     MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec),
7323                              RSPEC_ISSGI(ratespec)) * 4;
7324
7325                 if (RSPEC_STC(ratespec) == 0)
7326                         /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
7327                         nsyms =
7328                             CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
7329                                   APHY_TAIL_NBITS) * 1000, kNdps);
7330                 else
7331                         /* STBC needs to have even number of symbols */
7332                         nsyms =
7333                             2 *
7334                             CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
7335                                   APHY_TAIL_NBITS) * 1000, 2 * kNdps);
7336
7337                 nsyms += (tot_streams + 3);     /* (+3) account for HT-SIG(2) and HT-STF(1) */
7338                 /* 3 bytes/symbol @ legacy 6Mbps rate */
7339                 len = (3 * nsyms) - 3;  /* (-3) excluding service bits and tail bits */
7340         }
7341
7342         return (u16) len;
7343 }
7344
7345 /* calculate frame duration of a given rate and length, return time in usec unit */
7346 uint BCMFASTPATH
7347 wlc_calc_frame_time(wlc_info_t *wlc, ratespec_t ratespec, u8 preamble_type,
7348                     uint mac_len)
7349 {
7350         uint nsyms, dur = 0, Ndps, kNdps;
7351         uint rate = RSPEC2RATE(ratespec);
7352
7353         if (rate == 0) {
7354                 ASSERT(0);
7355                 WL_ERROR(("wl%d: WAR: using rate of 1 mbps\n", wlc->pub->unit));
7356                 rate = WLC_RATE_1M;
7357         }
7358
7359         WL_TRACE(("wl%d: wlc_calc_frame_time: rspec 0x%x, preamble_type %d, len%d\n", wlc->pub->unit, ratespec, preamble_type, mac_len));
7360
7361         if (IS_MCS(ratespec)) {
7362                 uint mcs = ratespec & RSPEC_RATE_MASK;
7363                 int tot_streams = MCS_TXS(mcs) + RSPEC_STC(ratespec);
7364                 ASSERT(WLC_PHY_11N_CAP(wlc->band));
7365                 ASSERT(WLC_IS_MIMO_PREAMBLE(preamble_type));
7366
7367                 dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
7368                 if (preamble_type == WLC_MM_PREAMBLE)
7369                         dur += PREN_MM_EXT;
7370                 /* 1000Ndbps = kbps * 4 */
7371                 kNdps =
7372                     MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec),
7373                              RSPEC_ISSGI(ratespec)) * 4;
7374
7375                 if (RSPEC_STC(ratespec) == 0)
7376                         /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
7377                         nsyms =
7378                             CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
7379                                   APHY_TAIL_NBITS) * 1000, kNdps);
7380                 else
7381                         /* STBC needs to have even number of symbols */
7382                         nsyms =
7383                             2 *
7384                             CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
7385                                   APHY_TAIL_NBITS) * 1000, 2 * kNdps);
7386
7387                 dur += APHY_SYMBOL_TIME * nsyms;
7388                 if (BAND_2G(wlc->band->bandtype))
7389                         dur += DOT11_OFDM_SIGNAL_EXTENSION;
7390         } else if (IS_OFDM(rate)) {
7391                 dur = APHY_PREAMBLE_TIME;
7392                 dur += APHY_SIGNAL_TIME;
7393                 /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
7394                 Ndps = rate * 2;
7395                 /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
7396                 nsyms =
7397                     CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS),
7398                          Ndps);
7399                 dur += APHY_SYMBOL_TIME * nsyms;
7400                 if (BAND_2G(wlc->band->bandtype))
7401                         dur += DOT11_OFDM_SIGNAL_EXTENSION;
7402         } else {
7403                 /* calc # bits * 2 so factor of 2 in rate (1/2 mbps) will divide out */
7404                 mac_len = mac_len * 8 * 2;
7405                 /* calc ceiling of bits/rate = microseconds of air time */
7406                 dur = (mac_len + rate - 1) / rate;
7407                 if (preamble_type & WLC_SHORT_PREAMBLE)
7408                         dur += BPHY_PLCP_SHORT_TIME;
7409                 else
7410                         dur += BPHY_PLCP_TIME;
7411         }
7412         return dur;
7413 }
7414
7415 /* The opposite of wlc_calc_frame_time */
7416 static uint
7417 wlc_calc_frame_len(wlc_info_t *wlc, ratespec_t ratespec, u8 preamble_type,
7418                    uint dur)
7419 {
7420         uint nsyms, mac_len, Ndps, kNdps;
7421         uint rate = RSPEC2RATE(ratespec);
7422
7423         WL_TRACE(("wl%d: wlc_calc_frame_len: rspec 0x%x, preamble_type %d, dur %d\n", wlc->pub->unit, ratespec, preamble_type, dur));
7424
7425         if (IS_MCS(ratespec)) {
7426                 uint mcs = ratespec & RSPEC_RATE_MASK;
7427                 int tot_streams = MCS_TXS(mcs) + RSPEC_STC(ratespec);
7428                 ASSERT(WLC_PHY_11N_CAP(wlc->band));
7429                 dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
7430                 /* payload calculation matches that of regular ofdm */
7431                 if (BAND_2G(wlc->band->bandtype))
7432                         dur -= DOT11_OFDM_SIGNAL_EXTENSION;
7433                 /* kNdbps = kbps * 4 */
7434                 kNdps =
7435                     MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec),
7436                              RSPEC_ISSGI(ratespec)) * 4;
7437                 nsyms = dur / APHY_SYMBOL_TIME;
7438                 mac_len =
7439                     ((nsyms * kNdps) -
7440                      ((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000;
7441         } else if (IS_OFDM(ratespec)) {
7442                 dur -= APHY_PREAMBLE_TIME;
7443                 dur -= APHY_SIGNAL_TIME;
7444                 /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
7445                 Ndps = rate * 2;
7446                 nsyms = dur / APHY_SYMBOL_TIME;
7447                 mac_len =
7448                     ((nsyms * Ndps) -
7449                      (APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8;
7450         } else {
7451                 if (preamble_type & WLC_SHORT_PREAMBLE)
7452                         dur -= BPHY_PLCP_SHORT_TIME;
7453                 else
7454                         dur -= BPHY_PLCP_TIME;
7455                 mac_len = dur * rate;
7456                 /* divide out factor of 2 in rate (1/2 mbps) */
7457                 mac_len = mac_len / 8 / 2;
7458         }
7459         return mac_len;
7460 }
7461
7462 static uint
7463 wlc_calc_ba_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type)
7464 {
7465         WL_TRACE(("wl%d: wlc_calc_ba_time: rspec 0x%x, preamble_type %d\n",
7466                   wlc->pub->unit, rspec, preamble_type));
7467         /* Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that is less than
7468          * or equal to the rate of the immediately previous frame in the FES
7469          */
7470         rspec = WLC_BASIC_RATE(wlc, rspec);
7471         ASSERT(VALID_RATE_DBG(wlc, rspec));
7472
7473         /* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */
7474         return wlc_calc_frame_time(wlc, rspec, preamble_type,
7475                                    (DOT11_BA_LEN + DOT11_BA_BITMAP_LEN +
7476                                     DOT11_FCS_LEN));
7477 }
7478
7479 static uint BCMFASTPATH
7480 wlc_calc_ack_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type)
7481 {
7482         uint dur = 0;
7483
7484         WL_TRACE(("wl%d: wlc_calc_ack_time: rspec 0x%x, preamble_type %d\n",
7485                   wlc->pub->unit, rspec, preamble_type));
7486         /* Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that is less than
7487          * or equal to the rate of the immediately previous frame in the FES
7488          */
7489         rspec = WLC_BASIC_RATE(wlc, rspec);
7490         ASSERT(VALID_RATE_DBG(wlc, rspec));
7491
7492         /* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */
7493         dur =
7494             wlc_calc_frame_time(wlc, rspec, preamble_type,
7495                                 (DOT11_ACK_LEN + DOT11_FCS_LEN));
7496         return dur;
7497 }
7498
7499 static uint
7500 wlc_calc_cts_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type)
7501 {
7502         WL_TRACE(("wl%d: wlc_calc_cts_time: ratespec 0x%x, preamble_type %d\n",
7503                   wlc->pub->unit, rspec, preamble_type));
7504         return wlc_calc_ack_time(wlc, rspec, preamble_type);
7505 }
7506
7507 /* derive wlc->band->basic_rate[] table from 'rateset' */
7508 void wlc_rate_lookup_init(wlc_info_t *wlc, wlc_rateset_t *rateset)
7509 {
7510         u8 rate;
7511         u8 mandatory;
7512         u8 cck_basic = 0;
7513         u8 ofdm_basic = 0;
7514         u8 *br = wlc->band->basic_rate;
7515         uint i;
7516
7517         /* incoming rates are in 500kbps units as in 802.11 Supported Rates */
7518         bzero(br, WLC_MAXRATE + 1);
7519
7520         /* For each basic rate in the rates list, make an entry in the
7521          * best basic lookup.
7522          */
7523         for (i = 0; i < rateset->count; i++) {
7524                 /* only make an entry for a basic rate */
7525                 if (!(rateset->rates[i] & WLC_RATE_FLAG))
7526                         continue;
7527
7528                 /* mask off basic bit */
7529                 rate = (rateset->rates[i] & RATE_MASK);
7530
7531                 if (rate > WLC_MAXRATE) {
7532                         WL_ERROR(("wlc_rate_lookup_init: invalid rate 0x%X in rate set\n", rateset->rates[i]));
7533                         continue;
7534                 }
7535
7536                 br[rate] = rate;
7537         }
7538
7539         /* The rate lookup table now has non-zero entries for each
7540          * basic rate, equal to the basic rate: br[basicN] = basicN
7541          *
7542          * To look up the best basic rate corresponding to any
7543          * particular rate, code can use the basic_rate table
7544          * like this
7545          *
7546          * basic_rate = wlc->band->basic_rate[tx_rate]
7547          *
7548          * Make sure there is a best basic rate entry for
7549          * every rate by walking up the table from low rates
7550          * to high, filling in holes in the lookup table
7551          */
7552
7553         for (i = 0; i < wlc->band->hw_rateset.count; i++) {
7554                 rate = wlc->band->hw_rateset.rates[i];
7555                 ASSERT(rate <= WLC_MAXRATE);
7556
7557                 if (br[rate] != 0) {
7558                         /* This rate is a basic rate.
7559                          * Keep track of the best basic rate so far by
7560                          * modulation type.
7561                          */
7562                         if (IS_OFDM(rate))
7563                                 ofdm_basic = rate;
7564                         else
7565                                 cck_basic = rate;
7566
7567                         continue;
7568                 }
7569
7570                 /* This rate is not a basic rate so figure out the
7571                  * best basic rate less than this rate and fill in
7572                  * the hole in the table
7573                  */
7574
7575                 br[rate] = IS_OFDM(rate) ? ofdm_basic : cck_basic;
7576
7577                 if (br[rate] != 0)
7578                         continue;
7579
7580                 if (IS_OFDM(rate)) {
7581                         /* In 11g and 11a, the OFDM mandatory rates are 6, 12, and 24 Mbps */
7582                         if (rate >= WLC_RATE_24M)
7583                                 mandatory = WLC_RATE_24M;
7584                         else if (rate >= WLC_RATE_12M)
7585                                 mandatory = WLC_RATE_12M;
7586                         else
7587                                 mandatory = WLC_RATE_6M;
7588                 } else {
7589                         /* In 11b, all the CCK rates are mandatory 1 - 11 Mbps */
7590                         mandatory = rate;
7591                 }
7592
7593                 br[rate] = mandatory;
7594         }
7595 }
7596
7597 static void wlc_write_rate_shm(wlc_info_t *wlc, u8 rate, u8 basic_rate)
7598 {
7599         u8 phy_rate, index;
7600         u8 basic_phy_rate, basic_index;
7601         u16 dir_table, basic_table;
7602         u16 basic_ptr;
7603
7604         /* Shared memory address for the table we are reading */
7605         dir_table = IS_OFDM(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B;
7606
7607         /* Shared memory address for the table we are writing */
7608         basic_table = IS_OFDM(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B;
7609
7610         /*
7611          * for a given rate, the LS-nibble of the PLCP SIGNAL field is
7612          * the index into the rate table.
7613          */
7614         phy_rate = rate_info[rate] & RATE_MASK;
7615         basic_phy_rate = rate_info[basic_rate] & RATE_MASK;
7616         index = phy_rate & 0xf;
7617         basic_index = basic_phy_rate & 0xf;
7618
7619         /* Find the SHM pointer to the ACK rate entry by looking in the
7620          * Direct-map Table
7621          */
7622         basic_ptr = wlc_read_shm(wlc, (dir_table + basic_index * 2));
7623
7624         /* Update the SHM BSS-basic-rate-set mapping table with the pointer
7625          * to the correct basic rate for the given incoming rate
7626          */
7627         wlc_write_shm(wlc, (basic_table + index * 2), basic_ptr);
7628 }
7629
7630 static const wlc_rateset_t *wlc_rateset_get_hwrs(wlc_info_t *wlc)
7631 {
7632         const wlc_rateset_t *rs_dflt;
7633
7634         if (WLC_PHY_11N_CAP(wlc->band)) {
7635                 if (BAND_5G(wlc->band->bandtype))
7636                         rs_dflt = &ofdm_mimo_rates;
7637                 else
7638                         rs_dflt = &cck_ofdm_mimo_rates;
7639         } else if (wlc->band->gmode)
7640                 rs_dflt = &cck_ofdm_rates;
7641         else
7642                 rs_dflt = &cck_rates;
7643
7644         return rs_dflt;
7645 }
7646
7647 void wlc_set_ratetable(wlc_info_t *wlc)
7648 {
7649         const wlc_rateset_t *rs_dflt;
7650         wlc_rateset_t rs;
7651         u8 rate, basic_rate;
7652         uint i;
7653
7654         rs_dflt = wlc_rateset_get_hwrs(wlc);
7655         ASSERT(rs_dflt != NULL);
7656
7657         wlc_rateset_copy(rs_dflt, &rs);
7658         wlc_rateset_mcs_upd(&rs, wlc->stf->txstreams);
7659
7660         /* walk the phy rate table and update SHM basic rate lookup table */
7661         for (i = 0; i < rs.count; i++) {
7662                 rate = rs.rates[i] & RATE_MASK;
7663
7664                 /* for a given rate WLC_BASIC_RATE returns the rate at
7665                  * which a response ACK/CTS should be sent.
7666                  */
7667                 basic_rate = WLC_BASIC_RATE(wlc, rate);
7668                 if (basic_rate == 0) {
7669                         /* This should only happen if we are using a
7670                          * restricted rateset.
7671                          */
7672                         basic_rate = rs.rates[0] & RATE_MASK;
7673                 }
7674
7675                 wlc_write_rate_shm(wlc, rate, basic_rate);
7676         }
7677 }
7678
7679 /*
7680  * Return true if the specified rate is supported by the specified band.
7681  * WLC_BAND_AUTO indicates the current band.
7682  */
7683 bool wlc_valid_rate(wlc_info_t *wlc, ratespec_t rspec, int band, bool verbose)
7684 {
7685         wlc_rateset_t *hw_rateset;
7686         uint i;
7687
7688         if ((band == WLC_BAND_AUTO) || (band == wlc->band->bandtype)) {
7689                 hw_rateset = &wlc->band->hw_rateset;
7690         } else if (NBANDS(wlc) > 1) {
7691                 hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset;
7692         } else {
7693                 /* other band specified and we are a single band device */
7694                 return FALSE;
7695         }
7696
7697         /* check if this is a mimo rate */
7698         if (IS_MCS(rspec)) {
7699                 if (!VALID_MCS((rspec & RSPEC_RATE_MASK)))
7700                         goto error;
7701
7702                 return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK));
7703         }
7704
7705         for (i = 0; i < hw_rateset->count; i++)
7706                 if (hw_rateset->rates[i] == RSPEC2RATE(rspec))
7707                         return TRUE;
7708  error:
7709         if (verbose) {
7710                 WL_ERROR(("wl%d: wlc_valid_rate: rate spec 0x%x not in hw_rateset\n", wlc->pub->unit, rspec));
7711         }
7712
7713         return FALSE;
7714 }
7715
7716 static void wlc_update_mimo_band_bwcap(wlc_info_t *wlc, u8 bwcap)
7717 {
7718         uint i;
7719         wlcband_t *band;
7720
7721         for (i = 0; i < NBANDS(wlc); i++) {
7722                 if (IS_SINGLEBAND_5G(wlc->deviceid))
7723                         i = BAND_5G_INDEX;
7724                 band = wlc->bandstate[i];
7725                 if (band->bandtype == WLC_BAND_5G) {
7726                         if ((bwcap == WLC_N_BW_40ALL)
7727                             || (bwcap == WLC_N_BW_20IN2G_40IN5G))
7728                                 band->mimo_cap_40 = TRUE;
7729                         else
7730                                 band->mimo_cap_40 = FALSE;
7731                 } else {
7732                         ASSERT(band->bandtype == WLC_BAND_2G);
7733                         if (bwcap == WLC_N_BW_40ALL)
7734                                 band->mimo_cap_40 = TRUE;
7735                         else
7736                                 band->mimo_cap_40 = FALSE;
7737                 }
7738         }
7739
7740         wlc->mimo_band_bwcap = bwcap;
7741 }
7742
7743 void wlc_mod_prb_rsp_rate_table(wlc_info_t *wlc, uint frame_len)
7744 {
7745         const wlc_rateset_t *rs_dflt;
7746         wlc_rateset_t rs;
7747         u8 rate;
7748         u16 entry_ptr;
7749         u8 plcp[D11_PHY_HDR_LEN];
7750         u16 dur, sifs;
7751         uint i;
7752
7753         sifs = SIFS(wlc->band);
7754
7755         rs_dflt = wlc_rateset_get_hwrs(wlc);
7756         ASSERT(rs_dflt != NULL);
7757
7758         wlc_rateset_copy(rs_dflt, &rs);
7759         wlc_rateset_mcs_upd(&rs, wlc->stf->txstreams);
7760
7761         /* walk the phy rate table and update MAC core SHM basic rate table entries */
7762         for (i = 0; i < rs.count; i++) {
7763                 rate = rs.rates[i] & RATE_MASK;
7764
7765                 entry_ptr = wlc_rate_shm_offset(wlc, rate);
7766
7767                 /* Calculate the Probe Response PLCP for the given rate */
7768                 wlc_compute_plcp(wlc, rate, frame_len, plcp);
7769
7770                 /* Calculate the duration of the Probe Response frame plus SIFS for the MAC */
7771                 dur =
7772                     (u16) wlc_calc_frame_time(wlc, rate, WLC_LONG_PREAMBLE,
7773                                                  frame_len);
7774                 dur += sifs;
7775
7776                 /* Update the SHM Rate Table entry Probe Response values */
7777                 wlc_write_shm(wlc, entry_ptr + M_RT_PRS_PLCP_POS,
7778                               (u16) (plcp[0] + (plcp[1] << 8)));
7779                 wlc_write_shm(wlc, entry_ptr + M_RT_PRS_PLCP_POS + 2,
7780                               (u16) (plcp[2] + (plcp[3] << 8)));
7781                 wlc_write_shm(wlc, entry_ptr + M_RT_PRS_DUR_POS, dur);
7782         }
7783 }
7784
7785 u16
7786 wlc_compute_bcntsfoff(wlc_info_t *wlc, ratespec_t rspec, bool short_preamble,
7787                       bool phydelay)
7788 {
7789         uint bcntsfoff = 0;
7790
7791         if (IS_MCS(rspec)) {
7792                 WL_ERROR(("wl%d: recd beacon with mcs rate; rspec 0x%x\n",
7793                           wlc->pub->unit, rspec));
7794         } else if (IS_OFDM(rspec)) {
7795                 /* tx delay from MAC through phy to air (2.1 usec) +
7796                  * phy header time (preamble + PLCP SIGNAL == 20 usec) +
7797                  * PLCP SERVICE + MAC header time (SERVICE + FC + DUR + A1 + A2 + A3 + SEQ == 26
7798                  * bytes at beacon rate)
7799                  */
7800                 bcntsfoff += phydelay ? D11A_PHY_TX_DELAY : 0;
7801                 bcntsfoff += APHY_PREAMBLE_TIME + APHY_SIGNAL_TIME;
7802                 bcntsfoff +=
7803                     wlc_compute_airtime(wlc, rspec,
7804                                         APHY_SERVICE_NBITS / 8 +
7805                                         DOT11_MAC_HDR_LEN);
7806         } else {
7807                 /* tx delay from MAC through phy to air (3.4 usec) +
7808                  * phy header time (long preamble + PLCP == 192 usec) +
7809                  * MAC header time (FC + DUR + A1 + A2 + A3 + SEQ == 24 bytes at beacon rate)
7810                  */
7811                 bcntsfoff += phydelay ? D11B_PHY_TX_DELAY : 0;
7812                 bcntsfoff +=
7813                     short_preamble ? D11B_PHY_SPREHDR_TIME :
7814                     D11B_PHY_LPREHDR_TIME;
7815                 bcntsfoff += wlc_compute_airtime(wlc, rspec, DOT11_MAC_HDR_LEN);
7816         }
7817         return (u16) (bcntsfoff);
7818 }
7819
7820 /*      Max buffering needed for beacon template/prb resp template is 142 bytes.
7821  *
7822  *      PLCP header is 6 bytes.
7823  *      802.11 A3 header is 24 bytes.
7824  *      Max beacon frame body template length is 112 bytes.
7825  *      Max probe resp frame body template length is 110 bytes.
7826  *
7827  *      *len on input contains the max length of the packet available.
7828  *
7829  *      The *len value is set to the number of bytes in buf used, and starts with the PLCP
7830  *      and included up to, but not including, the 4 byte FCS.
7831  */
7832 static void
7833 wlc_bcn_prb_template(wlc_info_t *wlc, uint type, ratespec_t bcn_rspec,
7834                      wlc_bsscfg_t *cfg, u16 *buf, int *len)
7835 {
7836         cck_phy_hdr_t *plcp;
7837         struct dot11_management_header *h;
7838         int hdr_len, body_len;
7839
7840         ASSERT(*len >= 142);
7841         ASSERT(type == FC_BEACON || type == FC_PROBE_RESP);
7842
7843         if (MBSS_BCN_ENAB(cfg) && type == FC_BEACON)
7844                 hdr_len = DOT11_MAC_HDR_LEN;
7845         else
7846                 hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN;
7847         body_len = *len - hdr_len;      /* calc buffer size provided for frame body */
7848
7849         *len = hdr_len + body_len;      /* return actual size */
7850
7851         /* format PHY and MAC headers */
7852         bzero((char *)buf, hdr_len);
7853
7854         plcp = (cck_phy_hdr_t *) buf;
7855
7856         /* PLCP for Probe Response frames are filled in from core's rate table */
7857         if (type == FC_BEACON && !MBSS_BCN_ENAB(cfg)) {
7858                 /* fill in PLCP */
7859                 wlc_compute_plcp(wlc, bcn_rspec,
7860                                  (DOT11_MAC_HDR_LEN + body_len + DOT11_FCS_LEN),
7861                                  (u8 *) plcp);
7862
7863         }
7864         /* "Regular" and 16 MBSS but not for 4 MBSS */
7865         /* Update the phytxctl for the beacon based on the rspec */
7866         if (!SOFTBCN_ENAB(cfg))
7867                 wlc_beacon_phytxctl_txant_upd(wlc, bcn_rspec);
7868
7869         if (MBSS_BCN_ENAB(cfg) && type == FC_BEACON)
7870                 h = (struct dot11_management_header *)&plcp[0];
7871         else
7872                 h = (struct dot11_management_header *)&plcp[1];
7873
7874         /* fill in 802.11 header */
7875         h->fc = htol16((u16) type);
7876
7877         /* DUR is 0 for multicast bcn, or filled in by MAC for prb resp */
7878         /* A1 filled in by MAC for prb resp, broadcast for bcn */
7879         if (type == FC_BEACON)
7880                 bcopy((const char *)&ether_bcast, (char *)&h->da,
7881                       ETHER_ADDR_LEN);
7882         bcopy((char *)&cfg->cur_etheraddr, (char *)&h->sa, ETHER_ADDR_LEN);
7883         bcopy((char *)&cfg->BSSID, (char *)&h->bssid, ETHER_ADDR_LEN);
7884
7885         /* SEQ filled in by MAC */
7886
7887         return;
7888 }
7889
7890 int wlc_get_header_len()
7891 {
7892         return TXOFF;
7893 }
7894
7895 /* Update a beacon for a particular BSS
7896  * For MBSS, this updates the software template and sets "latest" to the index of the
7897  * template updated.
7898  * Otherwise, it updates the hardware template.
7899  */
7900 void wlc_bss_update_beacon(wlc_info_t *wlc, wlc_bsscfg_t *cfg)
7901 {
7902         int len = BCN_TMPL_LEN;
7903
7904         /* Clear the soft intmask */
7905         wlc->defmacintmask &= ~MI_BCNTPL;
7906
7907         if (!cfg->up) {         /* Only allow updates on an UP bss */
7908                 return;
7909         }
7910
7911         if (MBSS_BCN_ENAB(cfg)) {       /* Optimize:  Some of if/else could be combined */
7912         } else if (HWBCN_ENAB(cfg)) {   /* Hardware beaconing for this config */
7913                 u16 bcn[BCN_TMPL_LEN / 2];
7914                 u32 both_valid = MCMD_BCN0VLD | MCMD_BCN1VLD;
7915                 d11regs_t *regs = wlc->regs;
7916                 osl_t *osh = NULL;
7917
7918                 osh = wlc->osh;
7919
7920                 /* Check if both templates are in use, if so sched. an interrupt
7921                  *      that will call back into this routine
7922                  */
7923                 if ((R_REG(osh, &regs->maccommand) & both_valid) == both_valid) {
7924                         /* clear any previous status */
7925                         W_REG(osh, &regs->macintstatus, MI_BCNTPL);
7926                 }
7927                 /* Check that after scheduling the interrupt both of the
7928                  *      templates are still busy. if not clear the int. & remask
7929                  */
7930                 if ((R_REG(osh, &regs->maccommand) & both_valid) == both_valid) {
7931                         wlc->defmacintmask |= MI_BCNTPL;
7932                         return;
7933                 }
7934
7935                 wlc->bcn_rspec =
7936                     wlc_lowest_basic_rspec(wlc, &cfg->current_bss->rateset);
7937                 ASSERT(wlc_valid_rate
7938                        (wlc, wlc->bcn_rspec,
7939                         CHSPEC_IS2G(cfg->current_bss->
7940                                     chanspec) ? WLC_BAND_2G : WLC_BAND_5G,
7941                         TRUE));
7942
7943                 /* update the template and ucode shm */
7944                 wlc_bcn_prb_template(wlc, FC_BEACON, wlc->bcn_rspec, cfg, bcn,
7945                                      &len);
7946                 wlc_write_hw_bcntemplates(wlc, bcn, len, FALSE);
7947         }
7948 }
7949
7950 /*
7951  * Update all beacons for the system.
7952  */
7953 void wlc_update_beacon(wlc_info_t *wlc)
7954 {
7955         int idx;
7956         wlc_bsscfg_t *bsscfg;
7957
7958         /* update AP or IBSS beacons */
7959         FOREACH_BSS(wlc, idx, bsscfg) {
7960                 if (bsscfg->up && (BSSCFG_AP(bsscfg) || !bsscfg->BSS))
7961                         wlc_bss_update_beacon(wlc, bsscfg);
7962         }
7963 }
7964
7965 /* Write ssid into shared memory */
7966 void wlc_shm_ssid_upd(wlc_info_t *wlc, wlc_bsscfg_t *cfg)
7967 {
7968         u8 *ssidptr = cfg->SSID;
7969         u16 base = M_SSID;
7970         u8 ssidbuf[DOT11_MAX_SSID_LEN];
7971
7972         /* padding the ssid with zero and copy it into shm */
7973         bzero(ssidbuf, DOT11_MAX_SSID_LEN);
7974         bcopy(ssidptr, ssidbuf, cfg->SSID_len);
7975
7976         wlc_copyto_shm(wlc, base, ssidbuf, DOT11_MAX_SSID_LEN);
7977
7978         if (!MBSS_BCN_ENAB(cfg))
7979                 wlc_write_shm(wlc, M_SSIDLEN, (u16) cfg->SSID_len);
7980 }
7981
7982 void wlc_update_probe_resp(wlc_info_t *wlc, bool suspend)
7983 {
7984         int idx;
7985         wlc_bsscfg_t *bsscfg;
7986
7987         /* update AP or IBSS probe responses */
7988         FOREACH_BSS(wlc, idx, bsscfg) {
7989                 if (bsscfg->up && (BSSCFG_AP(bsscfg) || !bsscfg->BSS))
7990                         wlc_bss_update_probe_resp(wlc, bsscfg, suspend);
7991         }
7992 }
7993
7994 void
7995 wlc_bss_update_probe_resp(wlc_info_t *wlc, wlc_bsscfg_t *cfg, bool suspend)
7996 {
7997         u16 prb_resp[BCN_TMPL_LEN / 2];
7998         int len = BCN_TMPL_LEN;
7999
8000         /* write the probe response to hardware, or save in the config structure */
8001         if (!MBSS_PRB_ENAB(cfg)) {
8002
8003                 /* create the probe response template */
8004                 wlc_bcn_prb_template(wlc, FC_PROBE_RESP, 0, cfg, prb_resp,
8005                                      &len);
8006
8007                 if (suspend)
8008                         wlc_suspend_mac_and_wait(wlc);
8009
8010                 /* write the probe response into the template region */
8011                 wlc_bmac_write_template_ram(wlc->hw, T_PRS_TPL_BASE,
8012                                             (len + 3) & ~3, prb_resp);
8013
8014                 /* write the length of the probe response frame (+PLCP/-FCS) */
8015                 wlc_write_shm(wlc, M_PRB_RESP_FRM_LEN, (u16) len);
8016
8017                 /* write the SSID and SSID length */
8018                 wlc_shm_ssid_upd(wlc, cfg);
8019
8020                 /*
8021                  * Write PLCP headers and durations for probe response frames at all rates.
8022                  * Use the actual frame length covered by the PLCP header for the call to
8023                  * wlc_mod_prb_rsp_rate_table() by subtracting the PLCP len and adding the FCS.
8024                  */
8025                 len += (-D11_PHY_HDR_LEN + DOT11_FCS_LEN);
8026                 wlc_mod_prb_rsp_rate_table(wlc, (u16) len);
8027
8028                 if (suspend)
8029                         wlc_enable_mac(wlc);
8030         } else {                /* Generating probe resp in sw; update local template */
8031                 ASSERT(0 && "No software probe response support without MBSS");
8032         }
8033 }
8034
8035 /* prepares pdu for transmission. returns BCM error codes */
8036 int wlc_prep_pdu(wlc_info_t *wlc, void *pdu, uint *fifop)
8037 {
8038         osl_t *osh;
8039         uint fifo;
8040         d11txh_t *txh;
8041         struct dot11_header *h;
8042         struct scb *scb;
8043         u16 fc;
8044
8045         osh = wlc->osh;
8046
8047         ASSERT(pdu);
8048         txh = (d11txh_t *) PKTDATA(pdu);
8049         ASSERT(txh);
8050         h = (struct dot11_header *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
8051         ASSERT(h);
8052         fc = ltoh16(h->fc);
8053
8054         /* get the pkt queue info. This was put at wlc_sendctl or wlc_send for PDU */
8055         fifo = ltoh16(txh->TxFrameID) & TXFID_QUEUE_MASK;
8056
8057         scb = NULL;
8058
8059         *fifop = fifo;
8060
8061         /* return if insufficient dma resources */
8062         if (TXAVAIL(wlc, fifo) < MAX_DMA_SEGS) {
8063                 /* Mark precedences related to this FIFO, unsendable */
8064                 WLC_TX_FIFO_CLEAR(wlc, fifo);
8065                 return BCME_BUSY;
8066         }
8067
8068         if (FC_TYPE(ltoh16(txh->MacFrameControl)) != FC_TYPE_DATA)
8069                 WLCNTINCR(wlc->pub->_cnt->txctl);
8070
8071         return 0;
8072 }
8073
8074 /* init tx reported rate mechanism */
8075 void wlc_reprate_init(wlc_info_t *wlc)
8076 {
8077         int i;
8078         wlc_bsscfg_t *bsscfg;
8079
8080         FOREACH_BSS(wlc, i, bsscfg) {
8081                 wlc_bsscfg_reprate_init(bsscfg);
8082         }
8083 }
8084
8085 /* per bsscfg init tx reported rate mechanism */
8086 void wlc_bsscfg_reprate_init(wlc_bsscfg_t *bsscfg)
8087 {
8088         bsscfg->txrspecidx = 0;
8089         bzero((char *)bsscfg->txrspec, sizeof(bsscfg->txrspec));
8090 }
8091
8092 /* Retrieve a consolidated set of revision information,
8093  * typically for the WLC_GET_REVINFO ioctl
8094  */
8095 int wlc_get_revision_info(wlc_info_t *wlc, void *buf, uint len)
8096 {
8097         wlc_rev_info_t *rinfo = (wlc_rev_info_t *) buf;
8098
8099         if (len < WL_REV_INFO_LEGACY_LENGTH)
8100                 return BCME_BUFTOOSHORT;
8101
8102         rinfo->vendorid = wlc->vendorid;
8103         rinfo->deviceid = wlc->deviceid;
8104         rinfo->radiorev = (wlc->band->radiorev << IDCODE_REV_SHIFT) |
8105             (wlc->band->radioid << IDCODE_ID_SHIFT);
8106         rinfo->chiprev = wlc->pub->sih->chiprev;
8107         rinfo->corerev = wlc->pub->corerev;
8108         rinfo->boardid = wlc->pub->sih->boardtype;
8109         rinfo->boardvendor = wlc->pub->sih->boardvendor;
8110         rinfo->boardrev = wlc->pub->boardrev;
8111         rinfo->ucoderev = wlc->ucode_rev;
8112         rinfo->driverrev = EPI_VERSION_NUM;
8113         rinfo->bus = wlc->pub->sih->bustype;
8114         rinfo->chipnum = wlc->pub->sih->chip;
8115
8116         if (len >= (offsetof(wlc_rev_info_t, chippkg))) {
8117                 rinfo->phytype = wlc->band->phytype;
8118                 rinfo->phyrev = wlc->band->phyrev;
8119                 rinfo->anarev = 0;      /* obsolete stuff, suppress */
8120         }
8121
8122         if (len >= sizeof(*rinfo)) {
8123                 rinfo->chippkg = wlc->pub->sih->chippkg;
8124         }
8125
8126         return BCME_OK;
8127 }
8128
8129 void wlc_default_rateset(wlc_info_t *wlc, wlc_rateset_t *rs)
8130 {
8131         wlc_rateset_default(rs, NULL, wlc->band->phytype, wlc->band->bandtype,
8132                             FALSE, RATE_MASK_FULL, (bool) N_ENAB(wlc->pub),
8133                             CHSPEC_WLC_BW(wlc->default_bss->chanspec),
8134                             wlc->stf->txstreams);
8135 }
8136
8137 static void wlc_bss_default_init(wlc_info_t *wlc)
8138 {
8139         chanspec_t chanspec;
8140         wlcband_t *band;
8141         wlc_bss_info_t *bi = wlc->default_bss;
8142
8143         /* init default and target BSS with some sane initial values */
8144         bzero((char *)(bi), sizeof(wlc_bss_info_t));
8145         bi->beacon_period = ISSIM_ENAB(wlc->pub->sih) ? BEACON_INTERVAL_DEF_QT :
8146             BEACON_INTERVAL_DEFAULT;
8147         bi->dtim_period = ISSIM_ENAB(wlc->pub->sih) ? DTIM_INTERVAL_DEF_QT :
8148             DTIM_INTERVAL_DEFAULT;
8149
8150         /* fill the default channel as the first valid channel
8151          * starting from the 2G channels
8152          */
8153         chanspec = CH20MHZ_CHSPEC(1);
8154         ASSERT(chanspec != INVCHANSPEC);
8155
8156         wlc->home_chanspec = bi->chanspec = chanspec;
8157
8158         /* find the band of our default channel */
8159         band = wlc->band;
8160         if (NBANDS(wlc) > 1 && band->bandunit != CHSPEC_WLCBANDUNIT(chanspec))
8161                 band = wlc->bandstate[OTHERBANDUNIT(wlc)];
8162
8163         /* init bss rates to the band specific default rate set */
8164         wlc_rateset_default(&bi->rateset, NULL, band->phytype, band->bandtype,
8165                             FALSE, RATE_MASK_FULL, (bool) N_ENAB(wlc->pub),
8166                             CHSPEC_WLC_BW(chanspec), wlc->stf->txstreams);
8167
8168         if (N_ENAB(wlc->pub))
8169                 bi->flags |= WLC_BSS_HT;
8170 }
8171
8172 /* Deferred event processing */
8173 static void wlc_process_eventq(void *arg)
8174 {
8175         wlc_info_t *wlc = (wlc_info_t *) arg;
8176         wlc_event_t *etmp;
8177
8178         while ((etmp = wlc_eventq_deq(wlc->eventq))) {
8179                 /* Perform OS specific event processing */
8180                 wl_event(wlc->wl, etmp->event.ifname, etmp);
8181                 if (etmp->data) {
8182                         osl_mfree(wlc->osh, etmp->data, etmp->event.datalen);
8183                         etmp->data = NULL;
8184                 }
8185                 wlc_event_free(wlc->eventq, etmp);
8186         }
8187 }
8188
8189 void
8190 wlc_uint64_sub(u32 *a_high, u32 *a_low, u32 b_high, u32 b_low)
8191 {
8192         if (b_low > *a_low) {
8193                 /* low half needs a carry */
8194                 b_high += 1;
8195         }
8196         *a_low -= b_low;
8197         *a_high -= b_high;
8198 }
8199
8200 static ratespec_t
8201 mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band, u32 int_val)
8202 {
8203         u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT;
8204         u8 rate = int_val & NRATE_RATE_MASK;
8205         ratespec_t rspec;
8206         bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE);
8207         bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT);
8208         bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY)
8209                                   == NRATE_OVERRIDE_MCS_ONLY);
8210         int bcmerror = 0;
8211
8212         if (!ismcs) {
8213                 return (ratespec_t) rate;
8214         }
8215
8216         /* validate the combination of rate/mcs/stf is allowed */
8217         if (N_ENAB(wlc->pub) && ismcs) {
8218                 /* mcs only allowed when nmode */
8219                 if (stf > PHY_TXC1_MODE_SDM) {
8220                         WL_ERROR(("wl%d: %s: Invalid stf\n", WLCWLUNIT(wlc),
8221                                   __func__));
8222                         bcmerror = BCME_RANGE;
8223                         goto done;
8224                 }
8225
8226                 /* mcs 32 is a special case, DUP mode 40 only */
8227                 if (rate == 32) {
8228                         if (!CHSPEC_IS40(wlc->home_chanspec) ||
8229                             ((stf != PHY_TXC1_MODE_SISO)
8230                              && (stf != PHY_TXC1_MODE_CDD))) {
8231                                 WL_ERROR(("wl%d: %s: Invalid mcs 32\n",
8232                                           WLCWLUNIT(wlc), __func__));
8233                                 bcmerror = BCME_RANGE;
8234                                 goto done;
8235                         }
8236                         /* mcs > 7 must use stf SDM */
8237                 } else if (rate > HIGHEST_SINGLE_STREAM_MCS) {
8238                         /* mcs > 7 must use stf SDM */
8239                         if (stf != PHY_TXC1_MODE_SDM) {
8240                                 WL_TRACE(("wl%d: %s: enabling SDM mode for mcs %d\n", WLCWLUNIT(wlc), __func__, rate));
8241                                 stf = PHY_TXC1_MODE_SDM;
8242                         }
8243                 } else {
8244                         /* MCS 0-7 may use SISO, CDD, and for phy_rev >= 3 STBC */
8245                         if ((stf > PHY_TXC1_MODE_STBC) ||
8246                             (!WLC_STBC_CAP_PHY(wlc)
8247                              && (stf == PHY_TXC1_MODE_STBC))) {
8248                                 WL_ERROR(("wl%d: %s: Invalid STBC\n",
8249                                           WLCWLUNIT(wlc), __func__));
8250                                 bcmerror = BCME_RANGE;
8251                                 goto done;
8252                         }
8253                 }
8254         } else if (IS_OFDM(rate)) {
8255                 if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {
8256                         WL_ERROR(("wl%d: %s: Invalid OFDM\n", WLCWLUNIT(wlc),
8257                                   __func__));
8258                         bcmerror = BCME_RANGE;
8259                         goto done;
8260                 }
8261         } else if (IS_CCK(rate)) {
8262                 if ((cur_band->bandtype != WLC_BAND_2G)
8263                     || (stf != PHY_TXC1_MODE_SISO)) {
8264                         WL_ERROR(("wl%d: %s: Invalid CCK\n", WLCWLUNIT(wlc),
8265                                   __func__));
8266                         bcmerror = BCME_RANGE;
8267                         goto done;
8268                 }
8269         } else {
8270                 WL_ERROR(("wl%d: %s: Unknown rate type\n", WLCWLUNIT(wlc),
8271                           __func__));
8272                 bcmerror = BCME_RANGE;
8273                 goto done;
8274         }
8275         /* make sure multiple antennae are available for non-siso rates */
8276         if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) {
8277                 WL_ERROR(("wl%d: %s: SISO antenna but !SISO request\n",
8278                           WLCWLUNIT(wlc), __func__));
8279                 bcmerror = BCME_RANGE;
8280                 goto done;
8281         }
8282
8283         rspec = rate;
8284         if (ismcs) {
8285                 rspec |= RSPEC_MIMORATE;
8286                 /* For STBC populate the STC field of the ratespec */
8287                 if (stf == PHY_TXC1_MODE_STBC) {
8288                         u8 stc;
8289                         stc = 1;        /* Nss for single stream is always 1 */
8290                         rspec |= (stc << RSPEC_STC_SHIFT);
8291                 }
8292         }
8293
8294         rspec |= (stf << RSPEC_STF_SHIFT);
8295
8296         if (override_mcs_only)
8297                 rspec |= RSPEC_OVERRIDE_MCS_ONLY;
8298
8299         if (issgi)
8300                 rspec |= RSPEC_SHORT_GI;
8301
8302         if ((rate != 0)
8303             && !wlc_valid_rate(wlc, rspec, cur_band->bandtype, TRUE)) {
8304                 return rate;
8305         }
8306
8307         return rspec;
8308  done:
8309         WL_ERROR(("Hoark\n"));
8310         return rate;
8311 }
8312
8313 /* formula:  IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */
8314 static int
8315 wlc_duty_cycle_set(wlc_info_t *wlc, int duty_cycle, bool isOFDM,
8316                    bool writeToShm)
8317 {
8318         int idle_busy_ratio_x_16 = 0;
8319         uint offset =
8320             isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM :
8321             M_TX_IDLE_BUSY_RATIO_X_16_CCK;
8322         if (duty_cycle > 100 || duty_cycle < 0) {
8323                 WL_ERROR(("wl%d:  duty cycle value off limit\n",
8324                           wlc->pub->unit));
8325                 return BCME_RANGE;
8326         }
8327         if (duty_cycle)
8328                 idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle;
8329         /* Only write to shared memory  when wl is up */
8330         if (writeToShm)
8331                 wlc_write_shm(wlc, offset, (u16) idle_busy_ratio_x_16);
8332
8333         if (isOFDM)
8334                 wlc->tx_duty_cycle_ofdm = (u16) duty_cycle;
8335         else
8336                 wlc->tx_duty_cycle_cck = (u16) duty_cycle;
8337
8338         return BCME_OK;
8339 }
8340
8341 /* Read a single u16 from shared memory.
8342  * SHM 'offset' needs to be an even address
8343  */
8344 u16 wlc_read_shm(wlc_info_t *wlc, uint offset)
8345 {
8346         return wlc_bmac_read_shm(wlc->hw, offset);
8347 }
8348
8349 /* Write a single u16 to shared memory.
8350  * SHM 'offset' needs to be an even address
8351  */
8352 void wlc_write_shm(wlc_info_t *wlc, uint offset, u16 v)
8353 {
8354         wlc_bmac_write_shm(wlc->hw, offset, v);
8355 }
8356
8357 /* Set a range of shared memory to a value.
8358  * SHM 'offset' needs to be an even address and
8359  * Range length 'len' must be an even number of bytes
8360  */
8361 void wlc_set_shm(wlc_info_t *wlc, uint offset, u16 v, int len)
8362 {
8363         /* offset and len need to be even */
8364         ASSERT((offset & 1) == 0);
8365         ASSERT((len & 1) == 0);
8366
8367         if (len <= 0)
8368                 return;
8369
8370         wlc_bmac_set_shm(wlc->hw, offset, v, len);
8371 }
8372
8373 /* Copy a buffer to shared memory.
8374  * SHM 'offset' needs to be an even address and
8375  * Buffer length 'len' must be an even number of bytes
8376  */
8377 void wlc_copyto_shm(wlc_info_t *wlc, uint offset, const void *buf, int len)
8378 {
8379         /* offset and len need to be even */
8380         ASSERT((offset & 1) == 0);
8381         ASSERT((len & 1) == 0);
8382
8383         if (len <= 0)
8384                 return;
8385         wlc_bmac_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL);
8386
8387 }
8388
8389 /* Copy from shared memory to a buffer.
8390  * SHM 'offset' needs to be an even address and
8391  * Buffer length 'len' must be an even number of bytes
8392  */
8393 void wlc_copyfrom_shm(wlc_info_t *wlc, uint offset, void *buf, int len)
8394 {
8395         /* offset and len need to be even */
8396         ASSERT((offset & 1) == 0);
8397         ASSERT((len & 1) == 0);
8398
8399         if (len <= 0)
8400                 return;
8401
8402         wlc_bmac_copyfrom_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL);
8403 }
8404
8405 /* wrapper BMAC functions to for HIGH driver access */
8406 void wlc_mctrl(wlc_info_t *wlc, u32 mask, u32 val)
8407 {
8408         wlc_bmac_mctrl(wlc->hw, mask, val);
8409 }
8410
8411 void wlc_corereset(wlc_info_t *wlc, u32 flags)
8412 {
8413         wlc_bmac_corereset(wlc->hw, flags);
8414 }
8415
8416 void wlc_mhf(wlc_info_t *wlc, u8 idx, u16 mask, u16 val, int bands)
8417 {
8418         wlc_bmac_mhf(wlc->hw, idx, mask, val, bands);
8419 }
8420
8421 u16 wlc_mhf_get(wlc_info_t *wlc, u8 idx, int bands)
8422 {
8423         return wlc_bmac_mhf_get(wlc->hw, idx, bands);
8424 }
8425
8426 int wlc_xmtfifo_sz_get(wlc_info_t *wlc, uint fifo, uint *blocks)
8427 {
8428         return wlc_bmac_xmtfifo_sz_get(wlc->hw, fifo, blocks);
8429 }
8430
8431 void wlc_write_template_ram(wlc_info_t *wlc, int offset, int len, void *buf)
8432 {
8433         wlc_bmac_write_template_ram(wlc->hw, offset, len, buf);
8434 }
8435
8436 void wlc_write_hw_bcntemplates(wlc_info_t *wlc, void *bcn, int len, bool both)
8437 {
8438         wlc_bmac_write_hw_bcntemplates(wlc->hw, bcn, len, both);
8439 }
8440
8441 void
8442 wlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset,
8443                   const struct ether_addr *addr)
8444 {
8445         wlc_bmac_set_addrmatch(wlc->hw, match_reg_offset, addr);
8446 }
8447
8448 void wlc_set_rcmta(wlc_info_t *wlc, int idx, const struct ether_addr *addr)
8449 {
8450         wlc_bmac_set_rcmta(wlc->hw, idx, addr);
8451 }
8452
8453 void wlc_read_tsf(wlc_info_t *wlc, u32 *tsf_l_ptr, u32 *tsf_h_ptr)
8454 {
8455         wlc_bmac_read_tsf(wlc->hw, tsf_l_ptr, tsf_h_ptr);
8456 }
8457
8458 void wlc_set_cwmin(wlc_info_t *wlc, u16 newmin)
8459 {
8460         wlc->band->CWmin = newmin;
8461         wlc_bmac_set_cwmin(wlc->hw, newmin);
8462 }
8463
8464 void wlc_set_cwmax(wlc_info_t *wlc, u16 newmax)
8465 {
8466         wlc->band->CWmax = newmax;
8467         wlc_bmac_set_cwmax(wlc->hw, newmax);
8468 }
8469
8470 void wlc_fifoerrors(wlc_info_t *wlc)
8471 {
8472
8473         wlc_bmac_fifoerrors(wlc->hw);
8474 }
8475
8476 /* Search mem rw utilities */
8477
8478 void wlc_pllreq(wlc_info_t *wlc, bool set, mbool req_bit)
8479 {
8480         wlc_bmac_pllreq(wlc->hw, set, req_bit);
8481 }
8482
8483 void wlc_reset_bmac_done(wlc_info_t *wlc)
8484 {
8485 #ifdef WLC_HIGH_ONLY
8486         wlc->reset_bmac_pending = FALSE;
8487 #endif
8488 }
8489
8490 void wlc_ht_mimops_cap_update(wlc_info_t *wlc, u8 mimops_mode)
8491 {
8492         wlc->ht_cap.cap &= ~HT_CAP_MIMO_PS_MASK;
8493         wlc->ht_cap.cap |= (mimops_mode << HT_CAP_MIMO_PS_SHIFT);
8494
8495         if (AP_ENAB(wlc->pub) && wlc->clk) {
8496                 wlc_update_beacon(wlc);
8497                 wlc_update_probe_resp(wlc, TRUE);
8498         }
8499 }
8500
8501 /* check for the particular priority flow control bit being set */
8502 bool
8503 wlc_txflowcontrol_prio_isset(wlc_info_t *wlc, wlc_txq_info_t *q, int prio)
8504 {
8505         uint prio_mask;
8506
8507         if (prio == ALLPRIO) {
8508                 prio_mask = TXQ_STOP_FOR_PRIOFC_MASK;
8509         } else {
8510                 ASSERT(prio >= 0 && prio <= MAXPRIO);
8511                 prio_mask = NBITVAL(prio);
8512         }
8513
8514         return (q->stopped & prio_mask) == prio_mask;
8515 }
8516
8517 /* propogate the flow control to all interfaces using the given tx queue */
8518 void wlc_txflowcontrol(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, int prio)
8519 {
8520         uint prio_bits;
8521         uint cur_bits;
8522
8523         WL_ERROR(("%s: flow contro kicks in\n", __func__));
8524
8525         if (prio == ALLPRIO) {
8526                 prio_bits = TXQ_STOP_FOR_PRIOFC_MASK;
8527         } else {
8528                 ASSERT(prio >= 0 && prio <= MAXPRIO);
8529                 prio_bits = NBITVAL(prio);
8530         }
8531
8532         cur_bits = qi->stopped & prio_bits;
8533
8534         /* Check for the case of no change and return early
8535          * Otherwise update the bit and continue
8536          */
8537         if (on) {
8538                 if (cur_bits == prio_bits) {
8539                         return;
8540                 }
8541                 mboolset(qi->stopped, prio_bits);
8542         } else {
8543                 if (cur_bits == 0) {
8544                         return;
8545                 }
8546                 mboolclr(qi->stopped, prio_bits);
8547         }
8548
8549         /* If there is a flow control override we will not change the external
8550          * flow control state.
8551          */
8552         if (qi->stopped & ~TXQ_STOP_FOR_PRIOFC_MASK) {
8553                 return;
8554         }
8555
8556         wlc_txflowcontrol_signal(wlc, qi, on, prio);
8557 }
8558
8559 void
8560 wlc_txflowcontrol_override(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on,
8561                            uint override)
8562 {
8563         uint prev_override;
8564
8565         ASSERT(override != 0);
8566         ASSERT((override & TXQ_STOP_FOR_PRIOFC_MASK) == 0);
8567
8568         prev_override = (qi->stopped & ~TXQ_STOP_FOR_PRIOFC_MASK);
8569
8570         /* Update the flow control bits and do an early return if there is
8571          * no change in the external flow control state.
8572          */
8573         if (on) {
8574                 mboolset(qi->stopped, override);
8575                 /* if there was a previous override bit on, then setting this
8576                  * makes no difference.
8577                  */
8578                 if (prev_override) {
8579                         return;
8580                 }
8581
8582                 wlc_txflowcontrol_signal(wlc, qi, ON, ALLPRIO);
8583         } else {
8584                 mboolclr(qi->stopped, override);
8585                 /* clearing an override bit will only make a difference for
8586                  * flow control if it was the only bit set. For any other
8587                  * override setting, just return
8588                  */
8589                 if (prev_override != override) {
8590                         return;
8591                 }
8592
8593                 if (qi->stopped == 0) {
8594                         wlc_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO);
8595                 } else {
8596                         int prio;
8597
8598                         for (prio = MAXPRIO; prio >= 0; prio--) {
8599                                 if (!mboolisset(qi->stopped, NBITVAL(prio)))
8600                                         wlc_txflowcontrol_signal(wlc, qi, OFF,
8601                                                                  prio);
8602                         }
8603                 }
8604         }
8605 }
8606
8607 static void wlc_txflowcontrol_reset(wlc_info_t *wlc)
8608 {
8609         wlc_txq_info_t *qi;
8610
8611         for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) {
8612                 if (qi->stopped) {
8613                         wlc_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO);
8614                         qi->stopped = 0;
8615                 }
8616         }
8617 }
8618
8619 static void
8620 wlc_txflowcontrol_signal(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on,
8621                          int prio)
8622 {
8623         wlc_if_t *wlcif;
8624
8625         for (wlcif = wlc->wlcif_list; wlcif != NULL; wlcif = wlcif->next) {
8626                 if (wlcif->qi == qi && wlcif->flags & WLC_IF_LINKED)
8627                         wl_txflowcontrol(wlc->wl, wlcif->wlif, on, prio);
8628         }
8629 }
8630
8631 static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, osl_t *osh)
8632 {
8633         wlc_txq_info_t *qi, *p;
8634
8635         qi = (wlc_txq_info_t *) wlc_calloc(osh, wlc->pub->unit,
8636                                            sizeof(wlc_txq_info_t));
8637         if (qi == NULL) {
8638                 return NULL;
8639         }
8640
8641         /* Have enough room for control packets along with HI watermark */
8642         /* Also, add room to txq for total psq packets if all the SCBs leave PS mode */
8643         /* The watermark for flowcontrol to OS packets will remain the same */
8644         pktq_init(&qi->q, WLC_PREC_COUNT,
8645                   (2 * wlc->pub->tunables->datahiwat) + PKTQ_LEN_DEFAULT +
8646                   wlc->pub->psq_pkts_total);
8647
8648         /* add this queue to the the global list */
8649         p = wlc->tx_queues;
8650         if (p == NULL) {
8651                 wlc->tx_queues = qi;
8652         } else {
8653                 while (p->next != NULL)
8654                         p = p->next;
8655                 p->next = qi;
8656         }
8657
8658         return qi;
8659 }
8660
8661 static void wlc_txq_free(wlc_info_t *wlc, osl_t *osh, wlc_txq_info_t *qi)
8662 {
8663         wlc_txq_info_t *p;
8664
8665         if (qi == NULL)
8666                 return;
8667
8668         /* remove the queue from the linked list */
8669         p = wlc->tx_queues;
8670         if (p == qi)
8671                 wlc->tx_queues = p->next;
8672         else {
8673                 while (p != NULL && p->next != qi)
8674                         p = p->next;
8675                 ASSERT(p->next == qi);
8676                 if (p != NULL)
8677                         p->next = p->next->next;
8678         }
8679
8680         osl_mfree(osh, qi, sizeof(wlc_txq_info_t));
8681 }