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