]>
Commit | Line | Data |
---|---|---|
a9533e7e HP |
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 | */ | |
3bec7bb9 | 16 | |
be1c09f9 | 17 | #include <linux/pci_ids.h> |
5973f660 | 18 | #include <linux/if_ether.h> |
45575664 | 19 | #include <net/mac80211.h> |
cc3cea5a | 20 | #include <brcm_hw_ids.h> |
27302e8f | 21 | #include <aiutils.h> |
8702fee6 | 22 | #include <chipcommon.h> |
cc3cea5a RV |
23 | #include "rate.h" |
24 | #include "scb.h" | |
cc3cea5a RV |
25 | #include "phy/phy_hal.h" |
26 | #include "channel.h" | |
cc3cea5a RV |
27 | #include "antsel.h" |
28 | #include "stf.h" | |
29 | #include "ampdu.h" | |
30 | #include "alloc.h" | |
31 | #include "mac80211_if.h" | |
8702fee6 | 32 | #include "ucode_loader.h" |
3bec7bb9 | 33 | #include "main.h" |
8c2c8216 | 34 | |
8702fee6 | 35 | |
35af8764 AS |
36 | /* |
37 | * WPA(2) definitions | |
38 | */ | |
39 | #define RSN_CAP_4_REPLAY_CNTRS 2 | |
40 | #define RSN_CAP_16_REPLAY_CNTRS 3 | |
41 | ||
42 | #define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS | |
43 | #define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS | |
44 | ||
70dfb584 AS |
45 | /* |
46 | * Indication for txflowcontrol that all priority bits in | |
47 | * TXQ_STOP_FOR_PRIOFC_MASK are to be considered. | |
48 | */ | |
49 | #define ALLPRIO -1 | |
50 | ||
a9533e7e | 51 | /* |
a9533e7e HP |
52 | * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL. |
53 | */ | |
3726ed4d | 54 | #define SSID_FMT_BUF_LEN ((4 * IEEE80211_MAX_SSID_LEN) + 1) |
a9533e7e | 55 | |
419ad34e AS |
56 | /* watchdog timer, in unit of ms */ |
57 | #define TIMER_INTERVAL_WATCHDOG 1000 | |
58 | /* radio monitor timer, in unit of ms */ | |
59 | #define TIMER_INTERVAL_RADIOCHK 800 | |
a9533e7e | 60 | |
7c783cef RV |
61 | /* Max MPC timeout, in unit of watchdog */ |
62 | #ifndef BRCMS_MPC_MAX_DELAYCNT | |
63 | #define BRCMS_MPC_MAX_DELAYCNT 10 | |
a9533e7e | 64 | #endif |
7c783cef RV |
65 | |
66 | /* Min MPC timeout, in unit of watchdog */ | |
67 | #define BRCMS_MPC_MIN_DELAYCNT 1 | |
68 | #define BRCMS_MPC_THRESHOLD 3 /* MPC count threshold level */ | |
a9533e7e | 69 | |
419ad34e AS |
70 | /* beacon interval, in unit of 1024TU */ |
71 | #define BEACON_INTERVAL_DEFAULT 100 | |
72 | /* DTIM interval, in unit of beacon interval */ | |
73 | #define DTIM_INTERVAL_DEFAULT 3 | |
a9533e7e HP |
74 | |
75 | /* Scale down delays to accommodate QT slow speed */ | |
419ad34e AS |
76 | /* beacon interval, in unit of 1024TU */ |
77 | #define BEACON_INTERVAL_DEF_QT 20 | |
78 | /* DTIM interval, in unit of beacon interval */ | |
79 | #define DTIM_INTERVAL_DEF_QT 1 | |
a9533e7e HP |
80 | |
81 | #define TBTT_ALIGN_LEEWAY_US 100 /* min leeway before first TBTT in us */ | |
82 | ||
434c14ef RV |
83 | /* Software feature flag defines used by wlfeatureflag */ |
84 | #define WL_SWFL_NOHWRADIO 0x0004 | |
85 | #define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */ | |
86 | #define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */ | |
87 | ||
88 | /* n-mode support capability */ | |
89 | /* 2x2 includes both 1x1 & 2x2 devices | |
90 | * reserved #define 2 for future when we want to separate 1x1 & 2x2 and | |
91 | * control it independently | |
92 | */ | |
93 | #define WL_11N_2x2 1 | |
94 | #define WL_11N_3x3 3 | |
95 | #define WL_11N_4x4 4 | |
96 | ||
97 | /* define 11n feature disable flags */ | |
98 | #define WLFEATURE_DISABLE_11N 0x00000001 | |
99 | #define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002 | |
100 | #define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004 | |
101 | #define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008 | |
102 | #define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010 | |
103 | #define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020 | |
104 | #define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040 | |
105 | #define WLFEATURE_DISABLE_11N_GF 0x00000080 | |
106 | ||
9152bf26 RV |
107 | #define EDCF_ACI_MASK 0x60 |
108 | #define EDCF_ACI_SHIFT 5 | |
109 | #define EDCF_ECWMIN_MASK 0x0f | |
110 | #define EDCF_ECWMAX_SHIFT 4 | |
111 | #define EDCF_AIFSN_MASK 0x0f | |
112 | #define EDCF_AIFSN_MAX 15 | |
113 | #define EDCF_ECWMAX_MASK 0xf0 | |
114 | ||
115 | #define EDCF_AC_BE_TXOP_STA 0x0000 | |
116 | #define EDCF_AC_BK_TXOP_STA 0x0000 | |
117 | #define EDCF_AC_VO_ACI_STA 0x62 | |
118 | #define EDCF_AC_VO_ECW_STA 0x32 | |
119 | #define EDCF_AC_VI_ACI_STA 0x42 | |
120 | #define EDCF_AC_VI_ECW_STA 0x43 | |
121 | #define EDCF_AC_BK_ECW_STA 0xA4 | |
122 | #define EDCF_AC_VI_TXOP_STA 0x005e | |
123 | #define EDCF_AC_VO_TXOP_STA 0x002f | |
124 | #define EDCF_AC_BE_ACI_STA 0x03 | |
125 | #define EDCF_AC_BE_ECW_STA 0xA4 | |
126 | #define EDCF_AC_BK_ACI_STA 0x27 | |
127 | #define EDCF_AC_VO_TXOP_AP 0x002f | |
128 | ||
129 | #define EDCF_TXOP2USEC(txop) ((txop) << 5) | |
130 | #define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) | |
131 | ||
132 | #define APHY_SYMBOL_TIME 4 | |
133 | #define APHY_PREAMBLE_TIME 16 | |
134 | #define APHY_SIGNAL_TIME 4 | |
135 | #define APHY_SIFS_TIME 16 | |
136 | #define APHY_SERVICE_NBITS 16 | |
137 | #define APHY_TAIL_NBITS 6 | |
138 | #define BPHY_SIFS_TIME 10 | |
139 | #define BPHY_PLCP_SHORT_TIME 96 | |
140 | ||
141 | #define PREN_PREAMBLE 24 | |
142 | #define PREN_MM_EXT 12 | |
143 | #define PREN_PREAMBLE_EXT 4 | |
144 | ||
145 | #define DOT11_MAC_HDR_LEN 24 | |
146 | #define DOT11_ACK_LEN 10 | |
147 | #define DOT11_BA_LEN 4 | |
148 | #define DOT11_OFDM_SIGNAL_EXTENSION 6 | |
149 | #define DOT11_MIN_FRAG_LEN 256 | |
150 | #define DOT11_RTS_LEN 16 | |
151 | #define DOT11_CTS_LEN 10 | |
152 | #define DOT11_BA_BITMAP_LEN 128 | |
153 | #define DOT11_MIN_BEACON_PERIOD 1 | |
154 | #define DOT11_MAX_BEACON_PERIOD 0xFFFF | |
155 | #define DOT11_MAXNUMFRAGS 16 | |
156 | #define DOT11_MAX_FRAG_LEN 2346 | |
157 | ||
158 | #define BPHY_PLCP_TIME 192 | |
159 | #define RIFS_11N_TIME 2 | |
160 | ||
161 | #define WME_VER 1 | |
162 | #define WME_SUBTYPE_PARAM_IE 1 | |
163 | #define WME_TYPE 2 | |
164 | #define WME_OUI "\x00\x50\xf2" | |
165 | ||
166 | #define AC_BE 0 | |
167 | #define AC_BK 1 | |
168 | #define AC_VI 2 | |
169 | #define AC_VO 3 | |
170 | ||
a9533e7e | 171 | /* |
419ad34e AS |
172 | * driver maintains internal 'tick'(wlc->pub->now) which increments in 1s |
173 | * OS timer(soft watchdog) it is not a wall clock and won't increment when | |
174 | * driver is in "down" state this low resolution driver tick can be used | |
175 | * for maintenance tasks such as phy calibration and scb update | |
a9533e7e HP |
176 | */ |
177 | ||
419ad34e AS |
178 | /* |
179 | * To inform the ucode of the last mcast frame posted | |
180 | * so that it can clear moredata bit | |
181 | */ | |
c654fce6 | 182 | #define BCMCFID(wlc, fid) brcms_b_write_shm((wlc)->hw, M_BCMC_FID, (fid)) |
a9533e7e | 183 | |
821e4e93 | 184 | #define BRCMS_WAR16165(wlc) ((!AP_ENAB(wlc->pub)) && (wlc->war16165)) |
a9533e7e | 185 | |
a9533e7e | 186 | /* Find basic rate for a given rate */ |
419ad34e AS |
187 | #define BRCMS_BASIC_RATE(wlc, rspec) \ |
188 | (IS_MCS(rspec) \ | |
189 | ? (wlc)->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK].leg_ofdm] \ | |
190 | : (wlc)->band->basic_rate[rspec & RSPEC_RATE_MASK]) | |
a9533e7e | 191 | |
419ad34e AS |
192 | #define FRAMETYPE(r, mimoframe) \ |
193 | (IS_MCS(r) ? mimoframe : (IS_CCK(r) ? FT_CCK : FT_OFDM)) | |
a9533e7e | 194 | |
419ad34e AS |
195 | /* rfdisable delay timer 500 ms, runs of ALP clock */ |
196 | #define RFDISABLE_DEFAULT 10000000 | |
a9533e7e | 197 | |
7c783cef | 198 | #define BRCMS_TEMPSENSE_PERIOD 10 /* 10 second timeout */ |
a9533e7e HP |
199 | |
200 | #define SCAN_IN_PROGRESS(x) 0 | |
201 | ||
4766ae6c BR |
202 | #define EPI_VERSION_NUM 0x054b0b00 |
203 | ||
a9533e7e HP |
204 | /* precedences numbers for wlc queues. These are twice as may levels as |
205 | * 802.1D priorities. | |
206 | * Odd numbers are used for HI priority traffic at same precedence levels | |
419ad34e AS |
207 | * These constants are used ONLY by wlc_prio2prec_map. Do not use them |
208 | * elsewhere. | |
a9533e7e | 209 | */ |
7c783cef RV |
210 | #define _BRCMS_PREC_NONE 0 /* None = - */ |
211 | #define _BRCMS_PREC_BK 2 /* BK - Background */ | |
212 | #define _BRCMS_PREC_BE 4 /* BE - Best-effort */ | |
213 | #define _BRCMS_PREC_EE 6 /* EE - Excellent-effort */ | |
214 | #define _BRCMS_PREC_CL 8 /* CL - Controlled Load */ | |
215 | #define _BRCMS_PREC_VI 10 /* Vi - Video */ | |
216 | #define _BRCMS_PREC_VO 12 /* Vo - Voice */ | |
217 | #define _BRCMS_PREC_NC 14 /* NC - Network Control */ | |
a9533e7e | 218 | |
b745b6bb | 219 | #define MAXMACLIST 64 /* max # source MAC matches */ |
8a76f1ee | 220 | #define BCN_TEMPLATE_COUNT 2 |
b745b6bb | 221 | |
7c783cef RV |
222 | /* The BSS is generating beacons in HW */ |
223 | #define BRCMS_BSSCFG_HW_BCN 0x20 | |
b745b6bb | 224 | |
7c783cef | 225 | #define HWBCN_ENAB(cfg) (((cfg)->flags & BRCMS_BSSCFG_HW_BCN) != 0) |
b745b6bb RV |
226 | |
227 | #define MBSS_BCN_ENAB(cfg) 0 | |
228 | #define MBSS_PRB_ENAB(cfg) 0 | |
229 | #define SOFTBCN_ENAB(pub) (0) | |
230 | ||
8702fee6 | 231 | #define SYNTHPU_DLY_APHY_US 3700 /* a phy synthpu_dly time in us */ |
419ad34e AS |
232 | #define SYNTHPU_DLY_BPHY_US 1050 /* b/g phy synthpu_dly time in us */ |
233 | #define SYNTHPU_DLY_NPHY_US 2048 /* n phy REV3 synthpu_dly time in us */ | |
8702fee6 RV |
234 | #define SYNTHPU_DLY_LPPHY_US 300 /* lpphy synthpu_dly time in us */ |
235 | ||
236 | #define SYNTHPU_DLY_PHY_US_QT 100 /* QT synthpu_dly time in us */ | |
237 | ||
238 | #define ANTCNT 10 /* vanilla M_MAX_ANTCNT value */ | |
239 | ||
240 | #define DMAREG(wlc_hw, direction, fifonum) \ | |
241 | ((direction == DMA_TX) ? \ | |
7b1cbc1d RV |
242 | &(wlc_hw->regs->fifo64regs[fifonum].dmaxmt) : \ |
243 | &(wlc_hw->regs->fifo64regs[fifonum].dmarcv)) | |
8702fee6 RV |
244 | |
245 | #define APHY_SLOT_TIME 9 | |
246 | #define BPHY_SLOT_TIME 20 | |
247 | ||
248 | /* | |
249 | * The following table lists the buffer memory allocated to xmt fifos in HW. | |
250 | * the size is in units of 256bytes(one block), total size is HW dependent | |
251 | * ucode has default fifo partition, sw can overwrite if necessary | |
252 | * | |
253 | * This is documented in twiki under the topic UcodeTxFifo. Please ensure | |
254 | * the twiki is updated before making changes. | |
255 | */ | |
256 | ||
419ad34e AS |
257 | /* Starting corerev for the fifo size table */ |
258 | #define XMTFIFOTBL_STARTREV 20 | |
a9533e7e | 259 | |
b745b6bb RV |
260 | /* Check if a particular BSS config is AP or STA */ |
261 | #define BSSCFG_AP(cfg) (0) | |
262 | #define BSSCFG_STA(cfg) (1) | |
263 | #define BSSCFG_IBSS(cfg) (!(cfg)->BSS) | |
264 | ||
49552d33 | 265 | /* iterate through all valid bsscfg entries */ |
b745b6bb | 266 | #define FOREACH_BSS(wlc, idx, cfg) \ |
49552d33 AS |
267 | for (idx = 0; (int) idx < BRCMS_MAXBSSCFG; idx++) { \ |
268 | cfg = (wlc)->bsscfg[idx]; \ | |
269 | if (!cfg) \ | |
270 | continue; | |
271 | /* close marker for iterator code block */ | |
272 | #define END_FOREACH_BSS() } | |
b745b6bb | 273 | |
a9533e7e HP |
274 | /* Shared memory location index for various AC params */ |
275 | #define wme_shmemacindex(ac) wme_ac2fifo[ac] | |
276 | ||
a9533e7e | 277 | /* currently the best mechanism for determining SIFS is the band in use */ |
7c783cef RV |
278 | #define SIFS(band) ((band)->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME : \ |
279 | BPHY_SIFS_TIME); | |
a9533e7e | 280 | |
8702fee6 RV |
281 | /* dup state between BMAC(struct brcms_hardware) and HIGH(struct brcms_c_info) |
282 | driver */ | |
283 | struct brcms_b_state { | |
284 | u32 machwcap; /* mac hw capibility */ | |
285 | u32 preamble_ovr; /* preamble override */ | |
286 | }; | |
287 | ||
8702fee6 RV |
288 | const u8 prio2fifo[NUMPRIO] = { |
289 | TX_AC_BE_FIFO, /* 0 BE AC_BE Best Effort */ | |
290 | TX_AC_BK_FIFO, /* 1 BK AC_BK Background */ | |
291 | TX_AC_BK_FIFO, /* 2 -- AC_BK Background */ | |
292 | TX_AC_BE_FIFO, /* 3 EE AC_BE Best Effort */ | |
293 | TX_AC_VI_FIFO, /* 4 CL AC_VI Video */ | |
294 | TX_AC_VI_FIFO, /* 5 VI AC_VI Video */ | |
295 | TX_AC_VO_FIFO, /* 6 VO AC_VO Voice */ | |
296 | TX_AC_VO_FIFO /* 7 NC AC_VO Voice */ | |
297 | }; | |
298 | ||
299 | /* debug/trace */ | |
300 | uint brcm_msg_level = | |
301 | #if defined(BCMDBG) | |
302 | LOG_ERROR_VAL; | |
303 | #else | |
304 | 0; | |
305 | #endif /* BCMDBG */ | |
306 | ||
307 | /* TX FIFO number to WME/802.1E Access Category */ | |
308 | const u8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE }; | |
309 | ||
310 | /* WME/802.1E Access Category to TX FIFO number */ | |
311 | static const u8 wme_ac2fifo[] = { 1, 0, 2, 3 }; | |
312 | ||
313 | static bool in_send_q; | |
314 | ||
315 | /* 802.1D Priority to precedence queue mapping */ | |
316 | const u8 wlc_prio2prec_map[] = { | |
317 | _BRCMS_PREC_BE, /* 0 BE - Best-effort */ | |
318 | _BRCMS_PREC_BK, /* 1 BK - Background */ | |
319 | _BRCMS_PREC_NONE, /* 2 None = - */ | |
320 | _BRCMS_PREC_EE, /* 3 EE - Excellent-effort */ | |
321 | _BRCMS_PREC_CL, /* 4 CL - Controlled Load */ | |
322 | _BRCMS_PREC_VI, /* 5 Vi - Video */ | |
323 | _BRCMS_PREC_VO, /* 6 Vo - Voice */ | |
324 | _BRCMS_PREC_NC, /* 7 NC - Network Control */ | |
325 | }; | |
326 | ||
327 | static u16 xmtfifo_sz[][NFIFO] = { | |
419ad34e AS |
328 | /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */ |
329 | {20, 192, 192, 21, 17, 5}, | |
330 | /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */ | |
331 | {9, 58, 22, 14, 14, 5}, | |
332 | /* corerev 22: 5120, 49152, 49152, 5376, 4352, 1280 */ | |
333 | {20, 192, 192, 21, 17, 5}, | |
334 | /* corerev 23: 5120, 49152, 49152, 5376, 4352, 1280 */ | |
335 | {20, 192, 192, 21, 17, 5}, | |
336 | /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */ | |
337 | {9, 58, 22, 14, 14, 5}, | |
8702fee6 RV |
338 | }; |
339 | ||
340 | static const u8 acbitmap2maxprio[] = { | |
341 | PRIO_8021D_BE, PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_BK, | |
342 | PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, | |
343 | PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, | |
344 | PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO | |
345 | }; | |
346 | ||
347 | #ifdef BCMDBG | |
348 | static const char * const fifo_names[] = { | |
349 | "AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" }; | |
350 | #else | |
351 | static const char fifo_names[6][0]; | |
352 | #endif | |
353 | ||
354 | #ifdef BCMDBG | |
355 | /* pointer to most recently allocated wl/wlc */ | |
356 | static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL); | |
357 | #endif | |
358 | ||
8702fee6 RV |
359 | /* |
360 | * Update the slot timing for standard 11b/g (20us slots) | |
361 | * or shortslot 11g (9us slots) | |
362 | * The PSM needs to be suspended for this call. | |
363 | */ | |
364 | static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw, | |
365 | bool shortslot) | |
366 | { | |
0da64910 | 367 | struct d11regs *regs; |
8702fee6 RV |
368 | |
369 | regs = wlc_hw->regs; | |
370 | ||
371 | if (shortslot) { | |
372 | /* 11g short slot: 11a timing */ | |
373 | W_REG(®s->ifs_slot, 0x0207); /* APHY_SLOT_TIME */ | |
374 | brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, APHY_SLOT_TIME); | |
375 | } else { | |
376 | /* 11g long slot: 11b timing */ | |
377 | W_REG(®s->ifs_slot, 0x0212); /* BPHY_SLOT_TIME */ | |
378 | brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, BPHY_SLOT_TIME); | |
379 | } | |
380 | } | |
381 | ||
2682e2a3 AS |
382 | static void brcms_c_write_inits(struct brcms_hardware *wlc_hw, |
383 | const struct d11init *inits) | |
384 | { | |
385 | int i; | |
386 | u8 *base; | |
387 | u8 *addr; | |
388 | u16 size; | |
389 | u32 value; | |
390 | ||
391 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
392 | ||
393 | base = (u8 *)wlc_hw->regs; | |
394 | ||
395 | for (i = 0; inits[i].addr != 0xffff; i++) { | |
396 | size = le16_to_cpu(inits[i].size); | |
397 | addr = base + le16_to_cpu(inits[i].addr); | |
398 | value = le32_to_cpu(inits[i].value); | |
399 | if (size == 2) | |
400 | W_REG((u16 *)addr, value); | |
401 | else if (size == 4) | |
402 | W_REG((u32 *)addr, value); | |
403 | else | |
404 | break; | |
405 | } | |
406 | } | |
407 | ||
408 | static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs) | |
409 | { | |
410 | u8 idx; | |
411 | u16 addr[] = { | |
412 | M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4, | |
413 | M_HOST_FLAGS5 | |
414 | }; | |
415 | ||
416 | for (idx = 0; idx < MHFMAX; idx++) | |
417 | brcms_b_write_shm(wlc_hw, addr[idx], mhfs[idx]); | |
418 | } | |
419 | ||
8702fee6 RV |
420 | static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw) |
421 | { | |
422 | struct wiphy *wiphy = wlc_hw->wlc->wiphy; | |
423 | ||
424 | /* init microcode host flags */ | |
425 | brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs); | |
426 | ||
427 | /* do band-specific ucode IHR, SHM, and SCR inits */ | |
428 | if (D11REV_IS(wlc_hw->corerev, 23)) { | |
8ea54c9f | 429 | if (BRCMS_ISNPHY(wlc_hw->band)) |
8702fee6 | 430 | brcms_c_write_inits(wlc_hw, d11n0bsinitvals16); |
8ea54c9f | 431 | else |
8702fee6 RV |
432 | wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" |
433 | " %d\n", __func__, wlc_hw->unit, | |
434 | wlc_hw->corerev); | |
8702fee6 RV |
435 | } else { |
436 | if (D11REV_IS(wlc_hw->corerev, 24)) { | |
8ea54c9f | 437 | if (BRCMS_ISLCNPHY(wlc_hw->band)) |
8702fee6 RV |
438 | brcms_c_write_inits(wlc_hw, |
439 | d11lcn0bsinitvals24); | |
8ea54c9f | 440 | else |
8702fee6 RV |
441 | wiphy_err(wiphy, "%s: wl%d: unsupported phy in" |
442 | " core rev %d\n", __func__, | |
443 | wlc_hw->unit, wlc_hw->corerev); | |
444 | } else { | |
445 | wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n", | |
446 | __func__, wlc_hw->unit, wlc_hw->corerev); | |
447 | } | |
448 | } | |
449 | } | |
450 | ||
2682e2a3 AS |
451 | static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk) |
452 | { | |
453 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk); | |
454 | ||
455 | wlc_hw->phyclk = clk; | |
456 | ||
457 | if (OFF == clk) { /* clear gmode bit, put phy into reset */ | |
458 | ||
459 | ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC | SICF_GMODE), | |
460 | (SICF_PRST | SICF_FGC)); | |
461 | udelay(1); | |
462 | ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_PRST); | |
463 | udelay(1); | |
464 | ||
465 | } else { /* take phy out of reset */ | |
466 | ||
467 | ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_FGC); | |
468 | udelay(1); | |
469 | ai_core_cflags(wlc_hw->sih, (SICF_FGC), 0); | |
470 | udelay(1); | |
471 | ||
472 | } | |
473 | } | |
474 | ||
8702fee6 RV |
475 | /* switch to new band but leave it inactive */ |
476 | static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit) | |
477 | { | |
478 | struct brcms_hardware *wlc_hw = wlc->hw; | |
479 | u32 macintmask; | |
480 | ||
481 | BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
482 | ||
483 | WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0); | |
484 | ||
485 | /* disable interrupts */ | |
486 | macintmask = brcms_intrsoff(wlc->wl); | |
487 | ||
488 | /* radio off */ | |
489 | wlc_phy_switch_radio(wlc_hw->band->pi, OFF); | |
490 | ||
491 | brcms_b_core_phy_clk(wlc_hw, OFF); | |
492 | ||
493 | brcms_c_setxband(wlc_hw, bandunit); | |
494 | ||
495 | return macintmask; | |
496 | } | |
497 | ||
498 | /* Process received frames */ | |
499 | /* | |
500 | * Return true if more frames need to be processed. false otherwise. | |
501 | * Param 'bound' indicates max. # frames to process before break out. | |
502 | */ | |
503 | static bool | |
504 | brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) | |
505 | { | |
506 | struct sk_buff *p; | |
507 | struct sk_buff *head = NULL; | |
508 | struct sk_buff *tail = NULL; | |
509 | uint n = 0; | |
510 | uint bound_limit = bound ? wlc_hw->wlc->pub->tunables->rxbnd : -1; | |
511 | struct brcms_d11rxhdr *wlc_rxhdr = NULL; | |
512 | ||
513 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
514 | /* gather received frames */ | |
515 | while ((p = dma_rx(wlc_hw->di[fifo]))) { | |
516 | ||
517 | if (!tail) | |
518 | head = tail = p; | |
519 | else { | |
520 | tail->prev = p; | |
521 | tail = p; | |
522 | } | |
523 | ||
524 | /* !give others some time to run! */ | |
525 | if (++n >= bound_limit) | |
526 | break; | |
527 | } | |
528 | ||
529 | /* post more rbufs */ | |
530 | dma_rxfill(wlc_hw->di[fifo]); | |
531 | ||
532 | /* process each frame */ | |
533 | while ((p = head) != NULL) { | |
534 | head = head->prev; | |
535 | p->prev = NULL; | |
536 | ||
537 | wlc_rxhdr = (struct brcms_d11rxhdr *) p->data; | |
538 | ||
419ad34e AS |
539 | /* |
540 | * compute the RSSI from d11rxhdr and record it in wlc_rxd11hr | |
541 | */ | |
8702fee6 RV |
542 | wlc_phy_rssi_compute(wlc_hw->band->pi, wlc_rxhdr); |
543 | ||
544 | brcms_c_recv(wlc_hw->wlc, p); | |
545 | } | |
546 | ||
547 | return n >= bound_limit; | |
548 | } | |
549 | ||
839f9f62 RV |
550 | static bool |
551 | brcms_b_dotxstatus(struct brcms_hardware *wlc_hw, struct tx_status *txs, | |
552 | u32 s2) | |
553 | { | |
554 | /* discard intermediate indications for ucode with one legitimate case: | |
419ad34e AS |
555 | * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, |
556 | * but the subsequent tx of DATA failed. so it will start rts/cts from | |
557 | * the beginning (resetting the rts transmission count) | |
839f9f62 RV |
558 | */ |
559 | if (!(txs->status & TX_STATUS_AMPDU) | |
8ea54c9f | 560 | && (txs->status & TX_STATUS_INTERMEDIATE)) |
839f9f62 | 561 | return false; |
839f9f62 RV |
562 | |
563 | return brcms_c_dotxstatus(wlc_hw->wlc, txs, s2); | |
564 | } | |
565 | ||
566 | /* process tx completion events in BMAC | |
567 | * Return true if more tx status need to be processed. false otherwise. | |
568 | */ | |
569 | static bool | |
570 | brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) | |
571 | { | |
572 | bool morepending = false; | |
573 | struct brcms_c_info *wlc = wlc_hw->wlc; | |
0da64910 | 574 | struct d11regs *regs; |
839f9f62 RV |
575 | struct tx_status txstatus, *txs; |
576 | u32 s1, s2; | |
577 | uint n = 0; | |
578 | /* | |
579 | * Param 'max_tx_num' indicates max. # tx status to process before | |
580 | * break out. | |
581 | */ | |
582 | uint max_tx_num = bound ? wlc->pub->tunables->txsbnd : -1; | |
583 | ||
584 | BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
585 | ||
586 | txs = &txstatus; | |
587 | regs = wlc_hw->regs; | |
588 | while (!(*fatal) | |
589 | && (s1 = R_REG(®s->frmtxstatus)) & TXS_V) { | |
590 | ||
591 | if (s1 == 0xffffffff) { | |
592 | wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", | |
593 | wlc_hw->unit, __func__); | |
594 | return morepending; | |
595 | } | |
596 | ||
597 | s2 = R_REG(®s->frmtxstatus2); | |
598 | ||
599 | txs->status = s1 & TXS_STATUS_MASK; | |
600 | txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT; | |
601 | txs->sequence = s2 & TXS_SEQ_MASK; | |
602 | txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT; | |
603 | txs->lasttxtime = 0; | |
604 | ||
605 | *fatal = brcms_b_dotxstatus(wlc_hw, txs, s2); | |
606 | ||
607 | /* !give others some time to run! */ | |
608 | if (++n >= max_tx_num) | |
609 | break; | |
610 | } | |
611 | ||
612 | if (*fatal) | |
613 | return 0; | |
614 | ||
615 | if (n >= max_tx_num) | |
616 | morepending = true; | |
617 | ||
618 | if (!pktq_empty(&wlc->pkt_queue->q)) | |
619 | brcms_c_send_q(wlc); | |
620 | ||
621 | return morepending; | |
622 | } | |
623 | ||
2682e2a3 AS |
624 | /* brcms_b_tx_fifo_suspended: |
625 | * Check the MAC's tx suspend status for a tx fifo. | |
626 | * | |
627 | * When the MAC acknowledges a tx suspend, it indicates that no more | |
628 | * packets will be transmitted out the radio. This is independent of | |
629 | * DMA channel suspension---the DMA may have finished suspending, or may still | |
630 | * be pulling data into a tx fifo, by the time the MAC acks the suspend | |
631 | * request. | |
632 | */ | |
633 | static bool brcms_b_tx_fifo_suspended(struct brcms_hardware *wlc_hw, | |
634 | uint tx_fifo) | |
635 | { | |
636 | /* check that a suspend has been requested and is no longer pending */ | |
637 | ||
638 | /* | |
639 | * for DMA mode, the suspend request is set in xmtcontrol of the DMA | |
640 | * engine, and the tx fifo suspend at the lower end of the MAC is | |
641 | * acknowledged in the chnstatus register. | |
642 | * | |
643 | * The tx fifo suspend completion is independent of the DMA suspend | |
644 | * completion and may be acked before or after the DMA is suspended. | |
645 | */ | |
646 | if (dma_txsuspended(wlc_hw->di[tx_fifo]) && | |
647 | (R_REG(&wlc_hw->regs->chnstatus) & | |
648 | (1 << tx_fifo)) == 0) | |
649 | return true; | |
650 | ||
651 | return false; | |
652 | } | |
653 | ||
8702fee6 RV |
654 | /* second-level interrupt processing |
655 | * Return true if another dpc needs to be re-scheduled. false otherwise. | |
656 | * Param 'bounded' indicates if applicable loops should be bounded. | |
657 | */ | |
658 | bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) | |
659 | { | |
660 | u32 macintstatus; | |
661 | struct brcms_hardware *wlc_hw = wlc->hw; | |
0da64910 | 662 | struct d11regs *regs = wlc_hw->regs; |
8702fee6 RV |
663 | bool fatal = false; |
664 | struct wiphy *wiphy = wlc->wiphy; | |
665 | ||
666 | if (DEVICEREMOVED(wlc)) { | |
667 | wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, | |
668 | __func__); | |
669 | brcms_down(wlc->wl); | |
670 | return false; | |
671 | } | |
672 | ||
673 | /* grab and clear the saved software intstatus bits */ | |
674 | macintstatus = wlc->macintstatus; | |
675 | wlc->macintstatus = 0; | |
676 | ||
677 | BCMMSG(wlc->wiphy, "wl%d: macintstatus 0x%x\n", | |
678 | wlc_hw->unit, macintstatus); | |
679 | ||
680 | WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */ | |
681 | ||
682 | /* BCN template is available */ | |
683 | /* ZZZ: Use AP_ACTIVE ? */ | |
684 | if (AP_ENAB(wlc->pub) && (!APSTA_ENAB(wlc->pub)) | |
8ea54c9f | 685 | && (macintstatus & MI_BCNTPL)) |
8702fee6 | 686 | brcms_c_update_beacon(wlc); |
8702fee6 RV |
687 | |
688 | /* tx status */ | |
689 | if (macintstatus & MI_TFS) { | |
690 | if (brcms_b_txstatus(wlc->hw, bounded, &fatal)) | |
691 | wlc->macintstatus |= MI_TFS; | |
692 | if (fatal) { | |
693 | wiphy_err(wiphy, "MI_TFS: fatal\n"); | |
694 | goto fatal; | |
695 | } | |
696 | } | |
697 | ||
698 | if (macintstatus & (MI_TBTT | MI_DTIM_TBTT)) | |
699 | brcms_c_tbtt(wlc); | |
700 | ||
701 | /* ATIM window end */ | |
702 | if (macintstatus & MI_ATIMWINEND) { | |
703 | BCMMSG(wlc->wiphy, "end of ATIM window\n"); | |
704 | OR_REG(®s->maccommand, wlc->qvalid); | |
705 | wlc->qvalid = 0; | |
706 | } | |
707 | ||
419ad34e AS |
708 | /* |
709 | * received data or control frame, MI_DMAINT is | |
710 | * indication of RX_FIFO interrupt | |
711 | */ | |
8702fee6 RV |
712 | if (macintstatus & MI_DMAINT) |
713 | if (brcms_b_recv(wlc_hw, RX_FIFO, bounded)) | |
714 | wlc->macintstatus |= MI_DMAINT; | |
715 | ||
716 | /* TX FIFO suspend/flush completion */ | |
717 | if (macintstatus & MI_TXSTOP) | |
718 | brcms_b_tx_fifo_suspended(wlc_hw, TX_DATA_FIFO); | |
719 | ||
720 | /* noise sample collected */ | |
8ea54c9f | 721 | if (macintstatus & MI_BG_NOISE) |
8702fee6 | 722 | wlc_phy_noise_sample_intr(wlc_hw->band->pi); |
8702fee6 RV |
723 | |
724 | if (macintstatus & MI_GP0) { | |
725 | wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d " | |
726 | "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now); | |
727 | ||
728 | printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n", | |
729 | __func__, wlc_hw->sih->chip, | |
730 | wlc_hw->sih->chiprev); | |
731 | /* big hammer */ | |
732 | brcms_init(wlc->wl); | |
733 | } | |
734 | ||
735 | /* gptimer timeout */ | |
8ea54c9f | 736 | if (macintstatus & MI_TO) |
8702fee6 | 737 | W_REG(®s->gptimer, 0); |
8702fee6 RV |
738 | |
739 | if (macintstatus & MI_RFDISABLE) { | |
740 | BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the" | |
741 | " RF Disable Input\n", wlc_hw->unit); | |
742 | brcms_rfkill_set_hw_state(wlc->wl); | |
743 | } | |
744 | ||
745 | /* send any enq'd tx packets. Just makes sure to jump start tx */ | |
746 | if (!pktq_empty(&wlc->pkt_queue->q)) | |
747 | brcms_c_send_q(wlc); | |
748 | ||
749 | /* it isn't done and needs to be resched if macintstatus is non-zero */ | |
750 | return wlc->macintstatus != 0; | |
751 | ||
752 | fatal: | |
753 | brcms_init(wlc->wl); | |
754 | return wlc->macintstatus != 0; | |
755 | } | |
756 | ||
11431424 | 757 | static int brcms_b_state_get(struct brcms_hardware *wlc_hw, |
8702fee6 RV |
758 | struct brcms_b_state *state) |
759 | { | |
760 | state->machwcap = wlc_hw->machwcap; | |
761 | ||
762 | return 0; | |
763 | } | |
764 | ||
2682e2a3 AS |
765 | /* set initial host flags value */ |
766 | static void | |
767 | brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init) | |
768 | { | |
769 | struct brcms_hardware *wlc_hw = wlc->hw; | |
770 | ||
771 | memset(mhfs, 0, MHFMAX * sizeof(u16)); | |
772 | ||
773 | mhfs[MHF2] |= mhf2_init; | |
774 | ||
775 | /* prohibit use of slowclock on multifunction boards */ | |
776 | if (wlc_hw->boardflags & BFL_NOPLLDOWN) | |
777 | mhfs[MHF1] |= MHF1_FORCEFASTCLK; | |
778 | ||
779 | if (BRCMS_ISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) { | |
780 | mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR; | |
781 | mhfs[MHF1] |= MHF1_IQSWAP_WAR; | |
782 | } | |
783 | } | |
784 | ||
8702fee6 RV |
785 | static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) |
786 | { | |
787 | uint i; | |
788 | char name[8]; | |
419ad34e AS |
789 | /* |
790 | * ucode host flag 2 needed for pio mode, independent of band and fifo | |
791 | */ | |
8702fee6 RV |
792 | u16 pio_mhf2 = 0; |
793 | struct brcms_hardware *wlc_hw = wlc->hw; | |
794 | uint unit = wlc_hw->unit; | |
795 | struct brcms_tunables *tune = wlc->pub->tunables; | |
796 | struct wiphy *wiphy = wlc->wiphy; | |
797 | ||
798 | /* name and offsets for dma_attach */ | |
799 | snprintf(name, sizeof(name), "wl%d", unit); | |
800 | ||
801 | if (wlc_hw->di[0] == 0) { /* Init FIFOs */ | |
8702fee6 | 802 | int dma_attach_err = 0; |
8702fee6 | 803 | |
8702fee6 RV |
804 | /* |
805 | * FIFO 0 | |
806 | * TX: TX_AC_BK_FIFO (TX AC Background data packets) | |
807 | * RX: RX_FIFO (RX data packets) | |
808 | */ | |
809 | wlc_hw->di[0] = dma_attach(name, wlc_hw->sih, | |
810 | (wme ? DMAREG(wlc_hw, DMA_TX, 0) : | |
811 | NULL), DMAREG(wlc_hw, DMA_RX, 0), | |
812 | (wme ? tune->ntxd : 0), tune->nrxd, | |
813 | tune->rxbufsz, -1, tune->nrxbufpost, | |
814 | BRCMS_HWRXOFF, &brcm_msg_level); | |
815 | dma_attach_err |= (NULL == wlc_hw->di[0]); | |
816 | ||
817 | /* | |
818 | * FIFO 1 | |
819 | * TX: TX_AC_BE_FIFO (TX AC Best-Effort data packets) | |
820 | * (legacy) TX_DATA_FIFO (TX data packets) | |
821 | * RX: UNUSED | |
822 | */ | |
823 | wlc_hw->di[1] = dma_attach(name, wlc_hw->sih, | |
824 | DMAREG(wlc_hw, DMA_TX, 1), NULL, | |
825 | tune->ntxd, 0, 0, -1, 0, 0, | |
826 | &brcm_msg_level); | |
827 | dma_attach_err |= (NULL == wlc_hw->di[1]); | |
828 | ||
829 | /* | |
830 | * FIFO 2 | |
831 | * TX: TX_AC_VI_FIFO (TX AC Video data packets) | |
832 | * RX: UNUSED | |
833 | */ | |
834 | wlc_hw->di[2] = dma_attach(name, wlc_hw->sih, | |
835 | DMAREG(wlc_hw, DMA_TX, 2), NULL, | |
836 | tune->ntxd, 0, 0, -1, 0, 0, | |
837 | &brcm_msg_level); | |
838 | dma_attach_err |= (NULL == wlc_hw->di[2]); | |
839 | /* | |
840 | * FIFO 3 | |
841 | * TX: TX_AC_VO_FIFO (TX AC Voice data packets) | |
842 | * (legacy) TX_CTL_FIFO (TX control & mgmt packets) | |
843 | */ | |
844 | wlc_hw->di[3] = dma_attach(name, wlc_hw->sih, | |
845 | DMAREG(wlc_hw, DMA_TX, 3), | |
846 | NULL, tune->ntxd, 0, 0, -1, | |
847 | 0, 0, &brcm_msg_level); | |
848 | dma_attach_err |= (NULL == wlc_hw->di[3]); | |
849 | /* Cleaner to leave this as if with AP defined */ | |
850 | ||
851 | if (dma_attach_err) { | |
852 | wiphy_err(wiphy, "wl%d: wlc_attach: dma_attach failed" | |
853 | "\n", unit); | |
854 | return false; | |
855 | } | |
856 | ||
857 | /* get pointer to dma engine tx flow control variable */ | |
858 | for (i = 0; i < NFIFO; i++) | |
859 | if (wlc_hw->di[i]) | |
860 | wlc_hw->txavail[i] = | |
861 | (uint *) dma_getvar(wlc_hw->di[i], | |
862 | "&txavail"); | |
863 | } | |
864 | ||
865 | /* initial ucode host flags */ | |
866 | brcms_c_mhfdef(wlc, wlc_hw->band->mhfs, pio_mhf2); | |
867 | ||
868 | return true; | |
869 | } | |
870 | ||
871 | static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw) | |
872 | { | |
873 | uint j; | |
874 | ||
875 | for (j = 0; j < NFIFO; j++) { | |
876 | if (wlc_hw->di[j]) { | |
877 | dma_detach(wlc_hw->di[j]); | |
878 | wlc_hw->di[j] = NULL; | |
879 | } | |
880 | } | |
881 | } | |
882 | ||
839f9f62 RV |
883 | /* |
884 | * Initialize brcms_c_info default values ... | |
885 | * may get overrides later in this function | |
886 | * BMAC_NOTES, move low out and resolve the dangling ones | |
8702fee6 | 887 | */ |
839f9f62 | 888 | static void brcms_b_info_init(struct brcms_hardware *wlc_hw) |
8702fee6 | 889 | { |
839f9f62 | 890 | struct brcms_c_info *wlc = wlc_hw->wlc; |
8702fee6 | 891 | |
839f9f62 RV |
892 | /* set default sw macintmask value */ |
893 | wlc->defmacintmask = DEF_MACINTMASK; | |
8702fee6 | 894 | |
839f9f62 RV |
895 | /* various 802.11g modes */ |
896 | wlc_hw->shortslot = false; | |
8702fee6 | 897 | |
839f9f62 RV |
898 | wlc_hw->SFBL = RETRY_SHORT_FB; |
899 | wlc_hw->LFBL = RETRY_LONG_FB; | |
8702fee6 | 900 | |
839f9f62 RV |
901 | /* default mac retry limits */ |
902 | wlc_hw->SRL = RETRY_SHORT_DEF; | |
903 | wlc_hw->LRL = RETRY_LONG_DEF; | |
904 | wlc_hw->chanspec = CH20MHZ_CHSPEC(1); | |
905 | } | |
8702fee6 | 906 | |
11431424 | 907 | static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw) |
839f9f62 RV |
908 | { |
909 | /* delay before first read of ucode state */ | |
910 | udelay(40); | |
8702fee6 | 911 | |
839f9f62 RV |
912 | /* wait until ucode is no longer asleep */ |
913 | SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) == | |
914 | DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly); | |
915 | } | |
8702fee6 | 916 | |
11431424 | 917 | static void brcms_b_hw_etheraddr(struct brcms_hardware *wlc_hw, u8 *ea) |
8702fee6 RV |
918 | { |
919 | memcpy(ea, wlc_hw->etheraddr, ETH_ALEN); | |
920 | } | |
921 | ||
922 | static int brcms_b_bandtype(struct brcms_hardware *wlc_hw) | |
923 | { | |
924 | return wlc_hw->band->bandtype; | |
925 | } | |
926 | ||
927 | /* control chip clock to save power, enable dynamic clock or force fast clock */ | |
928 | static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode) | |
929 | { | |
930 | if (PMUCTL_ENAB(wlc_hw->sih)) { | |
419ad34e AS |
931 | /* new chips with PMU, CCS_FORCEHT will distribute the HT clock |
932 | * on backplane, but mac core will still run on ALP(not HT) when | |
933 | * it enters powersave mode, which means the FCA bit may not be | |
934 | * set. Should wakeup mac if driver wants it to run on HT. | |
8702fee6 RV |
935 | */ |
936 | ||
937 | if (wlc_hw->clk) { | |
938 | if (mode == CLK_FAST) { | |
939 | OR_REG(&wlc_hw->regs->clk_ctl_st, | |
940 | CCS_FORCEHT); | |
941 | ||
942 | udelay(64); | |
943 | ||
944 | SPINWAIT(((R_REG | |
945 | (&wlc_hw->regs-> | |
946 | clk_ctl_st) & CCS_HTAVAIL) == 0), | |
947 | PMU_MAX_TRANSITION_DLY); | |
948 | WARN_ON(!(R_REG | |
949 | (&wlc_hw->regs-> | |
950 | clk_ctl_st) & CCS_HTAVAIL)); | |
951 | } else { | |
952 | if ((wlc_hw->sih->pmurev == 0) && | |
953 | (R_REG | |
954 | (&wlc_hw->regs-> | |
955 | clk_ctl_st) & (CCS_FORCEHT | CCS_HTAREQ))) | |
956 | SPINWAIT(((R_REG | |
957 | (&wlc_hw->regs-> | |
958 | clk_ctl_st) & CCS_HTAVAIL) | |
959 | == 0), | |
960 | PMU_MAX_TRANSITION_DLY); | |
961 | AND_REG(&wlc_hw->regs->clk_ctl_st, | |
962 | ~CCS_FORCEHT); | |
963 | } | |
964 | } | |
965 | wlc_hw->forcefastclk = (mode == CLK_FAST); | |
966 | } else { | |
967 | ||
968 | /* old chips w/o PMU, force HT through cc, | |
969 | * then use FCA to verify mac is running fast clock | |
970 | */ | |
971 | ||
972 | wlc_hw->forcefastclk = ai_clkctl_cc(wlc_hw->sih, mode); | |
973 | ||
974 | /* check fast clock is available (if core is not in reset) */ | |
975 | if (wlc_hw->forcefastclk && wlc_hw->clk) | |
976 | WARN_ON(!(ai_core_sflags(wlc_hw->sih, 0, 0) & | |
977 | SISF_FCLKA)); | |
978 | ||
419ad34e AS |
979 | /* |
980 | * keep the ucode wake bit on if forcefastclk is on since we | |
981 | * do not want ucode to put us back to slow clock when it dozes | |
982 | * for PM mode. Code below matches the wake override bit with | |
983 | * current forcefastclk state. Only setting bit in wake_override | |
984 | * instead of waking ucode immediately since old code had this | |
985 | * behavior. Older code set wlc->forcefastclk but only had the | |
986 | * wake happen if the wakup_ucode work (protected by an up | |
987 | * check) was executed just below. | |
8702fee6 RV |
988 | */ |
989 | if (wlc_hw->forcefastclk) | |
990 | mboolset(wlc_hw->wake_override, | |
991 | BRCMS_WAKE_OVERRIDE_FORCEFAST); | |
992 | else | |
993 | mboolclr(wlc_hw->wake_override, | |
994 | BRCMS_WAKE_OVERRIDE_FORCEFAST); | |
995 | } | |
996 | } | |
997 | ||
8702fee6 RV |
998 | /* set or clear ucode host flag bits |
999 | * it has an optimization for no-change write | |
1000 | * it only writes through shared memory when the core has clock; | |
1001 | * pre-CLK changes should use wlc_write_mhf to get around the optimization | |
1002 | * | |
1003 | * | |
1004 | * bands values are: BRCM_BAND_AUTO <--- Current band only | |
1005 | * BRCM_BAND_5G <--- 5G band only | |
1006 | * BRCM_BAND_2G <--- 2G band only | |
1007 | * BRCM_BAND_ALL <--- All bands | |
1008 | */ | |
1009 | void | |
1010 | brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val, | |
1011 | int bands) | |
1012 | { | |
1013 | u16 save; | |
1014 | u16 addr[MHFMAX] = { | |
1015 | M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4, | |
1016 | M_HOST_FLAGS5 | |
1017 | }; | |
1018 | struct brcms_hw_band *band; | |
1019 | ||
1020 | if ((val & ~mask) || idx >= MHFMAX) | |
1021 | return; /* error condition */ | |
1022 | ||
1023 | switch (bands) { | |
1024 | /* Current band only or all bands, | |
1025 | * then set the band to current band | |
1026 | */ | |
1027 | case BRCM_BAND_AUTO: | |
1028 | case BRCM_BAND_ALL: | |
1029 | band = wlc_hw->band; | |
1030 | break; | |
1031 | case BRCM_BAND_5G: | |
1032 | band = wlc_hw->bandstate[BAND_5G_INDEX]; | |
1033 | break; | |
1034 | case BRCM_BAND_2G: | |
1035 | band = wlc_hw->bandstate[BAND_2G_INDEX]; | |
1036 | break; | |
1037 | default: | |
1038 | band = NULL; /* error condition */ | |
1039 | } | |
1040 | ||
1041 | if (band) { | |
1042 | save = band->mhfs[idx]; | |
1043 | band->mhfs[idx] = (band->mhfs[idx] & ~mask) | val; | |
1044 | ||
1045 | /* optimization: only write through if changed, and | |
1046 | * changed band is the current band | |
1047 | */ | |
1048 | if (wlc_hw->clk && (band->mhfs[idx] != save) | |
1049 | && (band == wlc_hw->band)) | |
1050 | brcms_b_write_shm(wlc_hw, addr[idx], | |
1051 | (u16) band->mhfs[idx]); | |
1052 | } | |
1053 | ||
1054 | if (bands == BRCM_BAND_ALL) { | |
1055 | wlc_hw->bandstate[0]->mhfs[idx] = | |
1056 | (wlc_hw->bandstate[0]->mhfs[idx] & ~mask) | val; | |
1057 | wlc_hw->bandstate[1]->mhfs[idx] = | |
1058 | (wlc_hw->bandstate[1]->mhfs[idx] & ~mask) | val; | |
1059 | } | |
1060 | } | |
1061 | ||
8702fee6 RV |
1062 | /* set the maccontrol register to desired reset state and |
1063 | * initialize the sw cache of the register | |
1064 | */ | |
1065 | static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw) | |
1066 | { | |
1067 | /* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */ | |
1068 | wlc_hw->maccontrol = 0; | |
1069 | wlc_hw->suspended_fifos = 0; | |
1070 | wlc_hw->wake_override = 0; | |
1071 | wlc_hw->mute_override = 0; | |
1072 | brcms_b_mctrl(wlc_hw, ~0, MCTL_IHR_EN | MCTL_WAKE); | |
1073 | } | |
1074 | ||
2682e2a3 AS |
1075 | /* |
1076 | * write the software state of maccontrol and | |
1077 | * overrides to the maccontrol register | |
1078 | */ | |
1079 | static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw) | |
1080 | { | |
1081 | u32 maccontrol = wlc_hw->maccontrol; | |
1082 | ||
1083 | /* OR in the wake bit if overridden */ | |
1084 | if (wlc_hw->wake_override) | |
1085 | maccontrol |= MCTL_WAKE; | |
1086 | ||
1087 | /* set AP and INFRA bits for mute if needed */ | |
1088 | if (wlc_hw->mute_override) { | |
1089 | maccontrol &= ~(MCTL_AP); | |
1090 | maccontrol |= MCTL_INFRA; | |
1091 | } | |
1092 | ||
1093 | W_REG(&wlc_hw->regs->maccontrol, maccontrol); | |
1094 | } | |
1095 | ||
8702fee6 RV |
1096 | /* set or clear maccontrol bits */ |
1097 | void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val) | |
1098 | { | |
1099 | u32 maccontrol; | |
1100 | u32 new_maccontrol; | |
1101 | ||
1102 | if (val & ~mask) | |
1103 | return; /* error condition */ | |
1104 | maccontrol = wlc_hw->maccontrol; | |
1105 | new_maccontrol = (maccontrol & ~mask) | val; | |
1106 | ||
1107 | /* if the new maccontrol value is the same as the old, nothing to do */ | |
1108 | if (new_maccontrol == maccontrol) | |
1109 | return; | |
1110 | ||
1111 | /* something changed, cache the new value */ | |
1112 | wlc_hw->maccontrol = new_maccontrol; | |
1113 | ||
1114 | /* write the new values with overrides applied */ | |
1115 | brcms_c_mctrl_write(wlc_hw); | |
1116 | } | |
1117 | ||
8702fee6 RV |
1118 | void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw, |
1119 | u32 override_bit) | |
1120 | { | |
1121 | if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) { | |
1122 | mboolset(wlc_hw->wake_override, override_bit); | |
1123 | return; | |
1124 | } | |
1125 | ||
1126 | mboolset(wlc_hw->wake_override, override_bit); | |
1127 | ||
1128 | brcms_c_mctrl_write(wlc_hw); | |
1129 | brcms_b_wait_for_wake(wlc_hw); | |
1130 | ||
1131 | return; | |
1132 | } | |
1133 | ||
1134 | void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw, | |
1135 | u32 override_bit) | |
1136 | { | |
1137 | mboolclr(wlc_hw->wake_override, override_bit); | |
1138 | ||
1139 | if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) | |
1140 | return; | |
1141 | ||
1142 | brcms_c_mctrl_write(wlc_hw); | |
1143 | ||
1144 | return; | |
1145 | } | |
1146 | ||
1147 | /* When driver needs ucode to stop beaconing, it has to make sure that | |
1148 | * MCTL_AP is clear and MCTL_INFRA is set | |
1149 | * Mode MCTL_AP MCTL_INFRA | |
1150 | * AP 1 1 | |
1151 | * STA 0 1 <--- This will ensure no beacons | |
1152 | * IBSS 0 0 | |
1153 | */ | |
1154 | static void brcms_c_ucode_mute_override_set(struct brcms_hardware *wlc_hw) | |
1155 | { | |
1156 | wlc_hw->mute_override = 1; | |
1157 | ||
1158 | /* if maccontrol already has AP == 0 and INFRA == 1 without this | |
1159 | * override, then there is no change to write | |
1160 | */ | |
1161 | if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA) | |
1162 | return; | |
1163 | ||
1164 | brcms_c_mctrl_write(wlc_hw); | |
1165 | ||
1166 | return; | |
1167 | } | |
1168 | ||
1169 | /* Clear the override on AP and INFRA bits */ | |
1170 | static void brcms_c_ucode_mute_override_clear(struct brcms_hardware *wlc_hw) | |
1171 | { | |
1172 | if (wlc_hw->mute_override == 0) | |
1173 | return; | |
1174 | ||
1175 | wlc_hw->mute_override = 0; | |
1176 | ||
1177 | /* if maccontrol already has AP == 0 and INFRA == 1 without this | |
1178 | * override, then there is no change to write | |
1179 | */ | |
1180 | if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA) | |
1181 | return; | |
1182 | ||
1183 | brcms_c_mctrl_write(wlc_hw); | |
1184 | } | |
1185 | ||
1186 | /* | |
1187 | * Write a MAC address to the given match reg offset in the RXE match engine. | |
1188 | */ | |
11431424 | 1189 | static void |
8702fee6 RV |
1190 | brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset, |
1191 | const u8 *addr) | |
1192 | { | |
0da64910 | 1193 | struct d11regs *regs; |
8702fee6 RV |
1194 | u16 mac_l; |
1195 | u16 mac_m; | |
1196 | u16 mac_h; | |
1197 | ||
1198 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d: brcms_b_set_addrmatch\n", | |
1199 | wlc_hw->unit); | |
1200 | ||
1201 | regs = wlc_hw->regs; | |
1202 | mac_l = addr[0] | (addr[1] << 8); | |
1203 | mac_m = addr[2] | (addr[3] << 8); | |
1204 | mac_h = addr[4] | (addr[5] << 8); | |
1205 | ||
1206 | /* enter the MAC addr into the RXE match registers */ | |
1207 | W_REG(®s->rcm_ctl, RCM_INC_DATA | match_reg_offset); | |
1208 | W_REG(®s->rcm_mat_data, mac_l); | |
1209 | W_REG(®s->rcm_mat_data, mac_m); | |
1210 | W_REG(®s->rcm_mat_data, mac_h); | |
1211 | ||
1212 | } | |
1213 | ||
1214 | void | |
1215 | brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len, | |
1216 | void *buf) | |
1217 | { | |
0da64910 | 1218 | struct d11regs *regs; |
8702fee6 RV |
1219 | u32 word; |
1220 | bool be_bit; | |
1221 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
1222 | ||
1223 | regs = wlc_hw->regs; | |
1224 | W_REG(®s->tplatewrptr, offset); | |
1225 | ||
1226 | /* if MCTL_BIGEND bit set in mac control register, | |
1227 | * the chip swaps data in fifo, as well as data in | |
1228 | * template ram | |
1229 | */ | |
1230 | be_bit = (R_REG(®s->maccontrol) & MCTL_BIGEND) != 0; | |
1231 | ||
1232 | while (len > 0) { | |
1233 | memcpy(&word, buf, sizeof(u32)); | |
1234 | ||
1235 | if (be_bit) | |
1236 | word = cpu_to_be32(word); | |
1237 | else | |
1238 | word = cpu_to_le32(word); | |
1239 | ||
1240 | W_REG(®s->tplatewrdata, word); | |
1241 | ||
1242 | buf = (u8 *) buf + sizeof(u32); | |
1243 | len -= sizeof(u32); | |
1244 | } | |
1245 | } | |
1246 | ||
11431424 | 1247 | static void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin) |
8702fee6 RV |
1248 | { |
1249 | wlc_hw->band->CWmin = newmin; | |
1250 | ||
1251 | W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMIN); | |
1252 | (void)R_REG(&wlc_hw->regs->objaddr); | |
1253 | W_REG(&wlc_hw->regs->objdata, newmin); | |
1254 | } | |
1255 | ||
11431424 | 1256 | static void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax) |
8702fee6 RV |
1257 | { |
1258 | wlc_hw->band->CWmax = newmax; | |
1259 | ||
1260 | W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMAX); | |
1261 | (void)R_REG(&wlc_hw->regs->objaddr); | |
1262 | W_REG(&wlc_hw->regs->objdata, newmax); | |
1263 | } | |
1264 | ||
1265 | void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw) | |
1266 | { | |
1267 | bool fastclk; | |
1268 | ||
1269 | /* request FAST clock if not on */ | |
1270 | fastclk = wlc_hw->forcefastclk; | |
1271 | if (!fastclk) | |
1272 | brcms_b_clkctl_clk(wlc_hw, CLK_FAST); | |
1273 | ||
1274 | wlc_phy_bw_state_set(wlc_hw->band->pi, bw); | |
1275 | ||
1276 | brcms_b_phy_reset(wlc_hw); | |
1277 | wlc_phy_init(wlc_hw->band->pi, wlc_phy_chanspec_get(wlc_hw->band->pi)); | |
1278 | ||
1279 | /* restore the clk */ | |
1280 | if (!fastclk) | |
1281 | brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); | |
1282 | } | |
1283 | ||
1284 | static void | |
2f6b1dde | 1285 | brcms_c_write_hw_bcntemplate0(struct brcms_hardware *wlc_hw, u16 bcn[], |
8702fee6 RV |
1286 | int len) |
1287 | { | |
0da64910 | 1288 | struct d11regs *regs = wlc_hw->regs; |
8702fee6 RV |
1289 | |
1290 | brcms_b_write_template_ram(wlc_hw, T_BCN0_TPL_BASE, (len + 3) & ~3, | |
1291 | bcn); | |
1292 | /* write beacon length to SCR */ | |
1293 | brcms_b_write_shm(wlc_hw, M_BCN0_FRM_BYTESZ, (u16) len); | |
1294 | /* mark beacon0 valid */ | |
1295 | OR_REG(®s->maccommand, MCMD_BCN0VLD); | |
1296 | } | |
1297 | ||
1298 | static void | |
2f6b1dde | 1299 | brcms_c_write_hw_bcntemplate1(struct brcms_hardware *wlc_hw, u16 bcn[], |
8702fee6 RV |
1300 | int len) |
1301 | { | |
0da64910 | 1302 | struct d11regs *regs = wlc_hw->regs; |
8702fee6 RV |
1303 | |
1304 | brcms_b_write_template_ram(wlc_hw, T_BCN1_TPL_BASE, (len + 3) & ~3, | |
1305 | bcn); | |
1306 | /* write beacon length to SCR */ | |
1307 | brcms_b_write_shm(wlc_hw, M_BCN1_FRM_BYTESZ, (u16) len); | |
1308 | /* mark beacon1 valid */ | |
1309 | OR_REG(®s->maccommand, MCMD_BCN1VLD); | |
1310 | } | |
1311 | ||
8702fee6 RV |
1312 | static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw) |
1313 | { | |
1314 | u16 v; | |
1315 | struct brcms_c_info *wlc = wlc_hw->wlc; | |
1316 | /* update SYNTHPU_DLY */ | |
1317 | ||
8ea54c9f | 1318 | if (BRCMS_ISLCNPHY(wlc->band)) |
8702fee6 | 1319 | v = SYNTHPU_DLY_LPPHY_US; |
8ea54c9f | 1320 | else if (BRCMS_ISNPHY(wlc->band) && (NREV_GE(wlc->band->phyrev, 3))) |
8702fee6 | 1321 | v = SYNTHPU_DLY_NPHY_US; |
8ea54c9f | 1322 | else |
8702fee6 | 1323 | v = SYNTHPU_DLY_BPHY_US; |
8702fee6 RV |
1324 | |
1325 | brcms_b_write_shm(wlc_hw, M_SYNTHPU_DLY, v); | |
1326 | } | |
1327 | ||
2682e2a3 | 1328 | static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw) |
8702fee6 | 1329 | { |
2682e2a3 AS |
1330 | u16 phyctl; |
1331 | u16 phytxant = wlc_hw->bmac_phytxant; | |
1332 | u16 mask = PHY_TXC_ANT_MASK; | |
8702fee6 | 1333 | |
2682e2a3 AS |
1334 | /* set the Probe Response frame phy control word */ |
1335 | phyctl = brcms_b_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS); | |
1336 | phyctl = (phyctl & ~mask) | phytxant; | |
1337 | brcms_b_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl); | |
8702fee6 | 1338 | |
2682e2a3 AS |
1339 | /* set the Response (ACK/CTS) frame phy control word */ |
1340 | phyctl = brcms_b_read_shm(wlc_hw, M_RSP_PCTLWD); | |
1341 | phyctl = (phyctl & ~mask) | phytxant; | |
1342 | brcms_b_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl); | |
1343 | } | |
8702fee6 | 1344 | |
2682e2a3 AS |
1345 | static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw, |
1346 | u8 rate) | |
1347 | { | |
1348 | uint i; | |
1349 | u8 plcp_rate = 0; | |
1350 | struct plcp_signal_rate_lookup { | |
1351 | u8 rate; | |
1352 | u8 signal_rate; | |
1353 | }; | |
1354 | /* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */ | |
1355 | const struct plcp_signal_rate_lookup rate_lookup[] = { | |
1356 | {BRCM_RATE_6M, 0xB}, | |
1357 | {BRCM_RATE_9M, 0xF}, | |
1358 | {BRCM_RATE_12M, 0xA}, | |
1359 | {BRCM_RATE_18M, 0xE}, | |
1360 | {BRCM_RATE_24M, 0x9}, | |
1361 | {BRCM_RATE_36M, 0xD}, | |
1362 | {BRCM_RATE_48M, 0x8}, | |
1363 | {BRCM_RATE_54M, 0xC} | |
1364 | }; | |
8702fee6 | 1365 | |
2682e2a3 AS |
1366 | for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) { |
1367 | if (rate == rate_lookup[i].rate) { | |
1368 | plcp_rate = rate_lookup[i].signal_rate; | |
1369 | break; | |
1370 | } | |
1371 | } | |
8702fee6 | 1372 | |
2682e2a3 AS |
1373 | /* Find the SHM pointer to the rate table entry by looking in the |
1374 | * Direct-map Table | |
419ad34e | 1375 | */ |
2682e2a3 AS |
1376 | return 2 * brcms_b_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2)); |
1377 | } | |
8702fee6 | 1378 | |
2682e2a3 AS |
1379 | static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw) |
1380 | { | |
1381 | u8 rate; | |
1382 | u8 rates[8] = { | |
1383 | BRCM_RATE_6M, BRCM_RATE_9M, BRCM_RATE_12M, BRCM_RATE_18M, | |
1384 | BRCM_RATE_24M, BRCM_RATE_36M, BRCM_RATE_48M, BRCM_RATE_54M | |
1385 | }; | |
1386 | u16 entry_ptr; | |
1387 | u16 pctl1; | |
1388 | uint i; | |
1389 | ||
1390 | if (!BRCMS_PHY_11N_CAP(wlc_hw->band)) | |
1391 | return; | |
1392 | ||
1393 | /* walk the phy rate table and update the entries */ | |
1394 | for (i = 0; i < ARRAY_SIZE(rates); i++) { | |
1395 | rate = rates[i]; | |
1396 | ||
1397 | entry_ptr = brcms_b_ofdm_ratetable_offset(wlc_hw, rate); | |
1398 | ||
1399 | /* read the SHM Rate Table entry OFDM PCTL1 values */ | |
1400 | pctl1 = | |
1401 | brcms_b_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS); | |
1402 | ||
1403 | /* modify the value */ | |
1404 | pctl1 &= ~PHY_TXC1_MODE_MASK; | |
1405 | pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT); | |
1406 | ||
1407 | /* Update the SHM Rate Table entry OFDM PCTL1 values */ | |
1408 | brcms_b_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS, | |
1409 | pctl1); | |
1410 | } | |
1411 | } | |
1412 | ||
1413 | /* band-specific init */ | |
1414 | static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec) | |
1415 | { | |
1416 | struct brcms_hardware *wlc_hw = wlc->hw; | |
1417 | ||
1418 | BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, | |
1419 | wlc_hw->band->bandunit); | |
1420 | ||
1421 | brcms_c_ucode_bsinit(wlc_hw); | |
1422 | ||
1423 | wlc_phy_init(wlc_hw->band->pi, chanspec); | |
1424 | ||
1425 | brcms_c_ucode_txant_set(wlc_hw); | |
1426 | ||
1427 | /* | |
1428 | * cwmin is band-specific, update hardware | |
1429 | * with value for current band | |
1430 | */ | |
1431 | brcms_b_set_cwmin(wlc_hw, wlc_hw->band->CWmin); | |
1432 | brcms_b_set_cwmax(wlc_hw, wlc_hw->band->CWmax); | |
1433 | ||
1434 | brcms_b_update_slot_timing(wlc_hw, | |
8702fee6 RV |
1435 | BAND_5G(wlc_hw->band-> |
1436 | bandtype) ? true : wlc_hw-> | |
1437 | shortslot); | |
1438 | ||
1439 | /* write phytype and phyvers */ | |
1440 | brcms_b_write_shm(wlc_hw, M_PHYTYPE, (u16) wlc_hw->band->phytype); | |
1441 | brcms_b_write_shm(wlc_hw, M_PHYVER, (u16) wlc_hw->band->phyrev); | |
1442 | ||
419ad34e AS |
1443 | /* |
1444 | * initialize the txphyctl1 rate table since | |
1445 | * shmem is shared between bands | |
1446 | */ | |
8702fee6 RV |
1447 | brcms_upd_ofdm_pctl1_table(wlc_hw); |
1448 | ||
1449 | brcms_b_upd_synthpu(wlc_hw); | |
1450 | } | |
1451 | ||
8702fee6 RV |
1452 | /* Perform a soft reset of the PHY PLL */ |
1453 | void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw) | |
1454 | { | |
1455 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
1456 | ||
1457 | ai_corereg(wlc_hw->sih, SI_CC_IDX, | |
0da64910 | 1458 | offsetof(struct chipcregs, chipcontrol_addr), ~0, 0); |
8702fee6 RV |
1459 | udelay(1); |
1460 | ai_corereg(wlc_hw->sih, SI_CC_IDX, | |
0da64910 | 1461 | offsetof(struct chipcregs, chipcontrol_data), 0x4, 0); |
8702fee6 RV |
1462 | udelay(1); |
1463 | ai_corereg(wlc_hw->sih, SI_CC_IDX, | |
0da64910 | 1464 | offsetof(struct chipcregs, chipcontrol_data), 0x4, 4); |
8702fee6 RV |
1465 | udelay(1); |
1466 | ai_corereg(wlc_hw->sih, SI_CC_IDX, | |
0da64910 | 1467 | offsetof(struct chipcregs, chipcontrol_data), 0x4, 0); |
8702fee6 RV |
1468 | udelay(1); |
1469 | } | |
1470 | ||
1471 | /* light way to turn on phy clock without reset for NPHY only | |
1472 | * refer to brcms_b_core_phy_clk for full version | |
1473 | */ | |
1474 | void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk) | |
1475 | { | |
1476 | /* support(necessary for NPHY and HYPHY) only */ | |
1477 | if (!BRCMS_ISNPHY(wlc_hw->band)) | |
1478 | return; | |
1479 | ||
1480 | if (ON == clk) | |
1481 | ai_core_cflags(wlc_hw->sih, SICF_FGC, SICF_FGC); | |
1482 | else | |
1483 | ai_core_cflags(wlc_hw->sih, SICF_FGC, 0); | |
1484 | ||
1485 | } | |
1486 | ||
1487 | void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk) | |
1488 | { | |
1489 | if (ON == clk) | |
1490 | ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, SICF_MPCLKE); | |
1491 | else | |
1492 | ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, 0); | |
1493 | } | |
1494 | ||
1495 | void brcms_b_phy_reset(struct brcms_hardware *wlc_hw) | |
1496 | { | |
1497 | struct brcms_phy_pub *pih = wlc_hw->band->pi; | |
1498 | u32 phy_bw_clkbits; | |
1499 | bool phy_in_reset = false; | |
1500 | ||
1501 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
1502 | ||
1503 | if (pih == NULL) | |
1504 | return; | |
1505 | ||
1506 | phy_bw_clkbits = wlc_phy_clk_bwbits(wlc_hw->band->pi); | |
1507 | ||
1508 | /* Specific reset sequence required for NPHY rev 3 and 4 */ | |
1509 | if (BRCMS_ISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) && | |
1510 | NREV_LE(wlc_hw->band->phyrev, 4)) { | |
1511 | /* Set the PHY bandwidth */ | |
1512 | ai_core_cflags(wlc_hw->sih, SICF_BWMASK, phy_bw_clkbits); | |
1513 | ||
1514 | udelay(1); | |
1515 | ||
1516 | /* Perform a soft reset of the PHY PLL */ | |
1517 | brcms_b_core_phypll_reset(wlc_hw); | |
1518 | ||
1519 | /* reset the PHY */ | |
1520 | ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_PCLKE), | |
1521 | (SICF_PRST | SICF_PCLKE)); | |
1522 | phy_in_reset = true; | |
1523 | } else { | |
8702fee6 RV |
1524 | ai_core_cflags(wlc_hw->sih, |
1525 | (SICF_PRST | SICF_PCLKE | SICF_BWMASK), | |
1526 | (SICF_PRST | SICF_PCLKE | phy_bw_clkbits)); | |
1527 | } | |
1528 | ||
1529 | udelay(2); | |
1530 | brcms_b_core_phy_clk(wlc_hw, ON); | |
1531 | ||
1532 | if (pih) | |
1533 | wlc_phy_anacore(pih, ON); | |
1534 | } | |
1535 | ||
1536 | /* switch to and initialize new band */ | |
1537 | static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit, | |
6bd20a1b | 1538 | u16 chanspec) { |
8702fee6 RV |
1539 | struct brcms_c_info *wlc = wlc_hw->wlc; |
1540 | u32 macintmask; | |
1541 | ||
1542 | /* Enable the d11 core before accessing it */ | |
1543 | if (!ai_iscoreup(wlc_hw->sih)) { | |
1544 | ai_core_reset(wlc_hw->sih, 0, 0); | |
1545 | brcms_c_mctrl_reset(wlc_hw); | |
1546 | } | |
1547 | ||
1548 | macintmask = brcms_c_setband_inact(wlc, bandunit); | |
1549 | ||
1550 | if (!wlc_hw->up) | |
1551 | return; | |
1552 | ||
1553 | brcms_b_core_phy_clk(wlc_hw, ON); | |
1554 | ||
1555 | /* band-specific initializations */ | |
1556 | brcms_b_bsinit(wlc, chanspec); | |
1557 | ||
1558 | /* | |
1559 | * If there are any pending software interrupt bits, | |
1560 | * then replace these with a harmless nonzero value | |
1561 | * so brcms_c_dpc() will re-enable interrupts when done. | |
1562 | */ | |
1563 | if (wlc->macintstatus) | |
1564 | wlc->macintstatus = MI_DMAINT; | |
1565 | ||
1566 | /* restore macintmask */ | |
1567 | brcms_intrsrestore(wlc->wl, macintmask); | |
1568 | ||
1569 | /* ucode should still be suspended.. */ | |
1570 | WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0); | |
1571 | } | |
1572 | ||
1573 | /* low-level band switch utility routine */ | |
1574 | void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit) | |
1575 | { | |
1576 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, | |
1577 | bandunit); | |
1578 | ||
1579 | wlc_hw->band = wlc_hw->bandstate[bandunit]; | |
1580 | ||
419ad34e AS |
1581 | /* |
1582 | * BMAC_NOTE: | |
1583 | * until we eliminate need for wlc->band refs in low level code | |
1584 | */ | |
8702fee6 RV |
1585 | wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit]; |
1586 | ||
1587 | /* set gmode core flag */ | |
8ea54c9f | 1588 | if (wlc_hw->sbclk && !wlc_hw->noreset) |
8702fee6 RV |
1589 | ai_core_cflags(wlc_hw->sih, SICF_GMODE, |
1590 | ((bandunit == 0) ? SICF_GMODE : 0)); | |
8702fee6 RV |
1591 | } |
1592 | ||
1593 | static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw) | |
1594 | { | |
1595 | ||
1596 | /* reject unsupported corerev */ | |
1597 | if (!VALID_COREREV(wlc_hw->corerev)) { | |
1598 | wiphy_err(wlc_hw->wlc->wiphy, "unsupported core rev %d\n", | |
1599 | wlc_hw->corerev); | |
1600 | return false; | |
1601 | } | |
1602 | ||
1603 | return true; | |
1604 | } | |
1605 | ||
1606 | /* Validate some board info parameters */ | |
1607 | static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw) | |
1608 | { | |
1609 | uint boardrev = wlc_hw->boardrev; | |
1610 | ||
1611 | /* 4 bits each for board type, major, minor, and tiny version */ | |
1612 | uint brt = (boardrev & 0xf000) >> 12; | |
1613 | uint b0 = (boardrev & 0xf00) >> 8; | |
1614 | uint b1 = (boardrev & 0xf0) >> 4; | |
1615 | uint b2 = boardrev & 0xf; | |
1616 | ||
1617 | /* voards from other vendors are always considered valid */ | |
1618 | if (wlc_hw->sih->boardvendor != PCI_VENDOR_ID_BROADCOM) | |
1619 | return true; | |
1620 | ||
1621 | /* do some boardrev sanity checks when boardvendor is Broadcom */ | |
1622 | if (boardrev == 0) | |
1623 | return false; | |
1624 | ||
1625 | if (boardrev <= 0xff) | |
1626 | return true; | |
1627 | ||
1628 | if ((brt > 2) || (brt == 0) || (b0 > 9) || (b0 == 0) || (b1 > 9) | |
1629 | || (b2 > 9)) | |
1630 | return false; | |
1631 | ||
1632 | return true; | |
1633 | } | |
1634 | ||
1635 | static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw) | |
1636 | { | |
1637 | const char *varname = "macaddr"; | |
1638 | char *macaddr; | |
1639 | ||
1640 | /* If macaddr exists, use it (Sromrev4, CIS, ...). */ | |
1641 | macaddr = getvar(wlc_hw->vars, varname); | |
1642 | if (macaddr != NULL) | |
1643 | return macaddr; | |
1644 | ||
1645 | if (NBANDS_HW(wlc_hw) > 1) | |
1646 | varname = "et1macaddr"; | |
1647 | else | |
1648 | varname = "il0macaddr"; | |
1649 | ||
1650 | macaddr = getvar(wlc_hw->vars, varname); | |
8ea54c9f | 1651 | if (macaddr == NULL) |
8702fee6 RV |
1652 | wiphy_err(wlc_hw->wlc->wiphy, "wl%d: wlc_get_macaddr: macaddr " |
1653 | "getvar(%s) not found\n", wlc_hw->unit, varname); | |
8702fee6 RV |
1654 | |
1655 | return macaddr; | |
1656 | } | |
1657 | ||
2682e2a3 AS |
1658 | /* power both the pll and external oscillator on/off */ |
1659 | static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want) | |
1660 | { | |
1661 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d: want %d\n", wlc_hw->unit, want); | |
1662 | ||
1663 | /* | |
1664 | * dont power down if plldown is false or | |
1665 | * we must poll hw radio disable | |
1666 | */ | |
1667 | if (!want && wlc_hw->pllreq) | |
1668 | return; | |
1669 | ||
1670 | if (wlc_hw->sih) | |
1671 | ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want); | |
1672 | ||
1673 | wlc_hw->sbclk = want; | |
1674 | if (!wlc_hw->sbclk) { | |
1675 | wlc_hw->clk = false; | |
1676 | if (wlc_hw->band && wlc_hw->band->pi) | |
1677 | wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false); | |
1678 | } | |
1679 | } | |
1680 | ||
8702fee6 RV |
1681 | /* |
1682 | * Return true if radio is disabled, otherwise false. | |
1683 | * hw radio disable signal is an external pin, users activate it asynchronously | |
1684 | * this function could be called when driver is down and w/o clock | |
1685 | * it operates on different registers depending on corerev and boardflag. | |
1686 | */ | |
11431424 | 1687 | static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw) |
8702fee6 RV |
1688 | { |
1689 | bool v, clk, xtal; | |
1690 | u32 resetbits = 0, flags = 0; | |
1691 | ||
1692 | xtal = wlc_hw->sbclk; | |
1693 | if (!xtal) | |
1694 | brcms_b_xtal(wlc_hw, ON); | |
1695 | ||
1696 | /* may need to take core out of reset first */ | |
1697 | clk = wlc_hw->clk; | |
1698 | if (!clk) { | |
1699 | /* | |
1700 | * mac no longer enables phyclk automatically when driver | |
1701 | * accesses phyreg throughput mac. This can be skipped since | |
1702 | * only mac reg is accessed below | |
1703 | */ | |
1704 | flags |= SICF_PCLKE; | |
1705 | ||
419ad34e AS |
1706 | /* |
1707 | * AI chip doesn't restore bar0win2 on | |
1708 | * hibernation/resume, need sw fixup | |
1709 | */ | |
8702fee6 RV |
1710 | if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || |
1711 | (wlc_hw->sih->chip == BCM43225_CHIP_ID)) | |
0da64910 RV |
1712 | wlc_hw->regs = (struct d11regs *) |
1713 | ai_setcore(wlc_hw->sih, D11_CORE_ID, 0); | |
8702fee6 RV |
1714 | ai_core_reset(wlc_hw->sih, flags, resetbits); |
1715 | brcms_c_mctrl_reset(wlc_hw); | |
1716 | } | |
1717 | ||
1718 | v = ((R_REG(&wlc_hw->regs->phydebug) & PDBG_RFD) != 0); | |
1719 | ||
1720 | /* put core back into reset */ | |
1721 | if (!clk) | |
1722 | ai_core_disable(wlc_hw->sih, 0); | |
1723 | ||
1724 | if (!xtal) | |
1725 | brcms_b_xtal(wlc_hw, OFF); | |
1726 | ||
1727 | return v; | |
1728 | } | |
1729 | ||
8702fee6 RV |
1730 | static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo) |
1731 | { | |
1732 | struct dma_pub *di = wlc_hw->di[fifo]; | |
1733 | return dma_rxreset(di); | |
1734 | } | |
1735 | ||
1736 | /* d11 core reset | |
1737 | * ensure fask clock during reset | |
1738 | * reset dma | |
1739 | * reset d11(out of reset) | |
1740 | * reset phy(out of reset) | |
1741 | * clear software macintstatus for fresh new start | |
1742 | * one testing hack wlc_hw->noreset will bypass the d11/phy reset | |
1743 | */ | |
1744 | void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) | |
1745 | { | |
0da64910 | 1746 | struct d11regs *regs; |
8702fee6 RV |
1747 | uint i; |
1748 | bool fastclk; | |
1749 | u32 resetbits = 0; | |
1750 | ||
1751 | if (flags == BRCMS_USE_COREFLAGS) | |
1752 | flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0); | |
1753 | ||
1754 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
1755 | ||
1756 | regs = wlc_hw->regs; | |
1757 | ||
1758 | /* request FAST clock if not on */ | |
1759 | fastclk = wlc_hw->forcefastclk; | |
1760 | if (!fastclk) | |
1761 | brcms_b_clkctl_clk(wlc_hw, CLK_FAST); | |
1762 | ||
1763 | /* reset the dma engines except first time thru */ | |
1764 | if (ai_iscoreup(wlc_hw->sih)) { | |
1765 | for (i = 0; i < NFIFO; i++) | |
8ea54c9f | 1766 | if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i]))) |
8702fee6 RV |
1767 | wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: " |
1768 | "dma_txreset[%d]: cannot stop dma\n", | |
1769 | wlc_hw->unit, __func__, i); | |
8702fee6 RV |
1770 | |
1771 | if ((wlc_hw->di[RX_FIFO]) | |
8ea54c9f | 1772 | && (!wlc_dma_rxreset(wlc_hw, RX_FIFO))) |
8702fee6 RV |
1773 | wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: dma_rxreset" |
1774 | "[%d]: cannot stop dma\n", | |
1775 | wlc_hw->unit, __func__, RX_FIFO); | |
8702fee6 RV |
1776 | } |
1777 | /* if noreset, just stop the psm and return */ | |
1778 | if (wlc_hw->noreset) { | |
1779 | wlc_hw->wlc->macintstatus = 0; /* skip wl_dpc after down */ | |
1780 | brcms_b_mctrl(wlc_hw, MCTL_PSM_RUN | MCTL_EN_MAC, 0); | |
1781 | return; | |
1782 | } | |
1783 | ||
1784 | /* | |
1785 | * mac no longer enables phyclk automatically when driver accesses | |
1786 | * phyreg throughput mac, AND phy_reset is skipped at early stage when | |
1787 | * band->pi is invalid. need to enable PHY CLK | |
1788 | */ | |
1789 | flags |= SICF_PCLKE; | |
1790 | ||
419ad34e AS |
1791 | /* |
1792 | * reset the core | |
1793 | * In chips with PMU, the fastclk request goes through d11 core | |
1794 | * reg 0x1e0, which is cleared by the core_reset. have to re-request it. | |
1795 | * | |
1796 | * This adds some delay and we can optimize it by also requesting | |
1797 | * fastclk through chipcommon during this period if necessary. But | |
1798 | * that has to work coordinate with other driver like mips/arm since | |
1799 | * they may touch chipcommon as well. | |
8702fee6 RV |
1800 | */ |
1801 | wlc_hw->clk = false; | |
1802 | ai_core_reset(wlc_hw->sih, flags, resetbits); | |
1803 | wlc_hw->clk = true; | |
1804 | if (wlc_hw->band && wlc_hw->band->pi) | |
1805 | wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, true); | |
1806 | ||
1807 | brcms_c_mctrl_reset(wlc_hw); | |
1808 | ||
1809 | if (PMUCTL_ENAB(wlc_hw->sih)) | |
1810 | brcms_b_clkctl_clk(wlc_hw, CLK_FAST); | |
1811 | ||
1812 | brcms_b_phy_reset(wlc_hw); | |
1813 | ||
1814 | /* turn on PHY_PLL */ | |
1815 | brcms_b_core_phypll_ctl(wlc_hw, true); | |
1816 | ||
1817 | /* clear sw intstatus */ | |
1818 | wlc_hw->wlc->macintstatus = 0; | |
1819 | ||
1820 | /* restore the clk setting */ | |
1821 | if (!fastclk) | |
1822 | brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); | |
1823 | } | |
1824 | ||
1825 | /* txfifo sizes needs to be modified(increased) since the newer cores | |
1826 | * have more memory. | |
1827 | */ | |
1828 | static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw) | |
1829 | { | |
0da64910 | 1830 | struct d11regs *regs = wlc_hw->regs; |
8702fee6 RV |
1831 | u16 fifo_nu; |
1832 | u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk; | |
1833 | u16 txfifo_def, txfifo_def1; | |
1834 | u16 txfifo_cmd; | |
1835 | ||
1836 | /* tx fifos start at TXFIFO_START_BLK from the Base address */ | |
839f9f62 | 1837 | txfifo_startblk = TXFIFO_START_BLK; |
8702fee6 | 1838 | |
839f9f62 RV |
1839 | /* sequence of operations: reset fifo, set fifo size, reset fifo */ |
1840 | for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) { | |
8702fee6 | 1841 | |
839f9f62 RV |
1842 | txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu]; |
1843 | txfifo_def = (txfifo_startblk & 0xff) | | |
1844 | (((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT); | |
1845 | txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) | | |
1846 | ((((txfifo_endblk - | |
1847 | 1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT); | |
1848 | txfifo_cmd = | |
1849 | TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT); | |
8702fee6 | 1850 | |
839f9f62 RV |
1851 | W_REG(®s->xmtfifocmd, txfifo_cmd); |
1852 | W_REG(®s->xmtfifodef, txfifo_def); | |
1853 | W_REG(®s->xmtfifodef1, txfifo_def1); | |
8702fee6 | 1854 | |
839f9f62 | 1855 | W_REG(®s->xmtfifocmd, txfifo_cmd); |
8702fee6 | 1856 | |
839f9f62 | 1857 | txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu]; |
8702fee6 | 1858 | } |
839f9f62 RV |
1859 | /* |
1860 | * need to propagate to shm location to be in sync since ucode/hw won't | |
1861 | * do this | |
1862 | */ | |
1863 | brcms_b_write_shm(wlc_hw, M_FIFOSIZE0, | |
1864 | wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]); | |
1865 | brcms_b_write_shm(wlc_hw, M_FIFOSIZE1, | |
1866 | wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]); | |
1867 | brcms_b_write_shm(wlc_hw, M_FIFOSIZE2, | |
1868 | ((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw-> | |
1869 | xmtfifo_sz[TX_AC_BK_FIFO])); | |
1870 | brcms_b_write_shm(wlc_hw, M_FIFOSIZE3, | |
1871 | ((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw-> | |
1872 | xmtfifo_sz[TX_BCMC_FIFO])); | |
8702fee6 RV |
1873 | } |
1874 | ||
1875 | /* This function is used for changing the tsf frac register | |
1876 | * If spur avoidance mode is off, the mac freq will be 80/120/160Mhz | |
1877 | * If spur avoidance mode is on1, the mac freq will be 82/123/164Mhz | |
1878 | * If spur avoidance mode is on2, the mac freq will be 84/126/168Mhz | |
1879 | * HTPHY Formula is 2^26/freq(MHz) e.g. | |
1880 | * For spuron2 - 126MHz -> 2^26/126 = 532610.0 | |
1881 | * - 532610 = 0x82082 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x2082 | |
1882 | * For spuron: 123MHz -> 2^26/123 = 545600.5 | |
1883 | * - 545601 = 0x85341 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x5341 | |
1884 | * For spur off: 120MHz -> 2^26/120 = 559240.5 | |
1885 | * - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889 | |
1886 | */ | |
1887 | ||
1888 | void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode) | |
1889 | { | |
0da64910 | 1890 | struct d11regs *regs; |
8702fee6 RV |
1891 | regs = wlc_hw->regs; |
1892 | ||
1893 | if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || | |
1894 | (wlc_hw->sih->chip == BCM43225_CHIP_ID)) { | |
1895 | if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */ | |
1896 | W_REG(®s->tsf_clk_frac_l, 0x2082); | |
1897 | W_REG(®s->tsf_clk_frac_h, 0x8); | |
1898 | } else if (spurmode == WL_SPURAVOID_ON1) { /* 123Mhz */ | |
1899 | W_REG(®s->tsf_clk_frac_l, 0x5341); | |
1900 | W_REG(®s->tsf_clk_frac_h, 0x8); | |
1901 | } else { /* 120Mhz */ | |
1902 | W_REG(®s->tsf_clk_frac_l, 0x8889); | |
1903 | W_REG(®s->tsf_clk_frac_h, 0x8); | |
1904 | } | |
1905 | } else if (BRCMS_ISLCNPHY(wlc_hw->band)) { | |
1906 | if (spurmode == WL_SPURAVOID_ON1) { /* 82Mhz */ | |
1907 | W_REG(®s->tsf_clk_frac_l, 0x7CE0); | |
1908 | W_REG(®s->tsf_clk_frac_h, 0xC); | |
1909 | } else { /* 80Mhz */ | |
1910 | W_REG(®s->tsf_clk_frac_l, 0xCCCD); | |
1911 | W_REG(®s->tsf_clk_frac_h, 0xC); | |
1912 | } | |
1913 | } | |
1914 | } | |
1915 | ||
1916 | /* Initialize GPIOs that are controlled by D11 core */ | |
1917 | static void brcms_c_gpio_init(struct brcms_c_info *wlc) | |
1918 | { | |
1919 | struct brcms_hardware *wlc_hw = wlc->hw; | |
0da64910 | 1920 | struct d11regs *regs; |
8702fee6 RV |
1921 | u32 gc, gm; |
1922 | ||
1923 | regs = wlc_hw->regs; | |
1924 | ||
1925 | /* use GPIO select 0 to get all gpio signals from the gpio out reg */ | |
1926 | brcms_b_mctrl(wlc_hw, MCTL_GPOUT_SEL_MASK, 0); | |
1927 | ||
1928 | /* | |
1929 | * Common GPIO setup: | |
1930 | * G0 = LED 0 = WLAN Activity | |
1931 | * G1 = LED 1 = WLAN 2.4 GHz Radio State | |
1932 | * G2 = LED 2 = WLAN 5 GHz Radio State | |
1933 | * G4 = radio disable input (HI enabled, LO disabled) | |
1934 | */ | |
1935 | ||
1936 | gc = gm = 0; | |
1937 | ||
1938 | /* Allocate GPIOs for mimo antenna diversity feature */ | |
1939 | if (wlc_hw->antsel_type == ANTSEL_2x3) { | |
1940 | /* Enable antenna diversity, use 2x3 mode */ | |
1941 | brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN, | |
1942 | MHF3_ANTSEL_EN, BRCM_BAND_ALL); | |
1943 | brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, | |
1944 | MHF3_ANTSEL_MODE, BRCM_BAND_ALL); | |
1945 | ||
1946 | /* init superswitch control */ | |
1947 | wlc_phy_antsel_init(wlc_hw->band->pi, false); | |
1948 | ||
1949 | } else if (wlc_hw->antsel_type == ANTSEL_2x4) { | |
1950 | gm |= gc |= (BOARD_GPIO_12 | BOARD_GPIO_13); | |
1951 | /* | |
1952 | * The board itself is powered by these GPIOs | |
1953 | * (when not sending pattern) so set them high | |
1954 | */ | |
1955 | OR_REG(®s->psm_gpio_oe, | |
1956 | (BOARD_GPIO_12 | BOARD_GPIO_13)); | |
1957 | OR_REG(®s->psm_gpio_out, | |
1958 | (BOARD_GPIO_12 | BOARD_GPIO_13)); | |
1959 | ||
1960 | /* Enable antenna diversity, use 2x4 mode */ | |
1961 | brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN, | |
1962 | MHF3_ANTSEL_EN, BRCM_BAND_ALL); | |
1963 | brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, 0, | |
1964 | BRCM_BAND_ALL); | |
1965 | ||
1966 | /* Configure the desired clock to be 4Mhz */ | |
1967 | brcms_b_write_shm(wlc_hw, M_ANTSEL_CLKDIV, | |
1968 | ANTSEL_CLKDIV_4MHZ); | |
1969 | } | |
1970 | ||
419ad34e AS |
1971 | /* |
1972 | * gpio 9 controls the PA. ucode is responsible | |
1973 | * for wiggling out and oe | |
1974 | */ | |
8702fee6 RV |
1975 | if (wlc_hw->boardflags & BFL_PACTRL) |
1976 | gm |= gc |= BOARD_GPIO_PACTRL; | |
1977 | ||
1978 | /* apply to gpiocontrol register */ | |
1979 | ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY); | |
1980 | } | |
1981 | ||
2682e2a3 AS |
1982 | static void brcms_ucode_write(struct brcms_hardware *wlc_hw, const u32 ucode[], |
1983 | const uint nbytes) { | |
1984 | struct d11regs *regs = wlc_hw->regs; | |
1985 | uint i; | |
1986 | uint count; | |
1987 | ||
1988 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
1989 | ||
1990 | count = (nbytes / sizeof(u32)); | |
1991 | ||
1992 | W_REG(®s->objaddr, (OBJADDR_AUTO_INC | OBJADDR_UCM_SEL)); | |
1993 | (void)R_REG(®s->objaddr); | |
1994 | for (i = 0; i < count; i++) | |
1995 | W_REG(®s->objdata, le32_to_cpu(ucode[i])); | |
1996 | ||
1997 | } | |
1998 | ||
8702fee6 RV |
1999 | static void brcms_ucode_download(struct brcms_hardware *wlc_hw) |
2000 | { | |
2001 | struct brcms_c_info *wlc; | |
2002 | wlc = wlc_hw->wlc; | |
2003 | ||
2004 | if (wlc_hw->ucode_loaded) | |
2005 | return; | |
2006 | ||
2007 | if (D11REV_IS(wlc_hw->corerev, 23)) { | |
2008 | if (BRCMS_ISNPHY(wlc_hw->band)) { | |
2009 | brcms_ucode_write(wlc_hw, bcm43xx_16_mimo, | |
2010 | bcm43xx_16_mimosz); | |
2011 | wlc_hw->ucode_loaded = true; | |
2012 | } else | |
2013 | wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in " | |
2014 | "corerev %d\n", | |
2015 | __func__, wlc_hw->unit, wlc_hw->corerev); | |
2016 | } else if (D11REV_IS(wlc_hw->corerev, 24)) { | |
2017 | if (BRCMS_ISLCNPHY(wlc_hw->band)) { | |
2018 | brcms_ucode_write(wlc_hw, bcm43xx_24_lcn, | |
2019 | bcm43xx_24_lcnsz); | |
2020 | wlc_hw->ucode_loaded = true; | |
2021 | } else { | |
2022 | wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in " | |
2023 | "corerev %d\n", | |
2024 | __func__, wlc_hw->unit, wlc_hw->corerev); | |
2025 | } | |
2026 | } | |
2027 | } | |
2028 | ||
8702fee6 RV |
2029 | void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant) |
2030 | { | |
2031 | /* update sw state */ | |
2032 | wlc_hw->bmac_phytxant = phytxant; | |
2033 | ||
2034 | /* push to ucode if up */ | |
2035 | if (!wlc_hw->up) | |
2036 | return; | |
2037 | brcms_c_ucode_txant_set(wlc_hw); | |
2038 | ||
2039 | } | |
2040 | ||
2041 | u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw) | |
2042 | { | |
2043 | return (u16) wlc_hw->wlc->stf->txant; | |
2044 | } | |
2045 | ||
2046 | void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type) | |
2047 | { | |
2048 | wlc_hw->antsel_type = antsel_type; | |
2049 | ||
2050 | /* Update the antsel type for phy module to use */ | |
2051 | wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type); | |
2052 | } | |
2053 | ||
11431424 | 2054 | static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw) |
8702fee6 RV |
2055 | { |
2056 | bool fatal = false; | |
2057 | uint unit; | |
2058 | uint intstatus, idx; | |
0da64910 | 2059 | struct d11regs *regs = wlc_hw->regs; |
8702fee6 RV |
2060 | struct wiphy *wiphy = wlc_hw->wlc->wiphy; |
2061 | ||
2062 | unit = wlc_hw->unit; | |
2063 | ||
2064 | for (idx = 0; idx < NFIFO; idx++) { | |
2065 | /* read intstatus register and ignore any non-error bits */ | |
2066 | intstatus = | |
2067 | R_REG(®s->intctrlregs[idx].intstatus) & I_ERRORS; | |
2068 | if (!intstatus) | |
2069 | continue; | |
2070 | ||
2071 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d: intstatus%d 0x%x\n", | |
2072 | unit, idx, intstatus); | |
2073 | ||
2074 | if (intstatus & I_RO) { | |
2075 | wiphy_err(wiphy, "wl%d: fifo %d: receive fifo " | |
2076 | "overflow\n", unit, idx); | |
2077 | fatal = true; | |
2078 | } | |
2079 | ||
2080 | if (intstatus & I_PC) { | |
2081 | wiphy_err(wiphy, "wl%d: fifo %d: descriptor error\n", | |
2082 | unit, idx); | |
2083 | fatal = true; | |
2084 | } | |
2085 | ||
2086 | if (intstatus & I_PD) { | |
2087 | wiphy_err(wiphy, "wl%d: fifo %d: data error\n", unit, | |
2088 | idx); | |
2089 | fatal = true; | |
2090 | } | |
2091 | ||
2092 | if (intstatus & I_DE) { | |
2093 | wiphy_err(wiphy, "wl%d: fifo %d: descriptor protocol " | |
2094 | "error\n", unit, idx); | |
2095 | fatal = true; | |
2096 | } | |
2097 | ||
8ea54c9f | 2098 | if (intstatus & I_RU) |
8702fee6 RV |
2099 | wiphy_err(wiphy, "wl%d: fifo %d: receive descriptor " |
2100 | "underflow\n", idx, unit); | |
8702fee6 RV |
2101 | |
2102 | if (intstatus & I_XU) { | |
2103 | wiphy_err(wiphy, "wl%d: fifo %d: transmit fifo " | |
2104 | "underflow\n", idx, unit); | |
2105 | fatal = true; | |
2106 | } | |
2107 | ||
2108 | if (fatal) { | |
2109 | brcms_c_fatal_error(wlc_hw->wlc); /* big hammer */ | |
2110 | break; | |
2111 | } else | |
2112 | W_REG(®s->intctrlregs[idx].intstatus, | |
2113 | intstatus); | |
2114 | } | |
2115 | } | |
2116 | ||
2117 | void brcms_c_intrson(struct brcms_c_info *wlc) | |
2118 | { | |
2119 | struct brcms_hardware *wlc_hw = wlc->hw; | |
2120 | wlc->macintmask = wlc->defmacintmask; | |
2121 | W_REG(&wlc_hw->regs->macintmask, wlc->macintmask); | |
2122 | } | |
2123 | ||
419ad34e AS |
2124 | /* |
2125 | * callback for siutils.c, which has only wlc handler, no wl they both check | |
2126 | * up, not only because there is no need to off/restore d11 interrupt but also | |
2127 | * because per-port code may require sync with valid interrupt. | |
8702fee6 | 2128 | */ |
8702fee6 RV |
2129 | static u32 brcms_c_wlintrsoff(struct brcms_c_info *wlc) |
2130 | { | |
2131 | if (!wlc->hw->up) | |
2132 | return 0; | |
2133 | ||
2134 | return brcms_intrsoff(wlc->wl); | |
2135 | } | |
2136 | ||
2137 | static void brcms_c_wlintrsrestore(struct brcms_c_info *wlc, u32 macintmask) | |
2138 | { | |
2139 | if (!wlc->hw->up) | |
2140 | return; | |
2141 | ||
2142 | brcms_intrsrestore(wlc->wl, macintmask); | |
2143 | } | |
2144 | ||
2145 | u32 brcms_c_intrsoff(struct brcms_c_info *wlc) | |
2146 | { | |
2147 | struct brcms_hardware *wlc_hw = wlc->hw; | |
2148 | u32 macintmask; | |
2149 | ||
2150 | if (!wlc_hw->clk) | |
2151 | return 0; | |
2152 | ||
2153 | macintmask = wlc->macintmask; /* isr can still happen */ | |
2154 | ||
2155 | W_REG(&wlc_hw->regs->macintmask, 0); | |
2156 | (void)R_REG(&wlc_hw->regs->macintmask); /* sync readback */ | |
2157 | udelay(1); /* ensure int line is no longer driven */ | |
2158 | wlc->macintmask = 0; | |
2159 | ||
2160 | /* return previous macintmask; resolve race between us and our isr */ | |
2161 | return wlc->macintstatus ? 0 : macintmask; | |
2162 | } | |
2163 | ||
2164 | void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask) | |
2165 | { | |
2166 | struct brcms_hardware *wlc_hw = wlc->hw; | |
2167 | if (!wlc_hw->clk) | |
2168 | return; | |
2169 | ||
2170 | wlc->macintmask = macintmask; | |
2171 | W_REG(&wlc_hw->regs->macintmask, wlc->macintmask); | |
2172 | } | |
2173 | ||
839f9f62 RV |
2174 | static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw, |
2175 | uint tx_fifo) | |
2176 | { | |
2177 | u8 fifo = 1 << tx_fifo; | |
2178 | ||
2179 | /* Two clients of this code, 11h Quiet period and scanning. */ | |
2180 | ||
2181 | /* only suspend if not already suspended */ | |
2182 | if ((wlc_hw->suspended_fifos & fifo) == fifo) | |
2183 | return; | |
2184 | ||
2185 | /* force the core awake only if not already */ | |
2186 | if (wlc_hw->suspended_fifos == 0) | |
2187 | brcms_c_ucode_wake_override_set(wlc_hw, | |
2188 | BRCMS_WAKE_OVERRIDE_TXFIFO); | |
2189 | ||
2190 | wlc_hw->suspended_fifos |= fifo; | |
2191 | ||
2192 | if (wlc_hw->di[tx_fifo]) { | |
419ad34e AS |
2193 | /* |
2194 | * Suspending AMPDU transmissions in the middle can cause | |
2195 | * underflow which may result in mismatch between ucode and | |
2196 | * driver so suspend the mac before suspending the FIFO | |
839f9f62 RV |
2197 | */ |
2198 | if (BRCMS_PHY_11N_CAP(wlc_hw->band)) | |
2199 | brcms_c_suspend_mac_and_wait(wlc_hw->wlc); | |
2200 | ||
2201 | dma_txsuspend(wlc_hw->di[tx_fifo]); | |
2202 | ||
2203 | if (BRCMS_PHY_11N_CAP(wlc_hw->band)) | |
2204 | brcms_c_enable_mac(wlc_hw->wlc); | |
2205 | } | |
2206 | } | |
2207 | ||
2682e2a3 AS |
2208 | static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw, |
2209 | uint tx_fifo) | |
2210 | { | |
2211 | /* BMAC_NOTE: BRCMS_TX_FIFO_ENAB is done in brcms_c_dpc() for DMA case | |
2212 | * but need to be done here for PIO otherwise the watchdog will catch | |
2213 | * the inconsistency and fire | |
2214 | */ | |
2215 | /* Two clients of this code, 11h Quiet period and scanning. */ | |
2216 | if (wlc_hw->di[tx_fifo]) | |
2217 | dma_txresume(wlc_hw->di[tx_fifo]); | |
2218 | ||
2219 | /* allow core to sleep again */ | |
2220 | if (wlc_hw->suspended_fifos == 0) | |
2221 | return; | |
2222 | else { | |
2223 | wlc_hw->suspended_fifos &= ~(1 << tx_fifo); | |
2224 | if (wlc_hw->suspended_fifos == 0) | |
2225 | brcms_c_ucode_wake_override_clear(wlc_hw, | |
2226 | BRCMS_WAKE_OVERRIDE_TXFIFO); | |
2227 | } | |
2228 | } | |
2229 | ||
6bd20a1b | 2230 | static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags) |
8702fee6 RV |
2231 | { |
2232 | u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; | |
2233 | ||
2234 | if (on) { | |
2235 | /* suspend tx fifos */ | |
2236 | brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO); | |
2237 | brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO); | |
2238 | brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_BK_FIFO); | |
2239 | brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO); | |
2240 | ||
2241 | /* zero the address match register so we do not send ACKs */ | |
2242 | brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, | |
2243 | null_ether_addr); | |
2244 | } else { | |
2245 | /* resume tx fifos */ | |
8ea54c9f | 2246 | if (!wlc_hw->wlc->tx_suspended) |
8702fee6 | 2247 | brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO); |
8ea54c9f | 2248 | |
8702fee6 RV |
2249 | brcms_b_tx_fifo_resume(wlc_hw, TX_CTL_FIFO); |
2250 | brcms_b_tx_fifo_resume(wlc_hw, TX_AC_BK_FIFO); | |
2251 | brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO); | |
2252 | ||
2253 | /* Restore address */ | |
2254 | brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, | |
2255 | wlc_hw->etheraddr); | |
2256 | } | |
2257 | ||
2258 | wlc_phy_mute_upd(wlc_hw->band->pi, on, flags); | |
2259 | ||
2260 | if (on) | |
2261 | brcms_c_ucode_mute_override_set(wlc_hw); | |
2262 | else | |
2263 | brcms_c_ucode_mute_override_clear(wlc_hw); | |
2264 | } | |
2265 | ||
8702fee6 RV |
2266 | /* |
2267 | * Read and clear macintmask and macintstatus and intstatus registers. | |
2268 | * This routine should be called with interrupts off | |
2269 | * Return: | |
2270 | * -1 if DEVICEREMOVED(wlc) evaluates to true; | |
2271 | * 0 if the interrupt is not for us, or we are in some special cases; | |
2272 | * device interrupt status bits otherwise. | |
2273 | */ | |
2274 | static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr) | |
2275 | { | |
2276 | struct brcms_hardware *wlc_hw = wlc->hw; | |
0da64910 | 2277 | struct d11regs *regs = wlc_hw->regs; |
8702fee6 RV |
2278 | u32 macintstatus; |
2279 | ||
2280 | /* macintstatus includes a DMA interrupt summary bit */ | |
2281 | macintstatus = R_REG(®s->macintstatus); | |
2282 | ||
2283 | BCMMSG(wlc->wiphy, "wl%d: macintstatus: 0x%x\n", wlc_hw->unit, | |
2284 | macintstatus); | |
2285 | ||
2286 | /* detect cardbus removed, in power down(suspend) and in reset */ | |
2287 | if (DEVICEREMOVED(wlc)) | |
2288 | return -1; | |
2289 | ||
2290 | /* DEVICEREMOVED succeeds even when the core is still resetting, | |
2291 | * handle that case here. | |
2292 | */ | |
2293 | if (macintstatus == 0xffffffff) | |
2294 | return 0; | |
2295 | ||
2296 | /* defer unsolicited interrupts */ | |
2297 | macintstatus &= (in_isr ? wlc->macintmask : wlc->defmacintmask); | |
2298 | ||
2299 | /* if not for us */ | |
2300 | if (macintstatus == 0) | |
2301 | return 0; | |
2302 | ||
2303 | /* interrupts are already turned off for CFE build | |
2304 | * Caution: For CFE Turning off the interrupts again has some undesired | |
2305 | * consequences | |
2306 | */ | |
2307 | /* turn off the interrupts */ | |
2308 | W_REG(®s->macintmask, 0); | |
2309 | (void)R_REG(®s->macintmask); /* sync readback */ | |
2310 | wlc->macintmask = 0; | |
2311 | ||
2312 | /* clear device interrupts */ | |
2313 | W_REG(®s->macintstatus, macintstatus); | |
2314 | ||
2315 | /* MI_DMAINT is indication of non-zero intstatus */ | |
8ea54c9f | 2316 | if (macintstatus & MI_DMAINT) |
8702fee6 RV |
2317 | /* |
2318 | * only fifo interrupt enabled is I_RI in | |
2319 | * RX_FIFO. If MI_DMAINT is set, assume it | |
2320 | * is set and clear the interrupt. | |
2321 | */ | |
2322 | W_REG(®s->intctrlregs[RX_FIFO].intstatus, | |
2323 | DEF_RXINTMASK); | |
8702fee6 RV |
2324 | |
2325 | return macintstatus; | |
2326 | } | |
2327 | ||
2328 | /* Update wlc->macintstatus and wlc->intstatus[]. */ | |
2329 | /* Return true if they are updated successfully. false otherwise */ | |
2330 | bool brcms_c_intrsupd(struct brcms_c_info *wlc) | |
2331 | { | |
2332 | u32 macintstatus; | |
2333 | ||
2334 | /* read and clear macintstatus and intstatus registers */ | |
2335 | macintstatus = wlc_intstatus(wlc, false); | |
2336 | ||
2337 | /* device is removed */ | |
2338 | if (macintstatus == 0xffffffff) | |
2339 | return false; | |
2340 | ||
2341 | /* update interrupt status in software */ | |
2342 | wlc->macintstatus |= macintstatus; | |
2343 | ||
2344 | return true; | |
2345 | } | |
2346 | ||
2347 | /* | |
2348 | * First-level interrupt processing. | |
2349 | * Return true if this was our interrupt, false otherwise. | |
2350 | * *wantdpc will be set to true if further brcms_c_dpc() processing is required, | |
2351 | * false otherwise. | |
2352 | */ | |
2353 | bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc) | |
2354 | { | |
2355 | struct brcms_hardware *wlc_hw = wlc->hw; | |
2356 | u32 macintstatus; | |
2357 | ||
2358 | *wantdpc = false; | |
2359 | ||
2360 | if (!wlc_hw->up || !wlc->macintmask) | |
2361 | return false; | |
2362 | ||
2363 | /* read and clear macintstatus and intstatus registers */ | |
2364 | macintstatus = wlc_intstatus(wlc, true); | |
2365 | ||
2366 | if (macintstatus == 0xffffffff) | |
2367 | wiphy_err(wlc->wiphy, "DEVICEREMOVED detected in the ISR code" | |
2368 | " path\n"); | |
2369 | ||
2370 | /* it is not for us */ | |
2371 | if (macintstatus == 0) | |
2372 | return false; | |
2373 | ||
2374 | *wantdpc = true; | |
2375 | ||
2376 | /* save interrupt status bits */ | |
2377 | wlc->macintstatus = macintstatus; | |
2378 | ||
2379 | return true; | |
2380 | ||
2381 | } | |
2382 | ||
8702fee6 RV |
2383 | void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) |
2384 | { | |
2385 | struct brcms_hardware *wlc_hw = wlc->hw; | |
0da64910 | 2386 | struct d11regs *regs = wlc_hw->regs; |
8702fee6 RV |
2387 | u32 mc, mi; |
2388 | struct wiphy *wiphy = wlc->wiphy; | |
2389 | ||
2390 | BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, | |
2391 | wlc_hw->band->bandunit); | |
2392 | ||
2393 | /* | |
2394 | * Track overlapping suspend requests | |
2395 | */ | |
2396 | wlc_hw->mac_suspend_depth++; | |
2397 | if (wlc_hw->mac_suspend_depth > 1) | |
2398 | return; | |
2399 | ||
2400 | /* force the core awake */ | |
2401 | brcms_c_ucode_wake_override_set(wlc_hw, BRCMS_WAKE_OVERRIDE_MACSUSPEND); | |
2402 | ||
2403 | mc = R_REG(®s->maccontrol); | |
2404 | ||
2405 | if (mc == 0xffffffff) { | |
2406 | wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, | |
2407 | __func__); | |
2408 | brcms_down(wlc->wl); | |
2409 | return; | |
2410 | } | |
2411 | WARN_ON(mc & MCTL_PSM_JMP_0); | |
2412 | WARN_ON(!(mc & MCTL_PSM_RUN)); | |
2413 | WARN_ON(!(mc & MCTL_EN_MAC)); | |
2414 | ||
2415 | mi = R_REG(®s->macintstatus); | |
2416 | if (mi == 0xffffffff) { | |
2417 | wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, | |
2418 | __func__); | |
2419 | brcms_down(wlc->wl); | |
2420 | return; | |
2421 | } | |
2422 | WARN_ON(mi & MI_MACSSPNDD); | |
2423 | ||
2424 | brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, 0); | |
2425 | ||
2426 | SPINWAIT(!(R_REG(®s->macintstatus) & MI_MACSSPNDD), | |
2427 | BRCMS_MAX_MAC_SUSPEND); | |
2428 | ||
2429 | if (!(R_REG(®s->macintstatus) & MI_MACSSPNDD)) { | |
2430 | wiphy_err(wiphy, "wl%d: wlc_suspend_mac_and_wait: waited %d uS" | |
2431 | " and MI_MACSSPNDD is still not on.\n", | |
2432 | wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND); | |
2433 | wiphy_err(wiphy, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, " | |
2434 | "psm_brc 0x%04x\n", wlc_hw->unit, | |
2435 | R_REG(®s->psmdebug), | |
2436 | R_REG(®s->phydebug), | |
2437 | R_REG(®s->psm_brc)); | |
2438 | } | |
2439 | ||
2440 | mc = R_REG(®s->maccontrol); | |
2441 | if (mc == 0xffffffff) { | |
2442 | wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, | |
2443 | __func__); | |
2444 | brcms_down(wlc->wl); | |
2445 | return; | |
2446 | } | |
2447 | WARN_ON(mc & MCTL_PSM_JMP_0); | |
2448 | WARN_ON(!(mc & MCTL_PSM_RUN)); | |
2449 | WARN_ON(mc & MCTL_EN_MAC); | |
2450 | } | |
2451 | ||
2452 | void brcms_c_enable_mac(struct brcms_c_info *wlc) | |
2453 | { | |
2454 | struct brcms_hardware *wlc_hw = wlc->hw; | |
0da64910 | 2455 | struct d11regs *regs = wlc_hw->regs; |
8702fee6 RV |
2456 | u32 mc, mi; |
2457 | ||
2458 | BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, | |
2459 | wlc->band->bandunit); | |
2460 | ||
2461 | /* | |
2462 | * Track overlapping suspend requests | |
2463 | */ | |
2464 | wlc_hw->mac_suspend_depth--; | |
2465 | if (wlc_hw->mac_suspend_depth > 0) | |
2466 | return; | |
2467 | ||
2468 | mc = R_REG(®s->maccontrol); | |
2469 | WARN_ON(mc & MCTL_PSM_JMP_0); | |
2470 | WARN_ON(mc & MCTL_EN_MAC); | |
2471 | WARN_ON(!(mc & MCTL_PSM_RUN)); | |
2472 | ||
2473 | brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, MCTL_EN_MAC); | |
2474 | W_REG(®s->macintstatus, MI_MACSSPNDD); | |
2475 | ||
2476 | mc = R_REG(®s->maccontrol); | |
2477 | WARN_ON(mc & MCTL_PSM_JMP_0); | |
2478 | WARN_ON(!(mc & MCTL_EN_MAC)); | |
2479 | WARN_ON(!(mc & MCTL_PSM_RUN)); | |
2480 | ||
2481 | mi = R_REG(®s->macintstatus); | |
2482 | WARN_ON(mi & MI_MACSSPNDD); | |
2483 | ||
2484 | brcms_c_ucode_wake_override_clear(wlc_hw, | |
2485 | BRCMS_WAKE_OVERRIDE_MACSUSPEND); | |
2486 | } | |
2487 | ||
2682e2a3 | 2488 | void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode) |
8702fee6 RV |
2489 | { |
2490 | wlc_hw->hw_stf_ss_opmode = stf_mode; | |
2491 | ||
2492 | if (wlc_hw->clk) | |
2493 | brcms_upd_ofdm_pctl1_table(wlc_hw); | |
2494 | } | |
2495 | ||
8702fee6 RV |
2496 | static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw) |
2497 | { | |
0da64910 | 2498 | struct d11regs *regs; |
8702fee6 RV |
2499 | u32 w, val; |
2500 | struct wiphy *wiphy = wlc_hw->wlc->wiphy; | |
2501 | ||
2502 | BCMMSG(wiphy, "wl%d\n", wlc_hw->unit); | |
2503 | ||
2504 | regs = wlc_hw->regs; | |
2505 | ||
2506 | /* Validate dchip register access */ | |
2507 | ||
2508 | W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); | |
2509 | (void)R_REG(®s->objaddr); | |
2510 | w = R_REG(®s->objdata); | |
2511 | ||
2512 | /* Can we write and read back a 32bit register? */ | |
2513 | W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); | |
2514 | (void)R_REG(®s->objaddr); | |
2515 | W_REG(®s->objdata, (u32) 0xaa5555aa); | |
2516 | ||
2517 | W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); | |
2518 | (void)R_REG(®s->objaddr); | |
2519 | val = R_REG(®s->objdata); | |
2520 | if (val != (u32) 0xaa5555aa) { | |
2521 | wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, " | |
2522 | "expected 0xaa5555aa\n", wlc_hw->unit, val); | |
2523 | return false; | |
2524 | } | |
2525 | ||
2526 | W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); | |
2527 | (void)R_REG(®s->objaddr); | |
2528 | W_REG(®s->objdata, (u32) 0x55aaaa55); | |
2529 | ||
2530 | W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); | |
2531 | (void)R_REG(®s->objaddr); | |
2532 | val = R_REG(®s->objdata); | |
2533 | if (val != (u32) 0x55aaaa55) { | |
2534 | wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, " | |
2535 | "expected 0x55aaaa55\n", wlc_hw->unit, val); | |
2536 | return false; | |
2537 | } | |
2538 | ||
2539 | W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); | |
2540 | (void)R_REG(®s->objaddr); | |
2541 | W_REG(®s->objdata, w); | |
2542 | ||
2543 | /* clear CFPStart */ | |
2544 | W_REG(®s->tsf_cfpstart, 0); | |
2545 | ||
2546 | w = R_REG(®s->maccontrol); | |
2547 | if ((w != (MCTL_IHR_EN | MCTL_WAKE)) && | |
2548 | (w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) { | |
2549 | wiphy_err(wiphy, "wl%d: validate_chip_access: maccontrol = " | |
2550 | "0x%x, expected 0x%x or 0x%x\n", wlc_hw->unit, w, | |
2551 | (MCTL_IHR_EN | MCTL_WAKE), | |
2552 | (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE)); | |
2553 | return false; | |
2554 | } | |
2555 | ||
2556 | return true; | |
2557 | } | |
2558 | ||
2559 | #define PHYPLL_WAIT_US 100000 | |
2560 | ||
2561 | void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on) | |
2562 | { | |
0da64910 | 2563 | struct d11regs *regs; |
8702fee6 RV |
2564 | u32 tmp; |
2565 | ||
2566 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
2567 | ||
2568 | tmp = 0; | |
2569 | regs = wlc_hw->regs; | |
2570 | ||
2571 | if (on) { | |
2572 | if ((wlc_hw->sih->chip == BCM4313_CHIP_ID)) { | |
2573 | OR_REG(®s->clk_ctl_st, | |
2574 | (CCS_ERSRC_REQ_HT | CCS_ERSRC_REQ_D11PLL | | |
2575 | CCS_ERSRC_REQ_PHYPLL)); | |
2576 | SPINWAIT((R_REG(®s->clk_ctl_st) & | |
2577 | (CCS_ERSRC_AVAIL_HT)) != (CCS_ERSRC_AVAIL_HT), | |
2578 | PHYPLL_WAIT_US); | |
2579 | ||
2580 | tmp = R_REG(®s->clk_ctl_st); | |
2581 | if ((tmp & (CCS_ERSRC_AVAIL_HT)) != | |
8ea54c9f | 2582 | (CCS_ERSRC_AVAIL_HT)) |
8702fee6 RV |
2583 | wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on PHY" |
2584 | " PLL failed\n", __func__); | |
8702fee6 RV |
2585 | } else { |
2586 | OR_REG(®s->clk_ctl_st, | |
2587 | (CCS_ERSRC_REQ_D11PLL | CCS_ERSRC_REQ_PHYPLL)); | |
2588 | SPINWAIT((R_REG(®s->clk_ctl_st) & | |
2589 | (CCS_ERSRC_AVAIL_D11PLL | | |
2590 | CCS_ERSRC_AVAIL_PHYPLL)) != | |
2591 | (CCS_ERSRC_AVAIL_D11PLL | | |
2592 | CCS_ERSRC_AVAIL_PHYPLL), PHYPLL_WAIT_US); | |
2593 | ||
2594 | tmp = R_REG(®s->clk_ctl_st); | |
2595 | if ((tmp & | |
2596 | (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) | |
2597 | != | |
8ea54c9f | 2598 | (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) |
8702fee6 RV |
2599 | wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on " |
2600 | "PHY PLL failed\n", __func__); | |
8702fee6 RV |
2601 | } |
2602 | } else { | |
419ad34e AS |
2603 | /* |
2604 | * Since the PLL may be shared, other cores can still | |
2605 | * be requesting it; so we'll deassert the request but | |
2606 | * not wait for status to comply. | |
8702fee6 RV |
2607 | */ |
2608 | AND_REG(®s->clk_ctl_st, ~CCS_ERSRC_REQ_PHYPLL); | |
2609 | tmp = R_REG(®s->clk_ctl_st); | |
2610 | } | |
2611 | } | |
2612 | ||
2613 | void brcms_c_coredisable(struct brcms_hardware *wlc_hw) | |
2614 | { | |
2615 | bool dev_gone; | |
2616 | ||
2617 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
2618 | ||
2619 | dev_gone = DEVICEREMOVED(wlc_hw->wlc); | |
2620 | ||
2621 | if (dev_gone) | |
2622 | return; | |
2623 | ||
2624 | if (wlc_hw->noreset) | |
2625 | return; | |
2626 | ||
2627 | /* radio off */ | |
2628 | wlc_phy_switch_radio(wlc_hw->band->pi, OFF); | |
2629 | ||
2630 | /* turn off analog core */ | |
2631 | wlc_phy_anacore(wlc_hw->band->pi, OFF); | |
2632 | ||
2633 | /* turn off PHYPLL to save power */ | |
2634 | brcms_b_core_phypll_ctl(wlc_hw, false); | |
2635 | ||
2636 | /* No need to set wlc->pub->radio_active = OFF | |
2637 | * because this function needs down capability and | |
2638 | * radio_active is designed for BCMNODOWN. | |
2639 | */ | |
2640 | ||
2641 | /* remove gpio controls */ | |
2642 | if (wlc_hw->ucode_dbgsel) | |
2643 | ai_gpiocontrol(wlc_hw->sih, ~0, 0, GPIO_DRV_PRIORITY); | |
2644 | ||
2645 | wlc_hw->clk = false; | |
2646 | ai_core_disable(wlc_hw->sih, 0); | |
2647 | wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false); | |
2648 | } | |
2649 | ||
8702fee6 RV |
2650 | static void brcms_c_flushqueues(struct brcms_c_info *wlc) |
2651 | { | |
2652 | struct brcms_hardware *wlc_hw = wlc->hw; | |
2653 | uint i; | |
2654 | ||
2655 | wlc->txpend16165war = 0; | |
2656 | ||
2657 | /* free any posted tx packets */ | |
2658 | for (i = 0; i < NFIFO; i++) | |
2659 | if (wlc_hw->di[i]) { | |
2660 | dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL); | |
2661 | TXPKTPENDCLR(wlc, i); | |
2662 | BCMMSG(wlc->wiphy, "pktpend fifo %d clrd\n", i); | |
2663 | } | |
2664 | ||
2665 | /* free any posted rx packets */ | |
2666 | dma_rxreclaim(wlc_hw->di[RX_FIFO]); | |
2667 | } | |
2668 | ||
8702fee6 RV |
2669 | static u16 |
2670 | brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel) | |
2671 | { | |
0da64910 | 2672 | struct d11regs *regs = wlc_hw->regs; |
a918137a AS |
2673 | u16 *objdata_lo = (u16 *)®s->objdata; |
2674 | u16 *objdata_hi = objdata_lo + 1; | |
8702fee6 RV |
2675 | u16 v; |
2676 | ||
2677 | W_REG(®s->objaddr, sel | (offset >> 2)); | |
2678 | (void)R_REG(®s->objaddr); | |
8ea54c9f | 2679 | if (offset & 2) |
8702fee6 | 2680 | v = R_REG(objdata_hi); |
8ea54c9f | 2681 | else |
8702fee6 | 2682 | v = R_REG(objdata_lo); |
8702fee6 RV |
2683 | |
2684 | return v; | |
2685 | } | |
2686 | ||
2687 | static void | |
2688 | brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset, u16 v, | |
2689 | u32 sel) | |
2690 | { | |
0da64910 | 2691 | struct d11regs *regs = wlc_hw->regs; |
a918137a AS |
2692 | u16 *objdata_lo = (u16 *)®s->objdata; |
2693 | u16 *objdata_hi = objdata_lo + 1; | |
8702fee6 RV |
2694 | |
2695 | W_REG(®s->objaddr, sel | (offset >> 2)); | |
2696 | (void)R_REG(®s->objaddr); | |
8ea54c9f | 2697 | if (offset & 2) |
8702fee6 | 2698 | W_REG(objdata_hi, v); |
8ea54c9f | 2699 | else |
8702fee6 | 2700 | W_REG(objdata_lo, v); |
8702fee6 RV |
2701 | } |
2702 | ||
2682e2a3 AS |
2703 | u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset) |
2704 | { | |
2705 | return brcms_b_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL); | |
2706 | } | |
2707 | ||
2708 | void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v) | |
2709 | { | |
2710 | brcms_b_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL); | |
2711 | } | |
2712 | ||
8702fee6 RV |
2713 | /* Copy a buffer to shared memory of specified type . |
2714 | * SHM 'offset' needs to be an even address and | |
2715 | * Buffer length 'len' must be an even number of bytes | |
2716 | * 'sel' selects the type of memory | |
2717 | */ | |
2718 | void | |
2719 | brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, uint offset, | |
2720 | const void *buf, int len, u32 sel) | |
2721 | { | |
2722 | u16 v; | |
2723 | const u8 *p = (const u8 *)buf; | |
2724 | int i; | |
2725 | ||
2726 | if (len <= 0 || (offset & 1) || (len & 1)) | |
2727 | return; | |
2728 | ||
2729 | for (i = 0; i < len; i += 2) { | |
2730 | v = p[i] | (p[i + 1] << 8); | |
2731 | brcms_b_write_objmem(wlc_hw, offset + i, v, sel); | |
2732 | } | |
2733 | } | |
2734 | ||
2735 | /* Copy a piece of shared memory of specified type to a buffer . | |
2736 | * SHM 'offset' needs to be an even address and | |
2737 | * Buffer length 'len' must be an even number of bytes | |
2738 | * 'sel' selects the type of memory | |
2739 | */ | |
2740 | void | |
2741 | brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, void *buf, | |
2742 | int len, u32 sel) | |
2743 | { | |
2744 | u16 v; | |
2745 | u8 *p = (u8 *) buf; | |
2746 | int i; | |
2747 | ||
2748 | if (len <= 0 || (offset & 1) || (len & 1)) | |
2749 | return; | |
2750 | ||
2751 | for (i = 0; i < len; i += 2) { | |
2752 | v = brcms_b_read_objmem(wlc_hw, offset + i, sel); | |
2753 | p[i] = v & 0xFF; | |
2754 | p[i + 1] = (v >> 8) & 0xFF; | |
2755 | } | |
2756 | } | |
2757 | ||
11431424 | 2758 | static void brcms_b_copyfrom_vars(struct brcms_hardware *wlc_hw, char **buf, |
8702fee6 RV |
2759 | uint *len) |
2760 | { | |
2761 | BCMMSG(wlc_hw->wlc->wiphy, "nvram vars totlen=%d\n", | |
2762 | wlc_hw->vars_size); | |
2763 | ||
2764 | *buf = wlc_hw->vars; | |
2765 | *len = wlc_hw->vars_size; | |
2766 | } | |
2767 | ||
11431424 AS |
2768 | static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw, |
2769 | u16 SRL, u16 LRL) | |
8702fee6 RV |
2770 | { |
2771 | wlc_hw->SRL = SRL; | |
2772 | wlc_hw->LRL = LRL; | |
2773 | ||
2774 | /* write retry limit to SCR, shouldn't need to suspend */ | |
2775 | if (wlc_hw->up) { | |
2776 | W_REG(&wlc_hw->regs->objaddr, | |
2777 | OBJADDR_SCR_SEL | S_DOT11_SRC_LMT); | |
2778 | (void)R_REG(&wlc_hw->regs->objaddr); | |
2779 | W_REG(&wlc_hw->regs->objdata, wlc_hw->SRL); | |
2780 | W_REG(&wlc_hw->regs->objaddr, | |
2781 | OBJADDR_SCR_SEL | S_DOT11_LRC_LMT); | |
2782 | (void)R_REG(&wlc_hw->regs->objaddr); | |
2783 | W_REG(&wlc_hw->regs->objdata, wlc_hw->LRL); | |
2784 | } | |
2785 | } | |
2786 | ||
11431424 | 2787 | static void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, u32 req_bit) |
8702fee6 RV |
2788 | { |
2789 | if (set) { | |
2790 | if (mboolisset(wlc_hw->pllreq, req_bit)) | |
2791 | return; | |
2792 | ||
2793 | mboolset(wlc_hw->pllreq, req_bit); | |
2794 | ||
2795 | if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) { | |
8ea54c9f | 2796 | if (!wlc_hw->sbclk) |
8702fee6 | 2797 | brcms_b_xtal(wlc_hw, ON); |
8702fee6 RV |
2798 | } |
2799 | } else { | |
2800 | if (!mboolisset(wlc_hw->pllreq, req_bit)) | |
2801 | return; | |
2802 | ||
2803 | mboolclr(wlc_hw->pllreq, req_bit); | |
2804 | ||
2805 | if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) { | |
8ea54c9f | 2806 | if (wlc_hw->sbclk) |
8702fee6 | 2807 | brcms_b_xtal(wlc_hw, OFF); |
8702fee6 RV |
2808 | } |
2809 | } | |
2810 | ||
2811 | return; | |
2812 | } | |
2813 | ||
11431424 | 2814 | static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail) |
8702fee6 RV |
2815 | { |
2816 | wlc_hw->antsel_avail = antsel_avail; | |
2817 | } | |
2818 | ||
419ad34e AS |
2819 | /* |
2820 | * conditions under which the PM bit should be set in outgoing frames | |
2821 | * and STAY_AWAKE is meaningful | |
a9533e7e | 2822 | */ |
fe741e5e | 2823 | bool brcms_c_ps_allowed(struct brcms_c_info *wlc) |
a9533e7e HP |
2824 | { |
2825 | int idx; | |
471f1b51 | 2826 | struct brcms_bss_cfg *cfg; |
a9533e7e HP |
2827 | |
2828 | /* disallow PS when one of the following global conditions meets */ | |
5dc16874 | 2829 | if (!wlc->pub->associated) |
0965ae88 | 2830 | return false; |
a9533e7e HP |
2831 | |
2832 | /* disallow PS when one of these meets when not scanning */ | |
5dc16874 AS |
2833 | if (AP_ACTIVE(wlc) || wlc->monitor) |
2834 | return false; | |
a9533e7e | 2835 | |
7c783cef | 2836 | for (idx = 0; idx < BRCMS_MAXBSSCFG; idx++) { |
edb3f7cf AS |
2837 | cfg = wlc->bsscfg[idx]; |
2838 | if (cfg && BSSCFG_STA(cfg) && cfg->associated) { | |
2839 | /* | |
2840 | * disallow PS when one of the following | |
2841 | * bsscfg specific conditions meets | |
2842 | */ | |
7c783cef | 2843 | if (!cfg->BSS || !BRCMS_PORTOPEN(cfg)) |
edb3f7cf | 2844 | return false; |
a9533e7e | 2845 | |
839f9f62 RV |
2846 | if (!cfg->dtim_programmed) |
2847 | return false; | |
2848 | } | |
2849 | } | |
2850 | ||
2851 | return true; | |
2852 | } | |
2853 | ||
11431424 | 2854 | static void brcms_b_reset(struct brcms_hardware *wlc_hw) |
839f9f62 RV |
2855 | { |
2856 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
2857 | ||
2858 | /* reset the core */ | |
2859 | if (!DEVICEREMOVED(wlc_hw->wlc)) | |
2860 | brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); | |
2861 | ||
2862 | /* purge the dma rings */ | |
2863 | brcms_c_flushqueues(wlc_hw->wlc); | |
a9533e7e | 2864 | |
839f9f62 | 2865 | brcms_c_reset_bmac_done(wlc_hw->wlc); |
a9533e7e HP |
2866 | } |
2867 | ||
fe741e5e | 2868 | void brcms_c_reset(struct brcms_c_info *wlc) |
a2627bc0 | 2869 | { |
792aa408 | 2870 | BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); |
a9533e7e | 2871 | |
a9533e7e | 2872 | /* slurp up hw mac counters before core reset */ |
fe741e5e | 2873 | brcms_c_statsupd(wlc); |
a9533e7e | 2874 | |
e4cf544e AS |
2875 | /* reset our snapshot of macstat counters */ |
2876 | memset((char *)wlc->core->macstat_snapshot, 0, | |
cc87568a | 2877 | sizeof(struct macstat)); |
a9533e7e | 2878 | |
c654fce6 | 2879 | brcms_b_reset(wlc->hw); |
a9533e7e HP |
2880 | } |
2881 | ||
fe741e5e | 2882 | void brcms_c_fatal_error(struct brcms_c_info *wlc) |
a9533e7e | 2883 | { |
b8f092c9 RV |
2884 | wiphy_err(wlc->wiphy, "wl%d: fatal error, reinitializing\n", |
2885 | wlc->pub->unit); | |
8817f754 | 2886 | brcms_init(wlc->wl); |
a9533e7e HP |
2887 | } |
2888 | ||
fe741e5e | 2889 | /* Return the channel the driver should initialize during brcms_c_init. |
a9533e7e HP |
2890 | * the channel may have to be changed from the currently configured channel |
2891 | * if other configurations are in conflict (bandlocked, 11n mode disabled, | |
2892 | * invalid channel for current country, etc.) | |
2893 | */ | |
6bd20a1b | 2894 | static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc) |
a2627bc0 | 2895 | { |
6bd20a1b | 2896 | u16 chanspec = |
a9533e7e HP |
2897 | 1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE | |
2898 | WL_CHANSPEC_BAND_2G; | |
2899 | ||
a9533e7e HP |
2900 | return chanspec; |
2901 | } | |
2902 | ||
11431424 | 2903 | static struct scb global_scb; |
a9533e7e | 2904 | |
1c4c54ba | 2905 | static void brcms_c_init_scb(struct brcms_c_info *wlc, struct scb *scb) |
a9533e7e HP |
2906 | { |
2907 | int i; | |
2908 | scb->flags = SCB_WMECAP | SCB_HTCAP; | |
2909 | for (i = 0; i < NUMPRIO; i++) | |
2910 | scb->seqnum[i] = 0; | |
2911 | } | |
2912 | ||
839f9f62 RV |
2913 | /* d11 core init |
2914 | * reset PSM | |
2915 | * download ucode/PCM | |
2916 | * let ucode run to suspended | |
2917 | * download ucode inits | |
2918 | * config other core registers | |
2919 | * init dma | |
2920 | */ | |
2921 | static void brcms_b_coreinit(struct brcms_c_info *wlc) | |
2922 | { | |
2923 | struct brcms_hardware *wlc_hw = wlc->hw; | |
0da64910 | 2924 | struct d11regs *regs; |
839f9f62 RV |
2925 | u32 sflags; |
2926 | uint bcnint_us; | |
2927 | uint i = 0; | |
2928 | bool fifosz_fixup = false; | |
2929 | int err = 0; | |
2930 | u16 buf[NFIFO]; | |
2931 | struct wiphy *wiphy = wlc->wiphy; | |
2932 | ||
2933 | regs = wlc_hw->regs; | |
2934 | ||
2935 | BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
2936 | ||
2937 | /* reset PSM */ | |
2938 | brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE)); | |
2939 | ||
2940 | brcms_ucode_download(wlc_hw); | |
2941 | /* | |
2942 | * FIFOSZ fixup. driver wants to controls the fifo allocation. | |
2943 | */ | |
2944 | fifosz_fixup = true; | |
2945 | ||
2946 | /* let the PSM run to the suspended state, set mode to BSS STA */ | |
2947 | W_REG(®s->macintstatus, -1); | |
2948 | brcms_b_mctrl(wlc_hw, ~0, | |
2949 | (MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE)); | |
2950 | ||
2951 | /* wait for ucode to self-suspend after auto-init */ | |
2952 | SPINWAIT(((R_REG(®s->macintstatus) & MI_MACSSPNDD) == 0), | |
2953 | 1000 * 1000); | |
2954 | if ((R_REG(®s->macintstatus) & MI_MACSSPNDD) == 0) | |
2955 | wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-" | |
2956 | "suspend!\n", wlc_hw->unit); | |
2957 | ||
2958 | brcms_c_gpio_init(wlc); | |
2959 | ||
2960 | sflags = ai_core_sflags(wlc_hw->sih, 0, 0); | |
2961 | ||
2962 | if (D11REV_IS(wlc_hw->corerev, 23)) { | |
2963 | if (BRCMS_ISNPHY(wlc_hw->band)) | |
2964 | brcms_c_write_inits(wlc_hw, d11n0initvals16); | |
2965 | else | |
2966 | wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" | |
2967 | " %d\n", __func__, wlc_hw->unit, | |
2968 | wlc_hw->corerev); | |
2969 | } else if (D11REV_IS(wlc_hw->corerev, 24)) { | |
8ea54c9f | 2970 | if (BRCMS_ISLCNPHY(wlc_hw->band)) |
839f9f62 | 2971 | brcms_c_write_inits(wlc_hw, d11lcn0initvals24); |
8ea54c9f | 2972 | else |
839f9f62 RV |
2973 | wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" |
2974 | " %d\n", __func__, wlc_hw->unit, | |
2975 | wlc_hw->corerev); | |
839f9f62 RV |
2976 | } else { |
2977 | wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n", | |
2978 | __func__, wlc_hw->unit, wlc_hw->corerev); | |
2979 | } | |
2980 | ||
2981 | /* For old ucode, txfifo sizes needs to be modified(increased) */ | |
8ea54c9f | 2982 | if (fifosz_fixup == true) |
839f9f62 | 2983 | brcms_b_corerev_fifofixup(wlc_hw); |
839f9f62 RV |
2984 | |
2985 | /* check txfifo allocations match between ucode and driver */ | |
2986 | buf[TX_AC_BE_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE0); | |
2987 | if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) { | |
2988 | i = TX_AC_BE_FIFO; | |
2989 | err = -1; | |
2990 | } | |
2991 | buf[TX_AC_VI_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE1); | |
2992 | if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) { | |
2993 | i = TX_AC_VI_FIFO; | |
2994 | err = -1; | |
2995 | } | |
2996 | buf[TX_AC_BK_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE2); | |
2997 | buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff; | |
2998 | buf[TX_AC_BK_FIFO] &= 0xff; | |
2999 | if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) { | |
3000 | i = TX_AC_BK_FIFO; | |
3001 | err = -1; | |
3002 | } | |
3003 | if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) { | |
3004 | i = TX_AC_VO_FIFO; | |
3005 | err = -1; | |
3006 | } | |
3007 | buf[TX_BCMC_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE3); | |
3008 | buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff; | |
3009 | buf[TX_BCMC_FIFO] &= 0xff; | |
3010 | if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) { | |
3011 | i = TX_BCMC_FIFO; | |
3012 | err = -1; | |
3013 | } | |
3014 | if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) { | |
3015 | i = TX_ATIM_FIFO; | |
3016 | err = -1; | |
3017 | } | |
8ea54c9f | 3018 | if (err != 0) |
839f9f62 RV |
3019 | wiphy_err(wiphy, "wlc_coreinit: txfifo mismatch: ucode size %d" |
3020 | " driver size %d index %d\n", buf[i], | |
3021 | wlc_hw->xmtfifo_sz[i], i); | |
839f9f62 RV |
3022 | |
3023 | /* make sure we can still talk to the mac */ | |
3024 | WARN_ON(R_REG(®s->maccontrol) == 0xffffffff); | |
3025 | ||
3026 | /* band-specific inits done by wlc_bsinit() */ | |
3027 | ||
3028 | /* Set up frame burst size and antenna swap threshold init values */ | |
3029 | brcms_b_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST); | |
3030 | brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT); | |
3031 | ||
3032 | /* enable one rx interrupt per received frame */ | |
3033 | W_REG(®s->intrcvlazy[0], (1 << IRL_FC_SHIFT)); | |
3034 | ||
3035 | /* set the station mode (BSS STA) */ | |
3036 | brcms_b_mctrl(wlc_hw, | |
3037 | (MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP), | |
3038 | (MCTL_INFRA | MCTL_DISCARD_PMQ)); | |
3039 | ||
3040 | /* set up Beacon interval */ | |
3041 | bcnint_us = 0x8000 << 10; | |
3042 | W_REG(®s->tsf_cfprep, (bcnint_us << CFPREP_CBI_SHIFT)); | |
3043 | W_REG(®s->tsf_cfpstart, bcnint_us); | |
3044 | W_REG(®s->macintstatus, MI_GP1); | |
3045 | ||
3046 | /* write interrupt mask */ | |
3047 | W_REG(®s->intctrlregs[RX_FIFO].intmask, DEF_RXINTMASK); | |
3048 | ||
3049 | /* allow the MAC to control the PHY clock (dynamic on/off) */ | |
3050 | brcms_b_macphyclk_set(wlc_hw, ON); | |
3051 | ||
3052 | /* program dynamic clock control fast powerup delay register */ | |
3053 | wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih); | |
3054 | W_REG(®s->scc_fastpwrup_dly, wlc->fastpwrup_dly); | |
3055 | ||
3056 | /* tell the ucode the corerev */ | |
3057 | brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev); | |
3058 | ||
3059 | /* tell the ucode MAC capabilities */ | |
3060 | brcms_b_write_shm(wlc_hw, M_MACHW_CAP_L, | |
3061 | (u16) (wlc_hw->machwcap & 0xffff)); | |
3062 | brcms_b_write_shm(wlc_hw, M_MACHW_CAP_H, | |
3063 | (u16) ((wlc_hw-> | |
3064 | machwcap >> 16) & 0xffff)); | |
3065 | ||
3066 | /* write retry limits to SCR, this done after PSM init */ | |
3067 | W_REG(®s->objaddr, OBJADDR_SCR_SEL | S_DOT11_SRC_LMT); | |
3068 | (void)R_REG(®s->objaddr); | |
3069 | W_REG(®s->objdata, wlc_hw->SRL); | |
3070 | W_REG(®s->objaddr, OBJADDR_SCR_SEL | S_DOT11_LRC_LMT); | |
3071 | (void)R_REG(®s->objaddr); | |
3072 | W_REG(®s->objdata, wlc_hw->LRL); | |
3073 | ||
3074 | /* write rate fallback retry limits */ | |
3075 | brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL); | |
3076 | brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL); | |
3077 | ||
3078 | AND_REG(®s->ifs_ctl, 0x0FFF); | |
3079 | W_REG(®s->ifs_aifsn, EDCF_AIFSN_MIN); | |
3080 | ||
3081 | /* dma initializations */ | |
3082 | wlc->txpend16165war = 0; | |
3083 | ||
3084 | /* init the tx dma engines */ | |
3085 | for (i = 0; i < NFIFO; i++) { | |
3086 | if (wlc_hw->di[i]) | |
3087 | dma_txinit(wlc_hw->di[i]); | |
3088 | } | |
3089 | ||
3090 | /* init the rx dma engine(s) and post receive buffers */ | |
3091 | dma_rxinit(wlc_hw->di[RX_FIFO]); | |
3092 | dma_rxfill(wlc_hw->di[RX_FIFO]); | |
3093 | } | |
3094 | ||
3095 | void | |
11431424 | 3096 | static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec, |
839f9f62 RV |
3097 | bool mute) { |
3098 | u32 macintmask; | |
3099 | bool fastclk; | |
3100 | struct brcms_c_info *wlc = wlc_hw->wlc; | |
3101 | ||
3102 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
3103 | ||
3104 | /* request FAST clock if not on */ | |
3105 | fastclk = wlc_hw->forcefastclk; | |
3106 | if (!fastclk) | |
3107 | brcms_b_clkctl_clk(wlc_hw, CLK_FAST); | |
3108 | ||
3109 | /* disable interrupts */ | |
3110 | macintmask = brcms_intrsoff(wlc->wl); | |
3111 | ||
3112 | /* set up the specified band and chanspec */ | |
3113 | brcms_c_setxband(wlc_hw, CHSPEC_BANDUNIT(chanspec)); | |
3114 | wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec); | |
3115 | ||
3116 | /* do one-time phy inits and calibration */ | |
3117 | wlc_phy_cal_init(wlc_hw->band->pi); | |
3118 | ||
3119 | /* core-specific initialization */ | |
3120 | brcms_b_coreinit(wlc); | |
3121 | ||
3122 | /* suspend the tx fifos and mute the phy for preism cac time */ | |
3123 | if (mute) | |
3124 | brcms_b_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM); | |
3125 | ||
3126 | /* band-specific inits */ | |
3127 | brcms_b_bsinit(wlc, chanspec); | |
3128 | ||
3129 | /* restore macintmask */ | |
3130 | brcms_intrsrestore(wlc->wl, macintmask); | |
3131 | ||
3132 | /* seed wake_override with BRCMS_WAKE_OVERRIDE_MACSUSPEND since the mac | |
3133 | * is suspended and brcms_c_enable_mac() will clear this override bit. | |
3134 | */ | |
3135 | mboolset(wlc_hw->wake_override, BRCMS_WAKE_OVERRIDE_MACSUSPEND); | |
3136 | ||
3137 | /* | |
419ad34e AS |
3138 | * initialize mac_suspend_depth to 1 to match ucode |
3139 | * initial suspended state | |
839f9f62 RV |
3140 | */ |
3141 | wlc_hw->mac_suspend_depth = 1; | |
3142 | ||
3143 | /* restore the clk */ | |
3144 | if (!fastclk) | |
3145 | brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); | |
3146 | } | |
3147 | ||
2682e2a3 | 3148 | static u8 brcms_c_local_constraint_qdbm(struct brcms_c_info *wlc) |
a2627bc0 | 3149 | { |
2682e2a3 AS |
3150 | u8 local; |
3151 | s16 local_max; | |
a9533e7e | 3152 | |
2682e2a3 AS |
3153 | local = BRCMS_TXPWR_MAX; |
3154 | if (wlc->pub->associated && | |
3155 | (brcmu_chspec_ctlchan(wlc->chanspec) == | |
3156 | brcmu_chspec_ctlchan(wlc->home_chanspec))) { | |
a9533e7e | 3157 | |
2682e2a3 AS |
3158 | /* get the local power constraint if we are on the AP's |
3159 | * channel [802.11h, 7.3.2.13] | |
3160 | */ | |
3161 | /* Clamp the value between 0 and BRCMS_TXPWR_MAX w/o | |
3162 | * overflowing the target */ | |
3163 | local_max = | |
3164 | (wlc->txpwr_local_max - | |
3165 | wlc->txpwr_local_constraint) * BRCMS_TXPWR_DB_FACTOR; | |
3166 | if (local_max > 0 && local_max < BRCMS_TXPWR_MAX) | |
3167 | return (u8) local_max; | |
3168 | if (local_max < 0) | |
3169 | return 0; | |
3170 | } | |
a9533e7e | 3171 | |
2682e2a3 AS |
3172 | return local; |
3173 | } | |
a9533e7e | 3174 | |
2682e2a3 AS |
3175 | static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc, |
3176 | u16 chanspec) | |
3177 | { | |
3178 | /* Save our copy of the chanspec */ | |
3179 | wlc->chanspec = chanspec; | |
a9533e7e | 3180 | |
2682e2a3 AS |
3181 | /* Set the chanspec and power limits for this locale after computing |
3182 | * any 11h local tx power constraints. | |
3183 | */ | |
3184 | brcms_c_channel_set_chanspec(wlc->cmi, chanspec, | |
3185 | brcms_c_local_constraint_qdbm(wlc)); | |
a9533e7e | 3186 | |
2682e2a3 AS |
3187 | if (wlc->stf->ss_algosel_auto) |
3188 | brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel, | |
3189 | chanspec); | |
a9533e7e | 3190 | |
2682e2a3 | 3191 | brcms_c_stf_ss_update(wlc, wlc->band); |
a9533e7e | 3192 | |
2682e2a3 | 3193 | } |
a9533e7e | 3194 | |
2682e2a3 AS |
3195 | static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc, |
3196 | u16 chanspec) | |
3197 | { | |
3198 | struct brcms_c_rateset default_rateset; | |
3199 | uint parkband; | |
3200 | uint i, band_order[2]; | |
a9533e7e | 3201 | |
2682e2a3 AS |
3202 | BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); |
3203 | /* | |
3204 | * We might have been bandlocked during down and the chip | |
3205 | * power-cycled (hibernate). Figure out the right band to park on | |
3206 | */ | |
3207 | if (wlc->bandlocked || NBANDS(wlc) == 1) { | |
3208 | /* updated in brcms_c_bandlock() */ | |
3209 | parkband = wlc->band->bandunit; | |
3210 | band_order[0] = band_order[1] = parkband; | |
3211 | } else { | |
3212 | /* park on the band of the specified chanspec */ | |
3213 | parkband = CHSPEC_BANDUNIT(chanspec); | |
a9533e7e | 3214 | |
2682e2a3 AS |
3215 | /* order so that parkband initialize last */ |
3216 | band_order[0] = parkband ^ 1; | |
3217 | band_order[1] = parkband; | |
a9533e7e HP |
3218 | } |
3219 | ||
2682e2a3 AS |
3220 | /* make each band operational, software state init */ |
3221 | for (i = 0; i < NBANDS(wlc); i++) { | |
3222 | uint j = band_order[i]; | |
a9533e7e | 3223 | |
2682e2a3 | 3224 | wlc->band = wlc->bandstate[j]; |
a9533e7e | 3225 | |
2682e2a3 | 3226 | brcms_default_rateset(wlc, &default_rateset); |
a9533e7e | 3227 | |
2682e2a3 AS |
3228 | /* fill in hw_rate */ |
3229 | brcms_c_rateset_filter(&default_rateset, &wlc->band->hw_rateset, | |
3230 | false, BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK, | |
3231 | (bool) N_ENAB(wlc->pub)); | |
a9533e7e | 3232 | |
2682e2a3 AS |
3233 | /* init basic rate lookup */ |
3234 | brcms_c_rate_lookup_init(wlc, &default_rateset); | |
a9533e7e HP |
3235 | } |
3236 | ||
2682e2a3 AS |
3237 | /* sync up phy/radio chanspec */ |
3238 | brcms_c_set_phy_chanspec(wlc, chanspec); | |
3239 | } | |
a9533e7e | 3240 | |
2682e2a3 AS |
3241 | /* |
3242 | * ucode, hwmac update | |
3243 | * Channel dependent updates for ucode and hw | |
3244 | */ | |
3245 | static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc) | |
3246 | { | |
3247 | /* enable or disable any active IBSSs depending on whether or not | |
3248 | * we are on the home channel | |
3249 | */ | |
3250 | if (wlc->home_chanspec == BRCMS_BAND_PI_RADIO_CHANSPEC) { | |
3251 | if (wlc->pub->associated) { | |
3252 | /* | |
3253 | * BMAC_NOTE: This is something that should be fixed | |
3254 | * in ucode inits. I think that the ucode inits set | |
3255 | * up the bcn templates and shm values with a bogus | |
3256 | * beacon. This should not be done in the inits. If | |
3257 | * ucode needs to set up a beacon for testing, the | |
3258 | * test routines should write it down, not expect the | |
3259 | * inits to populate a bogus beacon. | |
3260 | */ | |
3261 | if (BRCMS_PHY_11N_CAP(wlc->band)) | |
3262 | brcms_c_write_shm(wlc, M_BCN_TXTSF_OFFSET, | |
3263 | wlc->band->bcntsfoff); | |
3264 | } | |
3265 | } else { | |
3266 | /* disable an active IBSS if we are not on the home channel */ | |
3267 | } | |
3268 | ||
3269 | /* update the various promisc bits */ | |
3270 | brcms_c_mac_bcn_promisc(wlc); | |
3271 | brcms_c_mac_promisc(wlc); | |
3272 | } | |
3273 | ||
3274 | /* band-specific init */ | |
3275 | static void brcms_c_bsinit(struct brcms_c_info *wlc) | |
3276 | { | |
3277 | BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", | |
3278 | wlc->pub->unit, wlc->band->bandunit); | |
3279 | ||
3280 | /* write ucode ACK/CTS rate table */ | |
3281 | brcms_c_set_ratetable(wlc); | |
3282 | ||
3283 | /* update some band specific mac configuration */ | |
3284 | brcms_c_ucode_mac_upd(wlc); | |
3285 | ||
3286 | /* init antenna selection */ | |
3287 | brcms_c_antsel_init(wlc->asi); | |
3288 | ||
3289 | } | |
3290 | ||
3291 | /* formula: IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */ | |
3292 | static int | |
3293 | brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM, | |
3294 | bool writeToShm) | |
3295 | { | |
3296 | int idle_busy_ratio_x_16 = 0; | |
3297 | uint offset = | |
3298 | isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM : | |
3299 | M_TX_IDLE_BUSY_RATIO_X_16_CCK; | |
3300 | if (duty_cycle > 100 || duty_cycle < 0) { | |
3301 | wiphy_err(wlc->wiphy, "wl%d: duty cycle value off limit\n", | |
3302 | wlc->pub->unit); | |
3303 | return -EINVAL; | |
3304 | } | |
3305 | if (duty_cycle) | |
3306 | idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle; | |
3307 | /* Only write to shared memory when wl is up */ | |
3308 | if (writeToShm) | |
3309 | brcms_c_write_shm(wlc, offset, (u16) idle_busy_ratio_x_16); | |
3310 | ||
3311 | if (isOFDM) | |
3312 | wlc->tx_duty_cycle_ofdm = (u16) duty_cycle; | |
3313 | else | |
3314 | wlc->tx_duty_cycle_cck = (u16) duty_cycle; | |
3315 | ||
3316 | return 0; | |
3317 | } | |
3318 | ||
3319 | /* | |
3320 | * Initialize the base precedence map for dequeueing | |
3321 | * from txq based on WME settings | |
3322 | */ | |
3323 | static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc) | |
3324 | { | |
3325 | wlc->tx_prec_map = BRCMS_PREC_BMP_ALL; | |
3326 | memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16)); | |
3327 | ||
3328 | /* | |
3329 | * For non-WME, both fifos have overlapping MAXPRIO. So just | |
3330 | * disable all precedences if either is full. | |
3331 | */ | |
3332 | if (!EDCF_ENAB(wlc->pub)) { | |
3333 | wlc->fifo2prec_map[TX_DATA_FIFO] = BRCMS_PREC_BMP_ALL; | |
3334 | wlc->fifo2prec_map[TX_CTL_FIFO] = BRCMS_PREC_BMP_ALL; | |
3335 | } else { | |
3336 | wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK; | |
3337 | wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE; | |
3338 | wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI; | |
3339 | wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO; | |
3340 | } | |
3341 | } | |
3342 | ||
3343 | static void | |
3344 | brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc, | |
3345 | struct brcms_txq_info *qi, bool on, int prio) | |
3346 | { | |
3347 | /* transmit flowcontrol is not yet implemented */ | |
3348 | } | |
3349 | ||
3350 | static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc) | |
3351 | { | |
3352 | struct brcms_txq_info *qi; | |
3353 | ||
3354 | for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) { | |
3355 | if (qi->stopped) { | |
3356 | brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO); | |
3357 | qi->stopped = 0; | |
3358 | } | |
3359 | } | |
3360 | } | |
3361 | ||
3362 | void brcms_c_init(struct brcms_c_info *wlc) | |
3363 | { | |
3364 | struct d11regs *regs; | |
3365 | u16 chanspec; | |
3366 | int i; | |
3367 | struct brcms_bss_cfg *bsscfg; | |
3368 | bool mute = false; | |
3369 | ||
3370 | BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); | |
3371 | ||
3372 | regs = wlc->regs; | |
3373 | ||
3374 | /* | |
3375 | * This will happen if a big-hammer was executed. In | |
3376 | * that case, we want to go back to the channel that | |
3377 | * we were on and not new channel | |
3378 | */ | |
3379 | if (wlc->pub->associated) | |
3380 | chanspec = wlc->home_chanspec; | |
3381 | else | |
3382 | chanspec = brcms_c_init_chanspec(wlc); | |
3383 | ||
3384 | brcms_b_init(wlc->hw, chanspec, mute); | |
3385 | ||
3386 | /* update beacon listen interval */ | |
3387 | brcms_c_bcn_li_upd(wlc); | |
3388 | ||
3389 | /* the world is new again, so is our reported rate */ | |
3390 | brcms_c_reprate_init(wlc); | |
3391 | ||
3392 | /* write ethernet address to core */ | |
3393 | FOREACH_BSS(wlc, i, bsscfg) | |
3394 | brcms_c_set_mac(bsscfg); | |
3395 | brcms_c_set_bssid(bsscfg); | |
3396 | END_FOREACH_BSS() | |
3397 | ||
3398 | /* Update tsf_cfprep if associated and up */ | |
3399 | if (wlc->pub->associated) { | |
3400 | FOREACH_BSS(wlc, i, bsscfg) | |
3401 | if (bsscfg->up) { | |
3402 | u32 bi; | |
3403 | ||
3404 | /* get beacon period and convert to uS */ | |
3405 | bi = bsscfg->current_bss->beacon_period << 10; | |
3406 | /* | |
3407 | * update since init path would reset | |
3408 | * to default value | |
3409 | */ | |
3410 | W_REG(®s->tsf_cfprep, | |
3411 | (bi << CFPREP_CBI_SHIFT)); | |
3412 | ||
3413 | /* Update maccontrol PM related bits */ | |
3414 | brcms_c_set_ps_ctrl(wlc); | |
3415 | ||
3416 | break; | |
3417 | } | |
3418 | END_FOREACH_BSS() | |
3419 | } | |
3420 | ||
3421 | brcms_c_bandinit_ordered(wlc, chanspec); | |
3422 | ||
3423 | brcms_c_init_scb(wlc, &global_scb); | |
3424 | ||
3425 | /* init probe response timeout */ | |
3426 | brcms_c_write_shm(wlc, M_PRS_MAXTIME, wlc->prb_resp_timeout); | |
3427 | ||
3428 | /* init max burst txop (framebursting) */ | |
3429 | brcms_c_write_shm(wlc, M_MBURST_TXOP, | |
3430 | (wlc-> | |
3431 | _rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP)); | |
3432 | ||
3433 | /* initialize maximum allowed duty cycle */ | |
3434 | brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, true, true); | |
3435 | brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, false, true); | |
3436 | ||
3437 | /* | |
3438 | * Update some shared memory locations related to | |
3439 | * max AMPDU size allowed to received | |
3440 | */ | |
3441 | brcms_c_ampdu_shm_upd(wlc->ampdu); | |
3442 | ||
3443 | /* band-specific inits */ | |
3444 | brcms_c_bsinit(wlc); | |
3445 | ||
3446 | /* Enable EDCF mode (while the MAC is suspended) */ | |
3447 | if (EDCF_ENAB(wlc->pub)) { | |
3448 | OR_REG(®s->ifs_ctl, IFS_USEEDCF); | |
3449 | brcms_c_edcf_setparams(wlc, false); | |
3450 | } | |
3451 | ||
3452 | /* Init precedence maps for empty FIFOs */ | |
3453 | brcms_c_tx_prec_map_init(wlc); | |
3454 | ||
3455 | /* read the ucode version if we have not yet done so */ | |
3456 | if (wlc->ucode_rev == 0) { | |
a9533e7e | 3457 | wlc->ucode_rev = |
fe741e5e RV |
3458 | brcms_c_read_shm(wlc, M_BOM_REV_MAJOR) << NBITS(u16); |
3459 | wlc->ucode_rev |= brcms_c_read_shm(wlc, M_BOM_REV_MINOR); | |
a9533e7e HP |
3460 | } |
3461 | ||
3462 | /* ..now really unleash hell (allow the MAC out of suspend) */ | |
fe741e5e | 3463 | brcms_c_enable_mac(wlc); |
a9533e7e HP |
3464 | |
3465 | /* clear tx flow control */ | |
1c4c54ba | 3466 | brcms_c_txflowcontrol_reset(wlc); |
a9533e7e HP |
3467 | |
3468 | /* clear tx data fifo suspends */ | |
0965ae88 | 3469 | wlc->tx_suspended = false; |
a9533e7e HP |
3470 | |
3471 | /* enable the RF Disable Delay timer */ | |
ff31c54c | 3472 | W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT); |
a9533e7e HP |
3473 | |
3474 | /* initialize mpc delay */ | |
7c783cef | 3475 | wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT; |
a9533e7e HP |
3476 | |
3477 | /* | |
3478 | * Initialize WME parameters; if they haven't been set by some other | |
3479 | * mechanism (IOVar, etc) then read them from the hardware. | |
3480 | */ | |
7c783cef RV |
3481 | if (BRCMS_WME_RETRY_SHORT_GET(wlc, 0) == 0) { |
3482 | /* Uninitialized; read from HW */ | |
a9533e7e HP |
3483 | int ac; |
3484 | ||
8ea54c9f | 3485 | for (ac = 0; ac < AC_COUNT; ac++) |
a9533e7e | 3486 | wlc->wme_retries[ac] = |
fe741e5e | 3487 | brcms_c_read_shm(wlc, M_AC_TXLMT_ADDR(ac)); |
a9533e7e HP |
3488 | } |
3489 | } | |
3490 | ||
fe741e5e | 3491 | void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc) |
a9533e7e HP |
3492 | { |
3493 | wlc->bcnmisc_monitor = promisc; | |
fe741e5e | 3494 | brcms_c_mac_bcn_promisc(wlc); |
a9533e7e HP |
3495 | } |
3496 | ||
fe741e5e | 3497 | void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc) |
a9533e7e HP |
3498 | { |
3499 | if ((AP_ENAB(wlc->pub) && (N_ENAB(wlc->pub) || wlc->band->gmode)) || | |
3500 | wlc->bcnmisc_ibss || wlc->bcnmisc_scan || wlc->bcnmisc_monitor) | |
fe741e5e | 3501 | brcms_c_mctrl(wlc, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC); |
a9533e7e | 3502 | else |
fe741e5e | 3503 | brcms_c_mctrl(wlc, MCTL_BCNS_PROMISC, 0); |
a9533e7e HP |
3504 | } |
3505 | ||
3506 | /* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */ | |
fe741e5e | 3507 | void brcms_c_mac_promisc(struct brcms_c_info *wlc) |
a9533e7e | 3508 | { |
66cbd3ab | 3509 | u32 promisc_bits = 0; |
a9533e7e | 3510 | |
419ad34e AS |
3511 | /* |
3512 | * promiscuous mode just sets MCTL_PROMISC | |
3513 | * Note: APs get all BSS traffic without the need to set | |
3514 | * the MCTL_PROMISC bit since all BSS data traffic is | |
3515 | * directed at the AP | |
a9533e7e | 3516 | */ |
5dc16874 | 3517 | if (PROMISC_ENAB(wlc->pub) && !AP_ENAB(wlc->pub)) |
a9533e7e HP |
3518 | promisc_bits |= MCTL_PROMISC; |
3519 | ||
3520 | /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL | |
3521 | * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is | |
fe741e5e | 3522 | * handled in brcms_c_mac_bcn_promisc() |
a9533e7e HP |
3523 | */ |
3524 | if (MONITOR_ENAB(wlc)) | |
3525 | promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL; | |
3526 | ||
fe741e5e | 3527 | brcms_c_mctrl(wlc, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits); |
a9533e7e HP |
3528 | } |
3529 | ||
a9533e7e | 3530 | /* push sw hps and wake state through hardware */ |
fe741e5e | 3531 | void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc) |
a9533e7e | 3532 | { |
66cbd3ab | 3533 | u32 v1, v2; |
c3ecec39 | 3534 | bool hps; |
a9533e7e HP |
3535 | bool awake_before; |
3536 | ||
3537 | hps = PS_ALLOWED(wlc); | |
a9533e7e | 3538 | |
c3ecec39 | 3539 | BCMMSG(wlc->wiphy, "wl%d: hps %d\n", wlc->pub->unit, hps); |
a9533e7e | 3540 | |
ff31c54c | 3541 | v1 = R_REG(&wlc->regs->maccontrol); |
c3ecec39 | 3542 | v2 = MCTL_WAKE; |
a9533e7e HP |
3543 | if (hps) |
3544 | v2 |= MCTL_HPS; | |
a9533e7e | 3545 | |
fe741e5e | 3546 | brcms_c_mctrl(wlc, MCTL_WAKE | MCTL_HPS, v2); |
a9533e7e HP |
3547 | |
3548 | awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0)); | |
3549 | ||
c3ecec39 | 3550 | if (!awake_before) |
c654fce6 | 3551 | brcms_b_wait_for_wake(wlc->hw); |
a9533e7e HP |
3552 | |
3553 | } | |
3554 | ||
3555 | /* | |
3556 | * Write this BSS config's MAC address to core. | |
3557 | * Updates RXE match engine. | |
3558 | */ | |
471f1b51 | 3559 | int brcms_c_set_mac(struct brcms_bss_cfg *cfg) |
a9533e7e HP |
3560 | { |
3561 | int err = 0; | |
fe741e5e | 3562 | struct brcms_c_info *wlc = cfg->wlc; |
a9533e7e | 3563 | |
8ea54c9f | 3564 | if (cfg == wlc->cfg) |
a9533e7e | 3565 | /* enter the MAC addr into the RXE match registers */ |
fe741e5e | 3566 | brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, cfg->cur_etheraddr); |
a9533e7e | 3567 | |
f52a0ad0 | 3568 | brcms_c_ampdu_macaddr_upd(wlc); |
a9533e7e HP |
3569 | |
3570 | return err; | |
3571 | } | |
3572 | ||
3573 | /* Write the BSS config's BSSID address to core (set_bssid in d11procs.tcl). | |
3574 | * Updates RXE match engine. | |
3575 | */ | |
471f1b51 | 3576 | void brcms_c_set_bssid(struct brcms_bss_cfg *cfg) |
a9533e7e | 3577 | { |
fe741e5e | 3578 | struct brcms_c_info *wlc = cfg->wlc; |
a9533e7e HP |
3579 | |
3580 | /* if primary config, we need to update BSSID in RXE match registers */ | |
8ea54c9f | 3581 | if (cfg == wlc->cfg) |
fe741e5e | 3582 | brcms_c_set_addrmatch(wlc, RCM_BSSID_OFFSET, cfg->BSSID); |
839f9f62 RV |
3583 | } |
3584 | ||
11431424 | 3585 | static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot) |
839f9f62 RV |
3586 | { |
3587 | wlc_hw->shortslot = shortslot; | |
3588 | ||
3589 | if (BAND_2G(brcms_b_bandtype(wlc_hw)) && wlc_hw->up) { | |
3590 | brcms_c_suspend_mac_and_wait(wlc_hw->wlc); | |
3591 | brcms_b_update_slot_timing(wlc_hw, shortslot); | |
3592 | brcms_c_enable_mac(wlc_hw->wlc); | |
3593 | } | |
a9533e7e HP |
3594 | } |
3595 | ||
3596 | /* | |
3597 | * Suspend the the MAC and update the slot timing | |
3598 | * for standard 11b/g (20us slots) or shortslot 11g (9us slots). | |
3599 | */ | |
fe741e5e | 3600 | void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot) |
a9533e7e HP |
3601 | { |
3602 | int idx; | |
471f1b51 | 3603 | struct brcms_bss_cfg *cfg; |
a9533e7e | 3604 | |
a9533e7e | 3605 | /* use the override if it is set */ |
7c783cef RV |
3606 | if (wlc->shortslot_override != BRCMS_SHORTSLOT_AUTO) |
3607 | shortslot = (wlc->shortslot_override == BRCMS_SHORTSLOT_ON); | |
a9533e7e HP |
3608 | |
3609 | if (wlc->shortslot == shortslot) | |
3610 | return; | |
3611 | ||
3612 | wlc->shortslot = shortslot; | |
3613 | ||
3614 | /* update the capability based on current shortslot mode */ | |
49552d33 | 3615 | FOREACH_BSS(wlc, idx, cfg) |
a9533e7e HP |
3616 | if (!cfg->associated) |
3617 | continue; | |
04795017 RV |
3618 | cfg->current_bss->capability &= |
3619 | ~WLAN_CAPABILITY_SHORT_SLOT_TIME; | |
a9533e7e | 3620 | if (wlc->shortslot) |
04795017 RV |
3621 | cfg->current_bss->capability |= |
3622 | WLAN_CAPABILITY_SHORT_SLOT_TIME; | |
49552d33 | 3623 | END_FOREACH_BSS() |
a9533e7e | 3624 | |
c654fce6 | 3625 | brcms_b_set_shortslot(wlc->hw, shortslot); |
a9533e7e HP |
3626 | } |
3627 | ||
419ad34e AS |
3628 | /* |
3629 | * propagate home chanspec to all bsscfgs in | |
3630 | * case bsscfg->current_bss->chanspec is referenced | |
3631 | */ | |
6bd20a1b | 3632 | void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec) |
a9533e7e HP |
3633 | { |
3634 | if (wlc->home_chanspec != chanspec) { | |
3635 | int idx; | |
471f1b51 | 3636 | struct brcms_bss_cfg *cfg; |
a9533e7e HP |
3637 | |
3638 | wlc->home_chanspec = chanspec; | |
3639 | ||
49552d33 | 3640 | FOREACH_BSS(wlc, idx, cfg) |
a9533e7e HP |
3641 | if (!cfg->associated) |
3642 | continue; | |
eff1b99a | 3643 | |
a9533e7e | 3644 | cfg->current_bss->chanspec = chanspec; |
49552d33 AS |
3645 | END_FOREACH_BSS() |
3646 | ||
a9533e7e HP |
3647 | |
3648 | } | |
3649 | } | |
3650 | ||
2682e2a3 AS |
3651 | void |
3652 | brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec, | |
3653 | bool mute, struct txpwr_limits *txpwr) | |
a9533e7e | 3654 | { |
2682e2a3 | 3655 | uint bandunit; |
a9533e7e | 3656 | |
2682e2a3 | 3657 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec); |
839f9f62 RV |
3658 | |
3659 | wlc_hw->chanspec = chanspec; | |
3660 | ||
3661 | /* Switch bands if necessary */ | |
3662 | if (NBANDS_HW(wlc_hw) > 1) { | |
3663 | bandunit = CHSPEC_BANDUNIT(chanspec); | |
3664 | if (wlc_hw->band->bandunit != bandunit) { | |
3665 | /* brcms_b_setband disables other bandunit, | |
3666 | * use light band switch if not up yet | |
3667 | */ | |
3668 | if (wlc_hw->up) { | |
3669 | wlc_phy_chanspec_radio_set(wlc_hw-> | |
3670 | bandstate[bandunit]-> | |
3671 | pi, chanspec); | |
3672 | brcms_b_setband(wlc_hw, bandunit, chanspec); | |
3673 | } else { | |
3674 | brcms_c_setxband(wlc_hw, bandunit); | |
3675 | } | |
3676 | } | |
3677 | } | |
3678 | ||
3679 | wlc_phy_initcal_enable(wlc_hw->band->pi, !mute); | |
3680 | ||
3681 | if (!wlc_hw->up) { | |
3682 | if (wlc_hw->clk) | |
3683 | wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, | |
3684 | chanspec); | |
3685 | wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec); | |
3686 | } else { | |
3687 | wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec); | |
3688 | wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec); | |
3689 | ||
3690 | /* Update muting of the channel */ | |
3691 | brcms_b_mute(wlc_hw, mute, 0); | |
3692 | } | |
3693 | } | |
3694 | ||
2682e2a3 AS |
3695 | /* switch to and initialize new band */ |
3696 | static void brcms_c_setband(struct brcms_c_info *wlc, | |
3697 | uint bandunit) | |
3698 | { | |
3699 | int idx; | |
3700 | struct brcms_bss_cfg *cfg; | |
3701 | ||
3702 | wlc->band = wlc->bandstate[bandunit]; | |
3703 | ||
3704 | if (!wlc->pub->up) | |
3705 | return; | |
3706 | ||
3707 | /* wait for at least one beacon before entering sleeping state */ | |
3708 | for (idx = 0; idx < BRCMS_MAXBSSCFG; idx++) { | |
3709 | cfg = wlc->bsscfg[idx]; | |
3710 | if (cfg && BSSCFG_STA(cfg) && cfg->associated) | |
3711 | cfg->PMawakebcn = true; | |
3712 | } | |
3713 | brcms_c_set_ps_ctrl(wlc); | |
3714 | ||
3715 | /* band-specific initializations */ | |
3716 | brcms_c_bsinit(wlc); | |
3717 | } | |
3718 | ||
6bd20a1b | 3719 | void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec) |
a9533e7e HP |
3720 | { |
3721 | uint bandunit; | |
0965ae88 | 3722 | bool switchband = false; |
6bd20a1b | 3723 | u16 old_chanspec = wlc->chanspec; |
a9533e7e | 3724 | |
f52a0ad0 | 3725 | if (!brcms_c_valid_chanspec_db(wlc->cmi, chanspec)) { |
b8f092c9 RV |
3726 | wiphy_err(wlc->wiphy, "wl%d: %s: Bad channel %d\n", |
3727 | wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec)); | |
a9533e7e HP |
3728 | return; |
3729 | } | |
3730 | ||
3731 | /* Switch bands if necessary */ | |
3732 | if (NBANDS(wlc) > 1) { | |
7c783cef | 3733 | bandunit = CHSPEC_BANDUNIT(chanspec); |
a9533e7e | 3734 | if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) { |
0f0881b0 | 3735 | switchband = true; |
a9533e7e | 3736 | if (wlc->bandlocked) { |
b8f092c9 RV |
3737 | wiphy_err(wlc->wiphy, "wl%d: %s: chspec %d " |
3738 | "band is locked!\n", | |
3739 | wlc->pub->unit, __func__, | |
3740 | CHSPEC_CHANNEL(chanspec)); | |
a9533e7e HP |
3741 | return; |
3742 | } | |
c654fce6 RV |
3743 | /* |
3744 | * should the setband call come after the | |
3745 | * brcms_b_chanspec() ? if the setband updates | |
1c4c54ba | 3746 | * (brcms_c_bsinit) use low level calls to inspect and |
c654fce6 RV |
3747 | * set state, the state inspected may be from the wrong |
3748 | * band, or the following brcms_b_set_chanspec() may | |
3749 | * undo the work. | |
a9533e7e | 3750 | */ |
1c4c54ba | 3751 | brcms_c_setband(wlc, bandunit); |
a9533e7e HP |
3752 | } |
3753 | } | |
3754 | ||
a9533e7e | 3755 | /* sync up phy/radio chanspec */ |
1c4c54ba | 3756 | brcms_c_set_phy_chanspec(wlc, chanspec); |
a9533e7e HP |
3757 | |
3758 | /* init antenna selection */ | |
3759 | if (CHSPEC_WLC_BW(old_chanspec) != CHSPEC_WLC_BW(chanspec)) { | |
f52a0ad0 | 3760 | brcms_c_antsel_init(wlc->asi); |
a9533e7e HP |
3761 | |
3762 | /* Fix the hardware rateset based on bw. | |
3763 | * Mainly add MCS32 for 40Mhz, remove MCS 32 for 20Mhz | |
3764 | */ | |
f52a0ad0 | 3765 | brcms_c_rateset_bw_mcs_filter(&wlc->band->hw_rateset, |
a9533e7e HP |
3766 | wlc->band-> |
3767 | mimo_cap_40 ? CHSPEC_WLC_BW(chanspec) | |
3768 | : 0); | |
3769 | } | |
3770 | ||
3771 | /* update some mac configuration since chanspec changed */ | |
1c4c54ba | 3772 | brcms_c_ucode_mac_upd(wlc); |
a9533e7e HP |
3773 | } |
3774 | ||
6bd20a1b | 3775 | u32 brcms_c_lowest_basic_rspec(struct brcms_c_info *wlc, |
fa67ebba | 3776 | struct brcms_c_rateset *rs) |
a9533e7e | 3777 | { |
6bd20a1b | 3778 | u32 lowest_basic_rspec; |
a9533e7e HP |
3779 | uint i; |
3780 | ||
3781 | /* Use the lowest basic rate */ | |
7c783cef | 3782 | lowest_basic_rspec = rs->rates[0] & BRCMS_RATE_MASK; |
a9533e7e | 3783 | for (i = 0; i < rs->count; i++) { |
7c783cef RV |
3784 | if (rs->rates[i] & BRCMS_RATE_FLAG) { |
3785 | lowest_basic_rspec = rs->rates[i] & BRCMS_RATE_MASK; | |
a9533e7e HP |
3786 | break; |
3787 | } | |
3788 | } | |
b61c23c8 | 3789 | |
419ad34e AS |
3790 | /* |
3791 | * pick siso/cdd as default for OFDM (note no basic | |
3792 | * rate MCSs are supported yet) | |
3793 | */ | |
8ea54c9f | 3794 | if (IS_OFDM(lowest_basic_rspec)) |
a9533e7e | 3795 | lowest_basic_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT); |
8ea54c9f | 3796 | |
90ea2296 | 3797 | return lowest_basic_rspec; |
a9533e7e HP |
3798 | } |
3799 | ||
419ad34e AS |
3800 | /* |
3801 | * This function changes the phytxctl for beacon based on current | |
3802 | * beacon ratespec AND txant setting as per this table: | |
a9533e7e | 3803 | * ratespec CCK ant = wlc->stf->txant |
8a76f1ee | 3804 | * OFDM ant = 3 |
a9533e7e | 3805 | */ |
fe741e5e | 3806 | void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc, |
6bd20a1b | 3807 | u32 bcn_rspec) |
a9533e7e | 3808 | { |
7d4df48e GKH |
3809 | u16 phyctl; |
3810 | u16 phytxant = wlc->stf->phytxant; | |
3811 | u16 mask = PHY_TXC_ANT_MASK; | |
a9533e7e HP |
3812 | |
3813 | /* for non-siso rates or default setting, use the available chains */ | |
7c783cef | 3814 | if (BRCMS_PHY_11N_CAP(wlc->band)) |
f52a0ad0 | 3815 | phytxant = brcms_c_stf_phytxchain_sel(wlc, bcn_rspec); |
a9533e7e | 3816 | |
fe741e5e | 3817 | phyctl = brcms_c_read_shm(wlc, M_BCN_PCTLWD); |
a9533e7e | 3818 | phyctl = (phyctl & ~mask) | phytxant; |
fe741e5e | 3819 | brcms_c_write_shm(wlc, M_BCN_PCTLWD, phyctl); |
a9533e7e HP |
3820 | } |
3821 | ||
419ad34e AS |
3822 | /* |
3823 | * centralized protection config change function to simplify debugging, no | |
3824 | * consistency checking this should be called only on changes to avoid overhead | |
3825 | * in periodic function | |
3826 | */ | |
fe741e5e | 3827 | void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val) |
a9533e7e | 3828 | { |
792aa408 | 3829 | BCMMSG(wlc->wiphy, "idx %d, val %d\n", idx, val); |
a9533e7e HP |
3830 | |
3831 | switch (idx) { | |
7c783cef | 3832 | case BRCMS_PROT_G_SPEC: |
a9533e7e HP |
3833 | wlc->protection->_g = (bool) val; |
3834 | break; | |
7c783cef | 3835 | case BRCMS_PROT_G_OVR: |
562c8850 | 3836 | wlc->protection->g_override = (s8) val; |
a9533e7e | 3837 | break; |
7c783cef | 3838 | case BRCMS_PROT_G_USER: |
41feb5ed | 3839 | wlc->protection->gmode_user = (u8) val; |
a9533e7e | 3840 | break; |
7c783cef | 3841 | case BRCMS_PROT_OVERLAP: |
562c8850 | 3842 | wlc->protection->overlap = (s8) val; |
a9533e7e | 3843 | break; |
7c783cef | 3844 | case BRCMS_PROT_N_USER: |
562c8850 | 3845 | wlc->protection->nmode_user = (s8) val; |
a9533e7e | 3846 | break; |
7c783cef | 3847 | case BRCMS_PROT_N_CFG: |
562c8850 | 3848 | wlc->protection->n_cfg = (s8) val; |
a9533e7e | 3849 | break; |
7c783cef | 3850 | case BRCMS_PROT_N_CFG_OVR: |
562c8850 | 3851 | wlc->protection->n_cfg_override = (s8) val; |
a9533e7e | 3852 | break; |
7c783cef | 3853 | case BRCMS_PROT_N_NONGF: |
a9533e7e HP |
3854 | wlc->protection->nongf = (bool) val; |
3855 | break; | |
7c783cef | 3856 | case BRCMS_PROT_N_NONGF_OVR: |
562c8850 | 3857 | wlc->protection->nongf_override = (s8) val; |
a9533e7e | 3858 | break; |
7c783cef | 3859 | case BRCMS_PROT_N_PAM_OVR: |
562c8850 | 3860 | wlc->protection->n_pam_override = (s8) val; |
a9533e7e | 3861 | break; |
7c783cef | 3862 | case BRCMS_PROT_N_OBSS: |
a9533e7e HP |
3863 | wlc->protection->n_obss = (bool) val; |
3864 | break; | |
3865 | ||
3866 | default: | |
a9533e7e HP |
3867 | break; |
3868 | } | |
3869 | ||
3870 | } | |
3871 | ||
1c4c54ba | 3872 | static void brcms_c_ht_update_sgi_rx(struct brcms_c_info *wlc, int val) |
a9533e7e | 3873 | { |
651bd3a9 RV |
3874 | wlc->ht_cap.cap_info &= ~(IEEE80211_HT_CAP_SGI_20 | |
3875 | IEEE80211_HT_CAP_SGI_40); | |
7c783cef | 3876 | wlc->ht_cap.cap_info |= (val & BRCMS_N_SGI_20) ? |
651bd3a9 | 3877 | IEEE80211_HT_CAP_SGI_20 : 0; |
7c783cef | 3878 | wlc->ht_cap.cap_info |= (val & BRCMS_N_SGI_40) ? |
651bd3a9 | 3879 | IEEE80211_HT_CAP_SGI_40 : 0; |
a9533e7e HP |
3880 | |
3881 | if (wlc->pub->up) { | |
fe741e5e RV |
3882 | brcms_c_update_beacon(wlc); |
3883 | brcms_c_update_probe_resp(wlc, true); | |
a9533e7e HP |
3884 | } |
3885 | } | |
3886 | ||
1c4c54ba | 3887 | static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val) |
a9533e7e HP |
3888 | { |
3889 | wlc->stf->ldpc = val; | |
3890 | ||
651bd3a9 | 3891 | wlc->ht_cap.cap_info &= ~IEEE80211_HT_CAP_LDPC_CODING; |
a9533e7e | 3892 | if (wlc->stf->ldpc != OFF) |
651bd3a9 | 3893 | wlc->ht_cap.cap_info |= IEEE80211_HT_CAP_LDPC_CODING; |
a9533e7e HP |
3894 | |
3895 | if (wlc->pub->up) { | |
fe741e5e RV |
3896 | brcms_c_update_beacon(wlc); |
3897 | brcms_c_update_probe_resp(wlc, true); | |
0965ae88 | 3898 | wlc_phy_ldpc_override_set(wlc->band->pi, (val ? true : false)); |
a9533e7e HP |
3899 | } |
3900 | } | |
3901 | ||
419ad34e AS |
3902 | /* |
3903 | * Initialize a WME Parameter Info Element with default | |
3904 | * STA parameters from WMM Spec, Table 12 | |
3905 | */ | |
cc87568a RV |
3906 | void |
3907 | brcms_c_wme_initparams_sta(struct brcms_c_info *wlc, struct wme_param_ie *pe) | |
a9533e7e | 3908 | { |
cc87568a | 3909 | static const struct wme_param_ie stadef = { |
a9533e7e HP |
3910 | WME_OUI, |
3911 | WME_TYPE, | |
3912 | WME_SUBTYPE_PARAM_IE, | |
3913 | WME_VER, | |
3914 | 0, | |
3915 | 0, | |
3916 | { | |
3917 | {EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA, | |
628f10ba | 3918 | cpu_to_le16(EDCF_AC_BE_TXOP_STA)}, |
a9533e7e | 3919 | {EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA, |
628f10ba | 3920 | cpu_to_le16(EDCF_AC_BK_TXOP_STA)}, |
a9533e7e | 3921 | {EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA, |
628f10ba | 3922 | cpu_to_le16(EDCF_AC_VI_TXOP_STA)}, |
a9533e7e | 3923 | {EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA, |
628f10ba | 3924 | cpu_to_le16(EDCF_AC_VO_TXOP_STA)} |
a9533e7e HP |
3925 | } |
3926 | }; | |
a9533e7e HP |
3927 | memcpy(pe, &stadef, sizeof(*pe)); |
3928 | } | |
3929 | ||
fe741e5e | 3930 | void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, |
a332bfc9 RV |
3931 | const struct ieee80211_tx_queue_params *params, |
3932 | bool suspend) | |
a9533e7e HP |
3933 | { |
3934 | int i; | |
cc87568a | 3935 | struct shm_acparams acp_shm; |
7d4df48e | 3936 | u16 *shm_entry; |
a9533e7e | 3937 | |
a9533e7e HP |
3938 | /* Only apply params if the core is out of reset and has clocks */ |
3939 | if (!wlc->clk) { | |
b8f092c9 RV |
3940 | wiphy_err(wlc->wiphy, "wl%d: %s : no-clock\n", wlc->pub->unit, |
3941 | __func__); | |
a9533e7e HP |
3942 | return; |
3943 | } | |
3944 | ||
a9533e7e | 3945 | do { |
cc87568a | 3946 | memset((char *)&acp_shm, 0, sizeof(struct shm_acparams)); |
a9533e7e | 3947 | /* fill in shm ac params struct */ |
628f10ba | 3948 | acp_shm.txop = le16_to_cpu(params->txop); |
a9533e7e HP |
3949 | /* convert from units of 32us to us for ucode */ |
3950 | wlc->edcf_txop[aci & 0x3] = acp_shm.txop = | |
3951 | EDCF_TXOP2USEC(acp_shm.txop); | |
3952 | acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK); | |
3953 | ||
3954 | if (aci == AC_VI && acp_shm.txop == 0 | |
3955 | && acp_shm.aifs < EDCF_AIFSN_MAX) | |
3956 | acp_shm.aifs++; | |
3957 | ||
3958 | if (acp_shm.aifs < EDCF_AIFSN_MIN | |
3959 | || acp_shm.aifs > EDCF_AIFSN_MAX) { | |
1c4c54ba | 3960 | wiphy_err(wlc->wiphy, "wl%d: edcf_setparams: bad " |
b8f092c9 | 3961 | "aifs %d\n", wlc->pub->unit, acp_shm.aifs); |
a9533e7e HP |
3962 | continue; |
3963 | } | |
3964 | ||
3965 | acp_shm.cwmin = params->cw_min; | |
3966 | acp_shm.cwmax = params->cw_max; | |
3967 | acp_shm.cwcur = acp_shm.cwmin; | |
3968 | acp_shm.bslots = | |
ff31c54c | 3969 | R_REG(&wlc->regs->tsf_random) & acp_shm.cwcur; |
a9533e7e HP |
3970 | acp_shm.reggap = acp_shm.bslots + acp_shm.aifs; |
3971 | /* Indicate the new params to the ucode */ | |
fe741e5e | 3972 | acp_shm.status = brcms_c_read_shm(wlc, (M_EDCF_QINFO + |
a9533e7e HP |
3973 | wme_shmemacindex(aci) * |
3974 | M_EDCF_QLEN + | |
3975 | M_EDCF_STATUS_OFF)); | |
3976 | acp_shm.status |= WME_STATUS_NEWAC; | |
3977 | ||
3978 | /* Fill in shm acparam table */ | |
7d4df48e | 3979 | shm_entry = (u16 *) &acp_shm; |
cc87568a | 3980 | for (i = 0; i < (int)sizeof(struct shm_acparams); i += 2) |
fe741e5e | 3981 | brcms_c_write_shm(wlc, |
a9533e7e HP |
3982 | M_EDCF_QINFO + |
3983 | wme_shmemacindex(aci) * M_EDCF_QLEN + i, | |
3984 | *shm_entry++); | |
3985 | ||
3986 | } while (0); | |
3987 | ||
839f9f62 RV |
3988 | if (suspend) |
3989 | brcms_c_suspend_mac_and_wait(wlc); | |
3990 | ||
3991 | if (suspend) | |
3992 | brcms_c_enable_mac(wlc); | |
3993 | ||
3994 | } | |
3995 | ||
3996 | void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend) | |
3997 | { | |
3998 | u16 aci; | |
3999 | int i_ac; | |
4000 | struct edcf_acparam *edcf_acp; | |
4001 | ||
4002 | struct ieee80211_tx_queue_params txq_pars; | |
4003 | struct ieee80211_tx_queue_params *params = &txq_pars; | |
4004 | ||
4005 | /* | |
4006 | * AP uses AC params from wme_param_ie_ap. | |
4007 | * AP advertises AC params from wme_param_ie. | |
4008 | * STA uses AC params from wme_param_ie. | |
4009 | */ | |
4010 | ||
4011 | edcf_acp = (struct edcf_acparam *) &wlc->wme_param_ie.acparam[0]; | |
4012 | ||
4013 | for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) { | |
4014 | /* find out which ac this set of params applies to */ | |
4015 | aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT; | |
4016 | ||
4017 | /* fill in shm ac params struct */ | |
4018 | params->txop = edcf_acp->TXOP; | |
4019 | params->aifs = edcf_acp->ACI; | |
4020 | ||
4021 | /* CWmin = 2^(ECWmin) - 1 */ | |
4022 | params->cw_min = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK); | |
4023 | /* CWmax = 2^(ECWmax) - 1 */ | |
4024 | params->cw_max = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK) | |
4025 | >> EDCF_ECWMAX_SHIFT); | |
4026 | brcms_c_wme_setparams(wlc, aci, params, suspend); | |
4027 | } | |
4028 | ||
4029 | if (suspend) | |
4030 | brcms_c_suspend_mac_and_wait(wlc); | |
4031 | ||
4032 | if (AP_ENAB(wlc->pub) && WME_ENAB(wlc->pub)) { | |
4033 | brcms_c_update_beacon(wlc); | |
4034 | brcms_c_update_probe_resp(wlc, false); | |
4035 | } | |
4036 | ||
4037 | if (suspend) | |
4038 | brcms_c_enable_mac(wlc); | |
4039 | ||
4040 | } | |
4041 | ||
2682e2a3 AS |
4042 | /* maintain LED behavior in down state */ |
4043 | static void brcms_c_down_led_upd(struct brcms_c_info *wlc) | |
839f9f62 | 4044 | { |
2682e2a3 AS |
4045 | /* |
4046 | * maintain LEDs while in down state, turn on sbclk if | |
4047 | * not available yet. Turn on sbclk if necessary | |
4048 | */ | |
4049 | if (!AP_ENAB(wlc->pub)) { | |
4050 | brcms_c_pllreq(wlc, true, BRCMS_PLLREQ_FLIP); | |
839f9f62 | 4051 | |
2682e2a3 | 4052 | brcms_c_pllreq(wlc, false, BRCMS_PLLREQ_FLIP); |
839f9f62 | 4053 | } |
2682e2a3 | 4054 | } |
839f9f62 | 4055 | |
2682e2a3 AS |
4056 | static bool brcms_c_radio_monitor_start(struct brcms_c_info *wlc) |
4057 | { | |
4058 | /* Don't start the timer if HWRADIO feature is disabled */ | |
4059 | if (wlc->radio_monitor || (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO)) | |
4060 | return true; | |
839f9f62 | 4061 | |
2682e2a3 AS |
4062 | wlc->radio_monitor = true; |
4063 | brcms_c_pllreq(wlc, true, BRCMS_PLLREQ_RADIO_MON); | |
4064 | brcms_add_timer(wlc->wl, wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, | |
4065 | true); | |
4066 | return true; | |
839f9f62 RV |
4067 | } |
4068 | ||
2682e2a3 | 4069 | void brcms_c_radio_disable(struct brcms_c_info *wlc) |
839f9f62 | 4070 | { |
2682e2a3 AS |
4071 | if (!wlc->pub->up) { |
4072 | brcms_c_down_led_upd(wlc); | |
4073 | return; | |
4074 | } | |
839f9f62 | 4075 | |
2682e2a3 AS |
4076 | brcms_c_radio_monitor_start(wlc); |
4077 | brcms_down(wlc->wl); | |
4078 | } | |
839f9f62 | 4079 | |
2682e2a3 AS |
4080 | static void brcms_c_radio_enable(struct brcms_c_info *wlc) |
4081 | { | |
4082 | if (wlc->pub->up) | |
4083 | return; | |
839f9f62 | 4084 | |
2682e2a3 AS |
4085 | if (DEVICEREMOVED(wlc)) |
4086 | return; | |
839f9f62 | 4087 | |
2682e2a3 AS |
4088 | brcms_up(wlc->wl); |
4089 | } | |
839f9f62 | 4090 | |
2682e2a3 AS |
4091 | bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc) |
4092 | { | |
4093 | if (!wlc->radio_monitor) | |
4094 | return true; | |
839f9f62 | 4095 | |
2682e2a3 AS |
4096 | wlc->radio_monitor = false; |
4097 | brcms_c_pllreq(wlc, false, BRCMS_PLLREQ_RADIO_MON); | |
4098 | return brcms_del_timer(wlc->wl, wlc->radio_timer); | |
4099 | } | |
839f9f62 | 4100 | |
2682e2a3 AS |
4101 | /* read hwdisable state and propagate to wlc flag */ |
4102 | static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc) | |
4103 | { | |
4104 | if (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO || wlc->pub->hw_off) | |
4105 | return; | |
4106 | ||
4107 | if (brcms_b_radio_read_hwdisabled(wlc->hw)) | |
4108 | mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE); | |
4109 | else | |
4110 | mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE); | |
4111 | } | |
4112 | ||
4113 | /* | |
4114 | * centralized radio disable/enable function, | |
4115 | * invoke radio enable/disable after updating hwradio status | |
4116 | */ | |
4117 | static void brcms_c_radio_upd(struct brcms_c_info *wlc) | |
4118 | { | |
4119 | if (wlc->pub->radio_disabled) | |
4120 | brcms_c_radio_disable(wlc); | |
4121 | else | |
4122 | brcms_c_radio_enable(wlc); | |
4123 | } | |
4124 | ||
4125 | /* update hwradio status and return it */ | |
4126 | bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc) | |
4127 | { | |
4128 | brcms_c_radio_hwdisable_upd(wlc); | |
4129 | ||
4130 | return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ? | |
4131 | true : false; | |
4132 | } | |
4133 | ||
4134 | /* periodical query hw radio button while driver is "down" */ | |
4135 | static void brcms_c_radio_timer(void *arg) | |
4136 | { | |
4137 | struct brcms_c_info *wlc = (struct brcms_c_info *) arg; | |
4138 | ||
4139 | if (DEVICEREMOVED(wlc)) { | |
4140 | wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit, | |
4141 | __func__); | |
4142 | brcms_down(wlc->wl); | |
4143 | return; | |
4144 | } | |
4145 | ||
4146 | /* cap mpc off count */ | |
4147 | if (wlc->mpc_offcnt < BRCMS_MPC_MAX_DELAYCNT) | |
4148 | wlc->mpc_offcnt++; | |
4149 | ||
4150 | brcms_c_radio_hwdisable_upd(wlc); | |
4151 | brcms_c_radio_upd(wlc); | |
4152 | } | |
4153 | ||
4154 | /* common low-level watchdog code */ | |
11431424 | 4155 | static void brcms_b_watchdog(void *arg) |
2682e2a3 AS |
4156 | { |
4157 | struct brcms_c_info *wlc = (struct brcms_c_info *) arg; | |
4158 | struct brcms_hardware *wlc_hw = wlc->hw; | |
4159 | ||
4160 | BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
4161 | ||
4162 | if (!wlc_hw->up) | |
4163 | return; | |
4164 | ||
4165 | /* increment second count */ | |
4166 | wlc_hw->now++; | |
4167 | ||
4168 | /* Check for FIFO error interrupts */ | |
4169 | brcms_b_fifoerrors(wlc_hw); | |
4170 | ||
4171 | /* make sure RX dma has buffers */ | |
4172 | dma_rxfill(wlc->hw->di[RX_FIFO]); | |
4173 | ||
4174 | wlc_phy_watchdog(wlc_hw->band->pi); | |
4175 | } | |
4176 | ||
4177 | /* common watchdog code */ | |
4178 | static void brcms_c_watchdog(void *arg) | |
4179 | { | |
4180 | struct brcms_c_info *wlc = (struct brcms_c_info *) arg; | |
4181 | int i; | |
4182 | struct brcms_bss_cfg *cfg; | |
4183 | ||
4184 | BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); | |
4185 | ||
4186 | if (!wlc->pub->up) | |
4187 | return; | |
4188 | ||
4189 | if (DEVICEREMOVED(wlc)) { | |
4190 | wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit, | |
4191 | __func__); | |
4192 | brcms_down(wlc->wl); | |
4193 | return; | |
4194 | } | |
4195 | ||
4196 | /* increment second count */ | |
4197 | wlc->pub->now++; | |
4198 | ||
4199 | /* delay radio disable */ | |
4200 | if (wlc->mpc_delay_off) { | |
4201 | if (--wlc->mpc_delay_off == 0) { | |
4202 | mboolset(wlc->pub->radio_disabled, | |
4203 | WL_RADIO_MPC_DISABLE); | |
4204 | if (wlc->mpc && brcms_c_ismpc(wlc)) | |
4205 | wlc->mpc_offcnt = 0; | |
4206 | wlc->mpc_laston_ts = OSL_SYSUPTIME(); | |
4207 | } | |
4208 | } | |
4209 | ||
4210 | /* mpc sync */ | |
4211 | brcms_c_radio_mpc_upd(wlc); | |
4212 | /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */ | |
4213 | brcms_c_radio_hwdisable_upd(wlc); | |
4214 | brcms_c_radio_upd(wlc); | |
4215 | /* if radio is disable, driver may be down, quit here */ | |
4216 | if (wlc->pub->radio_disabled) | |
4217 | return; | |
4218 | ||
4219 | brcms_b_watchdog(wlc); | |
4220 | ||
4221 | /* | |
4222 | * occasionally sample mac stat counters to | |
4223 | * detect 16-bit counter wrap | |
4224 | */ | |
4225 | if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0) | |
4226 | brcms_c_statsupd(wlc); | |
4227 | ||
4228 | /* Manage TKIP countermeasures timers */ | |
4229 | FOREACH_BSS(wlc, i, cfg) | |
4230 | if (cfg->tk_cm_dt) | |
4231 | cfg->tk_cm_dt--; | |
4232 | if (cfg->tk_cm_bt) | |
4233 | cfg->tk_cm_bt--; | |
4234 | END_FOREACH_BSS() | |
4235 | ||
4236 | if (BRCMS_ISNPHY(wlc->band) && !wlc->pub->tempsense_disable && | |
4237 | ((wlc->pub->now - wlc->tempsense_lasttime) >= | |
4238 | BRCMS_TEMPSENSE_PERIOD)) { | |
4239 | wlc->tempsense_lasttime = wlc->pub->now; | |
4240 | brcms_c_tempsense_upd(wlc); | |
4241 | } | |
4242 | } | |
4243 | ||
4244 | static void brcms_c_watchdog_by_timer(void *arg) | |
4245 | { | |
4246 | brcms_c_watchdog(arg); | |
4247 | } | |
4248 | ||
4249 | bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit) | |
4250 | { | |
4251 | wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer, | |
4252 | wlc, "watchdog"); | |
4253 | if (!wlc->wdtimer) { | |
4254 | wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for wdtimer " | |
4255 | "failed\n", unit); | |
4256 | goto fail; | |
4257 | } | |
4258 | ||
4259 | wlc->radio_timer = brcms_init_timer(wlc->wl, brcms_c_radio_timer, | |
4260 | wlc, "radio"); | |
4261 | if (!wlc->radio_timer) { | |
4262 | wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for radio_timer " | |
4263 | "failed\n", unit); | |
4264 | goto fail; | |
4265 | } | |
4266 | ||
4267 | return true; | |
4268 | ||
4269 | fail: | |
4270 | return false; | |
4271 | } | |
4272 | ||
4273 | /* | |
4274 | * Initialize brcms_c_info default values ... | |
4275 | * may get overrides later in this function | |
4276 | */ | |
4277 | void brcms_c_info_init(struct brcms_c_info *wlc, int unit) | |
4278 | { | |
4279 | int i; | |
4280 | /* Assume the device is there until proven otherwise */ | |
4281 | wlc->device_present = true; | |
4282 | ||
4283 | /* Save our copy of the chanspec */ | |
4284 | wlc->chanspec = CH20MHZ_CHSPEC(1); | |
4285 | ||
4286 | /* various 802.11g modes */ | |
4287 | wlc->shortslot = false; | |
4288 | wlc->shortslot_override = BRCMS_SHORTSLOT_AUTO; | |
4289 | ||
4290 | brcms_c_protection_upd(wlc, BRCMS_PROT_G_OVR, BRCMS_PROTECTION_AUTO); | |
4291 | brcms_c_protection_upd(wlc, BRCMS_PROT_G_SPEC, false); | |
4292 | ||
4293 | brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG_OVR, | |
4294 | BRCMS_PROTECTION_AUTO); | |
4295 | brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG, BRCMS_N_PROTECTION_OFF); | |
4296 | brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF_OVR, | |
4297 | BRCMS_PROTECTION_AUTO); | |
4298 | brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF, false); | |
4299 | brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, AUTO); | |
4300 | ||
4301 | brcms_c_protection_upd(wlc, BRCMS_PROT_OVERLAP, | |
4302 | BRCMS_PROTECTION_CTL_OVERLAP); | |
4303 | ||
4304 | /* 802.11g draft 4.0 NonERP elt advertisement */ | |
4305 | wlc->include_legacy_erp = true; | |
4306 | ||
4307 | wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF; | |
4308 | wlc->stf->txant = ANT_TX_DEF; | |
4309 | ||
4310 | wlc->prb_resp_timeout = BRCMS_PRB_RESP_TIMEOUT; | |
839f9f62 RV |
4311 | |
4312 | wlc->usr_fragthresh = DOT11_DEFAULT_FRAG_LEN; | |
4313 | for (i = 0; i < NFIFO; i++) | |
4314 | wlc->fragthresh[i] = DOT11_DEFAULT_FRAG_LEN; | |
4315 | wlc->RTSThresh = DOT11_DEFAULT_RTS_LEN; | |
4316 | ||
4317 | /* default rate fallback retry limits */ | |
4318 | wlc->SFBL = RETRY_SHORT_FB; | |
4319 | wlc->LFBL = RETRY_LONG_FB; | |
4320 | ||
4321 | /* default mac retry limits */ | |
4322 | wlc->SRL = RETRY_SHORT_DEF; | |
4323 | wlc->LRL = RETRY_LONG_DEF; | |
4324 | ||
4325 | /* Set flag to indicate that hw keys should be used when available. */ | |
4326 | wlc->wsec_swkeys = false; | |
4327 | ||
4328 | /* init the 4 static WEP default keys */ | |
4329 | for (i = 0; i < WSEC_MAX_DEFAULT_KEYS; i++) { | |
4330 | wlc->wsec_keys[i] = wlc->wsec_def_keys[i]; | |
4331 | wlc->wsec_keys[i]->idx = (u8) i; | |
4332 | } | |
4333 | ||
4334 | /* WME QoS mode is Auto by default */ | |
4335 | wlc->pub->_wme = AUTO; | |
839f9f62 RV |
4336 | wlc->pub->_ampdu = AMPDU_AGG_HOST; |
4337 | wlc->pub->bcmerror = 0; | |
4338 | wlc->pub->_coex = ON; | |
4339 | ||
4340 | /* initialize mpc delay */ | |
4341 | wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT; | |
4342 | } | |
4343 | ||
4344 | static bool brcms_c_state_bmac_sync(struct brcms_c_info *wlc) | |
4345 | { | |
4346 | struct brcms_b_state state_bmac = {0}; | |
4347 | ||
4348 | if (brcms_b_state_get(wlc->hw, &state_bmac) != 0) | |
4349 | return false; | |
4350 | ||
4351 | wlc->machwcap = state_bmac.machwcap; | |
4352 | brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, | |
4353 | (s8) state_bmac.preamble_ovr); | |
4354 | ||
4355 | return true; | |
4356 | } | |
4357 | ||
4358 | static uint brcms_c_attach_module(struct brcms_c_info *wlc) | |
4359 | { | |
4360 | uint err = 0; | |
4361 | uint unit; | |
4362 | unit = wlc->pub->unit; | |
4363 | ||
4364 | wlc->asi = brcms_c_antsel_attach(wlc); | |
4365 | if (wlc->asi == NULL) { | |
4366 | wiphy_err(wlc->wiphy, "wl%d: attach: antsel_attach " | |
4367 | "failed\n", unit); | |
4368 | err = 44; | |
4369 | goto fail; | |
4370 | } | |
4371 | ||
4372 | wlc->ampdu = brcms_c_ampdu_attach(wlc); | |
4373 | if (wlc->ampdu == NULL) { | |
4374 | wiphy_err(wlc->wiphy, "wl%d: attach: ampdu_attach " | |
4375 | "failed\n", unit); | |
4376 | err = 50; | |
4377 | goto fail; | |
4378 | } | |
4379 | ||
4380 | if ((brcms_c_stf_attach(wlc) != 0)) { | |
4381 | wiphy_err(wlc->wiphy, "wl%d: attach: stf_attach " | |
4382 | "failed\n", unit); | |
4383 | err = 68; | |
4384 | goto fail; | |
4385 | } | |
4386 | fail: | |
4387 | return err; | |
4388 | } | |
4389 | ||
2f6b1dde | 4390 | struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc) |
839f9f62 | 4391 | { |
2f6b1dde | 4392 | return wlc->pub; |
839f9f62 RV |
4393 | } |
4394 | ||
4395 | #define CHIP_SUPPORTS_11N(wlc) 1 | |
4396 | ||
4397 | /* low level attach | |
4398 | * run backplane attach, init nvram | |
4399 | * run phy attach | |
4400 | * initialize software state for each core and band | |
4401 | * put the whole chip in reset(driver down state), no clock | |
4402 | */ | |
11431424 AS |
4403 | static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, |
4404 | uint unit, bool piomode, void *regsva, | |
4405 | struct pci_dev *btparam) | |
839f9f62 RV |
4406 | { |
4407 | struct brcms_hardware *wlc_hw; | |
0da64910 | 4408 | struct d11regs *regs; |
839f9f62 RV |
4409 | char *macaddr = NULL; |
4410 | char *vars; | |
4411 | uint err = 0; | |
4412 | uint j; | |
4413 | bool wme = false; | |
4414 | struct shared_phy_params sha_params; | |
4415 | struct wiphy *wiphy = wlc->wiphy; | |
821e4e93 RV |
4416 | char *var; |
4417 | unsigned long res; | |
839f9f62 RV |
4418 | |
4419 | BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, vendor, | |
4420 | device); | |
a9533e7e | 4421 | |
839f9f62 | 4422 | wme = true; |
a9533e7e | 4423 | |
839f9f62 RV |
4424 | wlc_hw = wlc->hw; |
4425 | wlc_hw->wlc = wlc; | |
4426 | wlc_hw->unit = unit; | |
4427 | wlc_hw->band = wlc_hw->bandstate[0]; | |
4428 | wlc_hw->_piomode = piomode; | |
a9533e7e | 4429 | |
839f9f62 RV |
4430 | /* populate struct brcms_hardware with default values */ |
4431 | brcms_b_info_init(wlc_hw); | |
3b6ee723 | 4432 | |
839f9f62 | 4433 | /* |
419ad34e AS |
4434 | * Do the hardware portion of the attach. Also initialize software |
4435 | * state that depends on the particular hardware we are running. | |
839f9f62 | 4436 | */ |
821e4e93 | 4437 | wlc_hw->sih = ai_attach(regsva, btparam, |
839f9f62 RV |
4438 | &wlc_hw->vars, &wlc_hw->vars_size); |
4439 | if (wlc_hw->sih == NULL) { | |
4440 | wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n", | |
4441 | unit); | |
4442 | err = 11; | |
4443 | goto fail; | |
4444 | } | |
4445 | vars = wlc_hw->vars; | |
a9533e7e | 4446 | |
a9533e7e | 4447 | /* |
839f9f62 RV |
4448 | * Get vendid/devid nvram overwrites, which could be different |
4449 | * than those the BIOS recognizes for devices on PCMCIA_BUS, | |
4450 | * SDIO_BUS, and SROMless devices on PCI_BUS. | |
a9533e7e | 4451 | */ |
821e4e93 RV |
4452 | var = getvar(vars, "vendid"); |
4453 | if (var && !kstrtoul(var, 0, &res)) { | |
4454 | vendor = (u16)res; | |
4455 | wiphy_err(wiphy, "Overriding vendor id = 0x%x\n", | |
4456 | vendor); | |
4457 | } | |
4458 | var = getvar(vars, "devid"); | |
4459 | if (var && !kstrtoul(var, 0, &res)) { | |
4460 | u16 devid = (u16)res; | |
4461 | if (devid != 0xffff) { | |
4462 | device = devid; | |
4463 | wiphy_err(wiphy, "Overriding device id = 0x%x" | |
4464 | "\n", device); | |
839f9f62 | 4465 | } |
821e4e93 | 4466 | } |
a9533e7e | 4467 | |
821e4e93 RV |
4468 | /* verify again the device is supported */ |
4469 | if (!brcms_c_chipmatch(vendor, device)) { | |
4470 | wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported " | |
4471 | "vendor/device (0x%x/0x%x)\n", | |
4472 | unit, vendor, device); | |
4473 | err = 12; | |
4474 | goto fail; | |
839f9f62 | 4475 | } |
a9533e7e | 4476 | |
839f9f62 RV |
4477 | wlc_hw->vendorid = vendor; |
4478 | wlc_hw->deviceid = device; | |
a9533e7e | 4479 | |
839f9f62 | 4480 | /* set bar0 window to point at D11 core */ |
0da64910 RV |
4481 | wlc_hw->regs = (struct d11regs *) ai_setcore(wlc_hw->sih, D11_CORE_ID, |
4482 | 0); | |
839f9f62 | 4483 | wlc_hw->corerev = ai_corerev(wlc_hw->sih); |
a9533e7e | 4484 | |
839f9f62 | 4485 | regs = wlc_hw->regs; |
a9533e7e | 4486 | |
839f9f62 RV |
4487 | wlc->regs = wlc_hw->regs; |
4488 | ||
4489 | /* validate chip, chiprev and corerev */ | |
4490 | if (!brcms_c_isgoodchip(wlc_hw)) { | |
4491 | err = 13; | |
4492 | goto fail; | |
a9533e7e HP |
4493 | } |
4494 | ||
839f9f62 RV |
4495 | /* initialize power control registers */ |
4496 | ai_clkctl_init(wlc_hw->sih); | |
a9533e7e | 4497 | |
839f9f62 RV |
4498 | /* request fastclock and force fastclock for the rest of attach |
4499 | * bring the d11 core out of reset. | |
419ad34e AS |
4500 | * For PMU chips, the first wlc_clkctl_clk is no-op since core-clk |
4501 | * is still false; But it will be called again inside wlc_corereset, | |
4502 | * after d11 is out of reset. | |
839f9f62 RV |
4503 | */ |
4504 | brcms_b_clkctl_clk(wlc_hw, CLK_FAST); | |
4505 | brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); | |
a9533e7e | 4506 | |
839f9f62 RV |
4507 | if (!brcms_b_validate_chip_access(wlc_hw)) { |
4508 | wiphy_err(wiphy, "wl%d: brcms_b_attach: validate_chip_access " | |
4509 | "failed\n", unit); | |
4510 | err = 14; | |
a9533e7e HP |
4511 | goto fail; |
4512 | } | |
4513 | ||
839f9f62 RV |
4514 | /* get the board rev, used just below */ |
4515 | j = getintvar(vars, "boardrev"); | |
4516 | /* promote srom boardrev of 0xFF to 1 */ | |
4517 | if (j == BOARDREV_PROMOTABLE) | |
4518 | j = BOARDREV_PROMOTED; | |
4519 | wlc_hw->boardrev = (u16) j; | |
4520 | if (!brcms_c_validboardtype(wlc_hw)) { | |
4521 | wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom " | |
4522 | "board type (0x%x)" " or revision level (0x%x)\n", | |
4523 | unit, wlc_hw->sih->boardtype, wlc_hw->boardrev); | |
4524 | err = 15; | |
a9533e7e HP |
4525 | goto fail; |
4526 | } | |
839f9f62 RV |
4527 | wlc_hw->sromrev = (u8) getintvar(vars, "sromrev"); |
4528 | wlc_hw->boardflags = (u32) getintvar(vars, "boardflags"); | |
4529 | wlc_hw->boardflags2 = (u32) getintvar(vars, "boardflags2"); | |
a9533e7e | 4530 | |
839f9f62 RV |
4531 | if (wlc_hw->boardflags & BFL_NOPLLDOWN) |
4532 | brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED); | |
a9533e7e | 4533 | |
821e4e93 | 4534 | if (ai_pci_war16165(wlc_hw->sih)) |
839f9f62 | 4535 | wlc->war16165 = true; |
a9533e7e | 4536 | |
839f9f62 RV |
4537 | /* check device id(srom, nvram etc.) to set bands */ |
4538 | if (wlc_hw->deviceid == BCM43224_D11N_ID || | |
8ea54c9f | 4539 | wlc_hw->deviceid == BCM43224_D11N_ID_VEN1) |
839f9f62 RV |
4540 | /* Dualband boards */ |
4541 | wlc_hw->_nbands = 2; | |
8ea54c9f | 4542 | else |
839f9f62 | 4543 | wlc_hw->_nbands = 1; |
a9533e7e | 4544 | |
839f9f62 RV |
4545 | if ((wlc_hw->sih->chip == BCM43225_CHIP_ID)) |
4546 | wlc_hw->_nbands = 1; | |
a9533e7e | 4547 | |
839f9f62 RV |
4548 | /* BMAC_NOTE: remove init of pub values when brcms_c_attach() |
4549 | * unconditionally does the init of these values | |
4550 | */ | |
4551 | wlc->vendorid = wlc_hw->vendorid; | |
4552 | wlc->deviceid = wlc_hw->deviceid; | |
4553 | wlc->pub->sih = wlc_hw->sih; | |
4554 | wlc->pub->corerev = wlc_hw->corerev; | |
4555 | wlc->pub->sromrev = wlc_hw->sromrev; | |
4556 | wlc->pub->boardrev = wlc_hw->boardrev; | |
4557 | wlc->pub->boardflags = wlc_hw->boardflags; | |
4558 | wlc->pub->boardflags2 = wlc_hw->boardflags2; | |
4559 | wlc->pub->_nbands = wlc_hw->_nbands; | |
a9533e7e | 4560 | |
839f9f62 | 4561 | wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc); |
a9533e7e | 4562 | |
839f9f62 RV |
4563 | if (wlc_hw->physhim == NULL) { |
4564 | wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_shim_attach " | |
4565 | "failed\n", unit); | |
4566 | err = 25; | |
4567 | goto fail; | |
4568 | } | |
a9533e7e | 4569 | |
839f9f62 RV |
4570 | /* pass all the parameters to wlc_phy_shared_attach in one struct */ |
4571 | sha_params.sih = wlc_hw->sih; | |
4572 | sha_params.physhim = wlc_hw->physhim; | |
4573 | sha_params.unit = unit; | |
4574 | sha_params.corerev = wlc_hw->corerev; | |
4575 | sha_params.vars = vars; | |
4576 | sha_params.vid = wlc_hw->vendorid; | |
4577 | sha_params.did = wlc_hw->deviceid; | |
4578 | sha_params.chip = wlc_hw->sih->chip; | |
4579 | sha_params.chiprev = wlc_hw->sih->chiprev; | |
4580 | sha_params.chippkg = wlc_hw->sih->chippkg; | |
4581 | sha_params.sromrev = wlc_hw->sromrev; | |
4582 | sha_params.boardtype = wlc_hw->sih->boardtype; | |
4583 | sha_params.boardrev = wlc_hw->boardrev; | |
4584 | sha_params.boardvendor = wlc_hw->sih->boardvendor; | |
4585 | sha_params.boardflags = wlc_hw->boardflags; | |
4586 | sha_params.boardflags2 = wlc_hw->boardflags2; | |
839f9f62 | 4587 | sha_params.buscorerev = wlc_hw->sih->buscorerev; |
a9533e7e | 4588 | |
839f9f62 RV |
4589 | /* alloc and save pointer to shared phy state area */ |
4590 | wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params); | |
4591 | if (!wlc_hw->phy_sh) { | |
4592 | err = 16; | |
4593 | goto fail; | |
4594 | } | |
4595 | ||
4596 | /* initialize software state for each core and band */ | |
4597 | for (j = 0; j < NBANDS_HW(wlc_hw); j++) { | |
4598 | /* | |
4599 | * band0 is always 2.4Ghz | |
4600 | * band1, if present, is 5Ghz | |
4601 | */ | |
a9533e7e | 4602 | |
839f9f62 RV |
4603 | /* So if this is a single band 11a card, use band 1 */ |
4604 | if (IS_SINGLEBAND_5G(wlc_hw->deviceid)) | |
4605 | j = BAND_5G_INDEX; | |
a9533e7e | 4606 | |
839f9f62 | 4607 | brcms_c_setxband(wlc_hw, j); |
a9533e7e | 4608 | |
839f9f62 RV |
4609 | wlc_hw->band->bandunit = j; |
4610 | wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G; | |
4611 | wlc->band->bandunit = j; | |
4612 | wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G; | |
4613 | wlc->core->coreidx = ai_coreidx(wlc_hw->sih); | |
a9533e7e | 4614 | |
839f9f62 RV |
4615 | wlc_hw->machwcap = R_REG(®s->machwcap); |
4616 | wlc_hw->machwcap_backup = wlc_hw->machwcap; | |
a9533e7e | 4617 | |
839f9f62 RV |
4618 | /* init tx fifo size */ |
4619 | wlc_hw->xmtfifo_sz = | |
4620 | xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)]; | |
a9533e7e | 4621 | |
839f9f62 | 4622 | /* Get a phy for this band */ |
d89a4c80 RV |
4623 | wlc_hw->band->pi = |
4624 | wlc_phy_attach(wlc_hw->phy_sh, regs, | |
4625 | brcms_b_bandtype(wlc_hw), vars, | |
4626 | wlc->wiphy); | |
839f9f62 RV |
4627 | if (wlc_hw->band->pi == NULL) { |
4628 | wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_" | |
4629 | "attach failed\n", unit); | |
4630 | err = 17; | |
4631 | goto fail; | |
4632 | } | |
a9533e7e | 4633 | |
839f9f62 | 4634 | wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap); |
a9533e7e | 4635 | |
839f9f62 RV |
4636 | wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype, |
4637 | &wlc_hw->band->phyrev, | |
4638 | &wlc_hw->band->radioid, | |
4639 | &wlc_hw->band->radiorev); | |
4640 | wlc_hw->band->abgphy_encore = | |
4641 | wlc_phy_get_encore(wlc_hw->band->pi); | |
4642 | wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi); | |
4643 | wlc_hw->band->core_flags = | |
4644 | wlc_phy_get_coreflags(wlc_hw->band->pi); | |
a9533e7e | 4645 | |
839f9f62 RV |
4646 | /* verify good phy_type & supported phy revision */ |
4647 | if (BRCMS_ISNPHY(wlc_hw->band)) { | |
4648 | if (NCONF_HAS(wlc_hw->band->phyrev)) | |
4649 | goto good_phy; | |
4650 | else | |
4651 | goto bad_phy; | |
4652 | } else if (BRCMS_ISLCNPHY(wlc_hw->band)) { | |
4653 | if (LCNCONF_HAS(wlc_hw->band->phyrev)) | |
4654 | goto good_phy; | |
4655 | else | |
4656 | goto bad_phy; | |
4657 | } else { | |
4658 | bad_phy: | |
4659 | wiphy_err(wiphy, "wl%d: brcms_b_attach: unsupported " | |
4660 | "phy type/rev (%d/%d)\n", unit, | |
4661 | wlc_hw->band->phytype, wlc_hw->band->phyrev); | |
4662 | err = 18; | |
4663 | goto fail; | |
4664 | } | |
a9533e7e | 4665 | |
839f9f62 | 4666 | good_phy: |
419ad34e AS |
4667 | /* |
4668 | * BMAC_NOTE: wlc->band->pi should not be set below and should | |
4669 | * be done in the high level attach. However we can not make | |
4670 | * that change until all low level access is changed to | |
4671 | * wlc_hw->band->pi. Instead do the wlc->band->pi init below, | |
4672 | * keeping wlc_hw->band->pi as well for incremental update of | |
4673 | * low level fns, and cut over low only init when all fns | |
4674 | * updated. | |
839f9f62 RV |
4675 | */ |
4676 | wlc->band->pi = wlc_hw->band->pi; | |
4677 | wlc->band->phytype = wlc_hw->band->phytype; | |
4678 | wlc->band->phyrev = wlc_hw->band->phyrev; | |
4679 | wlc->band->radioid = wlc_hw->band->radioid; | |
4680 | wlc->band->radiorev = wlc_hw->band->radiorev; | |
a9533e7e | 4681 | |
839f9f62 RV |
4682 | /* default contention windows size limits */ |
4683 | wlc_hw->band->CWmin = APHY_CWMIN; | |
4684 | wlc_hw->band->CWmax = PHY_CWMAX; | |
a9533e7e | 4685 | |
839f9f62 RV |
4686 | if (!brcms_b_attach_dmapio(wlc, j, wme)) { |
4687 | err = 19; | |
4688 | goto fail; | |
4689 | } | |
4690 | } | |
a9533e7e | 4691 | |
839f9f62 RV |
4692 | /* disable core to match driver "down" state */ |
4693 | brcms_c_coredisable(wlc_hw); | |
a9533e7e | 4694 | |
839f9f62 | 4695 | /* Match driver "down" state */ |
821e4e93 | 4696 | ai_pci_down(wlc_hw->sih); |
a9533e7e | 4697 | |
839f9f62 RV |
4698 | /* register sb interrupt callback functions */ |
4699 | ai_register_intr_callback(wlc_hw->sih, (void *)brcms_c_wlintrsoff, | |
4700 | (void *)brcms_c_wlintrsrestore, NULL, wlc); | |
a9533e7e | 4701 | |
839f9f62 RV |
4702 | /* turn off pll and xtal to match driver "down" state */ |
4703 | brcms_b_xtal(wlc_hw, OFF); | |
a9533e7e | 4704 | |
419ad34e | 4705 | /* ******************************************************************* |
839f9f62 RV |
4706 | * The hardware is in the DOWN state at this point. D11 core |
4707 | * or cores are in reset with clocks off, and the board PLLs | |
4708 | * are off if possible. | |
4709 | * | |
4710 | * Beyond this point, wlc->sbclk == false and chip registers | |
4711 | * should not be touched. | |
4712 | ********************************************************************* | |
4713 | */ | |
a9533e7e | 4714 | |
839f9f62 RV |
4715 | /* init etheraddr state variables */ |
4716 | macaddr = brcms_c_get_macaddr(wlc_hw); | |
4717 | if (macaddr == NULL) { | |
4718 | wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n", | |
4719 | unit); | |
4720 | err = 21; | |
a9533e7e HP |
4721 | goto fail; |
4722 | } | |
5973f660 AS |
4723 | if (!mac_pton(macaddr, wlc_hw->etheraddr) || |
4724 | is_broadcast_ether_addr(wlc_hw->etheraddr) || | |
839f9f62 RV |
4725 | is_zero_ether_addr(wlc_hw->etheraddr)) { |
4726 | wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n", | |
4727 | unit, macaddr); | |
4728 | err = 22; | |
a9533e7e HP |
4729 | goto fail; |
4730 | } | |
839f9f62 RV |
4731 | |
4732 | BCMMSG(wlc->wiphy, | |
4733 | "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n", | |
4734 | wlc_hw->deviceid, wlc_hw->_nbands, | |
4735 | wlc_hw->sih->boardtype, macaddr); | |
4736 | ||
a9533e7e | 4737 | return err; |
a9533e7e | 4738 | |
839f9f62 RV |
4739 | fail: |
4740 | wiphy_err(wiphy, "wl%d: brcms_b_attach: failed with err %d\n", unit, | |
4741 | err); | |
4742 | return err; | |
a9533e7e HP |
4743 | } |
4744 | ||
2682e2a3 | 4745 | static void brcms_c_attach_antgain_init(struct brcms_c_info *wlc) |
0d2f0724 | 4746 | { |
2682e2a3 AS |
4747 | uint unit; |
4748 | unit = wlc->pub->unit; | |
a9533e7e | 4749 | |
2682e2a3 AS |
4750 | if ((wlc->band->antgain == -1) && (wlc->pub->sromrev == 1)) { |
4751 | /* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */ | |
4752 | wlc->band->antgain = 8; | |
4753 | } else if (wlc->band->antgain == -1) { | |
4754 | wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in" | |
4755 | " srom, using 2dB\n", unit, __func__); | |
4756 | wlc->band->antgain = 8; | |
4757 | } else { | |
4758 | s8 gain, fract; | |
4759 | /* Older sroms specified gain in whole dbm only. In order | |
4760 | * be able to specify qdbm granularity and remain backward | |
4761 | * compatible the whole dbms are now encoded in only | |
4762 | * low 6 bits and remaining qdbms are encoded in the hi 2 bits. | |
4763 | * 6 bit signed number ranges from -32 - 31. | |
4764 | * | |
4765 | * Examples: | |
4766 | * 0x1 = 1 db, | |
4767 | * 0xc1 = 1.75 db (1 + 3 quarters), | |
4768 | * 0x3f = -1 (-1 + 0 quarters), | |
4769 | * 0x7f = -.75 (-1 + 1 quarters) = -3 qdbm. | |
4770 | * 0xbf = -.50 (-1 + 2 quarters) = -2 qdbm. | |
4771 | */ | |
4772 | gain = wlc->band->antgain & 0x3f; | |
4773 | gain <<= 2; /* Sign extend */ | |
4774 | gain >>= 2; | |
4775 | fract = (wlc->band->antgain & 0xc0) >> 6; | |
4776 | wlc->band->antgain = 4 * gain + fract; | |
4777 | } | |
4778 | } | |
a9533e7e | 4779 | |
2682e2a3 AS |
4780 | static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc) |
4781 | { | |
4782 | int aa; | |
4783 | uint unit; | |
4784 | char *vars; | |
4785 | int bandtype; | |
4786 | ||
4787 | unit = wlc->pub->unit; | |
4788 | vars = wlc->pub->vars; | |
4789 | bandtype = wlc->band->bandtype; | |
4790 | ||
4791 | /* get antennas available */ | |
4792 | aa = (s8) getintvar(vars, (BAND_5G(bandtype) ? "aa5g" : "aa2g")); | |
4793 | if (aa == 0) | |
4794 | aa = (s8) getintvar(vars, | |
4795 | (BAND_5G(bandtype) ? "aa1" : "aa0")); | |
4796 | if ((aa < 1) || (aa > 15)) { | |
4797 | wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in" | |
4798 | " srom (0x%x), using 3\n", unit, __func__, aa); | |
4799 | aa = 3; | |
4800 | } | |
4801 | ||
4802 | /* reset the defaults if we have a single antenna */ | |
4803 | if (aa == 1) { | |
4804 | wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_0; | |
4805 | wlc->stf->txant = ANT_TX_FORCE_0; | |
4806 | } else if (aa == 2) { | |
4807 | wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_1; | |
4808 | wlc->stf->txant = ANT_TX_FORCE_1; | |
4809 | } else { | |
4810 | } | |
4811 | ||
4812 | /* Compute Antenna Gain */ | |
4813 | wlc->band->antgain = | |
4814 | (s8) getintvar(vars, (BAND_5G(bandtype) ? "ag1" : "ag0")); | |
4815 | brcms_c_attach_antgain_init(wlc); | |
4816 | ||
4817 | return true; | |
4818 | } | |
4819 | ||
4820 | static void brcms_c_bss_default_init(struct brcms_c_info *wlc) | |
4821 | { | |
4822 | u16 chanspec; | |
4823 | struct brcms_band *band; | |
4824 | struct brcms_bss_info *bi = wlc->default_bss; | |
4825 | ||
4826 | /* init default and target BSS with some sane initial values */ | |
4827 | memset((char *)(bi), 0, sizeof(struct brcms_bss_info)); | |
4828 | bi->beacon_period = BEACON_INTERVAL_DEFAULT; | |
4829 | bi->dtim_period = DTIM_INTERVAL_DEFAULT; | |
4830 | ||
4831 | /* fill the default channel as the first valid channel | |
4832 | * starting from the 2G channels | |
4833 | */ | |
4834 | chanspec = CH20MHZ_CHSPEC(1); | |
4835 | wlc->home_chanspec = bi->chanspec = chanspec; | |
4836 | ||
4837 | /* find the band of our default channel */ | |
4838 | band = wlc->band; | |
4839 | if (NBANDS(wlc) > 1 && band->bandunit != CHSPEC_BANDUNIT(chanspec)) | |
4840 | band = wlc->bandstate[OTHERBANDUNIT(wlc)]; | |
4841 | ||
4842 | /* init bss rates to the band specific default rate set */ | |
4843 | brcms_c_rateset_default(&bi->rateset, NULL, band->phytype, | |
4844 | band->bandtype, false, BRCMS_RATE_MASK_FULL, | |
4845 | (bool) N_ENAB(wlc->pub), CHSPEC_WLC_BW(chanspec), | |
4846 | wlc->stf->txstreams); | |
4847 | ||
4848 | if (N_ENAB(wlc->pub)) | |
4849 | bi->flags |= BRCMS_BSS_HT; | |
4850 | } | |
4851 | ||
4852 | static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc) | |
4853 | { | |
4854 | struct brcms_txq_info *qi, *p; | |
4855 | ||
4856 | qi = kzalloc(sizeof(struct brcms_txq_info), GFP_ATOMIC); | |
4857 | if (qi != NULL) { | |
4858 | /* | |
4859 | * Have enough room for control packets along with HI watermark | |
4860 | * Also, add room to txq for total psq packets if all the SCBs | |
4861 | * leave PS mode. The watermark for flowcontrol to OS packets | |
4862 | * will remain the same | |
4863 | */ | |
4864 | brcmu_pktq_init(&qi->q, BRCMS_PREC_COUNT, | |
4865 | (2 * wlc->pub->tunables->datahiwat) + PKTQ_LEN_DEFAULT | |
4866 | + wlc->pub->psq_pkts_total); | |
4867 | ||
4868 | /* add this queue to the the global list */ | |
4869 | p = wlc->tx_queues; | |
4870 | if (p == NULL) { | |
4871 | wlc->tx_queues = qi; | |
4872 | } else { | |
4873 | while (p->next != NULL) | |
4874 | p = p->next; | |
4875 | p->next = qi; | |
4876 | } | |
4877 | } | |
4878 | return qi; | |
4879 | } | |
4880 | ||
4881 | static void brcms_c_txq_free(struct brcms_c_info *wlc, | |
4882 | struct brcms_txq_info *qi) | |
4883 | { | |
4884 | struct brcms_txq_info *p; | |
4885 | ||
4886 | if (qi == NULL) | |
4887 | return; | |
4888 | ||
4889 | /* remove the queue from the linked list */ | |
4890 | p = wlc->tx_queues; | |
4891 | if (p == qi) | |
4892 | wlc->tx_queues = p->next; | |
4893 | else { | |
4894 | while (p != NULL && p->next != qi) | |
4895 | p = p->next; | |
4896 | if (p != NULL) | |
4897 | p->next = p->next->next; | |
4898 | } | |
4899 | ||
4900 | kfree(qi); | |
4901 | } | |
4902 | ||
4903 | static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap) | |
4904 | { | |
4905 | uint i; | |
4906 | struct brcms_band *band; | |
4907 | ||
4908 | for (i = 0; i < NBANDS(wlc); i++) { | |
4909 | if (IS_SINGLEBAND_5G(wlc->deviceid)) | |
4910 | i = BAND_5G_INDEX; | |
4911 | band = wlc->bandstate[i]; | |
4912 | if (band->bandtype == BRCM_BAND_5G) { | |
4913 | if ((bwcap == BRCMS_N_BW_40ALL) | |
4914 | || (bwcap == BRCMS_N_BW_20IN2G_40IN5G)) | |
4915 | band->mimo_cap_40 = true; | |
4916 | else | |
4917 | band->mimo_cap_40 = false; | |
4918 | } else { | |
4919 | if (bwcap == BRCMS_N_BW_40ALL) | |
4920 | band->mimo_cap_40 = true; | |
4921 | else | |
4922 | band->mimo_cap_40 = false; | |
4923 | } | |
4924 | } | |
4925 | } | |
4926 | ||
4927 | /* | |
4928 | * The common driver entry routine. Error codes should be unique | |
4929 | */ | |
4930 | struct brcms_c_info * | |
4931 | brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit, | |
4932 | bool piomode, void *regsva, struct pci_dev *btparam, uint *perr) | |
4933 | { | |
4934 | struct brcms_c_info *wlc; | |
4935 | uint err = 0; | |
4936 | uint j; | |
4937 | struct brcms_pub *pub; | |
4938 | uint n_disabled; | |
4939 | ||
4940 | /* allocate struct brcms_c_info state and its substructures */ | |
4941 | wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, device); | |
4942 | if (wlc == NULL) | |
4943 | goto fail; | |
4944 | wlc->wiphy = wl->wiphy; | |
4945 | pub = wlc->pub; | |
4946 | ||
4947 | #if defined(BCMDBG) | |
4948 | wlc_info_dbg = wlc; | |
a9533e7e HP |
4949 | #endif |
4950 | ||
4951 | wlc->band = wlc->bandstate[0]; | |
4952 | wlc->core = wlc->corestate; | |
4953 | wlc->wl = wl; | |
4954 | pub->unit = unit; | |
a9533e7e | 4955 | pub->_piomode = piomode; |
0965ae88 | 4956 | wlc->bandinit_pending = false; |
a9533e7e | 4957 | |
fe741e5e RV |
4958 | /* populate struct brcms_c_info with default values */ |
4959 | brcms_c_info_init(wlc, unit); | |
a9533e7e HP |
4960 | |
4961 | /* update sta/ap related parameters */ | |
fe741e5e | 4962 | brcms_c_ap_upd(wlc); |
a9533e7e HP |
4963 | |
4964 | /* 11n_disable nvram */ | |
4965 | n_disabled = getintvar(pub->vars, "11n_disable"); | |
4966 | ||
810acd19 AS |
4967 | /* |
4968 | * low level attach steps(all hw accesses go | |
4969 | * inside, no more in rest of the attach) | |
4970 | */ | |
c654fce6 | 4971 | err = brcms_b_attach(wlc, vendor, device, unit, piomode, regsva, |
821e4e93 | 4972 | btparam); |
a9533e7e HP |
4973 | if (err) |
4974 | goto fail; | |
4975 | ||
419ad34e AS |
4976 | /* |
4977 | * for some states, due to different info pointer(e,g, wlc, wlc_hw) or | |
4978 | * master/slave split, HIGH driver(both monolithic and HIGH_ONLY) needs | |
4979 | * to sync states FROM BMAC portion driver | |
a9533e7e | 4980 | */ |
1c4c54ba | 4981 | if (!brcms_c_state_bmac_sync(wlc)) { |
a9533e7e HP |
4982 | err = 20; |
4983 | goto fail; | |
4984 | } | |
4985 | ||
7c783cef | 4986 | pub->phy_11ncapable = BRCMS_PHY_11N_CAP(wlc->band); |
a9533e7e HP |
4987 | |
4988 | /* propagate *vars* from BMAC driver to high driver */ | |
c654fce6 | 4989 | brcms_b_copyfrom_vars(wlc->hw, &pub->vars, &wlc->vars_size); |
a9533e7e | 4990 | |
a9533e7e HP |
4991 | |
4992 | /* set maximum allowed duty cycle */ | |
4993 | wlc->tx_duty_cycle_ofdm = | |
7d4df48e | 4994 | (u16) getintvar(pub->vars, "tx_duty_cycle_ofdm"); |
a9533e7e | 4995 | wlc->tx_duty_cycle_cck = |
7d4df48e | 4996 | (u16) getintvar(pub->vars, "tx_duty_cycle_cck"); |
a9533e7e | 4997 | |
f52a0ad0 | 4998 | brcms_c_stf_phy_chain_calc(wlc); |
a9533e7e HP |
4999 | |
5000 | /* txchain 1: txant 0, txchain 2: txant 1 */ | |
7c783cef | 5001 | if (BRCMS_ISNPHY(wlc->band) && (wlc->stf->txstreams == 1)) |
a9533e7e HP |
5002 | wlc->stf->txant = wlc->stf->hw_txchain - 1; |
5003 | ||
5004 | /* push to BMAC driver */ | |
5005 | wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain, | |
5006 | wlc->stf->hw_rxchain); | |
5007 | ||
a9533e7e HP |
5008 | /* pull up some info resulting from the low attach */ |
5009 | { | |
5010 | int i; | |
5011 | for (i = 0; i < NFIFO; i++) | |
5012 | wlc->core->txavail[i] = wlc->hw->txavail[i]; | |
5013 | } | |
a9533e7e | 5014 | |
c654fce6 | 5015 | brcms_b_hw_etheraddr(wlc->hw, wlc->perm_etheraddr); |
a9533e7e | 5016 | |
02160695 | 5017 | memcpy(&pub->cur_etheraddr, &wlc->perm_etheraddr, ETH_ALEN); |
a9533e7e HP |
5018 | |
5019 | for (j = 0; j < NBANDS(wlc); j++) { | |
5020 | /* Use band 1 for single band 11a */ | |
5021 | if (IS_SINGLEBAND_5G(wlc->deviceid)) | |
5022 | j = BAND_5G_INDEX; | |
5023 | ||
5024 | wlc->band = wlc->bandstate[j]; | |
5025 | ||
1c4c54ba | 5026 | if (!brcms_c_attach_stf_ant_init(wlc)) { |
a9533e7e HP |
5027 | err = 24; |
5028 | goto fail; | |
5029 | } | |
5030 | ||
5031 | /* default contention windows size limits */ | |
5032 | wlc->band->CWmin = APHY_CWMIN; | |
5033 | wlc->band->CWmax = PHY_CWMAX; | |
5034 | ||
5035 | /* init gmode value */ | |
5036 | if (BAND_2G(wlc->band->bandtype)) { | |
5037 | wlc->band->gmode = GMODE_AUTO; | |
7c783cef | 5038 | brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, |
a9533e7e HP |
5039 | wlc->band->gmode); |
5040 | } | |
5041 | ||
5042 | /* init _n_enab supported mode */ | |
7c783cef | 5043 | if (BRCMS_PHY_11N_CAP(wlc->band) && CHIP_SUPPORTS_11N(wlc)) { |
a9533e7e HP |
5044 | if (n_disabled & WLFEATURE_DISABLE_11N) { |
5045 | pub->_n_enab = OFF; | |
7c783cef | 5046 | brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER, |
fe741e5e | 5047 | OFF); |
a9533e7e HP |
5048 | } else { |
5049 | pub->_n_enab = SUPPORT_11N; | |
7c783cef | 5050 | brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER, |
a9533e7e HP |
5051 | ((pub->_n_enab == |
5052 | SUPPORT_11N) ? WL_11N_2x2 : | |
5053 | WL_11N_3x3)); | |
5054 | } | |
5055 | } | |
5056 | ||
5057 | /* init per-band default rateset, depend on band->gmode */ | |
fe741e5e | 5058 | brcms_default_rateset(wlc, &wlc->band->defrateset); |
a9533e7e | 5059 | |
7c783cef | 5060 | /* fill in hw_rateset (used early by BRCM_SET_RATESET) */ |
f52a0ad0 | 5061 | brcms_c_rateset_filter(&wlc->band->defrateset, |
0965ae88 | 5062 | &wlc->band->hw_rateset, false, |
7c783cef | 5063 | BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK, |
a9533e7e HP |
5064 | (bool) N_ENAB(wlc->pub)); |
5065 | } | |
5066 | ||
419ad34e AS |
5067 | /* |
5068 | * update antenna config due to | |
5069 | * wlc->stf->txant/txchain/ant_rx_ovr change | |
5070 | */ | |
f52a0ad0 | 5071 | brcms_c_stf_phy_txant_upd(wlc); |
a9533e7e HP |
5072 | |
5073 | /* attach each modules */ | |
1c4c54ba | 5074 | err = brcms_c_attach_module(wlc); |
a9533e7e HP |
5075 | if (err != 0) |
5076 | goto fail; | |
5077 | ||
fe741e5e | 5078 | if (!brcms_c_timers_init(wlc, unit)) { |
1c4c54ba | 5079 | wiphy_err(wl->wiphy, "wl%d: %s: init_timer failed\n", unit, |
b8f092c9 | 5080 | __func__); |
a9533e7e HP |
5081 | err = 32; |
5082 | goto fail; | |
5083 | } | |
5084 | ||
5085 | /* depend on rateset, gmode */ | |
f52a0ad0 | 5086 | wlc->cmi = brcms_c_channel_mgr_attach(wlc); |
a9533e7e | 5087 | if (!wlc->cmi) { |
f52a0ad0 | 5088 | wiphy_err(wl->wiphy, "wl%d: %s: channel_mgr_attach failed" |
b8f092c9 | 5089 | "\n", unit, __func__); |
a9533e7e HP |
5090 | err = 33; |
5091 | goto fail; | |
5092 | } | |
5093 | ||
5094 | /* init default when all parameters are ready, i.e. ->rateset */ | |
1c4c54ba | 5095 | brcms_c_bss_default_init(wlc); |
a9533e7e HP |
5096 | |
5097 | /* | |
5098 | * Complete the wlc default state initializations.. | |
5099 | */ | |
5100 | ||
5101 | /* allocate our initial queue */ | |
1c4c54ba | 5102 | wlc->pkt_queue = brcms_c_txq_alloc(wlc); |
3a730500 | 5103 | if (wlc->pkt_queue == NULL) { |
b8f092c9 RV |
5104 | wiphy_err(wl->wiphy, "wl%d: %s: failed to malloc tx queue\n", |
5105 | unit, __func__); | |
a9533e7e HP |
5106 | err = 100; |
5107 | goto fail; | |
5108 | } | |
a9533e7e HP |
5109 | |
5110 | wlc->bsscfg[0] = wlc->cfg; | |
5111 | wlc->cfg->_idx = 0; | |
5112 | wlc->cfg->wlc = wlc; | |
5113 | pub->txmaxpkts = MAXTXPKTS; | |
5114 | ||
fe741e5e | 5115 | brcms_c_wme_initparams_sta(wlc, &wlc->wme_param_ie); |
a9533e7e HP |
5116 | |
5117 | wlc->mimoft = FT_HT; | |
651bd3a9 | 5118 | wlc->ht_cap.cap_info = HT_CAP; |
a9533e7e HP |
5119 | if (HT_ENAB(wlc->pub)) |
5120 | wlc->stf->ldpc = AUTO; | |
5121 | ||
5122 | wlc->mimo_40txbw = AUTO; | |
5123 | wlc->ofdm_40txbw = AUTO; | |
5124 | wlc->cck_40txbw = AUTO; | |
7c783cef | 5125 | brcms_c_update_mimo_band_bwcap(wlc, BRCMS_N_BW_20IN2G_40IN5G); |
a9533e7e | 5126 | |
a9533e7e | 5127 | /* Set default values of SGI */ |
7c783cef RV |
5128 | if (BRCMS_SGI_CAP_PHY(wlc)) { |
5129 | brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 | | |
5130 | BRCMS_N_SGI_40)); | |
a9533e7e | 5131 | wlc->sgi_tx = AUTO; |
7c783cef RV |
5132 | } else if (BRCMS_ISSSLPNPHY(wlc->band)) { |
5133 | brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 | | |
5134 | BRCMS_N_SGI_40)); | |
a9533e7e HP |
5135 | wlc->sgi_tx = AUTO; |
5136 | } else { | |
1c4c54ba | 5137 | brcms_c_ht_update_sgi_rx(wlc, 0); |
a9533e7e HP |
5138 | wlc->sgi_tx = OFF; |
5139 | } | |
5140 | ||
5141 | /* *******nvram 11n config overrides Start ********* */ | |
5142 | ||
5143 | /* apply the sgi override from nvram conf */ | |
5144 | if (n_disabled & WLFEATURE_DISABLE_11N_SGI_TX) | |
5145 | wlc->sgi_tx = OFF; | |
5146 | ||
5147 | if (n_disabled & WLFEATURE_DISABLE_11N_SGI_RX) | |
1c4c54ba | 5148 | brcms_c_ht_update_sgi_rx(wlc, 0); |
a9533e7e HP |
5149 | |
5150 | /* apply the stbc override from nvram conf */ | |
5151 | if (n_disabled & WLFEATURE_DISABLE_11N_STBC_TX) { | |
5152 | wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = OFF; | |
5153 | wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = OFF; | |
651bd3a9 | 5154 | wlc->ht_cap.cap_info &= ~IEEE80211_HT_CAP_TX_STBC; |
a9533e7e HP |
5155 | } |
5156 | if (n_disabled & WLFEATURE_DISABLE_11N_STBC_RX) | |
f52a0ad0 | 5157 | brcms_c_stf_stbc_rx_set(wlc, HT_CAP_RX_STBC_NO); |
a9533e7e HP |
5158 | |
5159 | /* apply the GF override from nvram conf */ | |
5160 | if (n_disabled & WLFEATURE_DISABLE_11N_GF) | |
651bd3a9 | 5161 | wlc->ht_cap.cap_info &= ~IEEE80211_HT_CAP_GRN_FLD; |
a9533e7e HP |
5162 | |
5163 | /* initialize radio_mpc_disable according to wlc->mpc */ | |
fe741e5e | 5164 | brcms_c_radio_mpc_upd(wlc); |
763456a6 | 5165 | brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail); |
a9533e7e HP |
5166 | |
5167 | if (perr) | |
5168 | *perr = 0; | |
5169 | ||
2f6b1dde | 5170 | return wlc; |
a9533e7e HP |
5171 | |
5172 | fail: | |
b8f092c9 RV |
5173 | wiphy_err(wl->wiphy, "wl%d: %s: failed with err %d\n", |
5174 | unit, __func__, err); | |
a9533e7e | 5175 | if (wlc) |
fe741e5e | 5176 | brcms_c_detach(wlc); |
a9533e7e HP |
5177 | |
5178 | if (perr) | |
5179 | *perr = err; | |
90ea2296 | 5180 | return NULL; |
a9533e7e HP |
5181 | } |
5182 | ||
1c4c54ba | 5183 | static void brcms_c_timers_deinit(struct brcms_c_info *wlc) |
a2627bc0 | 5184 | { |
a9533e7e HP |
5185 | /* free timer state */ |
5186 | if (wlc->wdtimer) { | |
8817f754 | 5187 | brcms_free_timer(wlc->wl, wlc->wdtimer); |
a9533e7e HP |
5188 | wlc->wdtimer = NULL; |
5189 | } | |
5190 | if (wlc->radio_timer) { | |
8817f754 | 5191 | brcms_free_timer(wlc->wl, wlc->radio_timer); |
a9533e7e HP |
5192 | wlc->radio_timer = NULL; |
5193 | } | |
5194 | } | |
5195 | ||
1c4c54ba | 5196 | static void brcms_c_detach_module(struct brcms_c_info *wlc) |
a2627bc0 | 5197 | { |
a9533e7e | 5198 | if (wlc->asi) { |
f52a0ad0 | 5199 | brcms_c_antsel_detach(wlc->asi); |
a9533e7e HP |
5200 | wlc->asi = NULL; |
5201 | } | |
5202 | ||
5203 | if (wlc->ampdu) { | |
f52a0ad0 | 5204 | brcms_c_ampdu_detach(wlc->ampdu); |
a9533e7e HP |
5205 | wlc->ampdu = NULL; |
5206 | } | |
5207 | ||
f52a0ad0 | 5208 | brcms_c_stf_detach(wlc); |
a9533e7e HP |
5209 | } |
5210 | ||
839f9f62 RV |
5211 | /* |
5212 | * low level detach | |
5213 | */ | |
11431424 | 5214 | static int brcms_b_detach(struct brcms_c_info *wlc) |
839f9f62 RV |
5215 | { |
5216 | uint i; | |
5217 | struct brcms_hw_band *band; | |
5218 | struct brcms_hardware *wlc_hw = wlc->hw; | |
5219 | int callbacks; | |
5220 | ||
5221 | callbacks = 0; | |
5222 | ||
5223 | if (wlc_hw->sih) { | |
419ad34e AS |
5224 | /* |
5225 | * detach interrupt sync mechanism since interrupt is disabled | |
5226 | * and per-port interrupt object may has been freed. this must | |
5227 | * be done before sb core switch | |
839f9f62 RV |
5228 | */ |
5229 | ai_deregister_intr_callback(wlc_hw->sih); | |
821e4e93 | 5230 | ai_pci_sleep(wlc_hw->sih); |
839f9f62 RV |
5231 | } |
5232 | ||
5233 | brcms_b_detach_dmapio(wlc_hw); | |
5234 | ||
5235 | band = wlc_hw->band; | |
5236 | for (i = 0; i < NBANDS_HW(wlc_hw); i++) { | |
5237 | if (band->pi) { | |
5238 | /* Detach this band's phy */ | |
5239 | wlc_phy_detach(band->pi); | |
5240 | band->pi = NULL; | |
5241 | } | |
5242 | band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)]; | |
5243 | } | |
5244 | ||
5245 | /* Free shared phy state */ | |
5246 | kfree(wlc_hw->phy_sh); | |
5247 | ||
5248 | wlc_phy_shim_detach(wlc_hw->physhim); | |
5249 | ||
5250 | /* free vars */ | |
5251 | kfree(wlc_hw->vars); | |
5252 | wlc_hw->vars = NULL; | |
5253 | ||
5254 | if (wlc_hw->sih) { | |
5255 | ai_detach(wlc_hw->sih); | |
5256 | wlc_hw->sih = NULL; | |
5257 | } | |
5258 | ||
5259 | return callbacks; | |
5260 | ||
5261 | } | |
5262 | ||
a9533e7e HP |
5263 | /* |
5264 | * Return a count of the number of driver callbacks still pending. | |
5265 | * | |
fe741e5e RV |
5266 | * General policy is that brcms_c_detach can only dealloc/free software states. |
5267 | * It can NOT touch hardware registers since the d11core may be in reset and | |
5268 | * clock may not be available. | |
5269 | * One exception is sb register access, which is possible if crystal is turned | |
5270 | * on after "down" state, driver should avoid software timer with the exception | |
5271 | * of radio_monitor. | |
a9533e7e | 5272 | */ |
fe741e5e | 5273 | uint brcms_c_detach(struct brcms_c_info *wlc) |
a2627bc0 | 5274 | { |
a9533e7e HP |
5275 | uint callbacks = 0; |
5276 | ||
5277 | if (wlc == NULL) | |
5278 | return 0; | |
5279 | ||
792aa408 | 5280 | BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); |
a9533e7e | 5281 | |
c654fce6 | 5282 | callbacks += brcms_b_detach(wlc); |
a9533e7e HP |
5283 | |
5284 | /* delete software timers */ | |
1c4c54ba | 5285 | if (!brcms_c_radio_monitor_stop(wlc)) |
a9533e7e HP |
5286 | callbacks++; |
5287 | ||
f52a0ad0 | 5288 | brcms_c_channel_mgr_detach(wlc->cmi); |
a9533e7e | 5289 | |
1c4c54ba | 5290 | brcms_c_timers_deinit(wlc); |
a9533e7e | 5291 | |
1c4c54ba | 5292 | brcms_c_detach_module(wlc); |
a9533e7e | 5293 | |
a9533e7e | 5294 | |
228a00f8 | 5295 | while (wlc->tx_queues != NULL) |
1c4c54ba | 5296 | brcms_c_txq_free(wlc, wlc->tx_queues); |
a9533e7e | 5297 | |
f52a0ad0 | 5298 | brcms_c_detach_mfree(wlc); |
90ea2296 | 5299 | return callbacks; |
a9533e7e HP |
5300 | } |
5301 | ||
5302 | /* update state that depends on the current value of "ap" */ | |
fe741e5e | 5303 | void brcms_c_ap_upd(struct brcms_c_info *wlc) |
a9533e7e HP |
5304 | { |
5305 | if (AP_ENAB(wlc->pub)) | |
7c783cef RV |
5306 | /* AP: short not allowed, but not enforced */ |
5307 | wlc->PLCPHdr_override = BRCMS_PLCP_AUTO; | |
a9533e7e | 5308 | else |
7c783cef RV |
5309 | /* STA-BSS; short capable */ |
5310 | wlc->PLCPHdr_override = BRCMS_PLCP_SHORT; | |
a9533e7e | 5311 | |
a9533e7e | 5312 | /* fixup mpc */ |
0f0881b0 | 5313 | wlc->mpc = true; |
a9533e7e HP |
5314 | } |
5315 | ||
2682e2a3 AS |
5316 | /* |
5317 | * return true if Minimum Power Consumption should | |
5318 | * be entered, false otherwise | |
5319 | */ | |
5320 | bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc) | |
a9533e7e | 5321 | { |
2682e2a3 AS |
5322 | return false; |
5323 | } | |
a9533e7e | 5324 | |
fe741e5e | 5325 | bool brcms_c_ismpc(struct brcms_c_info *wlc) |
a9533e7e | 5326 | { |
fe741e5e | 5327 | return (wlc->mpc_delay_off == 0) && (brcms_c_is_non_delay_mpc(wlc)); |
a9533e7e HP |
5328 | } |
5329 | ||
fe741e5e | 5330 | void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc) |
a9533e7e HP |
5331 | { |
5332 | bool mpc_radio, radio_state; | |
5333 | ||
5334 | /* | |
5335 | * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled | |
5336 | * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio | |
5337 | * monitor also when WL_RADIO_MPC_DISABLE is the only reason that | |
5338 | * the radio is going down. | |
5339 | */ | |
5340 | if (!wlc->mpc) { | |
5341 | if (!wlc->pub->radio_disabled) | |
5342 | return; | |
5343 | mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE); | |
1c4c54ba | 5344 | brcms_c_radio_upd(wlc); |
a9533e7e | 5345 | if (!wlc->pub->radio_disabled) |
1c4c54ba | 5346 | brcms_c_radio_monitor_stop(wlc); |
a9533e7e HP |
5347 | return; |
5348 | } | |
5349 | ||
5350 | /* | |
419ad34e AS |
5351 | * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in |
5352 | * wlc->pub->radio_disabled to go ON, always call radio_upd | |
5353 | * synchronously to go OFF, postpone radio_upd to later when | |
5354 | * context is safe(e.g. watchdog) | |
a9533e7e HP |
5355 | */ |
5356 | radio_state = | |
5357 | (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF : | |
5358 | ON); | |
fe741e5e | 5359 | mpc_radio = (brcms_c_ismpc(wlc) == true) ? OFF : ON; |
a9533e7e HP |
5360 | |
5361 | if (radio_state == ON && mpc_radio == OFF) | |
5362 | wlc->mpc_delay_off = wlc->mpc_dlycnt; | |
5363 | else if (radio_state == OFF && mpc_radio == ON) { | |
5364 | mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE); | |
1c4c54ba | 5365 | brcms_c_radio_upd(wlc); |
7c783cef RV |
5366 | if (wlc->mpc_offcnt < BRCMS_MPC_THRESHOLD) |
5367 | wlc->mpc_dlycnt = BRCMS_MPC_MAX_DELAYCNT; | |
5368 | else | |
5369 | wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT; | |
a9533e7e HP |
5370 | wlc->mpc_dur += OSL_SYSUPTIME() - wlc->mpc_laston_ts; |
5371 | } | |
419ad34e AS |
5372 | /* |
5373 | * Below logic is meant to capture the transition from mpc off | |
5374 | * to mpc on for reasons other than wlc->mpc_delay_off keeping | |
5375 | * the mpc off. In that case reset wlc->mpc_delay_off to | |
5376 | * wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off | |
a9533e7e | 5377 | */ |
0965ae88 | 5378 | if ((wlc->prev_non_delay_mpc == false) && |
8ea54c9f | 5379 | (brcms_c_is_non_delay_mpc(wlc) == true) && wlc->mpc_delay_off) |
a9533e7e | 5380 | wlc->mpc_delay_off = wlc->mpc_dlycnt; |
8ea54c9f | 5381 | |
fe741e5e | 5382 | wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc); |
a9533e7e | 5383 | } |
839f9f62 | 5384 | /* Initialize just the hardware when coming out of POR or S3/S5 system states */ |
11431424 | 5385 | static void brcms_b_hw_up(struct brcms_hardware *wlc_hw) |
839f9f62 RV |
5386 | { |
5387 | if (wlc_hw->wlc->pub->hw_up) | |
5388 | return; | |
5389 | ||
5390 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
5391 | ||
5392 | /* | |
5393 | * Enable pll and xtal, initialize the power control registers, | |
5394 | * and force fastclock for the remainder of brcms_c_up(). | |
5395 | */ | |
5396 | brcms_b_xtal(wlc_hw, ON); | |
5397 | ai_clkctl_init(wlc_hw->sih); | |
5398 | brcms_b_clkctl_clk(wlc_hw, CLK_FAST); | |
5399 | ||
821e4e93 | 5400 | ai_pci_fixcfg(wlc_hw->sih); |
839f9f62 | 5401 | |
821e4e93 RV |
5402 | /* |
5403 | * AI chip doesn't restore bar0win2 on | |
5404 | * hibernation/resume, need sw fixup | |
5405 | */ | |
5406 | if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || | |
5407 | (wlc_hw->sih->chip == BCM43225_CHIP_ID)) | |
5408 | wlc_hw->regs = (struct d11regs *) | |
5409 | ai_setcore(wlc_hw->sih, D11_CORE_ID, 0); | |
839f9f62 | 5410 | |
419ad34e AS |
5411 | /* |
5412 | * Inform phy that a POR reset has occurred so | |
5413 | * it does a complete phy init | |
5414 | */ | |
839f9f62 RV |
5415 | wlc_phy_por_inform(wlc_hw->band->pi); |
5416 | ||
5417 | wlc_hw->ucode_loaded = false; | |
5418 | wlc_hw->wlc->pub->hw_up = true; | |
5419 | ||
5420 | if ((wlc_hw->boardflags & BFL_FEM) | |
5421 | && (wlc_hw->sih->chip == BCM4313_CHIP_ID)) { | |
5422 | if (! | |
5423 | (wlc_hw->boardrev >= 0x1250 | |
5424 | && (wlc_hw->boardflags & BFL_FEM_BT))) | |
5425 | ai_epa_4313war(wlc_hw->sih); | |
5426 | } | |
5427 | } | |
5428 | ||
11431424 | 5429 | static int brcms_b_up_prep(struct brcms_hardware *wlc_hw) |
839f9f62 RV |
5430 | { |
5431 | uint coremask; | |
5432 | ||
5433 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
5434 | ||
5435 | /* | |
5436 | * Enable pll and xtal, initialize the power control registers, | |
5437 | * and force fastclock for the remainder of brcms_c_up(). | |
5438 | */ | |
5439 | brcms_b_xtal(wlc_hw, ON); | |
5440 | ai_clkctl_init(wlc_hw->sih); | |
5441 | brcms_b_clkctl_clk(wlc_hw, CLK_FAST); | |
5442 | ||
5443 | /* | |
5444 | * Configure pci/pcmcia here instead of in brcms_c_attach() | |
5445 | * to allow mfg hotswap: down, hotswap (chip power cycle), up. | |
5446 | */ | |
5447 | coremask = (1 << wlc_hw->wlc->core->coreidx); | |
5448 | ||
821e4e93 | 5449 | ai_pci_setup(wlc_hw->sih, coremask); |
839f9f62 RV |
5450 | |
5451 | /* | |
419ad34e AS |
5452 | * Need to read the hwradio status here to cover the case where the |
5453 | * system is loaded with the hw radio disabled. We do not want to | |
5454 | * bring the driver up in this case. | |
839f9f62 RV |
5455 | */ |
5456 | if (brcms_b_radio_read_hwdisabled(wlc_hw)) { | |
5457 | /* put SB PCI in down state again */ | |
821e4e93 | 5458 | ai_pci_down(wlc_hw->sih); |
839f9f62 RV |
5459 | brcms_b_xtal(wlc_hw, OFF); |
5460 | return -ENOMEDIUM; | |
5461 | } | |
5462 | ||
821e4e93 | 5463 | ai_pci_up(wlc_hw->sih); |
839f9f62 RV |
5464 | |
5465 | /* reset the d11 core */ | |
5466 | brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); | |
5467 | ||
5468 | return 0; | |
5469 | } | |
5470 | ||
11431424 | 5471 | static int brcms_b_up_finish(struct brcms_hardware *wlc_hw) |
839f9f62 RV |
5472 | { |
5473 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
5474 | ||
5475 | wlc_hw->up = true; | |
5476 | wlc_phy_hw_state_upd(wlc_hw->band->pi, true); | |
5477 | ||
5478 | /* FULLY enable dynamic power control and d11 core interrupt */ | |
5479 | brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); | |
5480 | brcms_intrson(wlc_hw->wlc->wl); | |
5481 | return 0; | |
5482 | } | |
5483 | ||
2682e2a3 AS |
5484 | /* |
5485 | * Write WME tunable parameters for retransmit/max rate | |
5486 | * from wlc struct to ucode | |
5487 | */ | |
5488 | static void brcms_c_wme_retries_write(struct brcms_c_info *wlc) | |
5489 | { | |
5490 | int ac; | |
5491 | ||
5492 | /* Need clock to do this */ | |
5493 | if (!wlc->clk) | |
5494 | return; | |
5495 | ||
5496 | for (ac = 0; ac < AC_COUNT; ac++) | |
5497 | brcms_c_write_shm(wlc, M_AC_TXLMT_ADDR(ac), | |
5498 | wlc->wme_retries[ac]); | |
5499 | } | |
5500 | ||
a9533e7e | 5501 | /* make interface operational */ |
fe741e5e | 5502 | int brcms_c_up(struct brcms_c_info *wlc) |
a2627bc0 | 5503 | { |
792aa408 | 5504 | BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); |
a9533e7e HP |
5505 | |
5506 | /* HW is turned off so don't try to access it */ | |
5507 | if (wlc->pub->hw_off || DEVICEREMOVED(wlc)) | |
b74ac12e | 5508 | return -ENOMEDIUM; |
a9533e7e HP |
5509 | |
5510 | if (!wlc->pub->hw_up) { | |
c654fce6 | 5511 | brcms_b_hw_up(wlc->hw); |
0f0881b0 | 5512 | wlc->pub->hw_up = true; |
a9533e7e HP |
5513 | } |
5514 | ||
5515 | if ((wlc->pub->boardflags & BFL_FEM) | |
dfa26436 | 5516 | && (wlc->pub->sih->chip == BCM4313_CHIP_ID)) { |
a9533e7e | 5517 | if (wlc->pub->boardrev >= 0x1250 |
8ea54c9f | 5518 | && (wlc->pub->boardflags & BFL_FEM_BT)) |
fe741e5e | 5519 | brcms_c_mhf(wlc, MHF5, MHF5_4313_GPIOCTRL, |
7c783cef | 5520 | MHF5_4313_GPIOCTRL, BRCM_BAND_ALL); |
8ea54c9f | 5521 | else |
fe741e5e | 5522 | brcms_c_mhf(wlc, MHF4, MHF4_EXTPA_ENABLE, |
7c783cef | 5523 | MHF4_EXTPA_ENABLE, BRCM_BAND_ALL); |
a9533e7e HP |
5524 | } |
5525 | ||
5526 | /* | |
419ad34e AS |
5527 | * Need to read the hwradio status here to cover the case where the |
5528 | * system is loaded with the hw radio disabled. We do not want to bring | |
5529 | * the driver up in this case. If radio is disabled, abort up, lower | |
5530 | * power, start radio timer and return 0(for NDIS) don't call | |
5531 | * radio_update to avoid looping brcms_c_up. | |
a9533e7e | 5532 | * |
c654fce6 | 5533 | * brcms_b_up_prep() returns either 0 or -BCME_RADIOOFF only |
a9533e7e HP |
5534 | */ |
5535 | if (!wlc->pub->radio_disabled) { | |
c654fce6 | 5536 | int status = brcms_b_up_prep(wlc->hw); |
b74ac12e | 5537 | if (status == -ENOMEDIUM) { |
a9533e7e HP |
5538 | if (!mboolisset |
5539 | (wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE)) { | |
5540 | int idx; | |
471f1b51 | 5541 | struct brcms_bss_cfg *bsscfg; |
a9533e7e HP |
5542 | mboolset(wlc->pub->radio_disabled, |
5543 | WL_RADIO_HW_DISABLE); | |
5544 | ||
49552d33 | 5545 | FOREACH_BSS(wlc, idx, bsscfg) |
a9533e7e HP |
5546 | if (!BSSCFG_STA(bsscfg) |
5547 | || !bsscfg->enable || !bsscfg->BSS) | |
5548 | continue; | |
1c4c54ba | 5549 | wiphy_err(wlc->wiphy, "wl%d.%d: up" |
b8f092c9 | 5550 | ": rfdisable -> " |
1c4c54ba | 5551 | "bsscfg_disable()\n", |
b8f092c9 | 5552 | wlc->pub->unit, idx); |
49552d33 | 5553 | END_FOREACH_BSS() |
a9533e7e | 5554 | } |
af4e9c09 | 5555 | } |
a9533e7e HP |
5556 | } |
5557 | ||
5558 | if (wlc->pub->radio_disabled) { | |
1c4c54ba | 5559 | brcms_c_radio_monitor_start(wlc); |
a9533e7e HP |
5560 | return 0; |
5561 | } | |
5562 | ||
1c4c54ba | 5563 | /* brcms_b_up_prep has done brcms_c_corereset(). so clk is on, set it */ |
0f0881b0 | 5564 | wlc->clk = true; |
a9533e7e | 5565 | |
1c4c54ba | 5566 | brcms_c_radio_monitor_stop(wlc); |
a9533e7e HP |
5567 | |
5568 | /* Set EDCF hostflags */ | |
8ea54c9f | 5569 | if (EDCF_ENAB(wlc->pub)) |
7c783cef | 5570 | brcms_c_mhf(wlc, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL); |
8ea54c9f | 5571 | else |
7c783cef | 5572 | brcms_c_mhf(wlc, MHF1, MHF1_EDCF, 0, BRCM_BAND_ALL); |
a9533e7e | 5573 | |
7c783cef | 5574 | if (BRCMS_WAR16165(wlc)) |
fe741e5e | 5575 | brcms_c_mhf(wlc, MHF2, MHF2_PCISLOWCLKWAR, MHF2_PCISLOWCLKWAR, |
7c783cef | 5576 | BRCM_BAND_ALL); |
a9533e7e | 5577 | |
8817f754 | 5578 | brcms_init(wlc->wl); |
0f0881b0 | 5579 | wlc->pub->up = true; |
a9533e7e HP |
5580 | |
5581 | if (wlc->bandinit_pending) { | |
fe741e5e RV |
5582 | brcms_c_suspend_mac_and_wait(wlc); |
5583 | brcms_c_set_chanspec(wlc, wlc->default_bss->chanspec); | |
0965ae88 | 5584 | wlc->bandinit_pending = false; |
fe741e5e | 5585 | brcms_c_enable_mac(wlc); |
a9533e7e HP |
5586 | } |
5587 | ||
c654fce6 | 5588 | brcms_b_up_finish(wlc->hw); |
a9533e7e HP |
5589 | |
5590 | /* other software states up after ISR is running */ | |
5591 | /* start APs that were to be brought up but are not up yet */ | |
1c4c54ba | 5592 | /* if (AP_ENAB(wlc->pub)) brcms_c_restart_ap(wlc->ap); */ |
a9533e7e HP |
5593 | |
5594 | /* Program the TX wme params with the current settings */ | |
1c4c54ba | 5595 | brcms_c_wme_retries_write(wlc); |
a9533e7e HP |
5596 | |
5597 | /* start one second watchdog timer */ | |
8817f754 | 5598 | brcms_add_timer(wlc->wl, wlc->wdtimer, TIMER_INTERVAL_WATCHDOG, true); |
0f0881b0 | 5599 | wlc->WDarmed = true; |
a9533e7e HP |
5600 | |
5601 | /* ensure antenna config is up to date */ | |
f52a0ad0 | 5602 | brcms_c_stf_phy_txant_upd(wlc); |
a9533e7e | 5603 | /* ensure LDPC config is in sync */ |
1c4c54ba | 5604 | brcms_c_ht_update_ldpc(wlc, wlc->stf->ldpc); |
a9533e7e | 5605 | |
90ea2296 | 5606 | return 0; |
a9533e7e HP |
5607 | } |
5608 | ||
1c4c54ba | 5609 | static uint brcms_c_down_del_timer(struct brcms_c_info *wlc) |
a2627bc0 | 5610 | { |
a9533e7e HP |
5611 | uint callbacks = 0; |
5612 | ||
5613 | return callbacks; | |
5614 | } | |
5615 | ||
11431424 | 5616 | static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw) |
839f9f62 RV |
5617 | { |
5618 | bool dev_gone; | |
5619 | uint callbacks = 0; | |
5620 | ||
5621 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
5622 | ||
5623 | if (!wlc_hw->up) | |
5624 | return callbacks; | |
5625 | ||
5626 | dev_gone = DEVICEREMOVED(wlc_hw->wlc); | |
5627 | ||
5628 | /* disable interrupts */ | |
5629 | if (dev_gone) | |
5630 | wlc_hw->wlc->macintmask = 0; | |
5631 | else { | |
5632 | /* now disable interrupts */ | |
5633 | brcms_intrsoff(wlc_hw->wlc->wl); | |
5634 | ||
5635 | /* ensure we're running on the pll clock again */ | |
5636 | brcms_b_clkctl_clk(wlc_hw, CLK_FAST); | |
5637 | } | |
5638 | /* down phy at the last of this stage */ | |
5639 | callbacks += wlc_phy_down(wlc_hw->band->pi); | |
5640 | ||
5641 | return callbacks; | |
5642 | } | |
5643 | ||
11431424 | 5644 | static int brcms_b_down_finish(struct brcms_hardware *wlc_hw) |
839f9f62 RV |
5645 | { |
5646 | uint callbacks = 0; | |
5647 | bool dev_gone; | |
5648 | ||
5649 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | |
5650 | ||
5651 | if (!wlc_hw->up) | |
5652 | return callbacks; | |
5653 | ||
5654 | wlc_hw->up = false; | |
5655 | wlc_phy_hw_state_upd(wlc_hw->band->pi, false); | |
5656 | ||
5657 | dev_gone = DEVICEREMOVED(wlc_hw->wlc); | |
5658 | ||
5659 | if (dev_gone) { | |
5660 | wlc_hw->sbclk = false; | |
5661 | wlc_hw->clk = false; | |
5662 | wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false); | |
5663 | ||
5664 | /* reclaim any posted packets */ | |
5665 | brcms_c_flushqueues(wlc_hw->wlc); | |
5666 | } else { | |
5667 | ||
5668 | /* Reset and disable the core */ | |
5669 | if (ai_iscoreup(wlc_hw->sih)) { | |
5670 | if (R_REG(&wlc_hw->regs->maccontrol) & | |
5671 | MCTL_EN_MAC) | |
5672 | brcms_c_suspend_mac_and_wait(wlc_hw->wlc); | |
5673 | callbacks += brcms_reset(wlc_hw->wlc->wl); | |
5674 | brcms_c_coredisable(wlc_hw); | |
5675 | } | |
5676 | ||
5677 | /* turn off primary xtal and pll */ | |
5678 | if (!wlc_hw->noreset) { | |
821e4e93 | 5679 | ai_pci_down(wlc_hw->sih); |
839f9f62 RV |
5680 | brcms_b_xtal(wlc_hw, OFF); |
5681 | } | |
5682 | } | |
5683 | ||
5684 | return callbacks; | |
5685 | } | |
5686 | ||
a9533e7e HP |
5687 | /* |
5688 | * Mark the interface nonoperational, stop the software mechanisms, | |
5689 | * disable the hardware, free any transient buffer state. | |
5690 | * Return a count of the number of driver callbacks still pending. | |
5691 | */ | |
fe741e5e | 5692 | uint brcms_c_down(struct brcms_c_info *wlc) |
a2627bc0 | 5693 | { |
a9533e7e HP |
5694 | |
5695 | uint callbacks = 0; | |
5696 | int i; | |
0965ae88 | 5697 | bool dev_gone = false; |
471f1b51 | 5698 | struct brcms_txq_info *qi; |
a9533e7e | 5699 | |
792aa408 | 5700 | BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); |
a9533e7e HP |
5701 | |
5702 | /* check if we are already in the going down path */ | |
5703 | if (wlc->going_down) { | |
b8f092c9 RV |
5704 | wiphy_err(wlc->wiphy, "wl%d: %s: Driver going down so return" |
5705 | "\n", wlc->pub->unit, __func__); | |
a9533e7e HP |
5706 | return 0; |
5707 | } | |
5708 | if (!wlc->pub->up) | |
90ea2296 | 5709 | return callbacks; |
a9533e7e HP |
5710 | |
5711 | /* in between, mpc could try to bring down again.. */ | |
0f0881b0 | 5712 | wlc->going_down = true; |
a9533e7e | 5713 | |
c654fce6 | 5714 | callbacks += brcms_b_bmac_down_prep(wlc->hw); |
a9533e7e HP |
5715 | |
5716 | dev_gone = DEVICEREMOVED(wlc); | |
5717 | ||
5718 | /* Call any registered down handlers */ | |
7c783cef | 5719 | for (i = 0; i < BRCMS_MAXMODULES; i++) { |
a9533e7e HP |
5720 | if (wlc->modulecb[i].down_fn) |
5721 | callbacks += | |
5722 | wlc->modulecb[i].down_fn(wlc->modulecb[i].hdl); | |
5723 | } | |
5724 | ||
5725 | /* cancel the watchdog timer */ | |
5726 | if (wlc->WDarmed) { | |
8817f754 | 5727 | if (!brcms_del_timer(wlc->wl, wlc->wdtimer)) |
a9533e7e | 5728 | callbacks++; |
0965ae88 | 5729 | wlc->WDarmed = false; |
a9533e7e HP |
5730 | } |
5731 | /* cancel all other timers */ | |
1c4c54ba | 5732 | callbacks += brcms_c_down_del_timer(wlc); |
a9533e7e | 5733 | |
0965ae88 | 5734 | wlc->pub->up = false; |
a9533e7e | 5735 | |
0965ae88 | 5736 | wlc_phy_mute_upd(wlc->band->pi, false, PHY_MUTE_ALL); |
a9533e7e HP |
5737 | |
5738 | /* clear txq flow control */ | |
1c4c54ba | 5739 | brcms_c_txflowcontrol_reset(wlc); |
a9533e7e HP |
5740 | |
5741 | /* flush tx queues */ | |
8ea54c9f | 5742 | for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) |
67ad48bc | 5743 | brcmu_pktq_flush(&qi->q, true, NULL, NULL); |
a9533e7e | 5744 | |
c654fce6 | 5745 | callbacks += brcms_b_down_finish(wlc->hw); |
a9533e7e | 5746 | |
fe741e5e | 5747 | /* brcms_b_down_finish has done brcms_c_coredisable(). so clk is off */ |
0965ae88 | 5748 | wlc->clk = false; |
a9533e7e | 5749 | |
0965ae88 | 5750 | wlc->going_down = false; |
90ea2296 | 5751 | return callbacks; |
a9533e7e HP |
5752 | } |
5753 | ||
5754 | /* Set the current gmode configuration */ | |
fe741e5e | 5755 | int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config) |
a9533e7e HP |
5756 | { |
5757 | int ret = 0; | |
5758 | uint i; | |
fa67ebba | 5759 | struct brcms_c_rateset rs; |
a9533e7e | 5760 | /* Default to 54g Auto */ |
7c783cef RV |
5761 | /* Advertise and use shortslot (-1/0/1 Auto/Off/On) */ |
5762 | s8 shortslot = BRCMS_SHORTSLOT_AUTO; | |
419ad34e AS |
5763 | bool shortslot_restrict = false; /* Restrict association to stations |
5764 | * that support shortslot | |
5765 | */ | |
0965ae88 | 5766 | bool ofdm_basic = false; /* Make 6, 12, and 24 basic rates */ |
7c783cef RV |
5767 | /* Advertise and use short preambles (-1/0/1 Auto/Off/On) */ |
5768 | int preamble = BRCMS_PLCP_LONG; | |
419ad34e AS |
5769 | bool preamble_restrict = false; /* Restrict association to stations |
5770 | * that support short preambles | |
a9533e7e | 5771 | */ |
471f1b51 | 5772 | struct brcms_band *band; |
a9533e7e HP |
5773 | |
5774 | /* if N-support is enabled, allow Gmode set as long as requested | |
5775 | * Gmode is not GMODE_LEGACY_B | |
5776 | */ | |
5777 | if (N_ENAB(wlc->pub) && gmode == GMODE_LEGACY_B) | |
e10d82d4 | 5778 | return -ENOTSUPP; |
a9533e7e HP |
5779 | |
5780 | /* verify that we are dealing with 2G band and grab the band pointer */ | |
7c783cef | 5781 | if (wlc->band->bandtype == BRCM_BAND_2G) |
a9533e7e HP |
5782 | band = wlc->band; |
5783 | else if ((NBANDS(wlc) > 1) && | |
7c783cef | 5784 | (wlc->bandstate[OTHERBANDUNIT(wlc)]->bandtype == BRCM_BAND_2G)) |
a9533e7e HP |
5785 | band = wlc->bandstate[OTHERBANDUNIT(wlc)]; |
5786 | else | |
e10d82d4 | 5787 | return -EINVAL; |
a9533e7e HP |
5788 | |
5789 | /* Legacy or bust when no OFDM is supported by regulatory */ | |
f52a0ad0 | 5790 | if ((brcms_c_channel_locale_flags_in_band(wlc->cmi, band->bandunit) & |
7c783cef | 5791 | BRCMS_NO_OFDM) && (gmode != GMODE_LEGACY_B)) |
b74ac12e | 5792 | return -EINVAL; |
a9533e7e HP |
5793 | |
5794 | /* update configuration value */ | |
0f0881b0 | 5795 | if (config == true) |
7c783cef | 5796 | brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); |
a9533e7e HP |
5797 | |
5798 | /* Clear supported rates filter */ | |
fa67ebba | 5799 | memset(&wlc->sup_rates_override, 0, sizeof(struct brcms_c_rateset)); |
a9533e7e HP |
5800 | |
5801 | /* Clear rateset override */ | |
fa67ebba | 5802 | memset(&rs, 0, sizeof(struct brcms_c_rateset)); |
a9533e7e HP |
5803 | |
5804 | switch (gmode) { | |
5805 | case GMODE_LEGACY_B: | |
7c783cef | 5806 | shortslot = BRCMS_SHORTSLOT_OFF; |
f52a0ad0 | 5807 | brcms_c_rateset_copy(&gphy_legacy_rates, &rs); |
a9533e7e HP |
5808 | |
5809 | break; | |
5810 | ||
5811 | case GMODE_LRS: | |
5812 | if (AP_ENAB(wlc->pub)) | |
f52a0ad0 RV |
5813 | brcms_c_rateset_copy(&cck_rates, |
5814 | &wlc->sup_rates_override); | |
a9533e7e HP |
5815 | break; |
5816 | ||
5817 | case GMODE_AUTO: | |
5818 | /* Accept defaults */ | |
5819 | break; | |
5820 | ||
5821 | case GMODE_ONLY: | |
0f0881b0 | 5822 | ofdm_basic = true; |
7c783cef | 5823 | preamble = BRCMS_PLCP_SHORT; |
0f0881b0 | 5824 | preamble_restrict = true; |
a9533e7e HP |
5825 | break; |
5826 | ||
5827 | case GMODE_PERFORMANCE: | |
419ad34e AS |
5828 | if (AP_ENAB(wlc->pub)) |
5829 | /* Put all rates into the Supported Rates element */ | |
f52a0ad0 | 5830 | brcms_c_rateset_copy(&cck_ofdm_rates, |
a9533e7e HP |
5831 | &wlc->sup_rates_override); |
5832 | ||
7c783cef | 5833 | shortslot = BRCMS_SHORTSLOT_ON; |
0f0881b0 GKH |
5834 | shortslot_restrict = true; |
5835 | ofdm_basic = true; | |
7c783cef | 5836 | preamble = BRCMS_PLCP_SHORT; |
0f0881b0 | 5837 | preamble_restrict = true; |
a9533e7e HP |
5838 | break; |
5839 | ||
5840 | default: | |
5841 | /* Error */ | |
b8f092c9 RV |
5842 | wiphy_err(wlc->wiphy, "wl%d: %s: invalid gmode %d\n", |
5843 | wlc->pub->unit, __func__, gmode); | |
e10d82d4 | 5844 | return -ENOTSUPP; |
a9533e7e HP |
5845 | } |
5846 | ||
5847 | /* | |
5848 | * If we are switching to gmode == GMODE_LEGACY_B, | |
5849 | * clean up rate info that may refer to OFDM rates. | |
5850 | */ | |
5851 | if ((gmode == GMODE_LEGACY_B) && (band->gmode != GMODE_LEGACY_B)) { | |
5852 | band->gmode = gmode; | |
5853 | if (band->rspec_override && !IS_CCK(band->rspec_override)) { | |
5854 | band->rspec_override = 0; | |
fe741e5e | 5855 | brcms_c_reprate_init(wlc); |
a9533e7e | 5856 | } |
8ea54c9f | 5857 | if (band->mrspec_override && !IS_CCK(band->mrspec_override)) |
a9533e7e | 5858 | band->mrspec_override = 0; |
a9533e7e HP |
5859 | } |
5860 | ||
5861 | band->gmode = gmode; | |
5862 | ||
a9533e7e HP |
5863 | wlc->shortslot_override = shortslot; |
5864 | ||
8ea54c9f | 5865 | if (AP_ENAB(wlc->pub)) |
a9533e7e HP |
5866 | /* wlc->ap->shortslot_restrict = shortslot_restrict; */ |
5867 | wlc->PLCPHdr_override = | |
5868 | (preamble != | |
7c783cef | 5869 | BRCMS_PLCP_LONG) ? BRCMS_PLCP_SHORT : BRCMS_PLCP_AUTO; |
a9533e7e | 5870 | |
7c783cef RV |
5871 | if ((AP_ENAB(wlc->pub) && preamble != BRCMS_PLCP_LONG) |
5872 | || preamble == BRCMS_PLCP_SHORT) | |
04795017 | 5873 | wlc->default_bss->capability |= WLAN_CAPABILITY_SHORT_PREAMBLE; |
a9533e7e | 5874 | else |
04795017 | 5875 | wlc->default_bss->capability &= ~WLAN_CAPABILITY_SHORT_PREAMBLE; |
a9533e7e HP |
5876 | |
5877 | /* Update shortslot capability bit for AP and IBSS */ | |
7c783cef RV |
5878 | if ((AP_ENAB(wlc->pub) && shortslot == BRCMS_SHORTSLOT_AUTO) || |
5879 | shortslot == BRCMS_SHORTSLOT_ON) | |
04795017 | 5880 | wlc->default_bss->capability |= WLAN_CAPABILITY_SHORT_SLOT_TIME; |
a9533e7e | 5881 | else |
04795017 RV |
5882 | wlc->default_bss->capability &= |
5883 | ~WLAN_CAPABILITY_SHORT_SLOT_TIME; | |
a9533e7e HP |
5884 | |
5885 | /* Use the default 11g rateset */ | |
5886 | if (!rs.count) | |
f52a0ad0 | 5887 | brcms_c_rateset_copy(&cck_ofdm_rates, &rs); |
a9533e7e HP |
5888 | |
5889 | if (ofdm_basic) { | |
5890 | for (i = 0; i < rs.count; i++) { | |
7c783cef RV |
5891 | if (rs.rates[i] == BRCM_RATE_6M |
5892 | || rs.rates[i] == BRCM_RATE_12M | |
5893 | || rs.rates[i] == BRCM_RATE_24M) | |
5894 | rs.rates[i] |= BRCMS_RATE_FLAG; | |
a9533e7e HP |
5895 | } |
5896 | } | |
5897 | ||
5898 | /* Set default bss rateset */ | |
5899 | wlc->default_bss->rateset.count = rs.count; | |
835ef44c | 5900 | memcpy(wlc->default_bss->rateset.rates, rs.rates, |
02160695 | 5901 | sizeof(wlc->default_bss->rateset.rates)); |
a9533e7e HP |
5902 | |
5903 | return ret; | |
5904 | } | |
5905 | ||
1c4c54ba | 5906 | static int brcms_c_nmode_validate(struct brcms_c_info *wlc, s32 nmode) |
a9533e7e HP |
5907 | { |
5908 | int err = 0; | |
5909 | ||
5910 | switch (nmode) { | |
5911 | ||
5912 | case OFF: | |
5913 | break; | |
5914 | ||
5915 | case AUTO: | |
5916 | case WL_11N_2x2: | |
5917 | case WL_11N_3x3: | |
7c783cef | 5918 | if (!(BRCMS_PHY_11N_CAP(wlc->band))) |
e10d82d4 | 5919 | err = -EINVAL; |
a9533e7e HP |
5920 | break; |
5921 | ||
5922 | default: | |
b74ac12e | 5923 | err = -EINVAL; |
a9533e7e HP |
5924 | break; |
5925 | } | |
5926 | ||
5927 | return err; | |
5928 | } | |
5929 | ||
fe741e5e | 5930 | int brcms_c_set_nmode(struct brcms_c_info *wlc, s32 nmode) |
a9533e7e HP |
5931 | { |
5932 | uint i; | |
5933 | int err; | |
5934 | ||
1c4c54ba | 5935 | err = brcms_c_nmode_validate(wlc, nmode); |
a9533e7e HP |
5936 | if (err) |
5937 | return err; | |
5938 | ||
5939 | switch (nmode) { | |
5940 | case OFF: | |
5941 | wlc->pub->_n_enab = OFF; | |
7c783cef | 5942 | wlc->default_bss->flags &= ~BRCMS_BSS_HT; |
a9533e7e | 5943 | /* delete the mcs rates from the default and hw ratesets */ |
f52a0ad0 | 5944 | brcms_c_rateset_mcs_clear(&wlc->default_bss->rateset); |
a9533e7e HP |
5945 | for (i = 0; i < NBANDS(wlc); i++) { |
5946 | memset(wlc->bandstate[i]->hw_rateset.mcs, 0, | |
5947 | MCSSET_LEN); | |
5948 | if (IS_MCS(wlc->band->rspec_override)) { | |
5949 | wlc->bandstate[i]->rspec_override = 0; | |
fe741e5e | 5950 | brcms_c_reprate_init(wlc); |
a9533e7e HP |
5951 | } |
5952 | if (IS_MCS(wlc->band->mrspec_override)) | |
5953 | wlc->bandstate[i]->mrspec_override = 0; | |
5954 | } | |
5955 | break; | |
5956 | ||
5957 | case AUTO: | |
5958 | if (wlc->stf->txstreams == WL_11N_3x3) | |
5959 | nmode = WL_11N_3x3; | |
5960 | else | |
5961 | nmode = WL_11N_2x2; | |
5962 | case WL_11N_2x2: | |
5963 | case WL_11N_3x3: | |
a9533e7e | 5964 | /* force GMODE_AUTO if NMODE is ON */ |
fe741e5e | 5965 | brcms_c_set_gmode(wlc, GMODE_AUTO, true); |
a9533e7e HP |
5966 | if (nmode == WL_11N_3x3) |
5967 | wlc->pub->_n_enab = SUPPORT_HT; | |
5968 | else | |
5969 | wlc->pub->_n_enab = SUPPORT_11N; | |
7c783cef | 5970 | wlc->default_bss->flags |= BRCMS_BSS_HT; |
a9533e7e | 5971 | /* add the mcs rates to the default and hw ratesets */ |
f52a0ad0 | 5972 | brcms_c_rateset_mcs_build(&wlc->default_bss->rateset, |
a9533e7e HP |
5973 | wlc->stf->txstreams); |
5974 | for (i = 0; i < NBANDS(wlc); i++) | |
5975 | memcpy(wlc->bandstate[i]->hw_rateset.mcs, | |
5976 | wlc->default_bss->rateset.mcs, MCSSET_LEN); | |
5977 | break; | |
5978 | ||
5979 | default: | |
a9533e7e HP |
5980 | break; |
5981 | } | |
5982 | ||
5983 | return err; | |
5984 | } | |
5985 | ||
fa67ebba RV |
5986 | static int |
5987 | brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs_arg) | |
a9533e7e | 5988 | { |
fa67ebba | 5989 | struct brcms_c_rateset rs, new; |
a9533e7e HP |
5990 | uint bandunit; |
5991 | ||
fa67ebba | 5992 | memcpy(&rs, rs_arg, sizeof(struct brcms_c_rateset)); |
a9533e7e HP |
5993 | |
5994 | /* check for bad count value */ | |
7c783cef | 5995 | if ((rs.count == 0) || (rs.count > BRCMS_NUMRATES)) |
e10d82d4 | 5996 | return -EINVAL; |
a9533e7e HP |
5997 | |
5998 | /* try the current band */ | |
5999 | bandunit = wlc->band->bandunit; | |
fa67ebba | 6000 | memcpy(&new, &rs, sizeof(struct brcms_c_rateset)); |
f52a0ad0 | 6001 | if (brcms_c_rate_hwrs_filter_sort_validate |
0f0881b0 | 6002 | (&new, &wlc->bandstate[bandunit]->hw_rateset, true, |
a9533e7e HP |
6003 | wlc->stf->txstreams)) |
6004 | goto good; | |
6005 | ||
6006 | /* try the other band */ | |
6007 | if (IS_MBAND_UNLOCKED(wlc)) { | |
6008 | bandunit = OTHERBANDUNIT(wlc); | |
fa67ebba | 6009 | memcpy(&new, &rs, sizeof(struct brcms_c_rateset)); |
f52a0ad0 | 6010 | if (brcms_c_rate_hwrs_filter_sort_validate(&new, |
a9533e7e HP |
6011 | &wlc-> |
6012 | bandstate[bandunit]-> | |
0f0881b0 | 6013 | hw_rateset, true, |
a9533e7e HP |
6014 | wlc->stf->txstreams)) |
6015 | goto good; | |
6016 | } | |
6017 | ||
b74ac12e | 6018 | return -EBADE; |
a9533e7e HP |
6019 | |
6020 | good: | |
6021 | /* apply new rateset */ | |
fa67ebba RV |
6022 | memcpy(&wlc->default_bss->rateset, &new, |
6023 | sizeof(struct brcms_c_rateset)); | |
02160695 | 6024 | memcpy(&wlc->bandstate[bandunit]->defrateset, &new, |
fa67ebba | 6025 | sizeof(struct brcms_c_rateset)); |
90ea2296 | 6026 | return 0; |
a9533e7e HP |
6027 | } |
6028 | ||
6029 | /* simplified integer set interface for common ioctl handler */ | |
fe741e5e | 6030 | int brcms_c_set(struct brcms_c_info *wlc, int cmd, int arg) |
a9533e7e | 6031 | { |
fe741e5e | 6032 | return brcms_c_ioctl(wlc, cmd, (void *)&arg, sizeof(arg), NULL); |
a9533e7e HP |
6033 | } |
6034 | ||
6035 | /* simplified integer get interface for common ioctl handler */ | |
fe741e5e | 6036 | int brcms_c_get(struct brcms_c_info *wlc, int cmd, int *arg) |
a9533e7e | 6037 | { |
fe741e5e | 6038 | return brcms_c_ioctl(wlc, cmd, arg, sizeof(int), NULL); |
a9533e7e HP |
6039 | } |
6040 | ||
1c4c54ba | 6041 | static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc) |
a9533e7e | 6042 | { |
41feb5ed | 6043 | u8 r; |
0965ae88 | 6044 | bool war = false; |
a9533e7e HP |
6045 | |
6046 | if (wlc->cfg->associated) | |
6047 | r = wlc->cfg->current_bss->rateset.rates[0]; | |
6048 | else | |
6049 | r = wlc->default_bss->rateset.rates[0]; | |
6050 | ||
6051 | wlc_phy_ofdm_rateset_war(wlc->band->pi, war); | |
6052 | ||
6053 | return; | |
6054 | } | |
6055 | ||
a9533e7e HP |
6056 | /* common ioctl handler. return: 0=ok, -1=error, positive=particular error */ |
6057 | static int | |
1c4c54ba RV |
6058 | _brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len, |
6059 | struct brcms_c_if *wlcif) | |
a9533e7e HP |
6060 | { |
6061 | int val, *pval; | |
6062 | bool bool_val; | |
6063 | int bcmerror; | |
a9533e7e HP |
6064 | struct scb *nextscb; |
6065 | bool ta_ok; | |
6066 | uint band; | |
471f1b51 | 6067 | struct brcms_bss_cfg *bsscfg; |
cc87568a | 6068 | struct brcms_bss_info *current_bss; |
a9533e7e HP |
6069 | |
6070 | /* update bsscfg pointer */ | |
94da409e AS |
6071 | bsscfg = wlc->cfg; |
6072 | current_bss = bsscfg->current_bss; | |
a9533e7e HP |
6073 | |
6074 | /* initialize the following to get rid of compiler warning */ | |
6075 | nextscb = NULL; | |
0965ae88 | 6076 | ta_ok = false; |
a9533e7e | 6077 | band = 0; |
a9533e7e HP |
6078 | |
6079 | /* If the device is turned off, then it's not "removed" */ | |
6080 | if (!wlc->pub->hw_off && DEVICEREMOVED(wlc)) { | |
b8f092c9 RV |
6081 | wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit, |
6082 | __func__); | |
8817f754 | 6083 | brcms_down(wlc->wl); |
b74ac12e | 6084 | return -EBADE; |
a9533e7e HP |
6085 | } |
6086 | ||
a9533e7e | 6087 | /* default argument is generic integer */ |
835ef44c | 6088 | pval = arg ? (int *)arg : NULL; |
a9533e7e | 6089 | |
49d468f6 RV |
6090 | /* |
6091 | * This will prevent misaligned access. The (void *) cast prevents a | |
6092 | * memcpy alignment issue on e.g. Sparc64 platforms. | |
6093 | */ | |
66cbd3ab | 6094 | if (pval && (u32) len >= sizeof(val)) |
49d468f6 | 6095 | memcpy((void *)&val, (void *)pval, sizeof(val)); |
a9533e7e HP |
6096 | else |
6097 | val = 0; | |
6098 | ||
6099 | /* bool conversion to avoid duplication below */ | |
6100 | bool_val = val != 0; | |
a9533e7e | 6101 | bcmerror = 0; |
a9533e7e | 6102 | |
7306e4e3 RV |
6103 | if ((arg == NULL) || (len <= 0)) { |
6104 | wiphy_err(wlc->wiphy, "wl%d: %s: Command %d needs arguments\n", | |
6105 | wlc->pub->unit, __func__, cmd); | |
6106 | bcmerror = -EINVAL; | |
6107 | goto done; | |
a9533e7e HP |
6108 | } |
6109 | ||
6110 | switch (cmd) { | |
6111 | ||
7c783cef | 6112 | case BRCM_SET_CHANNEL:{ |
6bd20a1b | 6113 | u16 chspec = CH20MHZ_CHSPEC(val); |
a9533e7e HP |
6114 | |
6115 | if (val < 0 || val > MAXCHANNEL) { | |
e10d82d4 | 6116 | bcmerror = -EINVAL; |
a9533e7e HP |
6117 | break; |
6118 | } | |
6119 | ||
f52a0ad0 | 6120 | if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec)) { |
e10d82d4 | 6121 | bcmerror = -EINVAL; |
a9533e7e HP |
6122 | break; |
6123 | } | |
6124 | ||
6125 | if (!wlc->pub->up && IS_MBAND_UNLOCKED(wlc)) { | |
6126 | if (wlc->band->bandunit != | |
7c783cef | 6127 | CHSPEC_BANDUNIT(chspec)) |
0f0881b0 | 6128 | wlc->bandinit_pending = true; |
a9533e7e | 6129 | else |
0965ae88 | 6130 | wlc->bandinit_pending = false; |
a9533e7e HP |
6131 | } |
6132 | ||
6133 | wlc->default_bss->chanspec = chspec; | |
1c4c54ba RV |
6134 | /* brcms_c_BSSinit() will sanitize the rateset before |
6135 | * using it.. */ | |
eff1b99a | 6136 | if (wlc->pub->up && |
7c783cef | 6137 | (BRCMS_BAND_PI_RADIO_CHANSPEC != chspec)) { |
fe741e5e RV |
6138 | brcms_c_set_home_chanspec(wlc, chspec); |
6139 | brcms_c_suspend_mac_and_wait(wlc); | |
6140 | brcms_c_set_chanspec(wlc, chspec); | |
6141 | brcms_c_enable_mac(wlc); | |
a9533e7e | 6142 | } |
a9533e7e HP |
6143 | break; |
6144 | } | |
6145 | ||
7c783cef | 6146 | case BRCM_SET_SRL: |
a9533e7e HP |
6147 | if (val >= 1 && val <= RETRY_SHORT_MAX) { |
6148 | int ac; | |
7d4df48e | 6149 | wlc->SRL = (u16) val; |
a9533e7e | 6150 | |
c654fce6 | 6151 | brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL); |
a9533e7e | 6152 | |
8ea54c9f | 6153 | for (ac = 0; ac < AC_COUNT; ac++) |
7c783cef | 6154 | BRCMS_WME_RETRY_SHORT_SET(wlc, ac, wlc->SRL); |
8ea54c9f | 6155 | |
1c4c54ba | 6156 | brcms_c_wme_retries_write(wlc); |
a9533e7e | 6157 | } else |
b74ac12e | 6158 | bcmerror = -EINVAL; |
a9533e7e HP |
6159 | break; |
6160 | ||
7c783cef | 6161 | case BRCM_SET_LRL: |
a9533e7e HP |
6162 | if (val >= 1 && val <= 255) { |
6163 | int ac; | |
7d4df48e | 6164 | wlc->LRL = (u16) val; |
a9533e7e | 6165 | |
c654fce6 | 6166 | brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL); |
a9533e7e | 6167 | |
8ea54c9f | 6168 | for (ac = 0; ac < AC_COUNT; ac++) |
7c783cef | 6169 | BRCMS_WME_RETRY_LONG_SET(wlc, ac, wlc->LRL); |
8ea54c9f | 6170 | |
1c4c54ba | 6171 | brcms_c_wme_retries_write(wlc); |
a9533e7e | 6172 | } else |
b74ac12e | 6173 | bcmerror = -EINVAL; |
a9533e7e HP |
6174 | break; |
6175 | ||
7c783cef | 6176 | case BRCM_GET_CURR_RATESET:{ |
786d00f7 RV |
6177 | struct brcm_rateset *ret_rs = |
6178 | (struct brcm_rateset *) arg; | |
fa67ebba | 6179 | struct brcms_c_rateset *rs; |
a9533e7e | 6180 | |
94da409e | 6181 | if (wlc->pub->associated) |
a9533e7e HP |
6182 | rs = ¤t_bss->rateset; |
6183 | else | |
6184 | rs = &wlc->default_bss->rateset; | |
6185 | ||
6186 | if (len < (int)(rs->count + sizeof(rs->count))) { | |
e10d82d4 | 6187 | bcmerror = -EOVERFLOW; |
a9533e7e HP |
6188 | break; |
6189 | } | |
6190 | ||
6191 | /* Copy only legacy rateset section */ | |
6192 | ret_rs->count = rs->count; | |
02160695 | 6193 | memcpy(&ret_rs->rates, &rs->rates, rs->count); |
a9533e7e HP |
6194 | break; |
6195 | } | |
6196 | ||
7c783cef | 6197 | case BRCM_SET_RATESET:{ |
fa67ebba | 6198 | struct brcms_c_rateset rs; |
786d00f7 RV |
6199 | struct brcm_rateset *in_rs = |
6200 | (struct brcm_rateset *) arg; | |
a9533e7e HP |
6201 | |
6202 | if (len < (int)(in_rs->count + sizeof(in_rs->count))) { | |
e10d82d4 | 6203 | bcmerror = -EOVERFLOW; |
a9533e7e HP |
6204 | break; |
6205 | } | |
6206 | ||
7c783cef | 6207 | if (in_rs->count > BRCMS_NUMRATES) { |
b74ac12e | 6208 | bcmerror = -ENOBUFS; |
a9533e7e HP |
6209 | break; |
6210 | } | |
6211 | ||
fa67ebba | 6212 | memset(&rs, 0, sizeof(struct brcms_c_rateset)); |
a9533e7e HP |
6213 | |
6214 | /* Copy only legacy rateset section */ | |
6215 | rs.count = in_rs->count; | |
02160695 | 6216 | memcpy(&rs.rates, &in_rs->rates, rs.count); |
a9533e7e HP |
6217 | |
6218 | /* merge rateset coming in with the current mcsset */ | |
6219 | if (N_ENAB(wlc->pub)) { | |
09f882b0 | 6220 | struct brcms_bss_info *mcsset_bss; |
a9533e7e | 6221 | if (bsscfg->associated) |
09f882b0 | 6222 | mcsset_bss = current_bss; |
a9533e7e | 6223 | else |
09f882b0 AS |
6224 | mcsset_bss = wlc->default_bss; |
6225 | memcpy(rs.mcs, &mcsset_bss->rateset.mcs[0], | |
6226 | MCSSET_LEN); | |
a9533e7e HP |
6227 | } |
6228 | ||
1c4c54ba | 6229 | bcmerror = brcms_c_set_rateset(wlc, &rs); |
a9533e7e HP |
6230 | |
6231 | if (!bcmerror) | |
1c4c54ba | 6232 | brcms_c_ofdm_rateset_war(wlc); |
a9533e7e HP |
6233 | |
6234 | break; | |
6235 | } | |
6236 | ||
7c783cef | 6237 | case BRCM_SET_BCNPRD: |
a9533e7e HP |
6238 | /* range [1, 0xffff] */ |
6239 | if (val >= DOT11_MIN_BEACON_PERIOD | |
7c783cef | 6240 | && val <= DOT11_MAX_BEACON_PERIOD) |
7d4df48e | 6241 | wlc->default_bss->beacon_period = (u16) val; |
7c783cef | 6242 | else |
b74ac12e | 6243 | bcmerror = -EINVAL; |
a9533e7e HP |
6244 | break; |
6245 | ||
7c783cef | 6246 | case BRCM_GET_PHYLIST: |
a9533e7e | 6247 | { |
580a0bd9 | 6248 | unsigned char *cp = arg; |
a9533e7e | 6249 | if (len < 3) { |
e10d82d4 | 6250 | bcmerror = -EOVERFLOW; |
a9533e7e HP |
6251 | break; |
6252 | } | |
6253 | ||
7c783cef | 6254 | if (BRCMS_ISNPHY(wlc->band)) |
a9533e7e | 6255 | *cp++ = 'n'; |
7c783cef | 6256 | else if (BRCMS_ISLCNPHY(wlc->band)) |
a9533e7e | 6257 | *cp++ = 'c'; |
7c783cef | 6258 | else if (BRCMS_ISSSLPNPHY(wlc->band)) |
a9533e7e | 6259 | *cp++ = 's'; |
a9533e7e HP |
6260 | *cp = '\0'; |
6261 | break; | |
6262 | } | |
6263 | ||
7c783cef RV |
6264 | case BRCMS_SET_SHORTSLOT_OVERRIDE: |
6265 | if (val != BRCMS_SHORTSLOT_AUTO && val != BRCMS_SHORTSLOT_OFF && | |
6266 | val != BRCMS_SHORTSLOT_ON) { | |
b74ac12e | 6267 | bcmerror = -EINVAL; |
a9533e7e HP |
6268 | break; |
6269 | } | |
6270 | ||
562c8850 | 6271 | wlc->shortslot_override = (s8) val; |
a9533e7e HP |
6272 | |
6273 | /* shortslot is an 11g feature, so no more work if we are | |
6274 | * currently on the 5G band | |
6275 | */ | |
6276 | if (BAND_5G(wlc->band->bandtype)) | |
6277 | break; | |
6278 | ||
6279 | if (wlc->pub->up && wlc->pub->associated) { | |
6280 | /* let watchdog or beacon processing update shortslot */ | |
6281 | } else if (wlc->pub->up) { | |
6282 | /* unassociated shortslot is off */ | |
fe741e5e | 6283 | brcms_c_switch_shortslot(wlc, false); |
a9533e7e | 6284 | } else { |
fe741e5e RV |
6285 | /* driver is down, so just update the brcms_c_info |
6286 | * value */ | |
8ea54c9f | 6287 | if (wlc->shortslot_override == BRCMS_SHORTSLOT_AUTO) |
0965ae88 | 6288 | wlc->shortslot = false; |
8ea54c9f | 6289 | else |
a9533e7e HP |
6290 | wlc->shortslot = |
6291 | (wlc->shortslot_override == | |
7c783cef | 6292 | BRCMS_SHORTSLOT_ON); |
a9533e7e HP |
6293 | } |
6294 | ||
6295 | break; | |
6296 | ||
a9533e7e HP |
6297 | } |
6298 | done: | |
6299 | ||
b74ac12e RV |
6300 | if (bcmerror) |
6301 | wlc->pub->bcmerror = bcmerror; | |
a9533e7e | 6302 | |
90ea2296 | 6303 | return bcmerror; |
a9533e7e HP |
6304 | } |
6305 | ||
2682e2a3 AS |
6306 | int |
6307 | brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len, | |
6308 | struct brcms_c_if *wlcif) | |
6309 | { | |
6310 | return _brcms_c_ioctl(wlc, cmd, arg, len, wlcif); | |
6311 | } | |
6312 | ||
a9533e7e | 6313 | /* |
c5e7c035 | 6314 | * register watchdog and down handlers. |
a9533e7e | 6315 | */ |
cc87568a | 6316 | int brcms_c_module_register(struct brcms_pub *pub, |
2f6b1dde | 6317 | const char *name, struct brcms_info *hdl, |
1a5f680d | 6318 | int (*d_fn)(void *handle)) |
0d2f0724 | 6319 | { |
fe741e5e | 6320 | struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc; |
a9533e7e HP |
6321 | int i; |
6322 | ||
a9533e7e | 6323 | /* find an empty entry and just add, no duplication check! */ |
7c783cef | 6324 | for (i = 0; i < BRCMS_MAXMODULES; i++) { |
a9533e7e HP |
6325 | if (wlc->modulecb[i].name[0] == '\0') { |
6326 | strncpy(wlc->modulecb[i].name, name, | |
6327 | sizeof(wlc->modulecb[i].name) - 1); | |
a9533e7e | 6328 | wlc->modulecb[i].hdl = hdl; |
a9533e7e HP |
6329 | wlc->modulecb[i].down_fn = d_fn; |
6330 | return 0; | |
6331 | } | |
6332 | } | |
6333 | ||
e10d82d4 | 6334 | return -ENOSR; |
a9533e7e HP |
6335 | } |
6336 | ||
6337 | /* unregister module callbacks */ | |
2f6b1dde RV |
6338 | int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, |
6339 | struct brcms_info *hdl) | |
0d2f0724 | 6340 | { |
fe741e5e | 6341 | struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc; |
a9533e7e HP |
6342 | int i; |
6343 | ||
6344 | if (wlc == NULL) | |
b74ac12e | 6345 | return -ENODATA; |
a9533e7e | 6346 | |
7c783cef | 6347 | for (i = 0; i < BRCMS_MAXMODULES; i++) { |
a9533e7e HP |
6348 | if (!strcmp(wlc->modulecb[i].name, name) && |
6349 | (wlc->modulecb[i].hdl == hdl)) { | |
12bacc1b | 6350 | memset(&wlc->modulecb[i], 0, sizeof(struct modulecb)); |
a9533e7e HP |
6351 | return 0; |
6352 | } | |
6353 | } | |
6354 | ||
6355 | /* table not found! */ | |
b74ac12e | 6356 | return -ENODATA; |
a9533e7e HP |
6357 | } |
6358 | ||
a9533e7e | 6359 | #ifdef BCMDBG |
d558dea7 | 6360 | static const char * const supr_reason[] = { |
a9533e7e HP |
6361 | "None", "PMQ Entry", "Flush request", |
6362 | "Previous frag failure", "Channel mismatch", | |
6363 | "Lifetime Expiry", "Underflow" | |
6364 | }; | |
6365 | ||
1c4c54ba | 6366 | static void brcms_c_print_txs_status(u16 s) |
a9533e7e | 6367 | { |
0bef7748 AS |
6368 | printk(KERN_DEBUG "[15:12] %d frame attempts\n", |
6369 | (s & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT); | |
6370 | printk(KERN_DEBUG " [11:8] %d rts attempts\n", | |
6371 | (s & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT); | |
6372 | printk(KERN_DEBUG " [7] %d PM mode indicated\n", | |
a9533e7e | 6373 | ((s & TX_STATUS_PMINDCTD) ? 1 : 0)); |
0bef7748 | 6374 | printk(KERN_DEBUG " [6] %d intermediate status\n", |
a9533e7e | 6375 | ((s & TX_STATUS_INTERMEDIATE) ? 1 : 0)); |
0bef7748 AS |
6376 | printk(KERN_DEBUG " [5] %d AMPDU\n", |
6377 | (s & TX_STATUS_AMPDU) ? 1 : 0); | |
6378 | printk(KERN_DEBUG " [4:2] %d Frame Suppressed Reason (%s)\n", | |
a9533e7e HP |
6379 | ((s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT), |
6380 | supr_reason[(s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT]); | |
0bef7748 AS |
6381 | printk(KERN_DEBUG " [1] %d acked\n", |
6382 | ((s & TX_STATUS_ACK_RCV) ? 1 : 0)); | |
a9533e7e HP |
6383 | } |
6384 | #endif /* BCMDBG */ | |
6385 | ||
cc87568a | 6386 | void brcms_c_print_txstatus(struct tx_status *txs) |
a9533e7e HP |
6387 | { |
6388 | #if defined(BCMDBG) | |
7d4df48e GKH |
6389 | u16 s = txs->status; |
6390 | u16 ackphyrxsh = txs->ackphyrxsh; | |
a9533e7e | 6391 | |
0bef7748 AS |
6392 | printk(KERN_DEBUG "\ntxpkt (MPDU) Complete\n"); |
6393 | ||
6394 | printk(KERN_DEBUG "FrameID: %04x ", txs->frameid); | |
6395 | printk(KERN_DEBUG "TxStatus: %04x", s); | |
6396 | printk(KERN_DEBUG "\n"); | |
a9533e7e | 6397 | |
1c4c54ba | 6398 | brcms_c_print_txs_status(s); |
0bef7748 AS |
6399 | |
6400 | printk(KERN_DEBUG "LastTxTime: %04x ", txs->lasttxtime); | |
6401 | printk(KERN_DEBUG "Seq: %04x ", txs->sequence); | |
6402 | printk(KERN_DEBUG "PHYTxStatus: %04x ", txs->phyerr); | |
6403 | printk(KERN_DEBUG "RxAckRSSI: %04x ", | |
a9533e7e | 6404 | (ackphyrxsh & PRXS1_JSSI_MASK) >> PRXS1_JSSI_SHIFT); |
0bef7748 AS |
6405 | printk(KERN_DEBUG "RxAckSQ: %04x", |
6406 | (ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT); | |
6407 | printk(KERN_DEBUG "\n"); | |
a9533e7e HP |
6408 | #endif /* defined(BCMDBG) */ |
6409 | } | |
6410 | ||
fe741e5e | 6411 | void brcms_c_statsupd(struct brcms_c_info *wlc) |
a9533e7e HP |
6412 | { |
6413 | int i; | |
cc87568a | 6414 | struct macstat macstats; |
a9533e7e | 6415 | #ifdef BCMDBG |
7d4df48e GKH |
6416 | u16 delta; |
6417 | u16 rxf0ovfl; | |
6418 | u16 txfunfl[NFIFO]; | |
a9533e7e HP |
6419 | #endif /* BCMDBG */ |
6420 | ||
6421 | /* if driver down, make no sense to update stats */ | |
6422 | if (!wlc->pub->up) | |
6423 | return; | |
6424 | ||
6425 | #ifdef BCMDBG | |
6426 | /* save last rx fifo 0 overflow count */ | |
6427 | rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl; | |
6428 | ||
6429 | /* save last tx fifo underflow count */ | |
6430 | for (i = 0; i < NFIFO; i++) | |
6431 | txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i]; | |
6432 | #endif /* BCMDBG */ | |
6433 | ||
e4cf544e | 6434 | /* Read mac stats from contiguous shared memory */ |
c654fce6 | 6435 | brcms_b_copyfrom_shm(wlc->hw, M_UCODE_MACSTAT, |
cc87568a | 6436 | &macstats, sizeof(struct macstat)); |
e4cf544e | 6437 | |
a9533e7e HP |
6438 | #ifdef BCMDBG |
6439 | /* check for rx fifo 0 overflow */ | |
7d4df48e | 6440 | delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl); |
a9533e7e | 6441 | if (delta) |
b8f092c9 RV |
6442 | wiphy_err(wlc->wiphy, "wl%d: %u rx fifo 0 overflows!\n", |
6443 | wlc->pub->unit, delta); | |
a9533e7e HP |
6444 | |
6445 | /* check for tx fifo underflows */ | |
6446 | for (i = 0; i < NFIFO; i++) { | |
6447 | delta = | |
7d4df48e | 6448 | (u16) (wlc->core->macstat_snapshot->txfunfl[i] - |
a9533e7e HP |
6449 | txfunfl[i]); |
6450 | if (delta) | |
b8f092c9 RV |
6451 | wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!" |
6452 | "\n", wlc->pub->unit, delta, i); | |
a9533e7e HP |
6453 | } |
6454 | #endif /* BCMDBG */ | |
6455 | ||
a9533e7e HP |
6456 | /* merge counters from dma module */ |
6457 | for (i = 0; i < NFIFO; i++) { | |
8ea54c9f | 6458 | if (wlc->hw->di[i]) |
a9533e7e | 6459 | dma_counterreset(wlc->hw->di[i]); |
a9533e7e | 6460 | } |
a9533e7e HP |
6461 | } |
6462 | ||
fe741e5e | 6463 | bool brcms_c_chipmatch(u16 vendor, u16 device) |
a9533e7e | 6464 | { |
be1c09f9 | 6465 | if (vendor != PCI_VENDOR_ID_BROADCOM) { |
1c4c54ba | 6466 | pr_err("chipmatch: unknown vendor id %04x\n", vendor); |
0965ae88 | 6467 | return false; |
a9533e7e HP |
6468 | } |
6469 | ||
5d6e3aec RV |
6470 | if (device == BCM43224_D11N_ID_VEN1) |
6471 | return true; | |
a9533e7e | 6472 | if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID)) |
0f0881b0 | 6473 | return true; |
a9533e7e | 6474 | if (device == BCM4313_D11N2G_ID) |
0f0881b0 | 6475 | return true; |
a9533e7e | 6476 | if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID)) |
0f0881b0 | 6477 | return true; |
a9533e7e | 6478 | |
1c4c54ba | 6479 | pr_err("chipmatch: unknown device id %04x\n", device); |
0965ae88 | 6480 | return false; |
a9533e7e HP |
6481 | } |
6482 | ||
a9533e7e | 6483 | #if defined(BCMDBG) |
cc87568a | 6484 | void brcms_c_print_txdesc(struct d11txh *txh) |
a9533e7e | 6485 | { |
628f10ba SF |
6486 | u16 mtcl = le16_to_cpu(txh->MacTxControlLow); |
6487 | u16 mtch = le16_to_cpu(txh->MacTxControlHigh); | |
6488 | u16 mfc = le16_to_cpu(txh->MacFrameControl); | |
6489 | u16 tfest = le16_to_cpu(txh->TxFesTimeNormal); | |
6490 | u16 ptcw = le16_to_cpu(txh->PhyTxControlWord); | |
6491 | u16 ptcw_1 = le16_to_cpu(txh->PhyTxControlWord_1); | |
6492 | u16 ptcw_1_Fbr = le16_to_cpu(txh->PhyTxControlWord_1_Fbr); | |
6493 | u16 ptcw_1_Rts = le16_to_cpu(txh->PhyTxControlWord_1_Rts); | |
6494 | u16 ptcw_1_FbrRts = le16_to_cpu(txh->PhyTxControlWord_1_FbrRts); | |
6495 | u16 mainrates = le16_to_cpu(txh->MainRates); | |
6496 | u16 xtraft = le16_to_cpu(txh->XtraFrameTypes); | |
41feb5ed GKH |
6497 | u8 *iv = txh->IV; |
6498 | u8 *ra = txh->TxFrameRA; | |
628f10ba | 6499 | u16 tfestfb = le16_to_cpu(txh->TxFesTimeFallback); |
41feb5ed | 6500 | u8 *rtspfb = txh->RTSPLCPFallback; |
628f10ba | 6501 | u16 rtsdfb = le16_to_cpu(txh->RTSDurFallback); |
41feb5ed | 6502 | u8 *fragpfb = txh->FragPLCPFallback; |
628f10ba SF |
6503 | u16 fragdfb = le16_to_cpu(txh->FragDurFallback); |
6504 | u16 mmodelen = le16_to_cpu(txh->MModeLen); | |
6505 | u16 mmodefbrlen = le16_to_cpu(txh->MModeFbrLen); | |
6506 | u16 tfid = le16_to_cpu(txh->TxFrameID); | |
6507 | u16 txs = le16_to_cpu(txh->TxStatus); | |
6508 | u16 mnmpdu = le16_to_cpu(txh->MaxNMpdus); | |
6509 | u16 mabyte = le16_to_cpu(txh->MaxABytes_MRT); | |
6510 | u16 mabyte_f = le16_to_cpu(txh->MaxABytes_FBR); | |
6511 | u16 mmbyte = le16_to_cpu(txh->MinMBytes); | |
a9533e7e | 6512 | |
41feb5ed | 6513 | u8 *rtsph = txh->RTSPhyHeader; |
f3dc3ea4 | 6514 | struct ieee80211_rts rts = txh->rts_frame; |
a9533e7e HP |
6515 | char hexbuf[256]; |
6516 | ||
6517 | /* add plcp header along with txh descriptor */ | |
34227316 AS |
6518 | printk(KERN_DEBUG "Raw TxDesc + plcp header:\n"); |
6519 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | |
cc87568a | 6520 | txh, sizeof(struct d11txh) + 48); |
a9533e7e | 6521 | |
0bef7748 AS |
6522 | printk(KERN_DEBUG "TxCtlLow: %04x ", mtcl); |
6523 | printk(KERN_DEBUG "TxCtlHigh: %04x ", mtch); | |
6524 | printk(KERN_DEBUG "FC: %04x ", mfc); | |
6525 | printk(KERN_DEBUG "FES Time: %04x\n", tfest); | |
6526 | printk(KERN_DEBUG "PhyCtl: %04x%s ", ptcw, | |
a9533e7e | 6527 | (ptcw & PHY_TXC_SHORT_HDR) ? " short" : ""); |
0bef7748 AS |
6528 | printk(KERN_DEBUG "PhyCtl_1: %04x ", ptcw_1); |
6529 | printk(KERN_DEBUG "PhyCtl_1_Fbr: %04x\n", ptcw_1_Fbr); | |
6530 | printk(KERN_DEBUG "PhyCtl_1_Rts: %04x ", ptcw_1_Rts); | |
6531 | printk(KERN_DEBUG "PhyCtl_1_Fbr_Rts: %04x\n", ptcw_1_FbrRts); | |
6532 | printk(KERN_DEBUG "MainRates: %04x ", mainrates); | |
6533 | printk(KERN_DEBUG "XtraFrameTypes: %04x ", xtraft); | |
6534 | printk(KERN_DEBUG "\n"); | |
a9533e7e | 6535 | |
67ad48bc | 6536 | brcmu_format_hex(hexbuf, iv, sizeof(txh->IV)); |
0bef7748 | 6537 | printk(KERN_DEBUG "SecIV: %s\n", hexbuf); |
67ad48bc | 6538 | brcmu_format_hex(hexbuf, ra, sizeof(txh->TxFrameRA)); |
0bef7748 | 6539 | printk(KERN_DEBUG "RA: %s\n", hexbuf); |
a9533e7e | 6540 | |
0bef7748 | 6541 | printk(KERN_DEBUG "Fb FES Time: %04x ", tfestfb); |
67ad48bc | 6542 | brcmu_format_hex(hexbuf, rtspfb, sizeof(txh->RTSPLCPFallback)); |
0bef7748 AS |
6543 | printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf); |
6544 | printk(KERN_DEBUG "RTS DUR: %04x ", rtsdfb); | |
67ad48bc | 6545 | brcmu_format_hex(hexbuf, fragpfb, sizeof(txh->FragPLCPFallback)); |
0bef7748 AS |
6546 | printk(KERN_DEBUG "PLCP: %s ", hexbuf); |
6547 | printk(KERN_DEBUG "DUR: %04x", fragdfb); | |
6548 | printk(KERN_DEBUG "\n"); | |
a9533e7e | 6549 | |
0bef7748 AS |
6550 | printk(KERN_DEBUG "MModeLen: %04x ", mmodelen); |
6551 | printk(KERN_DEBUG "MModeFbrLen: %04x\n", mmodefbrlen); | |
a9533e7e | 6552 | |
0bef7748 AS |
6553 | printk(KERN_DEBUG "FrameID: %04x\n", tfid); |
6554 | printk(KERN_DEBUG "TxStatus: %04x\n", txs); | |
a9533e7e | 6555 | |
0bef7748 AS |
6556 | printk(KERN_DEBUG "MaxNumMpdu: %04x\n", mnmpdu); |
6557 | printk(KERN_DEBUG "MaxAggbyte: %04x\n", mabyte); | |
6558 | printk(KERN_DEBUG "MaxAggbyte_fb: %04x\n", mabyte_f); | |
6559 | printk(KERN_DEBUG "MinByte: %04x\n", mmbyte); | |
a9533e7e | 6560 | |
67ad48bc | 6561 | brcmu_format_hex(hexbuf, rtsph, sizeof(txh->RTSPhyHeader)); |
0bef7748 | 6562 | printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf); |
67ad48bc | 6563 | brcmu_format_hex(hexbuf, (u8 *) &rts, sizeof(txh->rts_frame)); |
0bef7748 AS |
6564 | printk(KERN_DEBUG "RTS Frame: %s", hexbuf); |
6565 | printk(KERN_DEBUG "\n"); | |
a9533e7e HP |
6566 | } |
6567 | #endif /* defined(BCMDBG) */ | |
6568 | ||
6569 | #if defined(BCMDBG) | |
cc87568a | 6570 | void brcms_c_print_rxh(struct d11rxhdr *rxh) |
a9533e7e | 6571 | { |
7d4df48e GKH |
6572 | u16 len = rxh->RxFrameSize; |
6573 | u16 phystatus_0 = rxh->PhyRxStatus_0; | |
6574 | u16 phystatus_1 = rxh->PhyRxStatus_1; | |
6575 | u16 phystatus_2 = rxh->PhyRxStatus_2; | |
6576 | u16 phystatus_3 = rxh->PhyRxStatus_3; | |
6577 | u16 macstatus1 = rxh->RxStatus1; | |
6578 | u16 macstatus2 = rxh->RxStatus2; | |
a9533e7e HP |
6579 | char flagstr[64]; |
6580 | char lenbuf[20]; | |
67ad48bc | 6581 | static const struct brcmu_bit_desc macstat_flags[] = { |
a9533e7e HP |
6582 | {RXS_FCSERR, "FCSErr"}, |
6583 | {RXS_RESPFRAMETX, "Reply"}, | |
6584 | {RXS_PBPRES, "PADDING"}, | |
6585 | {RXS_DECATMPT, "DeCr"}, | |
6586 | {RXS_DECERR, "DeCrErr"}, | |
6587 | {RXS_BCNSENT, "Bcn"}, | |
6588 | {0, NULL} | |
6589 | }; | |
6590 | ||
34227316 | 6591 | printk(KERN_DEBUG "Raw RxDesc:\n"); |
cc87568a RV |
6592 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, rxh, |
6593 | sizeof(struct d11rxhdr)); | |
a9533e7e | 6594 | |
67ad48bc | 6595 | brcmu_format_flags(macstat_flags, macstatus1, flagstr, 64); |
a9533e7e HP |
6596 | |
6597 | snprintf(lenbuf, sizeof(lenbuf), "0x%x", len); | |
6598 | ||
0bef7748 | 6599 | printk(KERN_DEBUG "RxFrameSize: %6s (%d)%s\n", lenbuf, len, |
a9533e7e | 6600 | (rxh->PhyRxStatus_0 & PRXS0_SHORTH) ? " short preamble" : ""); |
0bef7748 | 6601 | printk(KERN_DEBUG "RxPHYStatus: %04x %04x %04x %04x\n", |
a9533e7e | 6602 | phystatus_0, phystatus_1, phystatus_2, phystatus_3); |
0bef7748 AS |
6603 | printk(KERN_DEBUG "RxMACStatus: %x %s\n", macstatus1, flagstr); |
6604 | printk(KERN_DEBUG "RXMACaggtype: %x\n", | |
6605 | (macstatus2 & RXS_AGGTYPE_MASK)); | |
6606 | printk(KERN_DEBUG "RxTSFTime: %04x\n", rxh->RxTSFTime); | |
a9533e7e | 6607 | } |
a9533e7e HP |
6608 | #endif /* defined(BCMDBG) */ |
6609 | ||
839f9f62 RV |
6610 | u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate) |
6611 | { | |
6612 | u16 table_ptr; | |
6613 | u8 phy_rate, index; | |
6614 | ||
6615 | /* get the phy specific rate encoding for the PLCP SIGNAL field */ | |
6616 | if (IS_OFDM(rate)) | |
6617 | table_ptr = M_RT_DIRMAP_A; | |
6618 | else | |
6619 | table_ptr = M_RT_DIRMAP_B; | |
6620 | ||
6621 | /* for a given rate, the LS-nibble of the PLCP SIGNAL field is | |
6622 | * the index into the rate table. | |
6623 | */ | |
6624 | phy_rate = rate_info[rate] & BRCMS_RATE_MASK; | |
6625 | index = phy_rate & 0xf; | |
6626 | ||
6627 | /* Find the SHM pointer to the rate table entry by looking in the | |
6628 | * Direct-map Table | |
6629 | */ | |
6630 | return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2)); | |
6631 | } | |
6632 | ||
1c4c54ba | 6633 | static u16 brcms_c_rate_shm_offset(struct brcms_c_info *wlc, u8 rate) |
a9533e7e | 6634 | { |
c654fce6 | 6635 | return brcms_b_rate_shm_offset(wlc->hw, rate); |
a9533e7e HP |
6636 | } |
6637 | ||
6638 | /* Callback for device removed */ | |
a9533e7e HP |
6639 | |
6640 | /* | |
6641 | * Attempts to queue a packet onto a multiple-precedence queue, | |
6642 | * if necessary evicting a lower precedence packet from the queue. | |
6643 | * | |
6644 | * 'prec' is the precedence number that has already been mapped | |
6645 | * from the packet priority. | |
6646 | * | |
0965ae88 | 6647 | * Returns true if packet consumed (queued), false if not. |
a9533e7e | 6648 | */ |
11431424 | 6649 | static bool brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q, |
2f6b1dde | 6650 | struct sk_buff *pkt, int prec) |
a9533e7e | 6651 | { |
fe741e5e | 6652 | return brcms_c_prec_enq_head(wlc, q, pkt, prec, false); |
a9533e7e HP |
6653 | } |
6654 | ||
de91ed29 | 6655 | bool |
fe741e5e RV |
6656 | brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q, |
6657 | struct sk_buff *pkt, int prec, bool head) | |
a9533e7e | 6658 | { |
c26b1378 | 6659 | struct sk_buff *p; |
a9533e7e HP |
6660 | int eprec = -1; /* precedence to evict from */ |
6661 | ||
6662 | /* Determine precedence from which to evict packet, if any */ | |
6663 | if (pktq_pfull(q, prec)) | |
6664 | eprec = prec; | |
6665 | else if (pktq_full(q)) { | |
67ad48bc | 6666 | p = brcmu_pktq_peek_tail(q, &eprec); |
a9533e7e | 6667 | if (eprec > prec) { |
b8f092c9 RV |
6668 | wiphy_err(wlc->wiphy, "%s: Failing: eprec %d > prec %d" |
6669 | "\n", __func__, eprec, prec); | |
0965ae88 | 6670 | return false; |
a9533e7e HP |
6671 | } |
6672 | } | |
6673 | ||
6674 | /* Evict if needed */ | |
6675 | if (eprec >= 0) { | |
6676 | bool discard_oldest; | |
6677 | ||
a9533e7e HP |
6678 | discard_oldest = AC_BITMAP_TST(wlc->wme_dp, eprec); |
6679 | ||
6680 | /* Refuse newer packet unless configured to discard oldest */ | |
6681 | if (eprec == prec && !discard_oldest) { | |
b8f092c9 RV |
6682 | wiphy_err(wlc->wiphy, "%s: No where to go, prec == %d" |
6683 | "\n", __func__, prec); | |
0965ae88 | 6684 | return false; |
a9533e7e HP |
6685 | } |
6686 | ||
6687 | /* Evict packet according to discard policy */ | |
67ad48bc RV |
6688 | p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : |
6689 | brcmu_pktq_pdeq_tail(q, eprec); | |
6690 | brcmu_pkt_buf_free_skb(p); | |
a9533e7e HP |
6691 | } |
6692 | ||
6693 | /* Enqueue */ | |
6694 | if (head) | |
67ad48bc | 6695 | p = brcmu_pktq_penq_head(q, prec, pkt); |
a9533e7e | 6696 | else |
67ad48bc | 6697 | p = brcmu_pktq_penq(q, prec, pkt); |
a9533e7e | 6698 | |
0f0881b0 | 6699 | return true; |
a9533e7e HP |
6700 | } |
6701 | ||
2f6b1dde RV |
6702 | void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb, |
6703 | struct sk_buff *sdu, uint prec) | |
a9533e7e | 6704 | { |
471f1b51 | 6705 | struct brcms_txq_info *qi = wlc->pkt_queue; /* Check me */ |
a9533e7e HP |
6706 | struct pktq *q = &qi->q; |
6707 | int prio; | |
6708 | ||
54991ad6 | 6709 | prio = sdu->priority; |
a9533e7e | 6710 | |
fe741e5e | 6711 | if (!brcms_c_prec_enq(wlc, q, sdu, prec)) { |
a9533e7e HP |
6712 | if (!EDCF_ENAB(wlc->pub) |
6713 | || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL)) | |
1c4c54ba | 6714 | wiphy_err(wlc->wiphy, "wl%d: txq_enq: txq overflow" |
b8f092c9 | 6715 | "\n", wlc->pub->unit); |
a9533e7e | 6716 | |
a30825a3 | 6717 | /* |
e52d30f2 | 6718 | * we might hit this condtion in case |
a30825a3 AS |
6719 | * packet flooding from mac80211 stack |
6720 | */ | |
67ad48bc | 6721 | brcmu_pkt_buf_free_skb(sdu); |
a9533e7e HP |
6722 | } |
6723 | ||
419ad34e AS |
6724 | /* |
6725 | * Check if flow control needs to be turned on after enqueuing the | |
6726 | * packet. Don't turn on flow control if EDCF is enabled. Driver | |
6727 | * would make the decision on what to drop instead of relying on | |
6728 | * stack to make the right decision | |
a9533e7e HP |
6729 | */ |
6730 | if (!EDCF_ENAB(wlc->pub) | |
6731 | || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL)) { | |
8ea54c9f | 6732 | if (pktq_len(q) >= wlc->pub->tunables->datahiwat) |
fe741e5e | 6733 | brcms_c_txflowcontrol(wlc, qi, ON, ALLPRIO); |
a9533e7e HP |
6734 | } else if (wlc->pub->_priofc) { |
6735 | if (pktq_plen(q, wlc_prio2prec_map[prio]) >= | |
8ea54c9f | 6736 | wlc->pub->tunables->datahiwat) |
fe741e5e | 6737 | brcms_c_txflowcontrol(wlc, qi, ON, prio); |
a9533e7e HP |
6738 | } |
6739 | } | |
6740 | ||
a9533e7e HP |
6741 | /* |
6742 | * bcmc_fid_generate: | |
6743 | * Generate frame ID for a BCMC packet. The frag field is not used | |
6744 | * for MC frames so is used as part of the sequence number. | |
6745 | */ | |
7d4df48e | 6746 | static inline u16 |
471f1b51 | 6747 | bcmc_fid_generate(struct brcms_c_info *wlc, struct brcms_bss_cfg *bsscfg, |
cc87568a | 6748 | struct d11txh *txh) |
a9533e7e | 6749 | { |
7d4df48e | 6750 | u16 frameid; |
a9533e7e | 6751 | |
628f10ba SF |
6752 | frameid = le16_to_cpu(txh->TxFrameID) & ~(TXFID_SEQ_MASK | |
6753 | TXFID_QUEUE_MASK); | |
a9533e7e HP |
6754 | frameid |= |
6755 | (((wlc-> | |
6756 | mc_fid_counter++) << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) | | |
6757 | TX_BCMC_FIFO; | |
6758 | ||
6759 | return frameid; | |
6760 | } | |
6761 | ||
2682e2a3 AS |
6762 | static uint |
6763 | brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec, | |
6764 | u8 preamble_type) | |
a9533e7e | 6765 | { |
2682e2a3 | 6766 | uint dur = 0; |
a9533e7e | 6767 | |
2682e2a3 AS |
6768 | BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d\n", |
6769 | wlc->pub->unit, rspec, preamble_type); | |
419ad34e | 6770 | /* |
2682e2a3 AS |
6771 | * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that |
6772 | * is less than or equal to the rate of the immediately previous | |
6773 | * frame in the FES | |
a9533e7e | 6774 | */ |
2682e2a3 AS |
6775 | rspec = BRCMS_BASIC_RATE(wlc, rspec); |
6776 | /* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */ | |
6777 | dur = | |
6778 | brcms_c_calc_frame_time(wlc, rspec, preamble_type, | |
6779 | (DOT11_ACK_LEN + FCS_LEN)); | |
6780 | return dur; | |
a9533e7e HP |
6781 | } |
6782 | ||
2682e2a3 AS |
6783 | static uint |
6784 | brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec, | |
6785 | u8 preamble_type) | |
a9533e7e | 6786 | { |
2682e2a3 AS |
6787 | BCMMSG(wlc->wiphy, "wl%d: ratespec 0x%x, preamble_type %d\n", |
6788 | wlc->pub->unit, rspec, preamble_type); | |
6789 | return brcms_c_calc_ack_time(wlc, rspec, preamble_type); | |
a9533e7e HP |
6790 | } |
6791 | ||
2682e2a3 AS |
6792 | static uint |
6793 | brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec, | |
6794 | u8 preamble_type) | |
a9533e7e | 6795 | { |
2682e2a3 AS |
6796 | BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, " |
6797 | "preamble_type %d\n", wlc->pub->unit, rspec, preamble_type); | |
6798 | /* | |
6799 | * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that | |
6800 | * is less than or equal to the rate of the immediately previous | |
6801 | * frame in the FES | |
6802 | */ | |
6803 | rspec = BRCMS_BASIC_RATE(wlc, rspec); | |
6804 | /* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */ | |
6805 | return brcms_c_calc_frame_time(wlc, rspec, preamble_type, | |
6806 | (DOT11_BA_LEN + DOT11_BA_BITMAP_LEN + | |
6807 | FCS_LEN)); | |
a9533e7e HP |
6808 | } |
6809 | ||
2682e2a3 AS |
6810 | /* brcms_c_compute_frame_dur() |
6811 | * | |
6812 | * Calculate the 802.11 MAC header DUR field for MPDU | |
6813 | * DUR for a single frame = 1 SIFS + 1 ACK | |
6814 | * DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time | |
6815 | * | |
6816 | * rate MPDU rate in unit of 500kbps | |
6817 | * next_frag_len next MPDU length in bytes | |
6818 | * preamble_type use short/GF or long/MM PLCP header | |
6819 | */ | |
6820 | static u16 | |
6821 | brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate, | |
6822 | u8 preamble_type, uint next_frag_len) | |
a9533e7e | 6823 | { |
2682e2a3 | 6824 | u16 dur, sifs; |
a9533e7e | 6825 | |
2682e2a3 | 6826 | sifs = SIFS(wlc->band); |
a9533e7e | 6827 | |
2682e2a3 AS |
6828 | dur = sifs; |
6829 | dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type); | |
a9533e7e | 6830 | |
2682e2a3 AS |
6831 | if (next_frag_len) { |
6832 | /* Double the current DUR to get 2 SIFS + 2 ACKs */ | |
6833 | dur *= 2; | |
6834 | /* add another SIFS and the frag time */ | |
6835 | dur += sifs; | |
6836 | dur += | |
6837 | (u16) brcms_c_calc_frame_time(wlc, rate, preamble_type, | |
6838 | next_frag_len); | |
6839 | } | |
6840 | return dur; | |
a9533e7e HP |
6841 | } |
6842 | ||
2682e2a3 AS |
6843 | /* The opposite of brcms_c_calc_frame_time */ |
6844 | static uint | |
6845 | brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec, | |
6846 | u8 preamble_type, uint dur) | |
a9533e7e | 6847 | { |
2682e2a3 AS |
6848 | uint nsyms, mac_len, Ndps, kNdps; |
6849 | uint rate = RSPEC2RATE(ratespec); | |
a9533e7e | 6850 | |
2682e2a3 AS |
6851 | BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n", |
6852 | wlc->pub->unit, ratespec, preamble_type, dur); | |
a9533e7e | 6853 | |
2682e2a3 AS |
6854 | if (IS_MCS(ratespec)) { |
6855 | uint mcs = ratespec & RSPEC_RATE_MASK; | |
6856 | int tot_streams = MCS_TXS(mcs) + RSPEC_STC(ratespec); | |
6857 | dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT); | |
6858 | /* payload calculation matches that of regular ofdm */ | |
6859 | if (BAND_2G(wlc->band->bandtype)) | |
6860 | dur -= DOT11_OFDM_SIGNAL_EXTENSION; | |
6861 | /* kNdbps = kbps * 4 */ | |
6862 | kNdps = | |
6863 | MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec), | |
6864 | RSPEC_ISSGI(ratespec)) * 4; | |
6865 | nsyms = dur / APHY_SYMBOL_TIME; | |
6866 | mac_len = | |
6867 | ((nsyms * kNdps) - | |
6868 | ((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000; | |
6869 | } else if (IS_OFDM(ratespec)) { | |
6870 | dur -= APHY_PREAMBLE_TIME; | |
6871 | dur -= APHY_SIGNAL_TIME; | |
6872 | /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */ | |
6873 | Ndps = rate * 2; | |
6874 | nsyms = dur / APHY_SYMBOL_TIME; | |
6875 | mac_len = | |
6876 | ((nsyms * Ndps) - | |
6877 | (APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8; | |
6878 | } else { | |
6879 | if (preamble_type & BRCMS_SHORT_PREAMBLE) | |
6880 | dur -= BPHY_PLCP_SHORT_TIME; | |
6881 | else | |
6882 | dur -= BPHY_PLCP_TIME; | |
6883 | mac_len = dur * rate; | |
6884 | /* divide out factor of 2 in rate (1/2 mbps) */ | |
6885 | mac_len = mac_len / 8 / 2; | |
a9533e7e | 6886 | } |
2682e2a3 | 6887 | return mac_len; |
a9533e7e HP |
6888 | } |
6889 | ||
2682e2a3 AS |
6890 | static u32 |
6891 | mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band, | |
6892 | u32 int_val) | |
a9533e7e | 6893 | { |
2682e2a3 AS |
6894 | u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT; |
6895 | u8 rate = int_val & NRATE_RATE_MASK; | |
6896 | u32 rspec; | |
6897 | bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE); | |
6898 | bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT); | |
6899 | bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY) | |
6900 | == NRATE_OVERRIDE_MCS_ONLY); | |
6901 | int bcmerror = 0; | |
a9533e7e | 6902 | |
2682e2a3 AS |
6903 | if (!ismcs) |
6904 | return (u32) rate; | |
a9533e7e | 6905 | |
2682e2a3 AS |
6906 | /* validate the combination of rate/mcs/stf is allowed */ |
6907 | if (N_ENAB(wlc->pub) && ismcs) { | |
6908 | /* mcs only allowed when nmode */ | |
6909 | if (stf > PHY_TXC1_MODE_SDM) { | |
6910 | wiphy_err(wlc->wiphy, "wl%d: %s: Invalid stf\n", | |
6911 | BRCMS_UNIT(wlc), __func__); | |
6912 | bcmerror = -EINVAL; | |
6913 | goto done; | |
6914 | } | |
a9533e7e | 6915 | |
2682e2a3 AS |
6916 | /* mcs 32 is a special case, DUP mode 40 only */ |
6917 | if (rate == 32) { | |
6918 | if (!CHSPEC_IS40(wlc->home_chanspec) || | |
6919 | ((stf != PHY_TXC1_MODE_SISO) | |
6920 | && (stf != PHY_TXC1_MODE_CDD))) { | |
6921 | wiphy_err(wlc->wiphy, "wl%d: %s: Invalid mcs " | |
6922 | "32\n", BRCMS_UNIT(wlc), __func__); | |
6923 | bcmerror = -EINVAL; | |
6924 | goto done; | |
6925 | } | |
6926 | /* mcs > 7 must use stf SDM */ | |
6927 | } else if (rate > HIGHEST_SINGLE_STREAM_MCS) { | |
6928 | /* mcs > 7 must use stf SDM */ | |
6929 | if (stf != PHY_TXC1_MODE_SDM) { | |
6930 | BCMMSG(wlc->wiphy, "wl%d: enabling " | |
6931 | "SDM mode for mcs %d\n", | |
6932 | BRCMS_UNIT(wlc), rate); | |
6933 | stf = PHY_TXC1_MODE_SDM; | |
6934 | } | |
6935 | } else { | |
6936 | /* | |
6937 | * MCS 0-7 may use SISO, CDD, and for | |
6938 | * phy_rev >= 3 STBC | |
6939 | */ | |
6940 | if ((stf > PHY_TXC1_MODE_STBC) || | |
6941 | (!BRCMS_STBC_CAP_PHY(wlc) | |
6942 | && (stf == PHY_TXC1_MODE_STBC))) { | |
6943 | wiphy_err(wlc->wiphy, "wl%d: %s: Invalid STBC" | |
6944 | "\n", BRCMS_UNIT(wlc), __func__); | |
6945 | bcmerror = -EINVAL; | |
6946 | goto done; | |
6947 | } | |
6948 | } | |
6949 | } else if (IS_OFDM(rate)) { | |
6950 | if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) { | |
6951 | wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n", | |
6952 | BRCMS_UNIT(wlc), __func__); | |
6953 | bcmerror = -EINVAL; | |
6954 | goto done; | |
6955 | } | |
6956 | } else if (IS_CCK(rate)) { | |
6957 | if ((cur_band->bandtype != BRCM_BAND_2G) | |
6958 | || (stf != PHY_TXC1_MODE_SISO)) { | |
6959 | wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n", | |
6960 | BRCMS_UNIT(wlc), __func__); | |
6961 | bcmerror = -EINVAL; | |
6962 | goto done; | |
6963 | } | |
6964 | } else { | |
6965 | wiphy_err(wlc->wiphy, "wl%d: %s: Unknown rate type\n", | |
6966 | BRCMS_UNIT(wlc), __func__); | |
6967 | bcmerror = -EINVAL; | |
6968 | goto done; | |
6969 | } | |
6970 | /* make sure multiple antennae are available for non-siso rates */ | |
6971 | if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) { | |
6972 | wiphy_err(wlc->wiphy, "wl%d: %s: SISO antenna but !SISO " | |
6973 | "request\n", BRCMS_UNIT(wlc), __func__); | |
6974 | bcmerror = -EINVAL; | |
6975 | goto done; | |
6976 | } | |
a9533e7e | 6977 | |
2682e2a3 AS |
6978 | rspec = rate; |
6979 | if (ismcs) { | |
6980 | rspec |= RSPEC_MIMORATE; | |
6981 | /* For STBC populate the STC field of the ratespec */ | |
6982 | if (stf == PHY_TXC1_MODE_STBC) { | |
6983 | u8 stc; | |
6984 | stc = 1; /* Nss for single stream is always 1 */ | |
6985 | rspec |= (stc << RSPEC_STC_SHIFT); | |
6986 | } | |
a9533e7e | 6987 | } |
2682e2a3 AS |
6988 | |
6989 | rspec |= (stf << RSPEC_STF_SHIFT); | |
6990 | ||
6991 | if (override_mcs_only) | |
6992 | rspec |= RSPEC_OVERRIDE_MCS_ONLY; | |
6993 | ||
6994 | if (issgi) | |
6995 | rspec |= RSPEC_SHORT_GI; | |
6996 | ||
6997 | if ((rate != 0) | |
6998 | && !brcms_c_valid_rate(wlc, rspec, cur_band->bandtype, true)) | |
6999 | return rate; | |
7000 | ||
7001 | return rspec; | |
7002 | done: | |
7003 | return rate; | |
a9533e7e HP |
7004 | } |
7005 | ||
2682e2a3 AS |
7006 | /* |
7007 | * Add struct d11txh, struct cck_phy_hdr. | |
a9533e7e | 7008 | * |
2682e2a3 AS |
7009 | * 'p' data must start with 802.11 MAC header |
7010 | * 'p' must allow enough bytes of local headers to be "pushed" onto the packet | |
7011 | * | |
7012 | * headroom == D11_PHY_HDR_LEN + D11_TXH_LEN (D11_TXH_LEN is now 104 bytes) | |
a9533e7e | 7013 | * |
a9533e7e | 7014 | */ |
2682e2a3 AS |
7015 | static u16 |
7016 | brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, | |
7017 | struct sk_buff *p, struct scb *scb, uint frag, | |
7018 | uint nfrags, uint queue, uint next_frag_len, | |
7019 | struct wsec_key *key, u32 rspec_override) | |
a9533e7e | 7020 | { |
3e9796f9 | 7021 | struct ieee80211_hdr *h; |
cc87568a | 7022 | struct d11txh *txh; |
41feb5ed | 7023 | u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN]; |
a9533e7e | 7024 | int len, phylen, rts_phylen; |
9d7326f9 AS |
7025 | u16 mch, phyctl, xfts, mainrates; |
7026 | u16 seq = 0, mcl = 0, status = 0, frameid = 0; | |
6bd20a1b | 7027 | u32 rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M }, rts_rspec[2] = { |
7c783cef | 7028 | BRCM_RATE_1M, BRCM_RATE_1M}; |
0965ae88 GKH |
7029 | bool use_rts = false; |
7030 | bool use_cts = false; | |
7031 | bool use_rifs = false; | |
7032 | bool short_preamble[2] = { false, false }; | |
7c783cef RV |
7033 | u8 preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE }; |
7034 | u8 rts_preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE }; | |
41feb5ed | 7035 | u8 *rts_plcp, rts_plcp_fallback[D11_PHY_HDR_LEN]; |
f3dc3ea4 | 7036 | struct ieee80211_rts *rts = NULL; |
a9533e7e HP |
7037 | bool qos; |
7038 | uint ac; | |
66cbd3ab | 7039 | u32 rate_val[2]; |
0965ae88 | 7040 | bool hwtkmic = false; |
7d4df48e | 7041 | u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ; |
a9533e7e | 7042 | #define ANTCFG_NONE 0xFF |
41feb5ed GKH |
7043 | u8 antcfg = ANTCFG_NONE; |
7044 | u8 fbantcfg = ANTCFG_NONE; | |
a9533e7e | 7045 | uint phyctl1_stf = 0; |
7d4df48e | 7046 | u16 durid = 0; |
a9533e7e HP |
7047 | struct ieee80211_tx_rate *txrate[2]; |
7048 | int k; | |
7049 | struct ieee80211_tx_info *tx_info; | |
7050 | bool is_mcs[2]; | |
7d4df48e | 7051 | u16 mimo_txbw; |
41feb5ed | 7052 | u8 mimo_preamble_type; |
a9533e7e | 7053 | |
2682e2a3 AS |
7054 | /* locate 802.11 MAC header */ |
7055 | h = (struct ieee80211_hdr *)(p->data); | |
7056 | qos = ieee80211_is_data_qos(h->frame_control); | |
7057 | ||
7058 | /* compute length of frame in bytes for use in PLCP computations */ | |
7059 | len = brcmu_pkttotlen(p); | |
7060 | phylen = len + FCS_LEN; | |
7061 | ||
7062 | /* If WEP enabled, add room in phylen for the additional bytes of | |
7063 | * ICV which MAC generates. We do NOT add the additional bytes to | |
7064 | * the packet itself, thus phylen = packet length + ICV_LEN + FCS_LEN | |
7065 | * in this case | |
7066 | */ | |
7067 | if (key) | |
7068 | phylen += key->icv_len; | |
7069 | ||
7070 | /* Get tx_info */ | |
7071 | tx_info = IEEE80211_SKB_CB(p); | |
7072 | ||
7073 | /* add PLCP */ | |
7074 | plcp = skb_push(p, D11_PHY_HDR_LEN); | |
7075 | ||
7076 | /* add Broadcom tx descriptor header */ | |
7077 | txh = (struct d11txh *) skb_push(p, D11_TXH_LEN); | |
7078 | memset(txh, 0, D11_TXH_LEN); | |
7079 | ||
7080 | /* setup frameid */ | |
7081 | if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | |
7082 | /* non-AP STA should never use BCMC queue */ | |
7083 | if (queue == TX_BCMC_FIFO) { | |
7084 | wiphy_err(wlc->wiphy, "wl%d: %s: ASSERT queue == " | |
7085 | "TX_BCMC!\n", BRCMS_UNIT(wlc), __func__); | |
7086 | frameid = bcmc_fid_generate(wlc, NULL, txh); | |
7087 | } else { | |
7088 | /* Increment the counter for first fragment */ | |
7089 | if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) | |
7090 | SCB_SEQNUM(scb, p->priority)++; | |
7091 | ||
7092 | /* extract fragment number from frame first */ | |
7093 | seq = le16_to_cpu(seq) & FRAGNUM_MASK; | |
7094 | seq |= (SCB_SEQNUM(scb, p->priority) << SEQNUM_SHIFT); | |
7095 | h->seq_ctrl = cpu_to_le16(seq); | |
7096 | ||
7097 | frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) | | |
7098 | (queue & TXFID_QUEUE_MASK); | |
7099 | } | |
7100 | } | |
7101 | frameid |= queue & TXFID_QUEUE_MASK; | |
7102 | ||
7103 | /* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */ | |
7104 | if (SCB_PS(scb) || ieee80211_is_beacon(h->frame_control)) | |
7105 | mcl |= TXC_IGNOREPMQ; | |
7106 | ||
7107 | txrate[0] = tx_info->control.rates; | |
7108 | txrate[1] = txrate[0] + 1; | |
7109 | ||
7110 | /* | |
7111 | * if rate control algorithm didn't give us a fallback | |
7112 | * rate, use the primary rate | |
7113 | */ | |
7114 | if (txrate[1]->idx < 0) | |
7115 | txrate[1] = txrate[0]; | |
7116 | ||
7117 | for (k = 0; k < hw->max_rates; k++) { | |
7118 | is_mcs[k] = | |
7119 | txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false; | |
7120 | if (!is_mcs[k]) { | |
7121 | if ((txrate[k]->idx >= 0) | |
7122 | && (txrate[k]->idx < | |
7123 | hw->wiphy->bands[tx_info->band]->n_bitrates)) { | |
7124 | rate_val[k] = | |
7125 | hw->wiphy->bands[tx_info->band]-> | |
7126 | bitrates[txrate[k]->idx].hw_value; | |
7127 | short_preamble[k] = | |
7128 | txrate[k]-> | |
7129 | flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ? | |
7130 | true : false; | |
7131 | } else { | |
7132 | rate_val[k] = BRCM_RATE_1M; | |
7133 | } | |
7134 | } else { | |
7135 | rate_val[k] = txrate[k]->idx; | |
7136 | } | |
7137 | ||
7138 | /* | |
7139 | * Currently only support same setting for primay and | |
7140 | * fallback rates. Unify flags for each rate into a | |
7141 | * single value for the frame | |
7142 | */ | |
7143 | use_rts |= | |
7144 | txrate[k]-> | |
7145 | flags & IEEE80211_TX_RC_USE_RTS_CTS ? true : false; | |
7146 | use_cts |= | |
7147 | txrate[k]-> | |
7148 | flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? true : false; | |
7149 | ||
7150 | if (is_mcs[k]) | |
7151 | rate_val[k] |= NRATE_MCS_INUSE; | |
7152 | ||
7153 | rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band, rate_val[k]); | |
7154 | ||
7155 | /* | |
7156 | * (1) RATE: | |
7157 | * determine and validate primary rate | |
7158 | * and fallback rates | |
7159 | */ | |
7160 | if (!RSPEC_ACTIVE(rspec[k])) { | |
7161 | rspec[k] = BRCM_RATE_1M; | |
7162 | } else { | |
7163 | if (!is_multicast_ether_addr(h->addr1)) { | |
7164 | /* set tx antenna config */ | |
7165 | brcms_c_antsel_antcfg_get(wlc->asi, false, | |
7166 | false, 0, 0, &antcfg, &fbantcfg); | |
7167 | } | |
7168 | } | |
7169 | } | |
7170 | ||
7171 | phyctl1_stf = wlc->stf->ss_opmode; | |
7172 | ||
7173 | if (N_ENAB(wlc->pub)) { | |
7174 | for (k = 0; k < hw->max_rates; k++) { | |
7175 | /* | |
7176 | * apply siso/cdd to single stream mcs's or ofdm | |
7177 | * if rspec is auto selected | |
7178 | */ | |
7179 | if (((IS_MCS(rspec[k]) && | |
7180 | IS_SINGLE_STREAM(rspec[k] & RSPEC_RATE_MASK)) || | |
7181 | IS_OFDM(rspec[k])) | |
7182 | && ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY) | |
7183 | || !(rspec[k] & RSPEC_OVERRIDE))) { | |
7184 | rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK); | |
7185 | ||
7186 | /* For SISO MCS use STBC if possible */ | |
7187 | if (IS_MCS(rspec[k]) | |
7188 | && BRCMS_STF_SS_STBC_TX(wlc, scb)) { | |
7189 | u8 stc; | |
7190 | ||
7191 | /* Nss for single stream is always 1 */ | |
7192 | stc = 1; | |
7193 | rspec[k] |= (PHY_TXC1_MODE_STBC << | |
7194 | RSPEC_STF_SHIFT) | | |
7195 | (stc << RSPEC_STC_SHIFT); | |
7196 | } else | |
7197 | rspec[k] |= | |
7198 | (phyctl1_stf << RSPEC_STF_SHIFT); | |
7199 | } | |
7200 | ||
7201 | /* | |
7202 | * Is the phy configured to use 40MHZ frames? If | |
7203 | * so then pick the desired txbw | |
7204 | */ | |
7205 | if (CHSPEC_WLC_BW(wlc->chanspec) == BRCMS_40_MHZ) { | |
7206 | /* default txbw is 20in40 SB */ | |
7207 | mimo_ctlchbw = mimo_txbw = | |
7208 | CHSPEC_SB_UPPER(BRCMS_BAND_PI_RADIO_CHANSPEC) | |
7209 | ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ; | |
7210 | ||
7211 | if (IS_MCS(rspec[k])) { | |
7212 | /* mcs 32 must be 40b/w DUP */ | |
7213 | if ((rspec[k] & RSPEC_RATE_MASK) | |
7214 | == 32) { | |
7215 | mimo_txbw = | |
7216 | PHY_TXC1_BW_40MHZ_DUP; | |
7217 | /* use override */ | |
7218 | } else if (wlc->mimo_40txbw != AUTO) | |
7219 | mimo_txbw = wlc->mimo_40txbw; | |
7220 | /* else check if dst is using 40 Mhz */ | |
7221 | else if (scb->flags & SCB_IS40) | |
7222 | mimo_txbw = PHY_TXC1_BW_40MHZ; | |
7223 | } else if (IS_OFDM(rspec[k])) { | |
7224 | if (wlc->ofdm_40txbw != AUTO) | |
7225 | mimo_txbw = wlc->ofdm_40txbw; | |
7226 | } else if (wlc->cck_40txbw != AUTO) { | |
7227 | mimo_txbw = wlc->cck_40txbw; | |
7228 | } | |
7229 | } else { | |
7230 | /* | |
7231 | * mcs32 is 40 b/w only. | |
7232 | * This is possible for probe packets on | |
7233 | * a STA during SCAN | |
7234 | */ | |
7235 | if ((rspec[k] & RSPEC_RATE_MASK) == 32) | |
7236 | /* mcs 0 */ | |
7237 | rspec[k] = RSPEC_MIMORATE; | |
7238 | ||
7239 | mimo_txbw = PHY_TXC1_BW_20MHZ; | |
7240 | } | |
7241 | ||
7242 | /* Set channel width */ | |
7243 | rspec[k] &= ~RSPEC_BW_MASK; | |
7244 | if ((k == 0) || ((k > 0) && IS_MCS(rspec[k]))) | |
7245 | rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT); | |
7246 | else | |
7247 | rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT); | |
7248 | ||
7249 | /* Disable short GI, not supported yet */ | |
7250 | rspec[k] &= ~RSPEC_SHORT_GI; | |
7251 | ||
7252 | mimo_preamble_type = BRCMS_MM_PREAMBLE; | |
7253 | if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD) | |
7254 | mimo_preamble_type = BRCMS_GF_PREAMBLE; | |
7255 | ||
7256 | if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) | |
7257 | && (!IS_MCS(rspec[k]))) { | |
7258 | wiphy_err(wlc->wiphy, "wl%d: %s: IEEE80211_TX_" | |
7259 | "RC_MCS != IS_MCS(rspec)\n", | |
7260 | BRCMS_UNIT(wlc), __func__); | |
7261 | } | |
7262 | ||
7263 | if (IS_MCS(rspec[k])) { | |
7264 | preamble_type[k] = mimo_preamble_type; | |
7265 | ||
7266 | /* | |
7267 | * if SGI is selected, then forced mm | |
7268 | * for single stream | |
7269 | */ | |
7270 | if ((rspec[k] & RSPEC_SHORT_GI) | |
7271 | && IS_SINGLE_STREAM(rspec[k] & | |
7272 | RSPEC_RATE_MASK)) | |
7273 | preamble_type[k] = BRCMS_MM_PREAMBLE; | |
7274 | } | |
7275 | ||
7276 | /* should be better conditionalized */ | |
7277 | if (!IS_MCS(rspec[0]) | |
7278 | && (tx_info->control.rates[0]. | |
7279 | flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)) | |
7280 | preamble_type[k] = BRCMS_SHORT_PREAMBLE; | |
7281 | } | |
7282 | } else { | |
7283 | for (k = 0; k < hw->max_rates; k++) { | |
7284 | /* Set ctrlchbw as 20Mhz */ | |
7285 | rspec[k] &= ~RSPEC_BW_MASK; | |
7286 | rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT); | |
7287 | ||
7288 | /* for nphy, stf of ofdm frames must follow policies */ | |
7289 | if (BRCMS_ISNPHY(wlc->band) && IS_OFDM(rspec[k])) { | |
7290 | rspec[k] &= ~RSPEC_STF_MASK; | |
7291 | rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT; | |
7292 | } | |
7293 | } | |
7294 | } | |
7295 | ||
7296 | /* Reset these for use with AMPDU's */ | |
7297 | txrate[0]->count = 0; | |
7298 | txrate[1]->count = 0; | |
7299 | ||
7300 | /* (2) PROTECTION, may change rspec */ | |
7301 | if ((ieee80211_is_data(h->frame_control) || | |
7302 | ieee80211_is_mgmt(h->frame_control)) && | |
7303 | (phylen > wlc->RTSThresh) && !is_multicast_ether_addr(h->addr1)) | |
7304 | use_rts = true; | |
7305 | ||
7306 | /* (3) PLCP: determine PLCP header and MAC duration, | |
7307 | * fill struct d11txh */ | |
7308 | brcms_c_compute_plcp(wlc, rspec[0], phylen, plcp); | |
7309 | brcms_c_compute_plcp(wlc, rspec[1], phylen, plcp_fallback); | |
7310 | memcpy(&txh->FragPLCPFallback, | |
7311 | plcp_fallback, sizeof(txh->FragPLCPFallback)); | |
7312 | ||
7313 | /* Length field now put in CCK FBR CRC field */ | |
7314 | if (IS_CCK(rspec[1])) { | |
7315 | txh->FragPLCPFallback[4] = phylen & 0xff; | |
7316 | txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8; | |
7317 | } | |
7318 | ||
7319 | /* MIMO-RATE: need validation ?? */ | |
7320 | mainrates = IS_OFDM(rspec[0]) ? | |
7321 | D11A_PHY_HDR_GRATE((struct ofdm_phy_hdr *) plcp) : | |
7322 | plcp[0]; | |
7323 | ||
7324 | /* DUR field for main rate */ | |
7325 | if (!ieee80211_is_pspoll(h->frame_control) && | |
7326 | !is_multicast_ether_addr(h->addr1) && !use_rifs) { | |
7327 | durid = | |
7328 | brcms_c_compute_frame_dur(wlc, rspec[0], preamble_type[0], | |
7329 | next_frag_len); | |
7330 | h->duration_id = cpu_to_le16(durid); | |
7331 | } else if (use_rifs) { | |
7332 | /* NAV protect to end of next max packet size */ | |
7333 | durid = | |
7334 | (u16) brcms_c_calc_frame_time(wlc, rspec[0], | |
7335 | preamble_type[0], | |
7336 | DOT11_MAX_FRAG_LEN); | |
7337 | durid += RIFS_11N_TIME; | |
7338 | h->duration_id = cpu_to_le16(durid); | |
7339 | } | |
7340 | ||
7341 | /* DUR field for fallback rate */ | |
7342 | if (ieee80211_is_pspoll(h->frame_control)) | |
7343 | txh->FragDurFallback = h->duration_id; | |
7344 | else if (is_multicast_ether_addr(h->addr1) || use_rifs) | |
7345 | txh->FragDurFallback = 0; | |
7346 | else { | |
7347 | durid = brcms_c_compute_frame_dur(wlc, rspec[1], | |
7348 | preamble_type[1], next_frag_len); | |
7349 | txh->FragDurFallback = cpu_to_le16(durid); | |
7350 | } | |
a9533e7e | 7351 | |
2682e2a3 AS |
7352 | /* (4) MAC-HDR: MacTxControlLow */ |
7353 | if (frag == 0) | |
7354 | mcl |= TXC_STARTMSDU; | |
a9533e7e | 7355 | |
2682e2a3 AS |
7356 | if (!is_multicast_ether_addr(h->addr1)) |
7357 | mcl |= TXC_IMMEDACK; | |
a9533e7e | 7358 | |
2682e2a3 AS |
7359 | if (BAND_5G(wlc->band->bandtype)) |
7360 | mcl |= TXC_FREQBAND_5G; | |
a9533e7e | 7361 | |
2682e2a3 AS |
7362 | if (CHSPEC_IS40(BRCMS_BAND_PI_RADIO_CHANSPEC)) |
7363 | mcl |= TXC_BW_40; | |
a9533e7e | 7364 | |
2682e2a3 AS |
7365 | /* set AMIC bit if using hardware TKIP MIC */ |
7366 | if (hwtkmic) | |
7367 | mcl |= TXC_AMIC; | |
a9533e7e | 7368 | |
2682e2a3 | 7369 | txh->MacTxControlLow = cpu_to_le16(mcl); |
a9533e7e | 7370 | |
2682e2a3 AS |
7371 | /* MacTxControlHigh */ |
7372 | mch = 0; | |
a9533e7e | 7373 | |
2682e2a3 AS |
7374 | /* Set fallback rate preamble type */ |
7375 | if ((preamble_type[1] == BRCMS_SHORT_PREAMBLE) || | |
7376 | (preamble_type[1] == BRCMS_GF_PREAMBLE)) { | |
7377 | if (RSPEC2RATE(rspec[1]) != BRCM_RATE_1M) | |
7378 | mch |= TXC_PREAMBLE_DATA_FB_SHORT; | |
a9533e7e | 7379 | } |
a9533e7e | 7380 | |
2682e2a3 AS |
7381 | /* MacFrameControl */ |
7382 | memcpy(&txh->MacFrameControl, &h->frame_control, sizeof(u16)); | |
7383 | txh->TxFesTimeNormal = cpu_to_le16(0); | |
a9533e7e | 7384 | |
2682e2a3 AS |
7385 | txh->TxFesTimeFallback = cpu_to_le16(0); |
7386 | ||
7387 | /* TxFrameRA */ | |
7388 | memcpy(&txh->TxFrameRA, &h->addr1, ETH_ALEN); | |
7389 | ||
7390 | /* TxFrameID */ | |
7391 | txh->TxFrameID = cpu_to_le16(frameid); | |
a9533e7e | 7392 | |
419ad34e | 7393 | /* |
2682e2a3 AS |
7394 | * TxStatus, Note the case of recreating the first frag of a suppressed |
7395 | * frame then we may need to reset the retry cnt's via the status reg | |
419ad34e | 7396 | */ |
2682e2a3 | 7397 | txh->TxStatus = cpu_to_le16(status); |
a9533e7e | 7398 | |
2682e2a3 AS |
7399 | /* |
7400 | * extra fields for ucode AMPDU aggregation, the new fields are added to | |
7401 | * the END of previous structure so that it's compatible in driver. | |
7402 | */ | |
7403 | txh->MaxNMpdus = cpu_to_le16(0); | |
7404 | txh->MaxABytes_MRT = cpu_to_le16(0); | |
7405 | txh->MaxABytes_FBR = cpu_to_le16(0); | |
7406 | txh->MinMBytes = cpu_to_le16(0); | |
8ea54c9f | 7407 | |
2682e2a3 AS |
7408 | /* (5) RTS/CTS: determine RTS/CTS PLCP header and MAC duration, |
7409 | * furnish struct d11txh */ | |
7410 | /* RTS PLCP header and RTS frame */ | |
7411 | if (use_rts || use_cts) { | |
7412 | if (use_rts && use_cts) | |
7413 | use_cts = false; | |
a9533e7e | 7414 | |
2682e2a3 AS |
7415 | for (k = 0; k < 2; k++) { |
7416 | rts_rspec[k] = brcms_c_rspec_to_rts_rspec(wlc, rspec[k], | |
7417 | false, | |
7418 | mimo_ctlchbw); | |
7419 | } | |
a9533e7e | 7420 | |
2682e2a3 AS |
7421 | if (!IS_OFDM(rts_rspec[0]) && |
7422 | !((RSPEC2RATE(rts_rspec[0]) == BRCM_RATE_1M) || | |
7423 | (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) { | |
7424 | rts_preamble_type[0] = BRCMS_SHORT_PREAMBLE; | |
7425 | mch |= TXC_PREAMBLE_RTS_MAIN_SHORT; | |
7426 | } | |
a9533e7e | 7427 | |
2682e2a3 AS |
7428 | if (!IS_OFDM(rts_rspec[1]) && |
7429 | !((RSPEC2RATE(rts_rspec[1]) == BRCM_RATE_1M) || | |
7430 | (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) { | |
7431 | rts_preamble_type[1] = BRCMS_SHORT_PREAMBLE; | |
7432 | mch |= TXC_PREAMBLE_RTS_FB_SHORT; | |
7433 | } | |
7434 | ||
7435 | /* RTS/CTS additions to MacTxControlLow */ | |
7436 | if (use_cts) { | |
7437 | txh->MacTxControlLow |= cpu_to_le16(TXC_SENDCTS); | |
a9533e7e | 7438 | } else { |
2682e2a3 AS |
7439 | txh->MacTxControlLow |= cpu_to_le16(TXC_SENDRTS); |
7440 | txh->MacTxControlLow |= cpu_to_le16(TXC_LONGFRAME); | |
a9533e7e | 7441 | } |
a9533e7e | 7442 | |
2682e2a3 AS |
7443 | /* RTS PLCP header */ |
7444 | rts_plcp = txh->RTSPhyHeader; | |
7445 | if (use_cts) | |
7446 | rts_phylen = DOT11_CTS_LEN + FCS_LEN; | |
7447 | else | |
7448 | rts_phylen = DOT11_RTS_LEN + FCS_LEN; | |
a9533e7e | 7449 | |
2682e2a3 | 7450 | brcms_c_compute_plcp(wlc, rts_rspec[0], rts_phylen, rts_plcp); |
a9533e7e | 7451 | |
2682e2a3 AS |
7452 | /* fallback rate version of RTS PLCP header */ |
7453 | brcms_c_compute_plcp(wlc, rts_rspec[1], rts_phylen, | |
7454 | rts_plcp_fallback); | |
7455 | memcpy(&txh->RTSPLCPFallback, rts_plcp_fallback, | |
7456 | sizeof(txh->RTSPLCPFallback)); | |
a9533e7e | 7457 | |
2682e2a3 AS |
7458 | /* RTS frame fields... */ |
7459 | rts = (struct ieee80211_rts *)&txh->rts_frame; | |
7460 | ||
7461 | durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec[0], | |
7462 | rspec[0], rts_preamble_type[0], | |
7463 | preamble_type[0], phylen, false); | |
7464 | rts->duration = cpu_to_le16(durid); | |
7465 | /* fallback rate version of RTS DUR field */ | |
7466 | durid = brcms_c_compute_rtscts_dur(wlc, use_cts, | |
7467 | rts_rspec[1], rspec[1], | |
7468 | rts_preamble_type[1], | |
7469 | preamble_type[1], phylen, false); | |
7470 | txh->RTSDurFallback = cpu_to_le16(durid); | |
7471 | ||
7472 | if (use_cts) { | |
7473 | rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | |
7474 | IEEE80211_STYPE_CTS); | |
7475 | ||
7476 | memcpy(&rts->ra, &h->addr2, ETH_ALEN); | |
7477 | } else { | |
7478 | rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | |
7479 | IEEE80211_STYPE_RTS); | |
7480 | ||
7481 | memcpy(&rts->ra, &h->addr1, 2 * ETH_ALEN); | |
7482 | } | |
7483 | ||
7484 | /* mainrate | |
7485 | * low 8 bits: main frag rate/mcs, | |
7486 | * high 8 bits: rts/cts rate/mcs | |
7487 | */ | |
7488 | mainrates |= (IS_OFDM(rts_rspec[0]) ? | |
7489 | D11A_PHY_HDR_GRATE( | |
7490 | (struct ofdm_phy_hdr *) rts_plcp) : | |
7491 | rts_plcp[0]) << 8; | |
7492 | } else { | |
7493 | memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN); | |
7494 | memset((char *)&txh->rts_frame, 0, | |
7495 | sizeof(struct ieee80211_rts)); | |
7496 | memset((char *)txh->RTSPLCPFallback, 0, | |
7497 | sizeof(txh->RTSPLCPFallback)); | |
7498 | txh->RTSDurFallback = 0; | |
7499 | } | |
a9533e7e | 7500 | |
2682e2a3 AS |
7501 | #ifdef SUPPORT_40MHZ |
7502 | /* add null delimiter count */ | |
7503 | if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && IS_MCS(rspec)) | |
7504 | txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = | |
7505 | brcm_c_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen); | |
a9533e7e | 7506 | |
2682e2a3 | 7507 | #endif |
8ea54c9f | 7508 | |
2682e2a3 AS |
7509 | /* |
7510 | * Now that RTS/RTS FB preamble types are updated, write | |
7511 | * the final value | |
7512 | */ | |
7513 | txh->MacTxControlHigh = cpu_to_le16(mch); | |
a9533e7e | 7514 | |
2682e2a3 AS |
7515 | /* |
7516 | * MainRates (both the rts and frag plcp rates have | |
7517 | * been calculated now) | |
7518 | */ | |
7519 | txh->MainRates = cpu_to_le16(mainrates); | |
a9533e7e | 7520 | |
2682e2a3 AS |
7521 | /* XtraFrameTypes */ |
7522 | xfts = FRAMETYPE(rspec[1], wlc->mimoft); | |
7523 | xfts |= (FRAMETYPE(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT); | |
7524 | xfts |= (FRAMETYPE(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT); | |
7525 | xfts |= | |
7526 | CHSPEC_CHANNEL(BRCMS_BAND_PI_RADIO_CHANSPEC) << XFTS_CHANNEL_SHIFT; | |
7527 | txh->XtraFrameTypes = cpu_to_le16(xfts); | |
a9533e7e | 7528 | |
2682e2a3 AS |
7529 | /* PhyTxControlWord */ |
7530 | phyctl = FRAMETYPE(rspec[0], wlc->mimoft); | |
7531 | if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) || | |
7532 | (preamble_type[0] == BRCMS_GF_PREAMBLE)) { | |
7533 | if (RSPEC2RATE(rspec[0]) != BRCM_RATE_1M) | |
7534 | phyctl |= PHY_TXC_SHORT_HDR; | |
7535 | } | |
a9533e7e | 7536 | |
2682e2a3 AS |
7537 | /* phytxant is properly bit shifted */ |
7538 | phyctl |= brcms_c_stf_d11hdrs_phyctl_txant(wlc, rspec[0]); | |
7539 | txh->PhyTxControlWord = cpu_to_le16(phyctl); | |
a9533e7e | 7540 | |
2682e2a3 AS |
7541 | /* PhyTxControlWord_1 */ |
7542 | if (BRCMS_PHY_11N_CAP(wlc->band)) { | |
7543 | u16 phyctl1 = 0; | |
a9533e7e | 7544 | |
2682e2a3 AS |
7545 | phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[0]); |
7546 | txh->PhyTxControlWord_1 = cpu_to_le16(phyctl1); | |
7547 | phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[1]); | |
7548 | txh->PhyTxControlWord_1_Fbr = cpu_to_le16(phyctl1); | |
a9533e7e | 7549 | |
2682e2a3 AS |
7550 | if (use_rts || use_cts) { |
7551 | phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[0]); | |
7552 | txh->PhyTxControlWord_1_Rts = cpu_to_le16(phyctl1); | |
7553 | phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[1]); | |
7554 | txh->PhyTxControlWord_1_FbrRts = cpu_to_le16(phyctl1); | |
a9533e7e | 7555 | } |
a9533e7e | 7556 | |
2682e2a3 AS |
7557 | /* |
7558 | * For mcs frames, if mixedmode(overloaded with long preamble) | |
7559 | * is going to be set, fill in non-zero MModeLen and/or | |
7560 | * MModeFbrLen it will be unnecessary if they are separated | |
7561 | */ | |
7562 | if (IS_MCS(rspec[0]) && | |
7563 | (preamble_type[0] == BRCMS_MM_PREAMBLE)) { | |
7564 | u16 mmodelen = | |
7565 | brcms_c_calc_lsig_len(wlc, rspec[0], phylen); | |
7566 | txh->MModeLen = cpu_to_le16(mmodelen); | |
7567 | } | |
7568 | ||
7569 | if (IS_MCS(rspec[1]) && | |
7570 | (preamble_type[1] == BRCMS_MM_PREAMBLE)) { | |
7571 | u16 mmodefbrlen = | |
7572 | brcms_c_calc_lsig_len(wlc, rspec[1], phylen); | |
7573 | txh->MModeFbrLen = cpu_to_le16(mmodefbrlen); | |
a9533e7e HP |
7574 | } |
7575 | } | |
7576 | ||
2682e2a3 AS |
7577 | ac = skb_get_queue_mapping(p); |
7578 | if (SCB_WME(scb) && qos && wlc->edcf_txop[ac]) { | |
7579 | uint frag_dur, dur, dur_fallback; | |
a9533e7e | 7580 | |
2682e2a3 AS |
7581 | /* WME: Update TXOP threshold */ |
7582 | if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) && frag == 0) { | |
7583 | frag_dur = | |
7584 | brcms_c_calc_frame_time(wlc, rspec[0], | |
7585 | preamble_type[0], phylen); | |
fd821d1e | 7586 | |
2682e2a3 AS |
7587 | if (rts) { |
7588 | /* 1 RTS or CTS-to-self frame */ | |
7589 | dur = | |
7590 | brcms_c_calc_cts_time(wlc, rts_rspec[0], | |
7591 | rts_preamble_type[0]); | |
7592 | dur_fallback = | |
7593 | brcms_c_calc_cts_time(wlc, rts_rspec[1], | |
7594 | rts_preamble_type[1]); | |
7595 | /* (SIFS + CTS) + SIFS + frame + SIFS + ACK */ | |
7596 | dur += le16_to_cpu(rts->duration); | |
7597 | dur_fallback += | |
7598 | le16_to_cpu(txh->RTSDurFallback); | |
7599 | } else if (use_rifs) { | |
7600 | dur = frag_dur; | |
7601 | dur_fallback = 0; | |
7602 | } else { | |
7603 | /* frame + SIFS + ACK */ | |
7604 | dur = frag_dur; | |
7605 | dur += | |
7606 | brcms_c_compute_frame_dur(wlc, rspec[0], | |
7607 | preamble_type[0], 0); | |
a9533e7e | 7608 | |
2682e2a3 AS |
7609 | dur_fallback = |
7610 | brcms_c_calc_frame_time(wlc, rspec[1], | |
7611 | preamble_type[1], | |
7612 | phylen); | |
7613 | dur_fallback += | |
7614 | brcms_c_compute_frame_dur(wlc, rspec[1], | |
7615 | preamble_type[1], 0); | |
7616 | } | |
7617 | /* NEED to set TxFesTimeNormal (hard) */ | |
7618 | txh->TxFesTimeNormal = cpu_to_le16((u16) dur); | |
7619 | /* | |
7620 | * NEED to set fallback rate version of | |
7621 | * TxFesTimeNormal (hard) | |
7622 | */ | |
7623 | txh->TxFesTimeFallback = | |
7624 | cpu_to_le16((u16) dur_fallback); | |
a9533e7e | 7625 | |
2682e2a3 AS |
7626 | /* |
7627 | * update txop byte threshold (txop minus intraframe | |
7628 | * overhead) | |
7629 | */ | |
7630 | if (wlc->edcf_txop[ac] >= (dur - frag_dur)) { | |
7631 | uint newfragthresh; | |
a9533e7e | 7632 | |
2682e2a3 AS |
7633 | newfragthresh = |
7634 | brcms_c_calc_frame_len(wlc, | |
7635 | rspec[0], preamble_type[0], | |
7636 | (wlc->edcf_txop[ac] - | |
7637 | (dur - frag_dur))); | |
7638 | /* range bound the fragthreshold */ | |
7639 | if (newfragthresh < DOT11_MIN_FRAG_LEN) | |
7640 | newfragthresh = | |
7641 | DOT11_MIN_FRAG_LEN; | |
7642 | else if (newfragthresh > | |
7643 | wlc->usr_fragthresh) | |
7644 | newfragthresh = | |
7645 | wlc->usr_fragthresh; | |
7646 | /* update the fragthresh and do txc update */ | |
7647 | if (wlc->fragthresh[queue] != | |
7648 | (u16) newfragthresh) | |
7649 | wlc->fragthresh[queue] = | |
7650 | (u16) newfragthresh; | |
7651 | } else { | |
7652 | wiphy_err(wlc->wiphy, "wl%d: %s txop invalid " | |
7653 | "for rate %d\n", | |
7654 | wlc->pub->unit, fifo_names[queue], | |
7655 | RSPEC2RATE(rspec[0])); | |
7656 | } | |
a9533e7e | 7657 | |
2682e2a3 AS |
7658 | if (dur > wlc->edcf_txop[ac]) |
7659 | wiphy_err(wlc->wiphy, "wl%d: %s: %s txop " | |
7660 | "exceeded phylen %d/%d dur %d/%d\n", | |
7661 | wlc->pub->unit, __func__, | |
7662 | fifo_names[queue], | |
7663 | phylen, wlc->fragthresh[queue], | |
7664 | dur, wlc->edcf_txop[ac]); | |
7665 | } | |
a9533e7e HP |
7666 | } |
7667 | ||
2682e2a3 AS |
7668 | return 0; |
7669 | } | |
a9533e7e | 7670 | |
2682e2a3 AS |
7671 | bool |
7672 | brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, | |
7673 | struct ieee80211_hw *hw) | |
7674 | { | |
7675 | u8 prio; | |
7676 | uint fifo; | |
7677 | struct scb *scb = &global_scb; | |
7678 | struct ieee80211_hdr *d11_header = (struct ieee80211_hdr *)(sdu->data); | |
a9533e7e | 7679 | |
2682e2a3 AS |
7680 | /* |
7681 | * 802.11 standard requires management traffic | |
7682 | * to go at highest priority | |
7683 | */ | |
7684 | prio = ieee80211_is_data(d11_header->frame_control) ? sdu->priority : | |
7685 | MAXPRIO; | |
7686 | fifo = prio2fifo[prio]; | |
7687 | if (unlikely | |
7688 | (brcms_c_d11hdrs_mac80211( | |
7689 | wlc, hw, sdu, scb, 0, 1, fifo, 0, NULL, 0))) | |
7690 | return -EINVAL; | |
7691 | brcms_c_txq_enq(wlc, scb, sdu, BRCMS_PRIO_TO_PREC(prio)); | |
7692 | brcms_c_send_q(wlc); | |
7693 | return 0; | |
7694 | } | |
a9533e7e | 7695 | |
2682e2a3 AS |
7696 | void brcms_c_send_q(struct brcms_c_info *wlc) |
7697 | { | |
7698 | struct sk_buff *pkt[DOT11_MAXNUMFRAGS]; | |
7699 | int prec; | |
7700 | u16 prec_map; | |
7701 | int err = 0, i, count; | |
7702 | uint fifo; | |
7703 | struct brcms_txq_info *qi = wlc->pkt_queue; | |
7704 | struct pktq *q = &qi->q; | |
7705 | struct ieee80211_tx_info *tx_info; | |
a9533e7e | 7706 | |
2682e2a3 AS |
7707 | if (in_send_q) |
7708 | return; | |
7709 | else | |
7710 | in_send_q = true; | |
a9533e7e | 7711 | |
2682e2a3 | 7712 | prec_map = wlc->tx_prec_map; |
a9533e7e | 7713 | |
2682e2a3 AS |
7714 | /* Send all the enq'd pkts that we can. |
7715 | * Dequeue packets with precedence with empty HW fifo only | |
7716 | */ | |
7717 | while (prec_map && (pkt[0] = brcmu_pktq_mdeq(q, prec_map, &prec))) { | |
7718 | tx_info = IEEE80211_SKB_CB(pkt[0]); | |
7719 | if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { | |
7720 | err = brcms_c_sendampdu(wlc->ampdu, qi, pkt, prec); | |
7721 | } else { | |
7722 | count = 1; | |
7723 | err = brcms_c_prep_pdu(wlc, pkt[0], &fifo); | |
7724 | if (!err) { | |
7725 | for (i = 0; i < count; i++) | |
7726 | brcms_c_txfifo(wlc, fifo, pkt[i], true, | |
7727 | 1); | |
7728 | } | |
7729 | } | |
a9533e7e | 7730 | |
2682e2a3 AS |
7731 | if (err == -EBUSY) { |
7732 | brcmu_pktq_penq_head(q, prec, pkt[0]); | |
7733 | /* | |
7734 | * If send failed due to any other reason than a | |
7735 | * change in HW FIFO condition, quit. Otherwise, | |
7736 | * read the new prec_map! | |
7737 | */ | |
7738 | if (prec_map == wlc->tx_prec_map) | |
7739 | break; | |
7740 | prec_map = wlc->tx_prec_map; | |
7741 | } | |
a9533e7e HP |
7742 | } |
7743 | ||
419ad34e | 7744 | /* |
2682e2a3 AS |
7745 | * Check if flow control needs to be turned off after |
7746 | * sending the packet | |
72345923 | 7747 | */ |
2682e2a3 AS |
7748 | if (!EDCF_ENAB(wlc->pub) |
7749 | || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL)) { | |
7750 | if (brcms_c_txflowcontrol_prio_isset(wlc, qi, ALLPRIO) | |
7751 | && (pktq_len(q) < wlc->pub->tunables->datahiwat / 2)) | |
7752 | brcms_c_txflowcontrol(wlc, qi, OFF, ALLPRIO); | |
7753 | } else if (wlc->pub->_priofc) { | |
7754 | int prio; | |
7755 | for (prio = MAXPRIO; prio >= 0; prio--) { | |
7756 | if (brcms_c_txflowcontrol_prio_isset(wlc, qi, prio) && | |
7757 | (pktq_plen(q, wlc_prio2prec_map[prio]) < | |
7758 | wlc->pub->tunables->datahiwat / 2)) | |
7759 | brcms_c_txflowcontrol(wlc, qi, OFF, prio); | |
a9533e7e | 7760 | } |
2682e2a3 AS |
7761 | } |
7762 | in_send_q = false; | |
7763 | } | |
a9533e7e | 7764 | |
2682e2a3 AS |
7765 | static void brcms_c_war16165(struct brcms_c_info *wlc, bool tx) |
7766 | { | |
7767 | if (tx) { | |
7768 | /* the post-increment is used in STAY_AWAKE macro */ | |
7769 | if (wlc->txpend16165war++ == 0) | |
7770 | brcms_c_set_ps_ctrl(wlc); | |
7771 | } else { | |
7772 | wlc->txpend16165war--; | |
7773 | if (wlc->txpend16165war == 0) | |
7774 | brcms_c_set_ps_ctrl(wlc); | |
7775 | } | |
7776 | } | |
a9533e7e | 7777 | |
2682e2a3 AS |
7778 | void |
7779 | brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p, | |
7780 | bool commit, s8 txpktpend) | |
7781 | { | |
7782 | u16 frameid = INVALIDFID; | |
7783 | struct d11txh *txh; | |
a9533e7e | 7784 | |
2682e2a3 | 7785 | txh = (struct d11txh *) (p->data); |
a9533e7e | 7786 | |
2682e2a3 AS |
7787 | /* When a BC/MC frame is being committed to the BCMC fifo |
7788 | * via DMA (NOT PIO), update ucode or BSS info as appropriate. | |
7789 | */ | |
7790 | if (fifo == TX_BCMC_FIFO) | |
7791 | frameid = le16_to_cpu(txh->TxFrameID); | |
a9533e7e | 7792 | |
2682e2a3 AS |
7793 | if (BRCMS_WAR16165(wlc)) |
7794 | brcms_c_war16165(wlc, true); | |
a9533e7e | 7795 | |
a9533e7e | 7796 | |
2682e2a3 AS |
7797 | /* |
7798 | * Bump up pending count for if not using rpc. If rpc is | |
7799 | * used, this will be handled in brcms_b_txfifo() | |
7800 | */ | |
7801 | if (commit) { | |
7802 | TXPKTPENDINC(wlc, fifo, txpktpend); | |
7803 | BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n", | |
7804 | txpktpend, TXPKTPENDGET(wlc, fifo)); | |
7805 | } | |
a9533e7e | 7806 | |
2682e2a3 AS |
7807 | /* Commit BCMC sequence number in the SHM frame ID location */ |
7808 | if (frameid != INVALIDFID) | |
7809 | BCMCFID(wlc, frameid); | |
a9533e7e | 7810 | |
2682e2a3 AS |
7811 | if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0) |
7812 | wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n"); | |
7813 | } | |
2fbd6b37 | 7814 | |
2682e2a3 AS |
7815 | /* |
7816 | * Compute PLCP, but only requires actual rate and length of pkt. | |
7817 | * Rate is given in the driver standard multiple of 500 kbps. | |
7818 | * le is set for 11 Mbps rate if necessary. | |
7819 | * Broken out for PRQ. | |
7820 | */ | |
7821 | ||
7822 | static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500, | |
7823 | uint length, u8 *plcp) | |
7824 | { | |
7825 | u16 usec = 0; | |
7826 | u8 le = 0; | |
2fbd6b37 | 7827 | |
2682e2a3 AS |
7828 | switch (rate_500) { |
7829 | case BRCM_RATE_1M: | |
7830 | usec = length << 3; | |
7831 | break; | |
7832 | case BRCM_RATE_2M: | |
7833 | usec = length << 2; | |
7834 | break; | |
7835 | case BRCM_RATE_5M5: | |
7836 | usec = (length << 4) / 11; | |
7837 | if ((length << 4) - (usec * 11) > 0) | |
7838 | usec++; | |
7839 | break; | |
7840 | case BRCM_RATE_11M: | |
7841 | usec = (length << 3) / 11; | |
7842 | if ((length << 3) - (usec * 11) > 0) { | |
7843 | usec++; | |
7844 | if ((usec * 11) - (length << 3) >= 8) | |
7845 | le = D11B_PLCP_SIGNAL_LE; | |
a9533e7e | 7846 | } |
2682e2a3 | 7847 | break; |
a9533e7e | 7848 | |
2682e2a3 AS |
7849 | default: |
7850 | wiphy_err(wlc->wiphy, | |
7851 | "brcms_c_cck_plcp_set: unsupported rate %d\n", | |
7852 | rate_500); | |
7853 | rate_500 = BRCM_RATE_1M; | |
7854 | usec = length << 3; | |
7855 | break; | |
a9533e7e | 7856 | } |
2682e2a3 AS |
7857 | /* PLCP signal byte */ |
7858 | plcp[0] = rate_500 * 5; /* r (500kbps) * 5 == r (100kbps) */ | |
7859 | /* PLCP service byte */ | |
7860 | plcp[1] = (u8) (le | D11B_PLCP_SIGNAL_LOCKED); | |
7861 | /* PLCP length u16, little endian */ | |
7862 | plcp[2] = usec & 0xff; | |
7863 | plcp[3] = (usec >> 8) & 0xff; | |
7864 | /* PLCP CRC16 */ | |
7865 | plcp[4] = 0; | |
7866 | plcp[5] = 0; | |
7867 | } | |
a9533e7e | 7868 | |
2682e2a3 AS |
7869 | /* Rate: 802.11 rate code, length: PSDU length in octets */ |
7870 | static void brcms_c_compute_mimo_plcp(u32 rspec, uint length, u8 *plcp) | |
7871 | { | |
7872 | u8 mcs = (u8) (rspec & RSPEC_RATE_MASK); | |
7873 | plcp[0] = mcs; | |
7874 | if (RSPEC_IS40MHZ(rspec) || (mcs == 32)) | |
7875 | plcp[0] |= MIMO_PLCP_40MHZ; | |
7876 | BRCMS_SET_MIMO_PLCP_LEN(plcp, length); | |
7877 | plcp[3] = RSPEC_MIMOPLCP3(rspec); /* rspec already holds this byte */ | |
7878 | plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */ | |
7879 | plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */ | |
7880 | plcp[5] = 0; | |
7881 | } | |
8ea54c9f | 7882 | |
2682e2a3 AS |
7883 | /* Rate: 802.11 rate code, length: PSDU length in octets */ |
7884 | static void | |
7885 | brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp) | |
7886 | { | |
7887 | u8 rate_signal; | |
7888 | u32 tmp = 0; | |
7889 | int rate = RSPEC2RATE(rspec); | |
a9533e7e | 7890 | |
419ad34e | 7891 | /* |
2682e2a3 AS |
7892 | * encode rate per 802.11a-1999 sec 17.3.4.1, with lsb |
7893 | * transmitted first | |
419ad34e | 7894 | */ |
2682e2a3 AS |
7895 | rate_signal = rate_info[rate] & BRCMS_RATE_MASK; |
7896 | memset(plcp, 0, D11_PHY_HDR_LEN); | |
7897 | D11A_PHY_HDR_SRATE((struct ofdm_phy_hdr *) plcp, rate_signal); | |
a9533e7e | 7898 | |
2682e2a3 AS |
7899 | tmp = (length & 0xfff) << 5; |
7900 | plcp[2] |= (tmp >> 16) & 0xff; | |
7901 | plcp[1] |= (tmp >> 8) & 0xff; | |
7902 | plcp[0] |= tmp & 0xff; | |
a9533e7e | 7903 | |
2682e2a3 AS |
7904 | return; |
7905 | } | |
a9533e7e | 7906 | |
2682e2a3 AS |
7907 | /* Rate: 802.11 rate code, length: PSDU length in octets */ |
7908 | static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rspec, | |
7909 | uint length, u8 *plcp) | |
7910 | { | |
7911 | int rate = RSPEC2RATE(rspec); | |
a9533e7e | 7912 | |
2682e2a3 AS |
7913 | brcms_c_cck_plcp_set(wlc, rate, length, plcp); |
7914 | } | |
a9533e7e | 7915 | |
2682e2a3 AS |
7916 | void |
7917 | brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec, | |
7918 | uint length, u8 *plcp) | |
7919 | { | |
7920 | if (IS_MCS(rspec)) | |
7921 | brcms_c_compute_mimo_plcp(rspec, length, plcp); | |
7922 | else if (IS_OFDM(rspec)) | |
7923 | brcms_c_compute_ofdm_plcp(rspec, length, plcp); | |
7924 | else | |
7925 | brcms_c_compute_cck_plcp(wlc, rspec, length, plcp); | |
7926 | return; | |
7927 | } | |
a9533e7e | 7928 | |
2682e2a3 AS |
7929 | /* brcms_c_compute_rtscts_dur() |
7930 | * | |
7931 | * Calculate the 802.11 MAC header DUR field for an RTS or CTS frame | |
7932 | * DUR for normal RTS/CTS w/ frame = 3 SIFS + 1 CTS + next frame time + 1 ACK | |
7933 | * DUR for CTS-TO-SELF w/ frame = 2 SIFS + next frame time + 1 ACK | |
7934 | * | |
7935 | * cts cts-to-self or rts/cts | |
7936 | * rts_rate rts or cts rate in unit of 500kbps | |
7937 | * rate next MPDU rate in unit of 500kbps | |
7938 | * frame_len next MPDU frame length in bytes | |
7939 | */ | |
7940 | u16 | |
7941 | brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only, | |
7942 | u32 rts_rate, | |
7943 | u32 frame_rate, u8 rts_preamble_type, | |
7944 | u8 frame_preamble_type, uint frame_len, bool ba) | |
7945 | { | |
7946 | u16 dur, sifs; | |
a9533e7e | 7947 | |
2682e2a3 | 7948 | sifs = SIFS(wlc->band); |
a9533e7e | 7949 | |
2682e2a3 AS |
7950 | if (!cts_only) { |
7951 | /* RTS/CTS */ | |
7952 | dur = 3 * sifs; | |
7953 | dur += | |
7954 | (u16) brcms_c_calc_cts_time(wlc, rts_rate, | |
7955 | rts_preamble_type); | |
7956 | } else { | |
7957 | /* CTS-TO-SELF */ | |
7958 | dur = 2 * sifs; | |
7959 | } | |
a9533e7e | 7960 | |
2682e2a3 AS |
7961 | dur += |
7962 | (u16) brcms_c_calc_frame_time(wlc, frame_rate, frame_preamble_type, | |
7963 | frame_len); | |
7964 | if (ba) | |
7965 | dur += | |
7966 | (u16) brcms_c_calc_ba_time(wlc, frame_rate, | |
7967 | BRCMS_SHORT_PREAMBLE); | |
7968 | else | |
7969 | dur += | |
7970 | (u16) brcms_c_calc_ack_time(wlc, frame_rate, | |
7971 | frame_preamble_type); | |
7972 | return dur; | |
7973 | } | |
7974 | ||
7975 | u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec) | |
7976 | { | |
7977 | u16 phyctl1 = 0; | |
7978 | u16 bw; | |
7979 | ||
7980 | if (BRCMS_ISLCNPHY(wlc->band)) { | |
7981 | bw = PHY_TXC1_BW_20MHZ; | |
7982 | } else { | |
7983 | bw = RSPEC_GET_BW(rspec); | |
7984 | /* 10Mhz is not supported yet */ | |
7985 | if (bw < PHY_TXC1_BW_20MHZ) { | |
7986 | wiphy_err(wlc->wiphy, "phytxctl1_calc: bw %d is " | |
7987 | "not supported yet, set to 20L\n", bw); | |
7988 | bw = PHY_TXC1_BW_20MHZ; | |
a9533e7e HP |
7989 | } |
7990 | } | |
7991 | ||
2682e2a3 AS |
7992 | if (IS_MCS(rspec)) { |
7993 | uint mcs = rspec & RSPEC_RATE_MASK; | |
a9533e7e | 7994 | |
2682e2a3 AS |
7995 | /* bw, stf, coding-type is part of RSPEC_PHYTXBYTE2 returns */ |
7996 | phyctl1 = RSPEC_PHYTXBYTE2(rspec); | |
7997 | /* set the upper byte of phyctl1 */ | |
7998 | phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8); | |
7999 | } else if (IS_CCK(rspec) && !BRCMS_ISLCNPHY(wlc->band) | |
8000 | && !BRCMS_ISSSLPNPHY(wlc->band)) { | |
8001 | /* | |
8002 | * In CCK mode LPPHY overloads OFDM Modulation bits with CCK | |
8003 | * Data Rate. Eventually MIMOPHY would also be converted to | |
8004 | * this format | |
8005 | */ | |
8006 | /* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */ | |
8007 | phyctl1 = (bw | (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT)); | |
8008 | } else { /* legacy OFDM/CCK */ | |
8009 | s16 phycfg; | |
8010 | /* get the phyctl byte from rate phycfg table */ | |
8011 | phycfg = brcms_c_rate_legacy_phyctl(RSPEC2RATE(rspec)); | |
8012 | if (phycfg == -1) { | |
8013 | wiphy_err(wlc->wiphy, "phytxctl1_calc: wrong " | |
8014 | "legacy OFDM/CCK rate\n"); | |
8015 | phycfg = 0; | |
8016 | } | |
8017 | /* set the upper byte of phyctl1 */ | |
8018 | phyctl1 = | |
8019 | (bw | (phycfg << 8) | | |
8020 | (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT)); | |
8021 | } | |
8022 | return phyctl1; | |
8023 | } | |
a9533e7e | 8024 | |
2682e2a3 AS |
8025 | u32 |
8026 | brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec, | |
8027 | bool use_rspec, u16 mimo_ctlchbw) | |
8028 | { | |
8029 | u32 rts_rspec = 0; | |
a9533e7e | 8030 | |
2682e2a3 AS |
8031 | if (use_rspec) |
8032 | /* use frame rate as rts rate */ | |
8033 | rts_rspec = rspec; | |
8034 | else if (wlc->band->gmode && wlc->protection->_g && !IS_CCK(rspec)) | |
8035 | /* Use 11Mbps as the g protection RTS target rate and fallback. | |
8036 | * Use the BRCMS_BASIC_RATE() lookup to find the best basic rate | |
8037 | * under the target in case 11 Mbps is not Basic. | |
8038 | * 6 and 9 Mbps are not usually selected by rate selection, but | |
8039 | * even if the OFDM rate we are protecting is 6 or 9 Mbps, 11 | |
8040 | * is more robust. | |
8041 | */ | |
8042 | rts_rspec = BRCMS_BASIC_RATE(wlc, BRCM_RATE_11M); | |
8043 | else | |
8044 | /* calculate RTS rate and fallback rate based on the frame rate | |
8045 | * RTS must be sent at a basic rate since it is a | |
8046 | * control frame, sec 9.6 of 802.11 spec | |
8047 | */ | |
8048 | rts_rspec = BRCMS_BASIC_RATE(wlc, rspec); | |
a9533e7e | 8049 | |
2682e2a3 AS |
8050 | if (BRCMS_PHY_11N_CAP(wlc->band)) { |
8051 | /* set rts txbw to correct side band */ | |
8052 | rts_rspec &= ~RSPEC_BW_MASK; | |
8ea54c9f | 8053 | |
2682e2a3 AS |
8054 | /* |
8055 | * if rspec/rspec_fallback is 40MHz, then send RTS on both | |
8056 | * 20MHz channel (DUP), otherwise send RTS on control channel | |
8057 | */ | |
8058 | if (RSPEC_IS40MHZ(rspec) && !IS_CCK(rts_rspec)) | |
8059 | rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT); | |
8060 | else | |
8061 | rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT); | |
a9533e7e | 8062 | |
2682e2a3 AS |
8063 | /* pick siso/cdd as default for ofdm */ |
8064 | if (IS_OFDM(rts_rspec)) { | |
8065 | rts_rspec &= ~RSPEC_STF_MASK; | |
8066 | rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT); | |
a9533e7e HP |
8067 | } |
8068 | } | |
2682e2a3 | 8069 | return rts_rspec; |
a9533e7e HP |
8070 | } |
8071 | ||
fe741e5e | 8072 | void brcms_c_tbtt(struct brcms_c_info *wlc) |
a9533e7e | 8073 | { |
471f1b51 | 8074 | struct brcms_bss_cfg *cfg = wlc->cfg; |
a9533e7e | 8075 | |
8ea54c9f | 8076 | if (!cfg->BSS) |
419ad34e AS |
8077 | /* |
8078 | * DirFrmQ is now valid...defer setting until end | |
8079 | * of ATIM window | |
8080 | */ | |
a9533e7e | 8081 | wlc->qvalid |= MCMD_DIRFRMQVAL; |
a9533e7e HP |
8082 | } |
8083 | ||
cc87568a | 8084 | /* process an individual struct tx_status */ |
de91ed29 | 8085 | bool |
cc87568a | 8086 | brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs, u32 frm_tx2) |
a9533e7e | 8087 | { |
c26b1378 | 8088 | struct sk_buff *p; |
a9533e7e | 8089 | uint queue; |
cc87568a | 8090 | struct d11txh *txh; |
a9533e7e HP |
8091 | struct scb *scb = NULL; |
8092 | bool free_pdu; | |
a9533e7e HP |
8093 | int tx_rts, tx_frame_count, tx_rts_count; |
8094 | uint totlen, supr_status; | |
8095 | bool lastframe; | |
3e9796f9 | 8096 | struct ieee80211_hdr *h; |
7d4df48e | 8097 | u16 mcl; |
a9533e7e HP |
8098 | struct ieee80211_tx_info *tx_info; |
8099 | struct ieee80211_tx_rate *txrate; | |
8100 | int i; | |
8101 | ||
419ad34e AS |
8102 | /* Compiler reference to avoid unused variable warning */ |
8103 | (void)(frm_tx2); | |
a9533e7e HP |
8104 | |
8105 | /* discard intermediate indications for ucode with one legitimate case: | |
419ad34e AS |
8106 | * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, |
8107 | * but the subsequent tx of DATA failed. so it will start rts/cts | |
8108 | * from the beginning (resetting the rts transmission count) | |
a9533e7e HP |
8109 | */ |
8110 | if (!(txs->status & TX_STATUS_AMPDU) | |
8111 | && (txs->status & TX_STATUS_INTERMEDIATE)) { | |
b8f092c9 RV |
8112 | wiphy_err(wlc->wiphy, "%s: INTERMEDIATE but not AMPDU\n", |
8113 | __func__); | |
0965ae88 | 8114 | return false; |
a9533e7e HP |
8115 | } |
8116 | ||
a9533e7e | 8117 | queue = txs->frameid & TXFID_QUEUE_MASK; |
a9533e7e HP |
8118 | if (queue >= NFIFO) { |
8119 | p = NULL; | |
8120 | goto fatal; | |
8121 | } | |
8122 | ||
8123 | p = GETNEXTTXP(wlc, queue); | |
7c783cef | 8124 | if (BRCMS_WAR16165(wlc)) |
1c4c54ba | 8125 | brcms_c_war16165(wlc, false); |
a9533e7e HP |
8126 | if (p == NULL) |
8127 | goto fatal; | |
8128 | ||
cc87568a | 8129 | txh = (struct d11txh *) (p->data); |
628f10ba | 8130 | mcl = le16_to_cpu(txh->MacTxControlLow); |
a9533e7e HP |
8131 | |
8132 | if (txs->phyerr) { | |
bc042b67 | 8133 | if (WL_ERROR_ON()) { |
b8f092c9 RV |
8134 | wiphy_err(wlc->wiphy, "phyerr 0x%x, rate 0x%x\n", |
8135 | txs->phyerr, txh->MainRates); | |
fe741e5e | 8136 | brcms_c_print_txdesc(txh); |
bc042b67 | 8137 | } |
fe741e5e | 8138 | brcms_c_print_txstatus(txs); |
a9533e7e HP |
8139 | } |
8140 | ||
628f10ba | 8141 | if (txs->frameid != cpu_to_le16(txh->TxFrameID)) |
a9533e7e | 8142 | goto fatal; |
a9533e7e | 8143 | tx_info = IEEE80211_SKB_CB(p); |
3e9796f9 | 8144 | h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN); |
a9533e7e | 8145 | |
8ada0be3 RV |
8146 | if (tx_info->control.sta) |
8147 | scb = (struct scb *)tx_info->control.sta->drv_priv; | |
a9533e7e | 8148 | |
a9533e7e | 8149 | if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { |
f52a0ad0 | 8150 | brcms_c_ampdu_dotxstatus(wlc->ampdu, scb, p, txs); |
0965ae88 | 8151 | return false; |
a9533e7e HP |
8152 | } |
8153 | ||
8154 | supr_status = txs->status & TX_STATUS_SUPR_MASK; | |
8155 | if (supr_status == TX_STATUS_SUPR_BADCH) | |
222508d7 RV |
8156 | BCMMSG(wlc->wiphy, |
8157 | "%s: Pkt tx suppressed, possibly channel %d\n", | |
8158 | __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec)); | |
a9533e7e | 8159 | |
628f10ba | 8160 | tx_rts = cpu_to_le16(txh->MacTxControlLow) & TXC_SENDRTS; |
a9533e7e HP |
8161 | tx_frame_count = |
8162 | (txs->status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT; | |
8163 | tx_rts_count = | |
8164 | (txs->status & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT; | |
8165 | ||
2fbd6b37 | 8166 | lastframe = !ieee80211_has_morefrags(h->frame_control); |
a9533e7e HP |
8167 | |
8168 | if (!lastframe) { | |
b8f092c9 | 8169 | wiphy_err(wlc->wiphy, "Not last frame!\n"); |
a9533e7e | 8170 | } else { |
94daaf70 RV |
8171 | /* |
8172 | * Set information to be consumed by Minstrel ht. | |
8173 | * | |
8174 | * The "fallback limit" is the number of tx attempts a given | |
8175 | * MPDU is sent at the "primary" rate. Tx attempts beyond that | |
8176 | * limit are sent at the "secondary" rate. | |
8177 | * A 'short frame' does not exceed RTS treshold. | |
8178 | */ | |
8179 | u16 sfbl, /* Short Frame Rate Fallback Limit */ | |
8180 | lfbl, /* Long Frame Rate Fallback Limit */ | |
8181 | fbl; | |
8182 | ||
a9533e7e | 8183 | if (queue < AC_COUNT) { |
7c783cef RV |
8184 | sfbl = BRCMS_WME_RETRY_SFB_GET(wlc, wme_fifo2ac[queue]); |
8185 | lfbl = BRCMS_WME_RETRY_LFB_GET(wlc, wme_fifo2ac[queue]); | |
a9533e7e HP |
8186 | } else { |
8187 | sfbl = wlc->SFBL; | |
8188 | lfbl = wlc->LFBL; | |
8189 | } | |
8190 | ||
8191 | txrate = tx_info->status.rates; | |
94daaf70 RV |
8192 | if (txrate[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) |
8193 | fbl = lfbl; | |
8194 | else | |
8195 | fbl = sfbl; | |
8196 | ||
8197 | ieee80211_tx_info_clear_status(tx_info); | |
8198 | ||
8199 | if ((tx_frame_count > fbl) && (txrate[1].idx >= 0)) { | |
419ad34e AS |
8200 | /* |
8201 | * rate selection requested a fallback rate | |
8202 | * and we used it | |
8203 | */ | |
94daaf70 RV |
8204 | txrate[0].count = fbl; |
8205 | txrate[1].count = tx_frame_count - fbl; | |
a9533e7e | 8206 | } else { |
419ad34e AS |
8207 | /* |
8208 | * rate selection did not request fallback rate, or | |
8209 | * we didn't need it | |
8210 | */ | |
94daaf70 | 8211 | txrate[0].count = tx_frame_count; |
419ad34e AS |
8212 | /* |
8213 | * rc80211_minstrel.c:minstrel_tx_status() expects | |
8214 | * unused rates to be marked with idx = -1 | |
8215 | */ | |
a9533e7e HP |
8216 | txrate[1].idx = -1; |
8217 | txrate[1].count = 0; | |
8218 | } | |
8219 | ||
8220 | /* clear the rest of the rates */ | |
8221 | for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) { | |
8222 | txrate[i].idx = -1; | |
8223 | txrate[i].count = 0; | |
8224 | } | |
8225 | ||
8226 | if (txs->status & TX_STATUS_ACK_RCV) | |
8227 | tx_info->flags |= IEEE80211_TX_STAT_ACK; | |
8228 | } | |
8229 | ||
67ad48bc | 8230 | totlen = brcmu_pkttotlen(p); |
0f0881b0 | 8231 | free_pdu = true; |
a9533e7e | 8232 | |
fe741e5e | 8233 | brcms_c_txfifo_complete(wlc, queue, 1); |
a9533e7e HP |
8234 | |
8235 | if (lastframe) { | |
54991ad6 AS |
8236 | p->next = NULL; |
8237 | p->prev = NULL; | |
a9533e7e | 8238 | /* remove PLCP & Broadcom tx descriptor header */ |
c303ecbd AS |
8239 | skb_pull(p, D11_PHY_HDR_LEN); |
8240 | skb_pull(p, D11_TXH_LEN); | |
a9533e7e | 8241 | ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); |
a9533e7e | 8242 | } else { |
b8f092c9 RV |
8243 | wiphy_err(wlc->wiphy, "%s: Not last frame => not calling " |
8244 | "tx_status\n", __func__); | |
a9533e7e HP |
8245 | } |
8246 | ||
0965ae88 | 8247 | return false; |
a9533e7e HP |
8248 | |
8249 | fatal: | |
a9533e7e | 8250 | if (p) |
67ad48bc | 8251 | brcmu_pkt_buf_free_skb(p); |
a9533e7e | 8252 | |
0f0881b0 | 8253 | return true; |
a9533e7e HP |
8254 | |
8255 | } | |
8256 | ||
de91ed29 | 8257 | void |
fe741e5e | 8258 | brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, s8 txpktpend) |
a9533e7e HP |
8259 | { |
8260 | TXPKTPENDDEC(wlc, fifo, txpktpend); | |
792aa408 RV |
8261 | BCMMSG(wlc->wiphy, "pktpend dec %d to %d\n", txpktpend, |
8262 | TXPKTPENDGET(wlc, fifo)); | |
a9533e7e HP |
8263 | |
8264 | /* There is more room; mark precedences related to this FIFO sendable */ | |
7c783cef | 8265 | BRCMS_TX_FIFO_ENAB(wlc, fifo); |
a9533e7e | 8266 | |
a9533e7e HP |
8267 | /* Clear MHF2_TXBCMC_NOW flag if BCMC fifo has drained */ |
8268 | if (AP_ENAB(wlc->pub) && | |
8ea54c9f | 8269 | !TXPKTPENDGET(wlc, TX_BCMC_FIFO)) |
7c783cef | 8270 | brcms_c_mhf(wlc, MHF2, MHF2_TXBCMC_NOW, 0, BRCM_BAND_AUTO); |
a9533e7e HP |
8271 | |
8272 | /* figure out which bsscfg is being worked on... */ | |
8273 | } | |
8274 | ||
a9533e7e | 8275 | /* Update beacon listen interval in shared memory */ |
fe741e5e | 8276 | void brcms_c_bcn_li_upd(struct brcms_c_info *wlc) |
a9533e7e HP |
8277 | { |
8278 | if (AP_ENAB(wlc->pub)) | |
8279 | return; | |
8280 | ||
8281 | /* wake up every DTIM is the default */ | |
8282 | if (wlc->bcn_li_dtim == 1) | |
fe741e5e | 8283 | brcms_c_write_shm(wlc, M_BCN_LI, 0); |
a9533e7e | 8284 | else |
fe741e5e | 8285 | brcms_c_write_shm(wlc, M_BCN_LI, |
a9533e7e HP |
8286 | (wlc->bcn_li_dtim << 8) | wlc->bcn_li_bcn); |
8287 | } | |
8288 | ||
11431424 | 8289 | static void |
839f9f62 RV |
8290 | brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr, |
8291 | u32 *tsf_h_ptr) | |
8292 | { | |
0da64910 | 8293 | struct d11regs *regs = wlc_hw->regs; |
839f9f62 RV |
8294 | |
8295 | /* read the tsf timer low, then high to get an atomic read */ | |
8296 | *tsf_l_ptr = R_REG(®s->tsf_timerlow); | |
8297 | *tsf_h_ptr = R_REG(®s->tsf_timerhigh); | |
8298 | ||
8299 | return; | |
8300 | } | |
8301 | ||
88ddf0c9 AS |
8302 | /* |
8303 | * recover 64bit TSF value from the 16bit TSF value in the rx header | |
8304 | * given the assumption that the TSF passed in header is within 65ms | |
8305 | * of the current tsf. | |
8306 | * | |
8307 | * 6 5 4 4 3 2 1 | |
8308 | * 3.......6.......8.......0.......2.......4.......6.......8......0 | |
8309 | * |<---------- tsf_h ----------->||<--- tsf_l -->||<-RxTSFTime ->| | |
8310 | * | |
8311 | * The RxTSFTime are the lowest 16 bits and provided by the ucode. The | |
c654fce6 | 8312 | * tsf_l is filled in by brcms_b_recv, which is done earlier in the |
88ddf0c9 AS |
8313 | * receive call sequence after rx interrupt. Only the higher 16 bits |
8314 | * are used. Finally, the tsf_h is read from the tsf register. | |
8315 | */ | |
1c4c54ba | 8316 | static u64 brcms_c_recover_tsf64(struct brcms_c_info *wlc, |
cc87568a | 8317 | struct brcms_d11rxhdr *rxh) |
88ddf0c9 AS |
8318 | { |
8319 | u32 tsf_h, tsf_l; | |
8320 | u16 rx_tsf_0_15, rx_tsf_16_31; | |
8321 | ||
c654fce6 | 8322 | brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h); |
88ddf0c9 AS |
8323 | |
8324 | rx_tsf_16_31 = (u16)(tsf_l >> 16); | |
8325 | rx_tsf_0_15 = rxh->rxhdr.RxTSFTime; | |
8326 | ||
8327 | /* | |
8328 | * a greater tsf time indicates the low 16 bits of | |
8329 | * tsf_l wrapped, so decrement the high 16 bits. | |
8330 | */ | |
8331 | if ((u16)tsf_l < rx_tsf_0_15) { | |
8332 | rx_tsf_16_31 -= 1; | |
8333 | if (rx_tsf_16_31 == 0xffff) | |
8334 | tsf_h -= 1; | |
8335 | } | |
8336 | ||
8337 | return ((u64)tsf_h << 32) | (((u32)rx_tsf_16_31 << 16) + rx_tsf_0_15); | |
8338 | } | |
8339 | ||
a9533e7e | 8340 | static void |
cc87568a | 8341 | prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh, |
fe741e5e | 8342 | struct sk_buff *p, |
a9533e7e HP |
8343 | struct ieee80211_rx_status *rx_status) |
8344 | { | |
cc87568a | 8345 | struct brcms_d11rxhdr *wlc_rxh = (struct brcms_d11rxhdr *) rxh; |
a9533e7e HP |
8346 | int preamble; |
8347 | int channel; | |
6bd20a1b | 8348 | u32 rspec; |
580a0bd9 | 8349 | unsigned char *plcp; |
a9533e7e | 8350 | |
88ddf0c9 | 8351 | /* fill in TSF and flag its presence */ |
1c4c54ba | 8352 | rx_status->mactime = brcms_c_recover_tsf64(wlc, wlc_rxh); |
88ddf0c9 | 8353 | rx_status->flag |= RX_FLAG_MACTIME_MPDU; |
a9533e7e | 8354 | |
7c783cef | 8355 | channel = BRCMS_CHAN_CHANNEL(rxh->RxChan); |
a9533e7e | 8356 | |
a9533e7e HP |
8357 | if (channel > 14) { |
8358 | rx_status->band = IEEE80211_BAND_5GHZ; | |
d69a1358 RV |
8359 | rx_status->freq = ieee80211_ofdm_chan_to_freq( |
8360 | WF_CHAN_FACTOR_5_G/2, channel); | |
8361 | ||
a9533e7e HP |
8362 | } else { |
8363 | rx_status->band = IEEE80211_BAND_2GHZ; | |
1b1d36b6 | 8364 | rx_status->freq = ieee80211_dsss_chan_to_freq(channel); |
a9533e7e HP |
8365 | } |
8366 | ||
419ad34e | 8367 | rx_status->signal = wlc_rxh->rssi; |
a9533e7e HP |
8368 | |
8369 | /* noise */ | |
8370 | /* qual */ | |
419ad34e AS |
8371 | rx_status->antenna = |
8372 | (rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0; | |
a9533e7e | 8373 | |
54991ad6 | 8374 | plcp = p->data; |
a9533e7e | 8375 | |
f52a0ad0 | 8376 | rspec = brcms_c_compute_rspec(rxh, plcp); |
a9533e7e HP |
8377 | if (IS_MCS(rspec)) { |
8378 | rx_status->rate_idx = rspec & RSPEC_RATE_MASK; | |
8379 | rx_status->flag |= RX_FLAG_HT; | |
8380 | if (RSPEC_IS40MHZ(rspec)) | |
8381 | rx_status->flag |= RX_FLAG_40MHZ; | |
8382 | } else { | |
8383 | switch (RSPEC2RATE(rspec)) { | |
7c783cef | 8384 | case BRCM_RATE_1M: |
a9533e7e HP |
8385 | rx_status->rate_idx = 0; |
8386 | break; | |
7c783cef | 8387 | case BRCM_RATE_2M: |
a9533e7e HP |
8388 | rx_status->rate_idx = 1; |
8389 | break; | |
7c783cef | 8390 | case BRCM_RATE_5M5: |
a9533e7e HP |
8391 | rx_status->rate_idx = 2; |
8392 | break; | |
7c783cef | 8393 | case BRCM_RATE_11M: |
a9533e7e HP |
8394 | rx_status->rate_idx = 3; |
8395 | break; | |
7c783cef | 8396 | case BRCM_RATE_6M: |
a9533e7e HP |
8397 | rx_status->rate_idx = 4; |
8398 | break; | |
7c783cef | 8399 | case BRCM_RATE_9M: |
a9533e7e HP |
8400 | rx_status->rate_idx = 5; |
8401 | break; | |
7c783cef | 8402 | case BRCM_RATE_12M: |
a9533e7e HP |
8403 | rx_status->rate_idx = 6; |
8404 | break; | |
7c783cef | 8405 | case BRCM_RATE_18M: |
a9533e7e HP |
8406 | rx_status->rate_idx = 7; |
8407 | break; | |
7c783cef | 8408 | case BRCM_RATE_24M: |
a9533e7e HP |
8409 | rx_status->rate_idx = 8; |
8410 | break; | |
7c783cef | 8411 | case BRCM_RATE_36M: |
a9533e7e HP |
8412 | rx_status->rate_idx = 9; |
8413 | break; | |
7c783cef | 8414 | case BRCM_RATE_48M: |
a9533e7e HP |
8415 | rx_status->rate_idx = 10; |
8416 | break; | |
7c783cef | 8417 | case BRCM_RATE_54M: |
a9533e7e HP |
8418 | rx_status->rate_idx = 11; |
8419 | break; | |
8420 | default: | |
b8f092c9 | 8421 | wiphy_err(wlc->wiphy, "%s: Unknown rate\n", __func__); |
a9533e7e HP |
8422 | } |
8423 | ||
5a84d6ad AS |
8424 | /* |
8425 | * For 5GHz, we should decrease the index as it is | |
8426 | * a subset of the 2.4G rates. See bitrates field | |
8427 | * of brcms_band_5GHz_nphy (in mac80211_if.c). | |
8428 | */ | |
8429 | if (rx_status->band == IEEE80211_BAND_5GHZ) | |
8430 | rx_status->rate_idx -= BRCMS_LEGACY_5G_RATE_OFFSET; | |
8431 | ||
a9533e7e HP |
8432 | /* Determine short preamble and rate_idx */ |
8433 | preamble = 0; | |
8434 | if (IS_CCK(rspec)) { | |
8435 | if (rxh->PhyRxStatus_0 & PRXS0_SHORTH) | |
e5b95845 | 8436 | rx_status->flag |= RX_FLAG_SHORTPRE; |
a9533e7e HP |
8437 | } else if (IS_OFDM(rspec)) { |
8438 | rx_status->flag |= RX_FLAG_SHORTPRE; | |
8439 | } else { | |
b8f092c9 RV |
8440 | wiphy_err(wlc->wiphy, "%s: Unknown modulation\n", |
8441 | __func__); | |
a9533e7e HP |
8442 | } |
8443 | } | |
8444 | ||
8445 | if (PLCP3_ISSGI(plcp[3])) | |
8446 | rx_status->flag |= RX_FLAG_SHORT_GI; | |
8447 | ||
8448 | if (rxh->RxStatus1 & RXS_DECERR) { | |
8449 | rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC; | |
b8f092c9 RV |
8450 | wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_PLCP_CRC\n", |
8451 | __func__); | |
a9533e7e HP |
8452 | } |
8453 | if (rxh->RxStatus1 & RXS_FCSERR) { | |
8454 | rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; | |
b8f092c9 RV |
8455 | wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_FCS_CRC\n", |
8456 | __func__); | |
a9533e7e HP |
8457 | } |
8458 | } | |
8459 | ||
a9533e7e | 8460 | static void |
cc87568a RV |
8461 | brcms_c_recvctl(struct brcms_c_info *wlc, struct d11rxhdr *rxh, |
8462 | struct sk_buff *p) | |
a9533e7e HP |
8463 | { |
8464 | int len_mpdu; | |
8465 | struct ieee80211_rx_status rx_status; | |
a9533e7e HP |
8466 | |
8467 | memset(&rx_status, 0, sizeof(rx_status)); | |
8468 | prep_mac80211_status(wlc, rxh, p, &rx_status); | |
8469 | ||
8470 | /* mac header+body length, exclude CRC and plcp header */ | |
3726ed4d | 8471 | len_mpdu = p->len - D11_PHY_HDR_LEN - FCS_LEN; |
c303ecbd | 8472 | skb_pull(p, D11_PHY_HDR_LEN); |
2cb8ada6 | 8473 | __skb_trim(p, len_mpdu); |
a9533e7e | 8474 | |
a9533e7e HP |
8475 | memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status)); |
8476 | ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p); | |
a9533e7e HP |
8477 | return; |
8478 | } | |
8479 | ||
a9533e7e HP |
8480 | /* Process received frames */ |
8481 | /* | |
0965ae88 | 8482 | * Return true if more frames need to be processed. false otherwise. |
a9533e7e HP |
8483 | * Param 'bound' indicates max. # frames to process before break out. |
8484 | */ | |
fe741e5e | 8485 | void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p) |
a9533e7e | 8486 | { |
cc87568a | 8487 | struct d11rxhdr *rxh; |
3e9796f9 | 8488 | struct ieee80211_hdr *h; |
a9533e7e HP |
8489 | uint len; |
8490 | bool is_amsdu; | |
a9533e7e | 8491 | |
792aa408 | 8492 | BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); |
a9533e7e | 8493 | |
a9533e7e | 8494 | /* frame starts with rxhdr */ |
cc87568a | 8495 | rxh = (struct d11rxhdr *) (p->data); |
a9533e7e HP |
8496 | |
8497 | /* strip off rxhdr */ | |
7c783cef | 8498 | skb_pull(p, BRCMS_HWRXOFF); |
a9533e7e HP |
8499 | |
8500 | /* fixup rx header endianness */ | |
f3171549 SF |
8501 | rxh->RxFrameSize = le16_to_cpu(rxh->RxFrameSize); |
8502 | rxh->PhyRxStatus_0 = le16_to_cpu(rxh->PhyRxStatus_0); | |
8503 | rxh->PhyRxStatus_1 = le16_to_cpu(rxh->PhyRxStatus_1); | |
8504 | rxh->PhyRxStatus_2 = le16_to_cpu(rxh->PhyRxStatus_2); | |
8505 | rxh->PhyRxStatus_3 = le16_to_cpu(rxh->PhyRxStatus_3); | |
8506 | rxh->PhyRxStatus_4 = le16_to_cpu(rxh->PhyRxStatus_4); | |
8507 | rxh->PhyRxStatus_5 = le16_to_cpu(rxh->PhyRxStatus_5); | |
8508 | rxh->RxStatus1 = le16_to_cpu(rxh->RxStatus1); | |
8509 | rxh->RxStatus2 = le16_to_cpu(rxh->RxStatus2); | |
8510 | rxh->RxTSFTime = le16_to_cpu(rxh->RxTSFTime); | |
8511 | rxh->RxChan = le16_to_cpu(rxh->RxChan); | |
a9533e7e HP |
8512 | |
8513 | /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */ | |
8514 | if (rxh->RxStatus1 & RXS_PBPRES) { | |
54991ad6 | 8515 | if (p->len < 2) { |
1c4c54ba | 8516 | wiphy_err(wlc->wiphy, "wl%d: recv: rcvd runt of " |
b8f092c9 | 8517 | "len %d\n", wlc->pub->unit, p->len); |
a9533e7e HP |
8518 | goto toss; |
8519 | } | |
c303ecbd | 8520 | skb_pull(p, 2); |
a9533e7e HP |
8521 | } |
8522 | ||
3e9796f9 | 8523 | h = (struct ieee80211_hdr *)(p->data + D11_PHY_HDR_LEN); |
54991ad6 | 8524 | len = p->len; |
a9533e7e HP |
8525 | |
8526 | if (rxh->RxStatus1 & RXS_FCSERR) { | |
8527 | if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) { | |
b8f092c9 RV |
8528 | wiphy_err(wlc->wiphy, "FCSERR while scanning******* -" |
8529 | " tossing\n"); | |
a9533e7e HP |
8530 | goto toss; |
8531 | } else { | |
b8f092c9 | 8532 | wiphy_err(wlc->wiphy, "RCSERR!!!\n"); |
a9533e7e HP |
8533 | goto toss; |
8534 | } | |
8535 | } | |
8536 | ||
8537 | /* check received pkt has at least frame control field */ | |
8ea54c9f | 8538 | if (len < D11_PHY_HDR_LEN + sizeof(h->frame_control)) |
a9533e7e | 8539 | goto toss; |
a9533e7e HP |
8540 | |
8541 | is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK; | |
8542 | ||
8543 | /* explicitly test bad src address to avoid sending bad deauth */ | |
8544 | if (!is_amsdu) { | |
8545 | /* CTS and ACK CTL frames are w/o a2 */ | |
2fbd6b37 SF |
8546 | |
8547 | if (ieee80211_is_data(h->frame_control) || | |
8548 | ieee80211_is_mgmt(h->frame_control)) { | |
3e9796f9 RV |
8549 | if ((is_zero_ether_addr(h->addr2) || |
8550 | is_multicast_ether_addr(h->addr2))) { | |
b8f092c9 RV |
8551 | wiphy_err(wlc->wiphy, "wl%d: %s: dropping a " |
8552 | "frame with invalid src mac address," | |
8553 | " a2: %pM\n", | |
d83b2a8a | 8554 | wlc->pub->unit, __func__, h->addr2); |
a9533e7e HP |
8555 | goto toss; |
8556 | } | |
a9533e7e HP |
8557 | } |
8558 | } | |
8559 | ||
8560 | /* due to sheer numbers, toss out probe reqs for now */ | |
2fbd6b37 SF |
8561 | if (ieee80211_is_probe_req(h->frame_control)) |
8562 | goto toss; | |
a9533e7e | 8563 | |
d571a566 | 8564 | if (is_amsdu) |
a9533e7e | 8565 | goto toss; |
a9533e7e | 8566 | |
1c4c54ba | 8567 | brcms_c_recvctl(wlc, rxh, p); |
a9533e7e HP |
8568 | return; |
8569 | ||
8570 | toss: | |
67ad48bc | 8571 | brcmu_pkt_buf_free_skb(p); |
a9533e7e HP |
8572 | } |
8573 | ||
8574 | /* calculate frame duration for Mixed-mode L-SIG spoofing, return | |
8575 | * number of bytes goes in the length field | |
8576 | * | |
8577 | * Formula given by HT PHY Spec v 1.13 | |
8578 | * len = 3(nsyms + nstream + 3) - 3 | |
8579 | */ | |
de91ed29 | 8580 | u16 |
6bd20a1b | 8581 | brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec, |
fe741e5e | 8582 | uint mac_len) |
a9533e7e HP |
8583 | { |
8584 | uint nsyms, len = 0, kNdps; | |
8585 | ||
792aa408 | 8586 | BCMMSG(wlc->wiphy, "wl%d: rate %d, len%d\n", |
f4528696 | 8587 | wlc->pub->unit, RSPEC2RATE(ratespec), mac_len); |
a9533e7e HP |
8588 | |
8589 | if (IS_MCS(ratespec)) { | |
8590 | uint mcs = ratespec & RSPEC_RATE_MASK; | |
8591 | /* MCS_TXS(mcs) returns num tx streams - 1 */ | |
8592 | int tot_streams = (MCS_TXS(mcs) + 1) + RSPEC_STC(ratespec); | |
8593 | ||
419ad34e AS |
8594 | /* |
8595 | * the payload duration calculation matches that | |
8596 | * of regular ofdm | |
8597 | */ | |
a9533e7e HP |
8598 | /* 1000Ndbps = kbps * 4 */ |
8599 | kNdps = | |
8600 | MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec), | |
8601 | RSPEC_ISSGI(ratespec)) * 4; | |
8602 | ||
8603 | if (RSPEC_STC(ratespec) == 0) | |
a9533e7e HP |
8604 | nsyms = |
8605 | CEIL((APHY_SERVICE_NBITS + 8 * mac_len + | |
8606 | APHY_TAIL_NBITS) * 1000, kNdps); | |
8607 | else | |
8608 | /* STBC needs to have even number of symbols */ | |
8609 | nsyms = | |
8610 | 2 * | |
8611 | CEIL((APHY_SERVICE_NBITS + 8 * mac_len + | |
8612 | APHY_TAIL_NBITS) * 1000, 2 * kNdps); | |
8613 | ||
419ad34e AS |
8614 | /* (+3) account for HT-SIG(2) and HT-STF(1) */ |
8615 | nsyms += (tot_streams + 3); | |
8616 | /* | |
8617 | * 3 bytes/symbol @ legacy 6Mbps rate | |
8618 | * (-3) excluding service bits and tail bits | |
8619 | */ | |
8620 | len = (3 * nsyms) - 3; | |
a9533e7e HP |
8621 | } |
8622 | ||
7d4df48e | 8623 | return (u16) len; |
a9533e7e HP |
8624 | } |
8625 | ||
419ad34e AS |
8626 | /* |
8627 | * calculate frame duration of a given rate and length, return | |
8628 | * time in usec unit | |
8629 | */ | |
de91ed29 | 8630 | uint |
6bd20a1b | 8631 | brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec, |
fe741e5e | 8632 | u8 preamble_type, uint mac_len) |
a9533e7e HP |
8633 | { |
8634 | uint nsyms, dur = 0, Ndps, kNdps; | |
8635 | uint rate = RSPEC2RATE(ratespec); | |
8636 | ||
8637 | if (rate == 0) { | |
b8f092c9 RV |
8638 | wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n", |
8639 | wlc->pub->unit); | |
7c783cef | 8640 | rate = BRCM_RATE_1M; |
a9533e7e HP |
8641 | } |
8642 | ||
792aa408 | 8643 | BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n", |
f4528696 | 8644 | wlc->pub->unit, ratespec, preamble_type, mac_len); |
a9533e7e HP |
8645 | |
8646 | if (IS_MCS(ratespec)) { | |
8647 | uint mcs = ratespec & RSPEC_RATE_MASK; | |
8648 | int tot_streams = MCS_TXS(mcs) + RSPEC_STC(ratespec); | |
a9533e7e HP |
8649 | |
8650 | dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT); | |
7c783cef | 8651 | if (preamble_type == BRCMS_MM_PREAMBLE) |
a9533e7e HP |
8652 | dur += PREN_MM_EXT; |
8653 | /* 1000Ndbps = kbps * 4 */ | |
8654 | kNdps = | |
8655 | MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec), | |
8656 | RSPEC_ISSGI(ratespec)) * 4; | |
8657 | ||
8658 | if (RSPEC_STC(ratespec) == 0) | |
a9533e7e HP |
8659 | nsyms = |
8660 | CEIL((APHY_SERVICE_NBITS + 8 * mac_len + | |
8661 | APHY_TAIL_NBITS) * 1000, kNdps); | |
8662 | else | |
8663 | /* STBC needs to have even number of symbols */ | |
8664 | nsyms = | |
8665 | 2 * | |
8666 | CEIL((APHY_SERVICE_NBITS + 8 * mac_len + | |
8667 | APHY_TAIL_NBITS) * 1000, 2 * kNdps); | |
8668 | ||
8669 | dur += APHY_SYMBOL_TIME * nsyms; | |
8670 | if (BAND_2G(wlc->band->bandtype)) | |
8671 | dur += DOT11_OFDM_SIGNAL_EXTENSION; | |
8672 | } else if (IS_OFDM(rate)) { | |
8673 | dur = APHY_PREAMBLE_TIME; | |
8674 | dur += APHY_SIGNAL_TIME; | |
8675 | /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */ | |
8676 | Ndps = rate * 2; | |
8677 | /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */ | |
8678 | nsyms = | |
8679 | CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS), | |
8680 | Ndps); | |
8681 | dur += APHY_SYMBOL_TIME * nsyms; | |
8682 | if (BAND_2G(wlc->band->bandtype)) | |
8683 | dur += DOT11_OFDM_SIGNAL_EXTENSION; | |
8684 | } else { | |
419ad34e AS |
8685 | /* |
8686 | * calc # bits * 2 so factor of 2 in rate (1/2 mbps) | |
8687 | * will divide out | |
8688 | */ | |
a9533e7e HP |
8689 | mac_len = mac_len * 8 * 2; |
8690 | /* calc ceiling of bits/rate = microseconds of air time */ | |
8691 | dur = (mac_len + rate - 1) / rate; | |
7c783cef | 8692 | if (preamble_type & BRCMS_SHORT_PREAMBLE) |
a9533e7e HP |
8693 | dur += BPHY_PLCP_SHORT_TIME; |
8694 | else | |
8695 | dur += BPHY_PLCP_TIME; | |
8696 | } | |
8697 | return dur; | |
8698 | } | |
8699 | ||
a9533e7e | 8700 | /* derive wlc->band->basic_rate[] table from 'rateset' */ |
fa67ebba RV |
8701 | void brcms_c_rate_lookup_init(struct brcms_c_info *wlc, |
8702 | struct brcms_c_rateset *rateset) | |
a9533e7e | 8703 | { |
41feb5ed GKH |
8704 | u8 rate; |
8705 | u8 mandatory; | |
8706 | u8 cck_basic = 0; | |
8707 | u8 ofdm_basic = 0; | |
8708 | u8 *br = wlc->band->basic_rate; | |
a9533e7e HP |
8709 | uint i; |
8710 | ||
8711 | /* incoming rates are in 500kbps units as in 802.11 Supported Rates */ | |
7c783cef | 8712 | memset(br, 0, BRCM_MAXRATE + 1); |
a9533e7e HP |
8713 | |
8714 | /* For each basic rate in the rates list, make an entry in the | |
8715 | * best basic lookup. | |
8716 | */ | |
8717 | for (i = 0; i < rateset->count; i++) { | |
8718 | /* only make an entry for a basic rate */ | |
7c783cef | 8719 | if (!(rateset->rates[i] & BRCMS_RATE_FLAG)) |
a9533e7e HP |
8720 | continue; |
8721 | ||
8722 | /* mask off basic bit */ | |
7c783cef | 8723 | rate = (rateset->rates[i] & BRCMS_RATE_MASK); |
a9533e7e | 8724 | |
7c783cef | 8725 | if (rate > BRCM_MAXRATE) { |
f52a0ad0 RV |
8726 | wiphy_err(wlc->wiphy, "brcms_c_rate_lookup_init: " |
8727 | "invalid rate 0x%X in rate set\n", | |
b8f092c9 | 8728 | rateset->rates[i]); |
a9533e7e HP |
8729 | continue; |
8730 | } | |
8731 | ||
8732 | br[rate] = rate; | |
8733 | } | |
8734 | ||
8735 | /* The rate lookup table now has non-zero entries for each | |
8736 | * basic rate, equal to the basic rate: br[basicN] = basicN | |
8737 | * | |
8738 | * To look up the best basic rate corresponding to any | |
8739 | * particular rate, code can use the basic_rate table | |
8740 | * like this | |
8741 | * | |
8742 | * basic_rate = wlc->band->basic_rate[tx_rate] | |
8743 | * | |
8744 | * Make sure there is a best basic rate entry for | |
8745 | * every rate by walking up the table from low rates | |
8746 | * to high, filling in holes in the lookup table | |
8747 | */ | |
8748 | ||
8749 | for (i = 0; i < wlc->band->hw_rateset.count; i++) { | |
8750 | rate = wlc->band->hw_rateset.rates[i]; | |
a9533e7e HP |
8751 | |
8752 | if (br[rate] != 0) { | |
8753 | /* This rate is a basic rate. | |
8754 | * Keep track of the best basic rate so far by | |
8755 | * modulation type. | |
8756 | */ | |
8757 | if (IS_OFDM(rate)) | |
8758 | ofdm_basic = rate; | |
8759 | else | |
8760 | cck_basic = rate; | |
8761 | ||
8762 | continue; | |
8763 | } | |
8764 | ||
8765 | /* This rate is not a basic rate so figure out the | |
8766 | * best basic rate less than this rate and fill in | |
8767 | * the hole in the table | |
8768 | */ | |
8769 | ||
8770 | br[rate] = IS_OFDM(rate) ? ofdm_basic : cck_basic; | |
8771 | ||
8772 | if (br[rate] != 0) | |
8773 | continue; | |
8774 | ||
8775 | if (IS_OFDM(rate)) { | |
419ad34e AS |
8776 | /* |
8777 | * In 11g and 11a, the OFDM mandatory rates | |
8778 | * are 6, 12, and 24 Mbps | |
8779 | */ | |
7c783cef RV |
8780 | if (rate >= BRCM_RATE_24M) |
8781 | mandatory = BRCM_RATE_24M; | |
8782 | else if (rate >= BRCM_RATE_12M) | |
8783 | mandatory = BRCM_RATE_12M; | |
a9533e7e | 8784 | else |
7c783cef | 8785 | mandatory = BRCM_RATE_6M; |
a9533e7e | 8786 | } else { |
419ad34e | 8787 | /* In 11b, all CCK rates are mandatory 1 - 11 Mbps */ |
a9533e7e HP |
8788 | mandatory = rate; |
8789 | } | |
8790 | ||
8791 | br[rate] = mandatory; | |
8792 | } | |
8793 | } | |
8794 | ||
1c4c54ba RV |
8795 | static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate, |
8796 | u8 basic_rate) | |
a9533e7e | 8797 | { |
41feb5ed GKH |
8798 | u8 phy_rate, index; |
8799 | u8 basic_phy_rate, basic_index; | |
7d4df48e GKH |
8800 | u16 dir_table, basic_table; |
8801 | u16 basic_ptr; | |
a9533e7e HP |
8802 | |
8803 | /* Shared memory address for the table we are reading */ | |
8804 | dir_table = IS_OFDM(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B; | |
8805 | ||
8806 | /* Shared memory address for the table we are writing */ | |
8807 | basic_table = IS_OFDM(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B; | |
8808 | ||
8809 | /* | |
8810 | * for a given rate, the LS-nibble of the PLCP SIGNAL field is | |
8811 | * the index into the rate table. | |
8812 | */ | |
7c783cef RV |
8813 | phy_rate = rate_info[rate] & BRCMS_RATE_MASK; |
8814 | basic_phy_rate = rate_info[basic_rate] & BRCMS_RATE_MASK; | |
a9533e7e HP |
8815 | index = phy_rate & 0xf; |
8816 | basic_index = basic_phy_rate & 0xf; | |
8817 | ||
8818 | /* Find the SHM pointer to the ACK rate entry by looking in the | |
8819 | * Direct-map Table | |
8820 | */ | |
fe741e5e | 8821 | basic_ptr = brcms_c_read_shm(wlc, (dir_table + basic_index * 2)); |
a9533e7e HP |
8822 | |
8823 | /* Update the SHM BSS-basic-rate-set mapping table with the pointer | |
8824 | * to the correct basic rate for the given incoming rate | |
8825 | */ | |
fe741e5e | 8826 | brcms_c_write_shm(wlc, (basic_table + index * 2), basic_ptr); |
a9533e7e HP |
8827 | } |
8828 | ||
fa67ebba RV |
8829 | static const struct brcms_c_rateset * |
8830 | brcms_c_rateset_get_hwrs(struct brcms_c_info *wlc) | |
a9533e7e | 8831 | { |
fa67ebba | 8832 | const struct brcms_c_rateset *rs_dflt; |
a9533e7e | 8833 | |
7c783cef | 8834 | if (BRCMS_PHY_11N_CAP(wlc->band)) { |
a9533e7e HP |
8835 | if (BAND_5G(wlc->band->bandtype)) |
8836 | rs_dflt = &ofdm_mimo_rates; | |
8837 | else | |
8838 | rs_dflt = &cck_ofdm_mimo_rates; | |
8839 | } else if (wlc->band->gmode) | |
8840 | rs_dflt = &cck_ofdm_rates; | |
8841 | else | |
8842 | rs_dflt = &cck_rates; | |
8843 | ||
8844 | return rs_dflt; | |
8845 | } | |
8846 | ||
fe741e5e | 8847 | void brcms_c_set_ratetable(struct brcms_c_info *wlc) |
a9533e7e | 8848 | { |
fa67ebba RV |
8849 | const struct brcms_c_rateset *rs_dflt; |
8850 | struct brcms_c_rateset rs; | |
41feb5ed | 8851 | u8 rate, basic_rate; |
a9533e7e HP |
8852 | uint i; |
8853 | ||
1c4c54ba | 8854 | rs_dflt = brcms_c_rateset_get_hwrs(wlc); |
a9533e7e | 8855 | |
f52a0ad0 RV |
8856 | brcms_c_rateset_copy(rs_dflt, &rs); |
8857 | brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams); | |
a9533e7e HP |
8858 | |
8859 | /* walk the phy rate table and update SHM basic rate lookup table */ | |
8860 | for (i = 0; i < rs.count; i++) { | |
7c783cef | 8861 | rate = rs.rates[i] & BRCMS_RATE_MASK; |
a9533e7e | 8862 | |
7c783cef | 8863 | /* for a given rate BRCMS_BASIC_RATE returns the rate at |
a9533e7e HP |
8864 | * which a response ACK/CTS should be sent. |
8865 | */ | |
7c783cef | 8866 | basic_rate = BRCMS_BASIC_RATE(wlc, rate); |
8ea54c9f | 8867 | if (basic_rate == 0) |
a9533e7e HP |
8868 | /* This should only happen if we are using a |
8869 | * restricted rateset. | |
8870 | */ | |
7c783cef | 8871 | basic_rate = rs.rates[0] & BRCMS_RATE_MASK; |
a9533e7e | 8872 | |
1c4c54ba | 8873 | brcms_c_write_rate_shm(wlc, rate, basic_rate); |
a9533e7e HP |
8874 | } |
8875 | } | |
8876 | ||
8877 | /* | |
8878 | * Return true if the specified rate is supported by the specified band. | |
7c783cef | 8879 | * BRCM_BAND_AUTO indicates the current band. |
a9533e7e | 8880 | */ |
6bd20a1b | 8881 | bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band, |
c6a9e1fc | 8882 | bool verbose) |
a9533e7e | 8883 | { |
fa67ebba | 8884 | struct brcms_c_rateset *hw_rateset; |
a9533e7e HP |
8885 | uint i; |
8886 | ||
8ea54c9f | 8887 | if ((band == BRCM_BAND_AUTO) || (band == wlc->band->bandtype)) |
a9533e7e | 8888 | hw_rateset = &wlc->band->hw_rateset; |
8ea54c9f | 8889 | else if (NBANDS(wlc) > 1) |
a9533e7e | 8890 | hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset; |
8ea54c9f | 8891 | else |
a9533e7e | 8892 | /* other band specified and we are a single band device */ |
0965ae88 | 8893 | return false; |
a9533e7e HP |
8894 | |
8895 | /* check if this is a mimo rate */ | |
8896 | if (IS_MCS(rspec)) { | |
8897 | if (!VALID_MCS((rspec & RSPEC_RATE_MASK))) | |
8898 | goto error; | |
8899 | ||
8900 | return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK)); | |
8901 | } | |
8902 | ||
8903 | for (i = 0; i < hw_rateset->count; i++) | |
8904 | if (hw_rateset->rates[i] == RSPEC2RATE(rspec)) | |
0f0881b0 | 8905 | return true; |
a9533e7e | 8906 | error: |
8ea54c9f | 8907 | if (verbose) |
1c4c54ba | 8908 | wiphy_err(wlc->wiphy, "wl%d: valid_rate: rate spec 0x%x " |
b8f092c9 | 8909 | "not in hw_rateset\n", wlc->pub->unit, rspec); |
a9533e7e | 8910 | |
0965ae88 | 8911 | return false; |
a9533e7e HP |
8912 | } |
8913 | ||
fe741e5e | 8914 | void brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len) |
a9533e7e | 8915 | { |
fa67ebba RV |
8916 | const struct brcms_c_rateset *rs_dflt; |
8917 | struct brcms_c_rateset rs; | |
41feb5ed | 8918 | u8 rate; |
7d4df48e | 8919 | u16 entry_ptr; |
41feb5ed | 8920 | u8 plcp[D11_PHY_HDR_LEN]; |
7d4df48e | 8921 | u16 dur, sifs; |
a9533e7e HP |
8922 | uint i; |
8923 | ||
8924 | sifs = SIFS(wlc->band); | |
8925 | ||
1c4c54ba | 8926 | rs_dflt = brcms_c_rateset_get_hwrs(wlc); |
a9533e7e | 8927 | |
f52a0ad0 RV |
8928 | brcms_c_rateset_copy(rs_dflt, &rs); |
8929 | brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams); | |
a9533e7e | 8930 | |
419ad34e AS |
8931 | /* |
8932 | * walk the phy rate table and update MAC core SHM | |
8933 | * basic rate table entries | |
8934 | */ | |
a9533e7e | 8935 | for (i = 0; i < rs.count; i++) { |
7c783cef | 8936 | rate = rs.rates[i] & BRCMS_RATE_MASK; |
a9533e7e | 8937 | |
1c4c54ba | 8938 | entry_ptr = brcms_c_rate_shm_offset(wlc, rate); |
a9533e7e HP |
8939 | |
8940 | /* Calculate the Probe Response PLCP for the given rate */ | |
fe741e5e | 8941 | brcms_c_compute_plcp(wlc, rate, frame_len, plcp); |
a9533e7e | 8942 | |
419ad34e AS |
8943 | /* |
8944 | * Calculate the duration of the Probe Response | |
8945 | * frame plus SIFS for the MAC | |
8946 | */ | |
7c783cef RV |
8947 | dur = (u16) brcms_c_calc_frame_time(wlc, rate, |
8948 | BRCMS_LONG_PREAMBLE, frame_len); | |
a9533e7e HP |
8949 | dur += sifs; |
8950 | ||
8951 | /* Update the SHM Rate Table entry Probe Response values */ | |
fe741e5e | 8952 | brcms_c_write_shm(wlc, entry_ptr + M_RT_PRS_PLCP_POS, |
7d4df48e | 8953 | (u16) (plcp[0] + (plcp[1] << 8))); |
fe741e5e | 8954 | brcms_c_write_shm(wlc, entry_ptr + M_RT_PRS_PLCP_POS + 2, |
7d4df48e | 8955 | (u16) (plcp[2] + (plcp[3] << 8))); |
fe741e5e | 8956 | brcms_c_write_shm(wlc, entry_ptr + M_RT_PRS_DUR_POS, dur); |
a9533e7e HP |
8957 | } |
8958 | } | |
8959 | ||
a9533e7e HP |
8960 | /* Max buffering needed for beacon template/prb resp template is 142 bytes. |
8961 | * | |
8962 | * PLCP header is 6 bytes. | |
8963 | * 802.11 A3 header is 24 bytes. | |
8964 | * Max beacon frame body template length is 112 bytes. | |
8965 | * Max probe resp frame body template length is 110 bytes. | |
8966 | * | |
8967 | * *len on input contains the max length of the packet available. | |
8968 | * | |
419ad34e AS |
8969 | * The *len value is set to the number of bytes in buf used, and starts |
8970 | * with the PLCP and included up to, but not including, the 4 byte FCS. | |
a9533e7e HP |
8971 | */ |
8972 | static void | |
1c4c54ba | 8973 | brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type, |
6bd20a1b | 8974 | u32 bcn_rspec, |
471f1b51 | 8975 | struct brcms_bss_cfg *cfg, u16 *buf, int *len) |
a9533e7e | 8976 | { |
a44d4236 | 8977 | static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; |
cc87568a | 8978 | struct cck_phy_hdr *plcp; |
392308d0 | 8979 | struct ieee80211_mgmt *h; |
a9533e7e HP |
8980 | int hdr_len, body_len; |
8981 | ||
2fbd6b37 | 8982 | if (MBSS_BCN_ENAB(cfg) && type == IEEE80211_STYPE_BEACON) |
a9533e7e HP |
8983 | hdr_len = DOT11_MAC_HDR_LEN; |
8984 | else | |
8985 | hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN; | |
a9533e7e | 8986 | |
419ad34e AS |
8987 | /* calc buffer size provided for frame body */ |
8988 | body_len = *len - hdr_len; | |
8989 | /* return actual size */ | |
8990 | *len = hdr_len + body_len; | |
a9533e7e HP |
8991 | |
8992 | /* format PHY and MAC headers */ | |
9249ede9 | 8993 | memset((char *)buf, 0, hdr_len); |
a9533e7e | 8994 | |
cc87568a | 8995 | plcp = (struct cck_phy_hdr *) buf; |
a9533e7e | 8996 | |
419ad34e AS |
8997 | /* |
8998 | * PLCP for Probe Response frames are filled in from | |
8999 | * core's rate table | |
9000 | */ | |
8ea54c9f | 9001 | if (type == IEEE80211_STYPE_BEACON && !MBSS_BCN_ENAB(cfg)) |
a9533e7e | 9002 | /* fill in PLCP */ |
fe741e5e | 9003 | brcms_c_compute_plcp(wlc, bcn_rspec, |
3726ed4d | 9004 | (DOT11_MAC_HDR_LEN + body_len + FCS_LEN), |
41feb5ed | 9005 | (u8 *) plcp); |
a9533e7e | 9006 | |
a9533e7e HP |
9007 | /* "Regular" and 16 MBSS but not for 4 MBSS */ |
9008 | /* Update the phytxctl for the beacon based on the rspec */ | |
9009 | if (!SOFTBCN_ENAB(cfg)) | |
fe741e5e | 9010 | brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec); |
a9533e7e | 9011 | |
2fbd6b37 | 9012 | if (MBSS_BCN_ENAB(cfg) && type == IEEE80211_STYPE_BEACON) |
392308d0 | 9013 | h = (struct ieee80211_mgmt *)&plcp[0]; |
a9533e7e | 9014 | else |
392308d0 | 9015 | h = (struct ieee80211_mgmt *)&plcp[1]; |
a9533e7e HP |
9016 | |
9017 | /* fill in 802.11 header */ | |
2fbd6b37 | 9018 | h->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | type); |
a9533e7e HP |
9019 | |
9020 | /* DUR is 0 for multicast bcn, or filled in by MAC for prb resp */ | |
9021 | /* A1 filled in by MAC for prb resp, broadcast for bcn */ | |
2fbd6b37 | 9022 | if (type == IEEE80211_STYPE_BEACON) |
02160695 SF |
9023 | memcpy(&h->da, ðer_bcast, ETH_ALEN); |
9024 | memcpy(&h->sa, &cfg->cur_etheraddr, ETH_ALEN); | |
9025 | memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN); | |
a9533e7e HP |
9026 | |
9027 | /* SEQ filled in by MAC */ | |
9028 | ||
9029 | return; | |
9030 | } | |
9031 | ||
fe741e5e | 9032 | int brcms_c_get_header_len() |
a9533e7e HP |
9033 | { |
9034 | return TXOFF; | |
9035 | } | |
9036 | ||
839f9f62 | 9037 | /* mac is assumed to be suspended at this point */ |
11431424 | 9038 | static void |
2f6b1dde | 9039 | brcms_b_write_hw_bcntemplates(struct brcms_hardware *wlc_hw, u16 bcn[], |
839f9f62 RV |
9040 | int len, bool both) |
9041 | { | |
0da64910 | 9042 | struct d11regs *regs = wlc_hw->regs; |
839f9f62 RV |
9043 | |
9044 | if (both) { | |
9045 | brcms_c_write_hw_bcntemplate0(wlc_hw, bcn, len); | |
9046 | brcms_c_write_hw_bcntemplate1(wlc_hw, bcn, len); | |
9047 | } else { | |
9048 | /* bcn 0 */ | |
9049 | if (!(R_REG(®s->maccommand) & MCMD_BCN0VLD)) | |
9050 | brcms_c_write_hw_bcntemplate0(wlc_hw, bcn, len); | |
9051 | /* bcn 1 */ | |
9052 | else if (! | |
9053 | (R_REG(®s->maccommand) & MCMD_BCN1VLD)) | |
9054 | brcms_c_write_hw_bcntemplate1(wlc_hw, bcn, len); | |
9055 | } | |
9056 | } | |
9057 | ||
11431424 AS |
9058 | static void brcms_c_write_hw_bcntemplates(struct brcms_c_info *wlc, u16 bcn[], |
9059 | int len, bool both) | |
2682e2a3 AS |
9060 | { |
9061 | brcms_b_write_hw_bcntemplates(wlc->hw, bcn, len, both); | |
9062 | } | |
9063 | ||
419ad34e AS |
9064 | /* |
9065 | * Update a beacon for a particular BSS | |
9066 | * For MBSS, this updates the software template and sets "latest" to | |
9067 | * the index of the template updated. Otherwise, it updates the hardware | |
9068 | * template. | |
a9533e7e | 9069 | */ |
fe741e5e | 9070 | void brcms_c_bss_update_beacon(struct brcms_c_info *wlc, |
471f1b51 | 9071 | struct brcms_bss_cfg *cfg) |
a9533e7e HP |
9072 | { |
9073 | int len = BCN_TMPL_LEN; | |
9074 | ||
9075 | /* Clear the soft intmask */ | |
9076 | wlc->defmacintmask &= ~MI_BCNTPL; | |
9077 | ||
8ea54c9f HP |
9078 | if (!cfg->up) |
9079 | /* Only allow updates on an UP bss */ | |
a9533e7e | 9080 | return; |
a9533e7e | 9081 | |
ff31c54c AS |
9082 | /* Optimize: Some of if/else could be combined */ |
9083 | if (!MBSS_BCN_ENAB(cfg) && HWBCN_ENAB(cfg)) { | |
9084 | /* Hardware beaconing for this config */ | |
7d4df48e | 9085 | u16 bcn[BCN_TMPL_LEN / 2]; |
66cbd3ab | 9086 | u32 both_valid = MCMD_BCN0VLD | MCMD_BCN1VLD; |
0da64910 | 9087 | struct d11regs *regs = wlc->regs; |
a9533e7e HP |
9088 | |
9089 | /* Check if both templates are in use, if so sched. an interrupt | |
9090 | * that will call back into this routine | |
9091 | */ | |
8ea54c9f | 9092 | if ((R_REG(®s->maccommand) & both_valid) == both_valid) |
a9533e7e | 9093 | /* clear any previous status */ |
ff31c54c | 9094 | W_REG(®s->macintstatus, MI_BCNTPL); |
8ea54c9f | 9095 | |
a9533e7e HP |
9096 | /* Check that after scheduling the interrupt both of the |
9097 | * templates are still busy. if not clear the int. & remask | |
9098 | */ | |
ff31c54c | 9099 | if ((R_REG(®s->maccommand) & both_valid) == both_valid) { |
a9533e7e HP |
9100 | wlc->defmacintmask |= MI_BCNTPL; |
9101 | return; | |
9102 | } | |
9103 | ||
9104 | wlc->bcn_rspec = | |
fe741e5e | 9105 | brcms_c_lowest_basic_rspec(wlc, &cfg->current_bss->rateset); |
a9533e7e | 9106 | /* update the template and ucode shm */ |
1c4c54ba | 9107 | brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_BEACON, |
2fbd6b37 | 9108 | wlc->bcn_rspec, cfg, bcn, &len); |
fe741e5e | 9109 | brcms_c_write_hw_bcntemplates(wlc, bcn, len, false); |
a9533e7e HP |
9110 | } |
9111 | } | |
9112 | ||
9113 | /* | |
9114 | * Update all beacons for the system. | |
9115 | */ | |
fe741e5e | 9116 | void brcms_c_update_beacon(struct brcms_c_info *wlc) |
a9533e7e HP |
9117 | { |
9118 | int idx; | |
471f1b51 | 9119 | struct brcms_bss_cfg *bsscfg; |
a9533e7e HP |
9120 | |
9121 | /* update AP or IBSS beacons */ | |
49552d33 | 9122 | FOREACH_BSS(wlc, idx, bsscfg) |
a9533e7e | 9123 | if (bsscfg->up && (BSSCFG_AP(bsscfg) || !bsscfg->BSS)) |
fe741e5e | 9124 | brcms_c_bss_update_beacon(wlc, bsscfg); |
49552d33 | 9125 | END_FOREACH_BSS() |
a9533e7e HP |
9126 | } |
9127 | ||
9128 | /* Write ssid into shared memory */ | |
471f1b51 | 9129 | void brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg) |
a9533e7e | 9130 | { |
41feb5ed | 9131 | u8 *ssidptr = cfg->SSID; |
7d4df48e | 9132 | u16 base = M_SSID; |
3726ed4d | 9133 | u8 ssidbuf[IEEE80211_MAX_SSID_LEN]; |
a9533e7e HP |
9134 | |
9135 | /* padding the ssid with zero and copy it into shm */ | |
3726ed4d | 9136 | memset(ssidbuf, 0, IEEE80211_MAX_SSID_LEN); |
02160695 | 9137 | memcpy(ssidbuf, ssidptr, cfg->SSID_len); |
a9533e7e | 9138 | |
fe741e5e | 9139 | brcms_c_copyto_shm(wlc, base, ssidbuf, IEEE80211_MAX_SSID_LEN); |
a9533e7e HP |
9140 | |
9141 | if (!MBSS_BCN_ENAB(cfg)) | |
fe741e5e | 9142 | brcms_c_write_shm(wlc, M_SSIDLEN, (u16) cfg->SSID_len); |
a9533e7e HP |
9143 | } |
9144 | ||
fe741e5e | 9145 | void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) |
a9533e7e HP |
9146 | { |
9147 | int idx; | |
471f1b51 | 9148 | struct brcms_bss_cfg *bsscfg; |
a9533e7e HP |
9149 | |
9150 | /* update AP or IBSS probe responses */ | |
49552d33 | 9151 | FOREACH_BSS(wlc, idx, bsscfg) |
a9533e7e | 9152 | if (bsscfg->up && (BSSCFG_AP(bsscfg) || !bsscfg->BSS)) |
fe741e5e | 9153 | brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend); |
49552d33 | 9154 | END_FOREACH_BSS() |
a9533e7e HP |
9155 | } |
9156 | ||
9157 | void | |
fe741e5e | 9158 | brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, |
471f1b51 | 9159 | struct brcms_bss_cfg *cfg, |
fe741e5e | 9160 | bool suspend) |
a9533e7e | 9161 | { |
7d4df48e | 9162 | u16 prb_resp[BCN_TMPL_LEN / 2]; |
a9533e7e HP |
9163 | int len = BCN_TMPL_LEN; |
9164 | ||
419ad34e AS |
9165 | /* |
9166 | * write the probe response to hardware, or save in | |
9167 | * the config structure | |
9168 | */ | |
a9533e7e HP |
9169 | if (!MBSS_PRB_ENAB(cfg)) { |
9170 | ||
9171 | /* create the probe response template */ | |
1c4c54ba RV |
9172 | brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0, |
9173 | cfg, prb_resp, &len); | |
a9533e7e HP |
9174 | |
9175 | if (suspend) | |
fe741e5e | 9176 | brcms_c_suspend_mac_and_wait(wlc); |
a9533e7e HP |
9177 | |
9178 | /* write the probe response into the template region */ | |
c654fce6 | 9179 | brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE, |
a9533e7e HP |
9180 | (len + 3) & ~3, prb_resp); |
9181 | ||
9182 | /* write the length of the probe response frame (+PLCP/-FCS) */ | |
fe741e5e | 9183 | brcms_c_write_shm(wlc, M_PRB_RESP_FRM_LEN, (u16) len); |
a9533e7e HP |
9184 | |
9185 | /* write the SSID and SSID length */ | |
fe741e5e | 9186 | brcms_c_shm_ssid_upd(wlc, cfg); |
a9533e7e HP |
9187 | |
9188 | /* | |
419ad34e AS |
9189 | * Write PLCP headers and durations for probe response frames |
9190 | * at all rates. Use the actual frame length covered by the | |
9191 | * PLCP header for the call to brcms_c_mod_prb_rsp_rate_table() | |
9192 | * by subtracting the PLCP len and adding the FCS. | |
a9533e7e | 9193 | */ |
3726ed4d | 9194 | len += (-D11_PHY_HDR_LEN + FCS_LEN); |
fe741e5e | 9195 | brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len); |
a9533e7e HP |
9196 | |
9197 | if (suspend) | |
fe741e5e | 9198 | brcms_c_enable_mac(wlc); |
419ad34e AS |
9199 | } else { |
9200 | /* Generating probe resp in sw; update local template */ | |
af4e9c09 | 9201 | /* error: No software probe response support without MBSS */ |
a9533e7e HP |
9202 | } |
9203 | } | |
9204 | ||
9205 | /* prepares pdu for transmission. returns BCM error codes */ | |
fe741e5e | 9206 | int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifop) |
a9533e7e | 9207 | { |
a9533e7e | 9208 | uint fifo; |
cc87568a | 9209 | struct d11txh *txh; |
3e9796f9 | 9210 | struct ieee80211_hdr *h; |
a9533e7e | 9211 | struct scb *scb; |
a9533e7e | 9212 | |
cc87568a | 9213 | txh = (struct d11txh *) (pdu->data); |
3e9796f9 | 9214 | h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN); |
a9533e7e | 9215 | |
1c4c54ba RV |
9216 | /* get the pkt queue info. This was put at brcms_c_sendctl or |
9217 | * brcms_c_send for PDU */ | |
628f10ba | 9218 | fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK; |
a9533e7e HP |
9219 | |
9220 | scb = NULL; | |
9221 | ||
9222 | *fifop = fifo; | |
9223 | ||
9224 | /* return if insufficient dma resources */ | |
9225 | if (TXAVAIL(wlc, fifo) < MAX_DMA_SEGS) { | |
9226 | /* Mark precedences related to this FIFO, unsendable */ | |
7c783cef | 9227 | BRCMS_TX_FIFO_CLEAR(wlc, fifo); |
e10d82d4 | 9228 | return -EBUSY; |
a9533e7e | 9229 | } |
a9533e7e HP |
9230 | return 0; |
9231 | } | |
9232 | ||
9233 | /* init tx reported rate mechanism */ | |
fe741e5e | 9234 | void brcms_c_reprate_init(struct brcms_c_info *wlc) |
a9533e7e HP |
9235 | { |
9236 | int i; | |
471f1b51 | 9237 | struct brcms_bss_cfg *bsscfg; |
a9533e7e | 9238 | |
49552d33 | 9239 | FOREACH_BSS(wlc, i, bsscfg) |
fe741e5e | 9240 | brcms_c_bsscfg_reprate_init(bsscfg); |
49552d33 | 9241 | END_FOREACH_BSS() |
a9533e7e HP |
9242 | } |
9243 | ||
9244 | /* per bsscfg init tx reported rate mechanism */ | |
471f1b51 | 9245 | void brcms_c_bsscfg_reprate_init(struct brcms_bss_cfg *bsscfg) |
a9533e7e HP |
9246 | { |
9247 | bsscfg->txrspecidx = 0; | |
9249ede9 | 9248 | memset((char *)bsscfg->txrspec, 0, sizeof(bsscfg->txrspec)); |
a9533e7e HP |
9249 | } |
9250 | ||
fa67ebba | 9251 | void brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs) |
a9533e7e | 9252 | { |
f52a0ad0 | 9253 | brcms_c_rateset_default(rs, NULL, wlc->band->phytype, |
7c783cef | 9254 | wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL, |
f52a0ad0 RV |
9255 | (bool) N_ENAB(wlc->pub), |
9256 | CHSPEC_WLC_BW(wlc->default_bss->chanspec), | |
9257 | wlc->stf->txstreams); | |
a9533e7e HP |
9258 | } |
9259 | ||
7d4df48e | 9260 | /* Read a single u16 from shared memory. |
a9533e7e HP |
9261 | * SHM 'offset' needs to be an even address |
9262 | */ | |
fe741e5e | 9263 | u16 brcms_c_read_shm(struct brcms_c_info *wlc, uint offset) |
a9533e7e | 9264 | { |
c654fce6 | 9265 | return brcms_b_read_shm(wlc->hw, offset); |
a9533e7e HP |
9266 | } |
9267 | ||
7d4df48e | 9268 | /* Write a single u16 to shared memory. |
a9533e7e HP |
9269 | * SHM 'offset' needs to be an even address |
9270 | */ | |
fe741e5e | 9271 | void brcms_c_write_shm(struct brcms_c_info *wlc, uint offset, u16 v) |
a9533e7e | 9272 | { |
c654fce6 | 9273 | brcms_b_write_shm(wlc->hw, offset, v); |
a9533e7e HP |
9274 | } |
9275 | ||
a9533e7e HP |
9276 | /* Copy a buffer to shared memory. |
9277 | * SHM 'offset' needs to be an even address and | |
9278 | * Buffer length 'len' must be an even number of bytes | |
9279 | */ | |
fe741e5e RV |
9280 | void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset, const void *buf, |
9281 | int len) | |
a9533e7e HP |
9282 | { |
9283 | /* offset and len need to be even */ | |
af4e9c09 | 9284 | if (len <= 0 || (offset & 1) || (len & 1)) |
a9533e7e | 9285 | return; |
af4e9c09 | 9286 | |
c654fce6 | 9287 | brcms_b_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL); |
a9533e7e HP |
9288 | |
9289 | } | |
9290 | ||
a9533e7e | 9291 | /* wrapper BMAC functions to for HIGH driver access */ |
fe741e5e | 9292 | void brcms_c_mctrl(struct brcms_c_info *wlc, u32 mask, u32 val) |
a9533e7e | 9293 | { |
c654fce6 | 9294 | brcms_b_mctrl(wlc->hw, mask, val); |
a9533e7e HP |
9295 | } |
9296 | ||
fe741e5e | 9297 | void brcms_c_mhf(struct brcms_c_info *wlc, u8 idx, u16 mask, u16 val, int bands) |
a9533e7e | 9298 | { |
c654fce6 | 9299 | brcms_b_mhf(wlc->hw, idx, mask, val, bands); |
a9533e7e HP |
9300 | } |
9301 | ||
11431424 | 9302 | static int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo, |
839f9f62 RV |
9303 | uint *blocks) |
9304 | { | |
9305 | if (fifo >= NFIFO) | |
9306 | return -EINVAL; | |
9307 | ||
9308 | *blocks = wlc_hw->xmtfifo_sz[fifo]; | |
9309 | ||
9310 | return 0; | |
9311 | } | |
9312 | ||
fe741e5e | 9313 | int brcms_c_xmtfifo_sz_get(struct brcms_c_info *wlc, uint fifo, uint *blocks) |
a9533e7e | 9314 | { |
c654fce6 | 9315 | return brcms_b_xmtfifo_sz_get(wlc->hw, fifo, blocks); |
a9533e7e HP |
9316 | } |
9317 | ||
fe741e5e | 9318 | void brcms_c_write_template_ram(struct brcms_c_info *wlc, int offset, int len, |
c6a9e1fc | 9319 | void *buf) |
a9533e7e | 9320 | { |
c654fce6 | 9321 | brcms_b_write_template_ram(wlc->hw, offset, len, buf); |
a9533e7e HP |
9322 | } |
9323 | ||
a9533e7e | 9324 | void |
fe741e5e | 9325 | brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset, |
a44d4236 | 9326 | const u8 *addr) |
a9533e7e | 9327 | { |
c654fce6 | 9328 | brcms_b_set_addrmatch(wlc->hw, match_reg_offset, addr); |
6677eaa3 AS |
9329 | if (match_reg_offset == RCM_BSSID_OFFSET) |
9330 | memcpy(wlc->cfg->BSSID, addr, ETH_ALEN); | |
a9533e7e HP |
9331 | } |
9332 | ||
6bd20a1b | 9333 | void brcms_c_pllreq(struct brcms_c_info *wlc, bool set, u32 req_bit) |
a9533e7e | 9334 | { |
c654fce6 | 9335 | brcms_b_pllreq(wlc->hw, set, req_bit); |
a9533e7e HP |
9336 | } |
9337 | ||
fe741e5e | 9338 | void brcms_c_reset_bmac_done(struct brcms_c_info *wlc) |
a9533e7e | 9339 | { |
a9533e7e HP |
9340 | } |
9341 | ||
a9533e7e HP |
9342 | /* check for the particular priority flow control bit being set */ |
9343 | bool | |
fe741e5e | 9344 | brcms_c_txflowcontrol_prio_isset(struct brcms_c_info *wlc, |
471f1b51 | 9345 | struct brcms_txq_info *q, |
fe741e5e | 9346 | int prio) |
a9533e7e HP |
9347 | { |
9348 | uint prio_mask; | |
9349 | ||
8ea54c9f | 9350 | if (prio == ALLPRIO) |
a9533e7e | 9351 | prio_mask = TXQ_STOP_FOR_PRIOFC_MASK; |
8ea54c9f | 9352 | else |
a9533e7e | 9353 | prio_mask = NBITVAL(prio); |
a9533e7e HP |
9354 | |
9355 | return (q->stopped & prio_mask) == prio_mask; | |
9356 | } | |
9357 | ||
25985edc | 9358 | /* propagate the flow control to all interfaces using the given tx queue */ |
fe741e5e | 9359 | void brcms_c_txflowcontrol(struct brcms_c_info *wlc, |
471f1b51 | 9360 | struct brcms_txq_info *qi, |
fe741e5e | 9361 | bool on, int prio) |
a9533e7e HP |
9362 | { |
9363 | uint prio_bits; | |
9364 | uint cur_bits; | |
9365 | ||
792aa408 | 9366 | BCMMSG(wlc->wiphy, "flow control kicks in\n"); |
a9533e7e | 9367 | |
8ea54c9f | 9368 | if (prio == ALLPRIO) |
a9533e7e | 9369 | prio_bits = TXQ_STOP_FOR_PRIOFC_MASK; |
8ea54c9f | 9370 | else |
a9533e7e | 9371 | prio_bits = NBITVAL(prio); |
a9533e7e HP |
9372 | |
9373 | cur_bits = qi->stopped & prio_bits; | |
9374 | ||
9375 | /* Check for the case of no change and return early | |
9376 | * Otherwise update the bit and continue | |
9377 | */ | |
9378 | if (on) { | |
8ea54c9f | 9379 | if (cur_bits == prio_bits) |
a9533e7e | 9380 | return; |
8ea54c9f | 9381 | |
a9533e7e HP |
9382 | mboolset(qi->stopped, prio_bits); |
9383 | } else { | |
8ea54c9f | 9384 | if (cur_bits == 0) |
a9533e7e | 9385 | return; |
8ea54c9f | 9386 | |
a9533e7e HP |
9387 | mboolclr(qi->stopped, prio_bits); |
9388 | } | |
9389 | ||
9390 | /* If there is a flow control override we will not change the external | |
9391 | * flow control state. | |
9392 | */ | |
8ea54c9f | 9393 | if (qi->stopped & ~TXQ_STOP_FOR_PRIOFC_MASK) |
a9533e7e | 9394 | return; |
a9533e7e | 9395 | |
1c4c54ba | 9396 | brcms_c_txflowcontrol_signal(wlc, qi, on, prio); |
a9533e7e HP |
9397 | } |
9398 | ||
9399 | void | |
fe741e5e | 9400 | brcms_c_txflowcontrol_override(struct brcms_c_info *wlc, |
471f1b51 | 9401 | struct brcms_txq_info *qi, |
fe741e5e | 9402 | bool on, uint override) |
a9533e7e HP |
9403 | { |
9404 | uint prev_override; | |
9405 | ||
a9533e7e HP |
9406 | prev_override = (qi->stopped & ~TXQ_STOP_FOR_PRIOFC_MASK); |
9407 | ||
9408 | /* Update the flow control bits and do an early return if there is | |
9409 | * no change in the external flow control state. | |
9410 | */ | |
9411 | if (on) { | |
9412 | mboolset(qi->stopped, override); | |
9413 | /* if there was a previous override bit on, then setting this | |
9414 | * makes no difference. | |
9415 | */ | |
8ea54c9f | 9416 | if (prev_override) |
a9533e7e | 9417 | return; |
a9533e7e | 9418 | |
1c4c54ba | 9419 | brcms_c_txflowcontrol_signal(wlc, qi, ON, ALLPRIO); |
a9533e7e HP |
9420 | } else { |
9421 | mboolclr(qi->stopped, override); | |
9422 | /* clearing an override bit will only make a difference for | |
9423 | * flow control if it was the only bit set. For any other | |
9424 | * override setting, just return | |
9425 | */ | |
8ea54c9f | 9426 | if (prev_override != override) |
a9533e7e | 9427 | return; |
a9533e7e HP |
9428 | |
9429 | if (qi->stopped == 0) { | |
1c4c54ba | 9430 | brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO); |
a9533e7e HP |
9431 | } else { |
9432 | int prio; | |
9433 | ||
9434 | for (prio = MAXPRIO; prio >= 0; prio--) { | |
9435 | if (!mboolisset(qi->stopped, NBITVAL(prio))) | |
1c4c54ba RV |
9436 | brcms_c_txflowcontrol_signal( |
9437 | wlc, qi, OFF, prio); | |
a9533e7e HP |
9438 | } |
9439 | } | |
9440 | } | |
9441 | } | |
9442 | ||
6a3be6e6 | 9443 | /* |
25985edc | 9444 | * Flag 'scan in progress' to withhold dynamic phy calibration |
6a3be6e6 | 9445 | */ |
fe741e5e | 9446 | void brcms_c_scan_start(struct brcms_c_info *wlc) |
6a3be6e6 RV |
9447 | { |
9448 | wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true); | |
9449 | } | |
9450 | ||
fe741e5e | 9451 | void brcms_c_scan_stop(struct brcms_c_info *wlc) |
6a3be6e6 RV |
9452 | { |
9453 | wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false); | |
9454 | } | |
d8a1fb44 | 9455 | |
fe741e5e | 9456 | void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state) |
d8a1fb44 AS |
9457 | { |
9458 | wlc->pub->associated = state; | |
9459 | wlc->cfg->associated = state; | |
9460 | } | |
9ee63c6a RV |
9461 | |
9462 | /* | |
9463 | * When a remote STA/AP is removed by Mac80211, or when it can no longer accept | |
9464 | * AMPDU traffic, packets pending in hardware have to be invalidated so that | |
9465 | * when later on hardware releases them, they can be handled appropriately. | |
9466 | */ | |
471f1b51 | 9467 | void brcms_c_inval_dma_pkts(struct brcms_hardware *hw, |
9ee63c6a RV |
9468 | struct ieee80211_sta *sta, |
9469 | void (*dma_callback_fn)) | |
9470 | { | |
70963f98 | 9471 | struct dma_pub *dmah; |
9ee63c6a RV |
9472 | int i; |
9473 | for (i = 0; i < NFIFO; i++) { | |
9474 | dmah = hw->di[i]; | |
9475 | if (dmah != NULL) | |
9476 | dma_walk_packets(dmah, dma_callback_fn, sta); | |
9477 | } | |
9478 | } | |
94da409e | 9479 | |
fe741e5e | 9480 | int brcms_c_get_curband(struct brcms_c_info *wlc) |
94da409e AS |
9481 | { |
9482 | return wlc->band->bandunit; | |
9483 | } | |
12392c6d | 9484 | |
fe741e5e | 9485 | void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop) |
12392c6d AS |
9486 | { |
9487 | /* flush packet queue when requested */ | |
9488 | if (drop) | |
67ad48bc | 9489 | brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL); |
12392c6d AS |
9490 | |
9491 | /* wait for queue and DMA fifos to run dry */ | |
3a730500 | 9492 | while (!pktq_empty(&wlc->pkt_queue->q) || |
8ea54c9f | 9493 | TXPKTPENDTOT(wlc) > 0) |
8817f754 | 9494 | brcms_msleep(wlc->wl, 1); |
12392c6d | 9495 | } |
c5e7c035 | 9496 | |
fe741e5e RV |
9497 | int brcms_c_set_par(struct brcms_c_info *wlc, enum wlc_par_id par_id, |
9498 | int int_val) | |
c5e7c035 RV |
9499 | { |
9500 | int err = 0; | |
9501 | ||
9502 | switch (par_id) { | |
9503 | case IOV_BCN_LI_BCN: | |
9504 | wlc->bcn_li_bcn = (u8) int_val; | |
9505 | if (wlc->pub->up) | |
fe741e5e | 9506 | brcms_c_bcn_li_upd(wlc); |
c5e7c035 RV |
9507 | break; |
9508 | /* As long as override is false, this only sets the *user* | |
9509 | targets. User can twiddle this all he wants with no harm. | |
9510 | wlc_phy_txpower_set() explicitly sets override to false if | |
9511 | not internal or test. | |
9512 | */ | |
9513 | case IOV_QTXPOWER:{ | |
9514 | u8 qdbm; | |
9515 | bool override; | |
9516 | ||
9517 | /* Remove override bit and clip to max qdbm value */ | |
9518 | qdbm = (u8)min_t(u32, (int_val & ~WL_TXPWR_OVERRIDE), 0xff); | |
9519 | /* Extract override setting */ | |
9520 | override = (int_val & WL_TXPWR_OVERRIDE) ? true : false; | |
9521 | err = | |
9522 | wlc_phy_txpower_set(wlc->band->pi, qdbm, override); | |
9523 | break; | |
9524 | } | |
9525 | case IOV_MPC: | |
9526 | wlc->mpc = (bool)int_val; | |
fe741e5e | 9527 | brcms_c_radio_mpc_upd(wlc); |
c5e7c035 RV |
9528 | break; |
9529 | default: | |
9530 | err = -ENOTSUPP; | |
9531 | } | |
9532 | return err; | |
9533 | } | |
9534 | ||
fe741e5e RV |
9535 | int brcms_c_get_par(struct brcms_c_info *wlc, enum wlc_par_id par_id, |
9536 | int *ret_int_ptr) | |
c5e7c035 RV |
9537 | { |
9538 | int err = 0; | |
9539 | ||
9540 | switch (par_id) { | |
9541 | case IOV_BCN_LI_BCN: | |
9542 | *ret_int_ptr = wlc->bcn_li_bcn; | |
9543 | break; | |
9544 | case IOV_QTXPOWER: { | |
9545 | uint qdbm; | |
9546 | bool override; | |
9547 | ||
9548 | err = wlc_phy_txpower_get(wlc->band->pi, &qdbm, | |
9549 | &override); | |
9550 | if (err != 0) | |
9551 | return err; | |
9552 | ||
9553 | /* Return qdbm units */ | |
9554 | *ret_int_ptr = | |
9555 | qdbm | (override ? WL_TXPWR_OVERRIDE : 0); | |
9556 | break; | |
9557 | } | |
9558 | case IOV_MPC: | |
9559 | *ret_int_ptr = (s32) wlc->mpc; | |
9560 | break; | |
9561 | default: | |
9562 | err = -ENOTSUPP; | |
9563 | } | |
9564 | return err; | |
9565 | } | |
d794fec0 AS |
9566 | |
9567 | /* | |
9568 | * Search the name=value vars for a specific one and return its value. | |
9569 | * Returns NULL if not found. | |
9570 | */ | |
9571 | char *getvar(char *vars, const char *name) | |
9572 | { | |
9573 | char *s; | |
9574 | int len; | |
9575 | ||
9576 | if (!name) | |
9577 | return NULL; | |
9578 | ||
9579 | len = strlen(name); | |
9580 | if (len == 0) | |
9581 | return NULL; | |
9582 | ||
9583 | /* first look in vars[] */ | |
9584 | for (s = vars; s && *s;) { | |
9585 | if ((memcmp(s, name, len) == 0) && (s[len] == '=')) | |
9586 | return &s[len + 1]; | |
9587 | ||
9588 | while (*s++) | |
9589 | ; | |
9590 | } | |
9591 | /* nothing found */ | |
9592 | return NULL; | |
9593 | } | |
9594 | ||
9595 | /* | |
9596 | * Search the vars for a specific one and return its value as | |
9597 | * an integer. Returns 0 if not found. | |
9598 | */ | |
9599 | int getintvar(char *vars, const char *name) | |
9600 | { | |
9601 | char *val; | |
3f7e0c5d | 9602 | unsigned long res; |
d794fec0 AS |
9603 | |
9604 | val = getvar(vars, name); | |
3f7e0c5d AS |
9605 | if (val && !kstrtoul(val, 0, &res)) |
9606 | return res; | |
d794fec0 | 9607 | |
3f7e0c5d | 9608 | return 0; |
d794fec0 | 9609 | } |