blob: 976a53183f685d90b565604de166adc0346b2503 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Joe Perches02f77192012-01-15 00:38:44 -080017#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
Arend van Spriel5b435de2011-10-05 13:19:03 +020019#include <linux/pci_ids.h>
20#include <linux/if_ether.h>
21#include <net/mac80211.h>
22#include <brcm_hw_ids.h>
23#include <aiutils.h>
24#include <chipcommon.h>
25#include "rate.h"
26#include "scb.h"
27#include "phy/phy_hal.h"
28#include "channel.h"
29#include "antsel.h"
30#include "stf.h"
31#include "ampdu.h"
32#include "mac80211_if.h"
33#include "ucode_loader.h"
34#include "main.h"
Alwin Beukers23038212011-10-18 14:02:58 +020035#include "soc.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020036
37/*
38 * Indication for txflowcontrol that all priority bits in
39 * TXQ_STOP_FOR_PRIOFC_MASK are to be considered.
40 */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +020041#define ALLPRIO -1
Arend van Spriel5b435de2011-10-05 13:19:03 +020042
43/* watchdog timer, in unit of ms */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +020044#define TIMER_INTERVAL_WATCHDOG 1000
Arend van Spriel5b435de2011-10-05 13:19:03 +020045/* radio monitor timer, in unit of ms */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +020046#define TIMER_INTERVAL_RADIOCHK 800
Arend van Spriel5b435de2011-10-05 13:19:03 +020047
Arend van Spriel5b435de2011-10-05 13:19:03 +020048/* beacon interval, in unit of 1024TU */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +020049#define BEACON_INTERVAL_DEFAULT 100
Arend van Spriel5b435de2011-10-05 13:19:03 +020050
51/* n-mode support capability */
52/* 2x2 includes both 1x1 & 2x2 devices
53 * reserved #define 2 for future when we want to separate 1x1 & 2x2 and
54 * control it independently
55 */
56#define WL_11N_2x2 1
57#define WL_11N_3x3 3
58#define WL_11N_4x4 4
59
Alwin Beukers73ffc2f2011-10-18 14:02:57 +020060#define EDCF_ACI_MASK 0x60
61#define EDCF_ACI_SHIFT 5
62#define EDCF_ECWMIN_MASK 0x0f
63#define EDCF_ECWMAX_SHIFT 4
64#define EDCF_AIFSN_MASK 0x0f
65#define EDCF_AIFSN_MAX 15
66#define EDCF_ECWMAX_MASK 0xf0
Arend van Spriel5b435de2011-10-05 13:19:03 +020067
Alwin Beukers73ffc2f2011-10-18 14:02:57 +020068#define EDCF_AC_BE_TXOP_STA 0x0000
69#define EDCF_AC_BK_TXOP_STA 0x0000
70#define EDCF_AC_VO_ACI_STA 0x62
71#define EDCF_AC_VO_ECW_STA 0x32
72#define EDCF_AC_VI_ACI_STA 0x42
73#define EDCF_AC_VI_ECW_STA 0x43
74#define EDCF_AC_BK_ECW_STA 0xA4
75#define EDCF_AC_VI_TXOP_STA 0x005e
76#define EDCF_AC_VO_TXOP_STA 0x002f
77#define EDCF_AC_BE_ACI_STA 0x03
78#define EDCF_AC_BE_ECW_STA 0xA4
79#define EDCF_AC_BK_ACI_STA 0x27
80#define EDCF_AC_VO_TXOP_AP 0x002f
Arend van Spriel5b435de2011-10-05 13:19:03 +020081
Alwin Beukers73ffc2f2011-10-18 14:02:57 +020082#define EDCF_TXOP2USEC(txop) ((txop) << 5)
83#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1)
Arend van Spriel5b435de2011-10-05 13:19:03 +020084
Alwin Beukers73ffc2f2011-10-18 14:02:57 +020085#define APHY_SYMBOL_TIME 4
86#define APHY_PREAMBLE_TIME 16
87#define APHY_SIGNAL_TIME 4
88#define APHY_SIFS_TIME 16
89#define APHY_SERVICE_NBITS 16
90#define APHY_TAIL_NBITS 6
91#define BPHY_SIFS_TIME 10
92#define BPHY_PLCP_SHORT_TIME 96
Arend van Spriel5b435de2011-10-05 13:19:03 +020093
Alwin Beukers73ffc2f2011-10-18 14:02:57 +020094#define PREN_PREAMBLE 24
95#define PREN_MM_EXT 12
96#define PREN_PREAMBLE_EXT 4
Arend van Spriel5b435de2011-10-05 13:19:03 +020097
98#define DOT11_MAC_HDR_LEN 24
Alwin Beukers73ffc2f2011-10-18 14:02:57 +020099#define DOT11_ACK_LEN 10
100#define DOT11_BA_LEN 4
Arend van Spriel5b435de2011-10-05 13:19:03 +0200101#define DOT11_OFDM_SIGNAL_EXTENSION 6
102#define DOT11_MIN_FRAG_LEN 256
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200103#define DOT11_RTS_LEN 16
104#define DOT11_CTS_LEN 10
Arend van Spriel5b435de2011-10-05 13:19:03 +0200105#define DOT11_BA_BITMAP_LEN 128
106#define DOT11_MIN_BEACON_PERIOD 1
107#define DOT11_MAX_BEACON_PERIOD 0xFFFF
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200108#define DOT11_MAXNUMFRAGS 16
Arend van Spriel5b435de2011-10-05 13:19:03 +0200109#define DOT11_MAX_FRAG_LEN 2346
110
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200111#define BPHY_PLCP_TIME 192
112#define RIFS_11N_TIME 2
Arend van Spriel5b435de2011-10-05 13:19:03 +0200113
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200114/* length of the BCN template area */
115#define BCN_TMPL_LEN 512
Arend van Spriel5b435de2011-10-05 13:19:03 +0200116
117/* brcms_bss_info flag bit values */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200118#define BRCMS_BSS_HT 0x0020 /* BSS is HT (MIMO) capable */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200119
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200120/* chip rx buffer offset */
121#define BRCMS_HWRXOFF 38
Arend van Spriel5b435de2011-10-05 13:19:03 +0200122
123/* rfdisable delay timer 500 ms, runs of ALP clock */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200124#define RFDISABLE_DEFAULT 10000000
Arend van Spriel5b435de2011-10-05 13:19:03 +0200125
126#define BRCMS_TEMPSENSE_PERIOD 10 /* 10 second timeout */
127
128/* precedences numbers for wlc queues. These are twice as may levels as
129 * 802.1D priorities.
130 * Odd numbers are used for HI priority traffic at same precedence levels
131 * These constants are used ONLY by wlc_prio2prec_map. Do not use them
132 * elsewhere.
133 */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200134#define _BRCMS_PREC_NONE 0 /* None = - */
135#define _BRCMS_PREC_BK 2 /* BK - Background */
136#define _BRCMS_PREC_BE 4 /* BE - Best-effort */
137#define _BRCMS_PREC_EE 6 /* EE - Excellent-effort */
138#define _BRCMS_PREC_CL 8 /* CL - Controlled Load */
139#define _BRCMS_PREC_VI 10 /* Vi - Video */
140#define _BRCMS_PREC_VO 12 /* Vo - Voice */
141#define _BRCMS_PREC_NC 14 /* NC - Network Control */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200142
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200143/* synthpu_dly times in us */
144#define SYNTHPU_DLY_APHY_US 3700
145#define SYNTHPU_DLY_BPHY_US 1050
146#define SYNTHPU_DLY_NPHY_US 2048
147#define SYNTHPU_DLY_LPPHY_US 300
Arend van Spriel5b435de2011-10-05 13:19:03 +0200148
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200149#define ANTCNT 10 /* vanilla M_MAX_ANTCNT val */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200150
151/* Per-AC retry limit register definitions; uses defs.h bitfield macros */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200152#define EDCF_SHORT_S 0
153#define EDCF_SFB_S 4
154#define EDCF_LONG_S 8
155#define EDCF_LFB_S 12
156#define EDCF_SHORT_M BITFIELD_MASK(4)
157#define EDCF_SFB_M BITFIELD_MASK(4)
158#define EDCF_LONG_M BITFIELD_MASK(4)
159#define EDCF_LFB_M BITFIELD_MASK(4)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200160
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200161#define RETRY_SHORT_DEF 7 /* Default Short retry Limit */
162#define RETRY_SHORT_MAX 255 /* Maximum Short retry Limit */
163#define RETRY_LONG_DEF 4 /* Default Long retry count */
164#define RETRY_SHORT_FB 3 /* Short count for fb rate */
165#define RETRY_LONG_FB 2 /* Long count for fb rate */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200166
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200167#define APHY_CWMIN 15
168#define PHY_CWMAX 1023
Arend van Spriel5b435de2011-10-05 13:19:03 +0200169
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200170#define EDCF_AIFSN_MIN 1
Arend van Spriel5b435de2011-10-05 13:19:03 +0200171
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200172#define FRAGNUM_MASK 0xF
Arend van Spriel5b435de2011-10-05 13:19:03 +0200173
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200174#define APHY_SLOT_TIME 9
175#define BPHY_SLOT_TIME 20
Arend van Spriel5b435de2011-10-05 13:19:03 +0200176
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200177#define WL_SPURAVOID_OFF 0
178#define WL_SPURAVOID_ON1 1
179#define WL_SPURAVOID_ON2 2
Arend van Spriel5b435de2011-10-05 13:19:03 +0200180
181/* invalid core flags, use the saved coreflags */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200182#define BRCMS_USE_COREFLAGS 0xffffffff
Arend van Spriel5b435de2011-10-05 13:19:03 +0200183
184/* values for PLCPHdr_override */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200185#define BRCMS_PLCP_AUTO -1
186#define BRCMS_PLCP_SHORT 0
187#define BRCMS_PLCP_LONG 1
Arend van Spriel5b435de2011-10-05 13:19:03 +0200188
189/* values for g_protection_override and n_protection_override */
190#define BRCMS_PROTECTION_AUTO -1
191#define BRCMS_PROTECTION_OFF 0
192#define BRCMS_PROTECTION_ON 1
193#define BRCMS_PROTECTION_MMHDR_ONLY 2
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200194#define BRCMS_PROTECTION_CTS_ONLY 3
Arend van Spriel5b435de2011-10-05 13:19:03 +0200195
196/* values for g_protection_control and n_protection_control */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200197#define BRCMS_PROTECTION_CTL_OFF 0
Arend van Spriel5b435de2011-10-05 13:19:03 +0200198#define BRCMS_PROTECTION_CTL_LOCAL 1
199#define BRCMS_PROTECTION_CTL_OVERLAP 2
200
201/* values for n_protection */
202#define BRCMS_N_PROTECTION_OFF 0
203#define BRCMS_N_PROTECTION_OPTIONAL 1
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200204#define BRCMS_N_PROTECTION_20IN40 2
Arend van Spriel5b435de2011-10-05 13:19:03 +0200205#define BRCMS_N_PROTECTION_MIXEDMODE 3
206
207/* values for band specific 40MHz capabilities */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200208#define BRCMS_N_BW_20ALL 0
209#define BRCMS_N_BW_40ALL 1
210#define BRCMS_N_BW_20IN2G_40IN5G 2
Arend van Spriel5b435de2011-10-05 13:19:03 +0200211
212/* bitflags for SGI support (sgi_rx iovar) */
213#define BRCMS_N_SGI_20 0x01
214#define BRCMS_N_SGI_40 0x02
215
216/* defines used by the nrate iovar */
217/* MSC in use,indicates b0-6 holds an mcs */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200218#define NRATE_MCS_INUSE 0x00000080
Arend van Spriel5b435de2011-10-05 13:19:03 +0200219/* rate/mcs value */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200220#define NRATE_RATE_MASK 0x0000007f
Arend van Spriel5b435de2011-10-05 13:19:03 +0200221/* stf mode mask: siso, cdd, stbc, sdm */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200222#define NRATE_STF_MASK 0x0000ff00
Arend van Spriel5b435de2011-10-05 13:19:03 +0200223/* stf mode shift */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200224#define NRATE_STF_SHIFT 8
Arend van Spriel5b435de2011-10-05 13:19:03 +0200225/* bit indicate to override mcs only */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200226#define NRATE_OVERRIDE_MCS_ONLY 0x40000000
227#define NRATE_SGI_MASK 0x00800000 /* sgi mode */
228#define NRATE_SGI_SHIFT 23 /* sgi mode */
229#define NRATE_LDPC_CODING 0x00400000 /* adv coding in use */
230#define NRATE_LDPC_SHIFT 22 /* ldpc shift */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200231
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200232#define NRATE_STF_SISO 0 /* stf mode SISO */
233#define NRATE_STF_CDD 1 /* stf mode CDD */
234#define NRATE_STF_STBC 2 /* stf mode STBC */
235#define NRATE_STF_SDM 3 /* stf mode SDM */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200236
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200237#define MAX_DMA_SEGS 4
Arend van Spriel5b435de2011-10-05 13:19:03 +0200238
239/* Max # of entries in Tx FIFO based on 4kb page size */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200240#define NTXD 256
Arend van Spriel5b435de2011-10-05 13:19:03 +0200241/* Max # of entries in Rx FIFO based on 4kb page size */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200242#define NRXD 256
Arend van Spriel5b435de2011-10-05 13:19:03 +0200243
244/* try to keep this # rbufs posted to the chip */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200245#define NRXBUFPOST 32
Arend van Spriel5b435de2011-10-05 13:19:03 +0200246
247/* data msg txq hiwat mark */
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200248#define BRCMS_DATAHIWAT 50
Arend van Spriel5b435de2011-10-05 13:19:03 +0200249
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200250/* max # frames to process in brcms_c_recv() */
251#define RXBND 8
252/* max # tx status to process in wlc_txstatus() */
253#define TXSBND 8
Arend van Spriel5b435de2011-10-05 13:19:03 +0200254
Alwin Beukers44760652011-10-12 20:51:31 +0200255/* brcmu_format_flags() bit description structure */
256struct brcms_c_bit_desc {
257 u32 bit;
258 const char *name;
259};
260
Arend van Spriel5b435de2011-10-05 13:19:03 +0200261/*
262 * The following table lists the buffer memory allocated to xmt fifos in HW.
263 * the size is in units of 256bytes(one block), total size is HW dependent
264 * ucode has default fifo partition, sw can overwrite if necessary
265 *
266 * This is documented in twiki under the topic UcodeTxFifo. Please ensure
267 * the twiki is updated before making changes.
268 */
269
270/* Starting corerev for the fifo size table */
271#define XMTFIFOTBL_STARTREV 20
272
273struct d11init {
274 __le16 addr;
275 __le16 size;
276 __le32 value;
277};
278
Arend van Spriel5b435de2011-10-05 13:19:03 +0200279struct edcf_acparam {
280 u8 ACI;
281 u8 ECW;
282 u16 TXOP;
283} __packed;
284
285const u8 prio2fifo[NUMPRIO] = {
286 TX_AC_BE_FIFO, /* 0 BE AC_BE Best Effort */
287 TX_AC_BK_FIFO, /* 1 BK AC_BK Background */
288 TX_AC_BK_FIFO, /* 2 -- AC_BK Background */
289 TX_AC_BE_FIFO, /* 3 EE AC_BE Best Effort */
290 TX_AC_VI_FIFO, /* 4 CL AC_VI Video */
291 TX_AC_VI_FIFO, /* 5 VI AC_VI Video */
292 TX_AC_VO_FIFO, /* 6 VO AC_VO Voice */
293 TX_AC_VO_FIFO /* 7 NC AC_VO Voice */
294};
295
296/* debug/trace */
297uint brcm_msg_level =
Joe Perches8ae74652012-01-15 00:38:38 -0800298#if defined(DEBUG)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200299 LOG_ERROR_VAL;
300#else
301 0;
Joe Perches8ae74652012-01-15 00:38:38 -0800302#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200303
304/* TX FIFO number to WME/802.1E Access Category */
Arend van Sprielb7eec422011-11-10 20:30:18 +0100305static const u8 wme_fifo2ac[] = {
306 IEEE80211_AC_BK,
307 IEEE80211_AC_BE,
308 IEEE80211_AC_VI,
309 IEEE80211_AC_VO,
310 IEEE80211_AC_BE,
311 IEEE80211_AC_BE
312};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200313
Arend van Sprielb7eec422011-11-10 20:30:18 +0100314/* ieee80211 Access Category to TX FIFO number */
315static const u8 wme_ac2fifo[] = {
316 TX_AC_VO_FIFO,
317 TX_AC_VI_FIFO,
318 TX_AC_BE_FIFO,
319 TX_AC_BK_FIFO
320};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200321
322/* 802.1D Priority to precedence queue mapping */
323const u8 wlc_prio2prec_map[] = {
324 _BRCMS_PREC_BE, /* 0 BE - Best-effort */
325 _BRCMS_PREC_BK, /* 1 BK - Background */
326 _BRCMS_PREC_NONE, /* 2 None = - */
327 _BRCMS_PREC_EE, /* 3 EE - Excellent-effort */
328 _BRCMS_PREC_CL, /* 4 CL - Controlled Load */
329 _BRCMS_PREC_VI, /* 5 Vi - Video */
330 _BRCMS_PREC_VO, /* 6 Vo - Voice */
331 _BRCMS_PREC_NC, /* 7 NC - Network Control */
332};
333
334static const u16 xmtfifo_sz[][NFIFO] = {
335 /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */
336 {20, 192, 192, 21, 17, 5},
337 /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */
338 {9, 58, 22, 14, 14, 5},
339 /* corerev 22: 5120, 49152, 49152, 5376, 4352, 1280 */
340 {20, 192, 192, 21, 17, 5},
341 /* corerev 23: 5120, 49152, 49152, 5376, 4352, 1280 */
342 {20, 192, 192, 21, 17, 5},
343 /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */
344 {9, 58, 22, 14, 14, 5},
345};
346
Joe Perches8ae74652012-01-15 00:38:38 -0800347#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +0200348static const char * const fifo_names[] = {
349 "AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" };
350#else
351static const char fifo_names[6][0];
352#endif
353
Joe Perches8ae74652012-01-15 00:38:38 -0800354#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +0200355/* pointer to most recently allocated wl/wlc */
356static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);
357#endif
358
Alwin Beukers73ffc2f2011-10-18 14:02:57 +0200359/* Find basic rate for a given rate */
360static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
361{
362 if (is_mcs_rate(rspec))
363 return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
364 .leg_ofdm];
365 return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
366}
367
368static u16 frametype(u32 rspec, u8 mimoframe)
369{
370 if (is_mcs_rate(rspec))
371 return mimoframe;
372 return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;
373}
374
Alwin Beukers94bdc2a2011-10-12 20:51:13 +0200375/* currently the best mechanism for determining SIFS is the band in use */
376static u16 get_sifs(struct brcms_band *band)
377{
378 return band->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME :
379 BPHY_SIFS_TIME;
380}
381
382/*
383 * Detect Card removed.
384 * Even checking an sbconfig register read will not false trigger when the core
385 * is in reset it breaks CF address mechanism. Accessing gphy phyversion will
386 * cause SB error if aphy is in reset on 4306B0-DB. Need a simple accessible
387 * reg with fixed 0/1 pattern (some platforms return all 0).
388 * If clocks are present, call the sb routine which will figure out if the
389 * device is removed.
390 */
391static bool brcms_deviceremoved(struct brcms_c_info *wlc)
392{
Arend van Spriel16d28122011-12-08 15:06:51 -0800393 u32 macctrl;
394
Alwin Beukers94bdc2a2011-10-12 20:51:13 +0200395 if (!wlc->hw->clk)
396 return ai_deviceremoved(wlc->hw->sih);
Arend van Spriel16d28122011-12-08 15:06:51 -0800397 macctrl = bcma_read32(wlc->hw->d11core,
398 D11REGOFFS(maccontrol));
399 return (macctrl & (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN;
Alwin Beukers94bdc2a2011-10-12 20:51:13 +0200400}
401
402/* sum the individual fifo tx pending packet counts */
403static s16 brcms_txpktpendtot(struct brcms_c_info *wlc)
404{
405 return wlc->core->txpktpend[0] + wlc->core->txpktpend[1] +
406 wlc->core->txpktpend[2] + wlc->core->txpktpend[3];
407}
408
409static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc)
410{
411 return wlc->pub->_nbands > 1 && !wlc->bandlocked;
412}
413
414static int brcms_chspec_bw(u16 chanspec)
415{
416 if (CHSPEC_IS40(chanspec))
417 return BRCMS_40_MHZ;
418 if (CHSPEC_IS20(chanspec))
419 return BRCMS_20_MHZ;
420
421 return BRCMS_10_MHZ;
422}
423
Arend van Spriel5b435de2011-10-05 13:19:03 +0200424static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg)
425{
426 if (cfg == NULL)
427 return;
428
429 kfree(cfg->current_bss);
430 kfree(cfg);
431}
432
433static void brcms_c_detach_mfree(struct brcms_c_info *wlc)
434{
435 if (wlc == NULL)
436 return;
437
438 brcms_c_bsscfg_mfree(wlc->bsscfg);
439 kfree(wlc->pub);
440 kfree(wlc->modulecb);
441 kfree(wlc->default_bss);
442 kfree(wlc->protection);
443 kfree(wlc->stf);
444 kfree(wlc->bandstate[0]);
445 kfree(wlc->corestate->macstat_snapshot);
446 kfree(wlc->corestate);
447 kfree(wlc->hw->bandstate[0]);
448 kfree(wlc->hw);
449
450 /* free the wlc */
451 kfree(wlc);
452 wlc = NULL;
453}
454
455static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit)
456{
457 struct brcms_bss_cfg *cfg;
458
459 cfg = kzalloc(sizeof(struct brcms_bss_cfg), GFP_ATOMIC);
460 if (cfg == NULL)
461 goto fail;
462
463 cfg->current_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC);
464 if (cfg->current_bss == NULL)
465 goto fail;
466
467 return cfg;
468
469 fail:
470 brcms_c_bsscfg_mfree(cfg);
471 return NULL;
472}
473
474static struct brcms_c_info *
475brcms_c_attach_malloc(uint unit, uint *err, uint devid)
476{
477 struct brcms_c_info *wlc;
478
479 wlc = kzalloc(sizeof(struct brcms_c_info), GFP_ATOMIC);
480 if (wlc == NULL) {
481 *err = 1002;
482 goto fail;
483 }
484
485 /* allocate struct brcms_c_pub state structure */
486 wlc->pub = kzalloc(sizeof(struct brcms_pub), GFP_ATOMIC);
487 if (wlc->pub == NULL) {
488 *err = 1003;
489 goto fail;
490 }
491 wlc->pub->wlc = wlc;
492
493 /* allocate struct brcms_hardware state structure */
494
495 wlc->hw = kzalloc(sizeof(struct brcms_hardware), GFP_ATOMIC);
496 if (wlc->hw == NULL) {
497 *err = 1005;
498 goto fail;
499 }
500 wlc->hw->wlc = wlc;
501
502 wlc->hw->bandstate[0] =
503 kzalloc(sizeof(struct brcms_hw_band) * MAXBANDS, GFP_ATOMIC);
504 if (wlc->hw->bandstate[0] == NULL) {
505 *err = 1006;
506 goto fail;
507 } else {
508 int i;
509
510 for (i = 1; i < MAXBANDS; i++)
511 wlc->hw->bandstate[i] = (struct brcms_hw_band *)
512 ((unsigned long)wlc->hw->bandstate[0] +
513 (sizeof(struct brcms_hw_band) * i));
514 }
515
516 wlc->modulecb =
517 kzalloc(sizeof(struct modulecb) * BRCMS_MAXMODULES, GFP_ATOMIC);
518 if (wlc->modulecb == NULL) {
519 *err = 1009;
520 goto fail;
521 }
522
523 wlc->default_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC);
524 if (wlc->default_bss == NULL) {
525 *err = 1010;
526 goto fail;
527 }
528
529 wlc->bsscfg = brcms_c_bsscfg_malloc(unit);
530 if (wlc->bsscfg == NULL) {
531 *err = 1011;
532 goto fail;
533 }
534
535 wlc->protection = kzalloc(sizeof(struct brcms_protection),
536 GFP_ATOMIC);
537 if (wlc->protection == NULL) {
538 *err = 1016;
539 goto fail;
540 }
541
542 wlc->stf = kzalloc(sizeof(struct brcms_stf), GFP_ATOMIC);
543 if (wlc->stf == NULL) {
544 *err = 1017;
545 goto fail;
546 }
547
548 wlc->bandstate[0] =
549 kzalloc(sizeof(struct brcms_band)*MAXBANDS, GFP_ATOMIC);
550 if (wlc->bandstate[0] == NULL) {
551 *err = 1025;
552 goto fail;
553 } else {
554 int i;
555
556 for (i = 1; i < MAXBANDS; i++)
557 wlc->bandstate[i] = (struct brcms_band *)
558 ((unsigned long)wlc->bandstate[0]
559 + (sizeof(struct brcms_band)*i));
560 }
561
562 wlc->corestate = kzalloc(sizeof(struct brcms_core), GFP_ATOMIC);
563 if (wlc->corestate == NULL) {
564 *err = 1026;
565 goto fail;
566 }
567
568 wlc->corestate->macstat_snapshot =
569 kzalloc(sizeof(struct macstat), GFP_ATOMIC);
570 if (wlc->corestate->macstat_snapshot == NULL) {
571 *err = 1027;
572 goto fail;
573 }
574
575 return wlc;
576
577 fail:
578 brcms_c_detach_mfree(wlc);
579 return NULL;
580}
581
582/*
583 * Update the slot timing for standard 11b/g (20us slots)
584 * or shortslot 11g (9us slots)
585 * The PSM needs to be suspended for this call.
586 */
587static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
588 bool shortslot)
589{
Arend van Spriel16d28122011-12-08 15:06:51 -0800590 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200591
592 if (shortslot) {
593 /* 11g short slot: 11a timing */
Arend van Spriel16d28122011-12-08 15:06:51 -0800594 bcma_write16(core, D11REGOFFS(ifs_slot), 0x0207);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200595 brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, APHY_SLOT_TIME);
596 } else {
597 /* 11g long slot: 11b timing */
Arend van Spriel16d28122011-12-08 15:06:51 -0800598 bcma_write16(core, D11REGOFFS(ifs_slot), 0x0212);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200599 brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, BPHY_SLOT_TIME);
600 }
601}
602
Alwin Beukers94bdc2a2011-10-12 20:51:13 +0200603/*
604 * calculate frame duration of a given rate and length, return
605 * time in usec unit
606 */
Arend van Spriel094b1992011-10-18 14:03:07 +0200607static uint brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
608 u8 preamble_type, uint mac_len)
Alwin Beukers94bdc2a2011-10-12 20:51:13 +0200609{
610 uint nsyms, dur = 0, Ndps, kNdps;
611 uint rate = rspec2rate(ratespec);
612
613 if (rate == 0) {
614 wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n",
615 wlc->pub->unit);
616 rate = BRCM_RATE_1M;
617 }
618
619 BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n",
620 wlc->pub->unit, ratespec, preamble_type, mac_len);
621
622 if (is_mcs_rate(ratespec)) {
623 uint mcs = ratespec & RSPEC_RATE_MASK;
624 int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
625
626 dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
627 if (preamble_type == BRCMS_MM_PREAMBLE)
628 dur += PREN_MM_EXT;
629 /* 1000Ndbps = kbps * 4 */
630 kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
631 rspec_issgi(ratespec)) * 4;
632
633 if (rspec_stc(ratespec) == 0)
634 nsyms =
635 CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
636 APHY_TAIL_NBITS) * 1000, kNdps);
637 else
638 /* STBC needs to have even number of symbols */
639 nsyms =
640 2 *
641 CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
642 APHY_TAIL_NBITS) * 1000, 2 * kNdps);
643
644 dur += APHY_SYMBOL_TIME * nsyms;
645 if (wlc->band->bandtype == BRCM_BAND_2G)
646 dur += DOT11_OFDM_SIGNAL_EXTENSION;
647 } else if (is_ofdm_rate(rate)) {
648 dur = APHY_PREAMBLE_TIME;
649 dur += APHY_SIGNAL_TIME;
650 /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
651 Ndps = rate * 2;
652 /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
653 nsyms =
654 CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS),
655 Ndps);
656 dur += APHY_SYMBOL_TIME * nsyms;
657 if (wlc->band->bandtype == BRCM_BAND_2G)
658 dur += DOT11_OFDM_SIGNAL_EXTENSION;
659 } else {
660 /*
661 * calc # bits * 2 so factor of 2 in rate (1/2 mbps)
662 * will divide out
663 */
664 mac_len = mac_len * 8 * 2;
665 /* calc ceiling of bits/rate = microseconds of air time */
666 dur = (mac_len + rate - 1) / rate;
667 if (preamble_type & BRCMS_SHORT_PREAMBLE)
668 dur += BPHY_PLCP_SHORT_TIME;
669 else
670 dur += BPHY_PLCP_TIME;
671 }
672 return dur;
673}
674
Arend van Spriel5b435de2011-10-05 13:19:03 +0200675static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
676 const struct d11init *inits)
677{
Arend van Spriel16d28122011-12-08 15:06:51 -0800678 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200679 int i;
Arend van Spriel16d28122011-12-08 15:06:51 -0800680 uint offset;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200681 u16 size;
682 u32 value;
683
684 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
685
Arend van Spriel5b435de2011-10-05 13:19:03 +0200686 for (i = 0; inits[i].addr != cpu_to_le16(0xffff); i++) {
687 size = le16_to_cpu(inits[i].size);
Arend van Spriel16d28122011-12-08 15:06:51 -0800688 offset = le16_to_cpu(inits[i].addr);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200689 value = le32_to_cpu(inits[i].value);
690 if (size == 2)
Arend van Spriel16d28122011-12-08 15:06:51 -0800691 bcma_write16(core, offset, value);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200692 else if (size == 4)
Arend van Spriel16d28122011-12-08 15:06:51 -0800693 bcma_write32(core, offset, value);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200694 else
695 break;
696 }
697}
698
699static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs)
700{
701 u8 idx;
702 u16 addr[] = {
703 M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
704 M_HOST_FLAGS5
705 };
706
707 for (idx = 0; idx < MHFMAX; idx++)
708 brcms_b_write_shm(wlc_hw, addr[idx], mhfs[idx]);
709}
710
711static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw)
712{
713 struct wiphy *wiphy = wlc_hw->wlc->wiphy;
714 struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
715
716 /* init microcode host flags */
717 brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);
718
719 /* do band-specific ucode IHR, SHM, and SCR inits */
720 if (D11REV_IS(wlc_hw->corerev, 23)) {
721 if (BRCMS_ISNPHY(wlc_hw->band))
722 brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);
723 else
724 wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
725 " %d\n", __func__, wlc_hw->unit,
726 wlc_hw->corerev);
727 } else {
728 if (D11REV_IS(wlc_hw->corerev, 24)) {
729 if (BRCMS_ISLCNPHY(wlc_hw->band))
730 brcms_c_write_inits(wlc_hw,
731 ucode->d11lcn0bsinitvals24);
732 else
733 wiphy_err(wiphy, "%s: wl%d: unsupported phy in"
734 " core rev %d\n", __func__,
735 wlc_hw->unit, wlc_hw->corerev);
736 } else {
737 wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
738 __func__, wlc_hw->unit, wlc_hw->corerev);
739 }
740 }
741}
742
Arend van Spriela8779e42011-12-08 15:06:58 -0800743static void brcms_b_core_ioctl(struct brcms_hardware *wlc_hw, u32 m, u32 v)
744{
745 struct bcma_device *core = wlc_hw->d11core;
746 u32 ioctl = bcma_aread32(core, BCMA_IOCTL) & ~m;
747
748 bcma_awrite32(core, BCMA_IOCTL, ioctl | v);
749}
750
Arend van Spriel5b435de2011-10-05 13:19:03 +0200751static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk)
752{
753 BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk);
754
755 wlc_hw->phyclk = clk;
756
757 if (OFF == clk) { /* clear gmode bit, put phy into reset */
758
Arend van Spriela8779e42011-12-08 15:06:58 -0800759 brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC | SICF_GMODE),
760 (SICF_PRST | SICF_FGC));
Arend van Spriel5b435de2011-10-05 13:19:03 +0200761 udelay(1);
Arend van Spriela8779e42011-12-08 15:06:58 -0800762 brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC), SICF_PRST);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200763 udelay(1);
764
765 } else { /* take phy out of reset */
766
Arend van Spriela8779e42011-12-08 15:06:58 -0800767 brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC), SICF_FGC);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200768 udelay(1);
Arend van Spriela8779e42011-12-08 15:06:58 -0800769 brcms_b_core_ioctl(wlc_hw, SICF_FGC, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200770 udelay(1);
771
772 }
773}
774
Alwin Beukers94bdc2a2011-10-12 20:51:13 +0200775/* low-level band switch utility routine */
776static void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit)
777{
778 BCMMSG(wlc_hw->wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
779 bandunit);
780
781 wlc_hw->band = wlc_hw->bandstate[bandunit];
782
783 /*
784 * BMAC_NOTE:
785 * until we eliminate need for wlc->band refs in low level code
786 */
787 wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit];
788
789 /* set gmode core flag */
Arend van Spriela8779e42011-12-08 15:06:58 -0800790 if (wlc_hw->sbclk && !wlc_hw->noreset) {
791 u32 gmode = 0;
792
793 if (bandunit == 0)
794 gmode = SICF_GMODE;
795
796 brcms_b_core_ioctl(wlc_hw, SICF_GMODE, gmode);
797 }
Alwin Beukers94bdc2a2011-10-12 20:51:13 +0200798}
799
Arend van Spriel5b435de2011-10-05 13:19:03 +0200800/* switch to new band but leave it inactive */
801static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)
802{
803 struct brcms_hardware *wlc_hw = wlc->hw;
804 u32 macintmask;
Arend van Spriel16d28122011-12-08 15:06:51 -0800805 u32 macctrl;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200806
807 BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
Arend van Spriel16d28122011-12-08 15:06:51 -0800808 macctrl = bcma_read32(wlc_hw->d11core,
809 D11REGOFFS(maccontrol));
810 WARN_ON((macctrl & MCTL_EN_MAC) != 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200811
812 /* disable interrupts */
813 macintmask = brcms_intrsoff(wlc->wl);
814
815 /* radio off */
816 wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
817
818 brcms_b_core_phy_clk(wlc_hw, OFF);
819
820 brcms_c_setxband(wlc_hw, bandunit);
821
822 return macintmask;
823}
824
Arend van Spriel5b435de2011-10-05 13:19:03 +0200825/* process an individual struct tx_status */
826static bool
827brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
828{
829 struct sk_buff *p;
830 uint queue;
831 struct d11txh *txh;
832 struct scb *scb = NULL;
833 bool free_pdu;
834 int tx_rts, tx_frame_count, tx_rts_count;
835 uint totlen, supr_status;
836 bool lastframe;
837 struct ieee80211_hdr *h;
838 u16 mcl;
839 struct ieee80211_tx_info *tx_info;
840 struct ieee80211_tx_rate *txrate;
841 int i;
842
843 /* discard intermediate indications for ucode with one legitimate case:
844 * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange,
845 * but the subsequent tx of DATA failed. so it will start rts/cts
846 * from the beginning (resetting the rts transmission count)
847 */
848 if (!(txs->status & TX_STATUS_AMPDU)
849 && (txs->status & TX_STATUS_INTERMEDIATE)) {
850 wiphy_err(wlc->wiphy, "%s: INTERMEDIATE but not AMPDU\n",
851 __func__);
852 return false;
853 }
854
855 queue = txs->frameid & TXFID_QUEUE_MASK;
856 if (queue >= NFIFO) {
857 p = NULL;
858 goto fatal;
859 }
860
861 p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
862 if (p == NULL)
863 goto fatal;
864
865 txh = (struct d11txh *) (p->data);
866 mcl = le16_to_cpu(txh->MacTxControlLow);
867
868 if (txs->phyerr) {
869 if (brcm_msg_level & LOG_ERROR_VAL) {
870 wiphy_err(wlc->wiphy, "phyerr 0x%x, rate 0x%x\n",
871 txs->phyerr, txh->MainRates);
872 brcms_c_print_txdesc(txh);
873 }
874 brcms_c_print_txstatus(txs);
875 }
876
877 if (txs->frameid != le16_to_cpu(txh->TxFrameID))
878 goto fatal;
879 tx_info = IEEE80211_SKB_CB(p);
880 h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
881
882 if (tx_info->control.sta)
883 scb = &wlc->pri_scb;
884
885 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
886 brcms_c_ampdu_dotxstatus(wlc->ampdu, scb, p, txs);
887 return false;
888 }
889
890 supr_status = txs->status & TX_STATUS_SUPR_MASK;
891 if (supr_status == TX_STATUS_SUPR_BADCH)
892 BCMMSG(wlc->wiphy,
893 "%s: Pkt tx suppressed, possibly channel %d\n",
894 __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec));
895
896 tx_rts = le16_to_cpu(txh->MacTxControlLow) & TXC_SENDRTS;
897 tx_frame_count =
898 (txs->status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT;
899 tx_rts_count =
900 (txs->status & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT;
901
902 lastframe = !ieee80211_has_morefrags(h->frame_control);
903
904 if (!lastframe) {
905 wiphy_err(wlc->wiphy, "Not last frame!\n");
906 } else {
907 /*
908 * Set information to be consumed by Minstrel ht.
909 *
910 * The "fallback limit" is the number of tx attempts a given
911 * MPDU is sent at the "primary" rate. Tx attempts beyond that
912 * limit are sent at the "secondary" rate.
913 * A 'short frame' does not exceed RTS treshold.
914 */
915 u16 sfbl, /* Short Frame Rate Fallback Limit */
916 lfbl, /* Long Frame Rate Fallback Limit */
917 fbl;
918
Arend van Sprielb7eec422011-11-10 20:30:18 +0100919 if (queue < IEEE80211_NUM_ACS) {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200920 sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
921 EDCF_SFB);
922 lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
923 EDCF_LFB);
924 } else {
925 sfbl = wlc->SFBL;
926 lfbl = wlc->LFBL;
927 }
928
929 txrate = tx_info->status.rates;
930 if (txrate[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
931 fbl = lfbl;
932 else
933 fbl = sfbl;
934
935 ieee80211_tx_info_clear_status(tx_info);
936
937 if ((tx_frame_count > fbl) && (txrate[1].idx >= 0)) {
938 /*
939 * rate selection requested a fallback rate
940 * and we used it
941 */
942 txrate[0].count = fbl;
943 txrate[1].count = tx_frame_count - fbl;
944 } else {
945 /*
946 * rate selection did not request fallback rate, or
947 * we didn't need it
948 */
949 txrate[0].count = tx_frame_count;
950 /*
951 * rc80211_minstrel.c:minstrel_tx_status() expects
952 * unused rates to be marked with idx = -1
953 */
954 txrate[1].idx = -1;
955 txrate[1].count = 0;
956 }
957
958 /* clear the rest of the rates */
959 for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
960 txrate[i].idx = -1;
961 txrate[i].count = 0;
962 }
963
964 if (txs->status & TX_STATUS_ACK_RCV)
965 tx_info->flags |= IEEE80211_TX_STAT_ACK;
966 }
967
Arend van Sprielad4d71f2011-11-10 20:30:26 +0100968 totlen = p->len;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200969 free_pdu = true;
970
971 brcms_c_txfifo_complete(wlc, queue, 1);
972
973 if (lastframe) {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200974 /* remove PLCP & Broadcom tx descriptor header */
975 skb_pull(p, D11_PHY_HDR_LEN);
976 skb_pull(p, D11_TXH_LEN);
977 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p);
978 } else {
979 wiphy_err(wlc->wiphy, "%s: Not last frame => not calling "
980 "tx_status\n", __func__);
981 }
982
983 return false;
984
985 fatal:
986 if (p)
987 brcmu_pkt_buf_free_skb(p);
988
989 return true;
990
991}
992
993/* process tx completion events in BMAC
994 * Return true if more tx status need to be processed. false otherwise.
995 */
996static bool
997brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
998{
999 bool morepending = false;
1000 struct brcms_c_info *wlc = wlc_hw->wlc;
Arend van Spriel16d28122011-12-08 15:06:51 -08001001 struct bcma_device *core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001002 struct tx_status txstatus, *txs;
1003 u32 s1, s2;
1004 uint n = 0;
1005 /*
1006 * Param 'max_tx_num' indicates max. # tx status to process before
1007 * break out.
1008 */
1009 uint max_tx_num = bound ? TXSBND : -1;
1010
1011 BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
1012
1013 txs = &txstatus;
Arend van Spriel16d28122011-12-08 15:06:51 -08001014 core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001015 *fatal = false;
Arend van Spriel16d28122011-12-08 15:06:51 -08001016 s1 = bcma_read32(core, D11REGOFFS(frmtxstatus));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001017 while (!(*fatal)
Arend van Spriel16d28122011-12-08 15:06:51 -08001018 && (s1 & TXS_V)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001019
1020 if (s1 == 0xffffffff) {
1021 wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n",
1022 wlc_hw->unit, __func__);
1023 return morepending;
1024 }
Arend van Spriel16d28122011-12-08 15:06:51 -08001025 s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001026
1027 txs->status = s1 & TXS_STATUS_MASK;
1028 txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT;
1029 txs->sequence = s2 & TXS_SEQ_MASK;
1030 txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT;
1031 txs->lasttxtime = 0;
1032
1033 *fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs);
1034
1035 /* !give others some time to run! */
1036 if (++n >= max_tx_num)
1037 break;
Arend van Spriel16d28122011-12-08 15:06:51 -08001038 s1 = bcma_read32(core, D11REGOFFS(frmtxstatus));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001039 }
1040
1041 if (*fatal)
1042 return 0;
1043
1044 if (n >= max_tx_num)
1045 morepending = true;
1046
1047 if (!pktq_empty(&wlc->pkt_queue->q))
1048 brcms_c_send_q(wlc);
1049
1050 return morepending;
1051}
1052
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02001053static void brcms_c_tbtt(struct brcms_c_info *wlc)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001054{
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02001055 if (!wlc->bsscfg->BSS)
1056 /*
1057 * DirFrmQ is now valid...defer setting until end
1058 * of ATIM window
1059 */
1060 wlc->qvalid |= MCMD_DIRFRMQVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001061}
1062
1063/* set initial host flags value */
1064static void
1065brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init)
1066{
1067 struct brcms_hardware *wlc_hw = wlc->hw;
1068
1069 memset(mhfs, 0, MHFMAX * sizeof(u16));
1070
1071 mhfs[MHF2] |= mhf2_init;
1072
1073 /* prohibit use of slowclock on multifunction boards */
1074 if (wlc_hw->boardflags & BFL_NOPLLDOWN)
1075 mhfs[MHF1] |= MHF1_FORCEFASTCLK;
1076
1077 if (BRCMS_ISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) {
1078 mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR;
1079 mhfs[MHF1] |= MHF1_IQSWAP_WAR;
1080 }
1081}
1082
Arend van Spriele81da652011-12-08 15:06:53 -08001083static uint
1084dmareg(uint direction, uint fifonum)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001085{
1086 if (direction == DMA_TX)
Arend van Spriele81da652011-12-08 15:06:53 -08001087 return offsetof(struct d11regs, fifo64regs[fifonum].dmaxmt);
1088 return offsetof(struct d11regs, fifo64regs[fifonum].dmarcv);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001089}
1090
1091static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
1092{
1093 uint i;
1094 char name[8];
1095 /*
1096 * ucode host flag 2 needed for pio mode, independent of band and fifo
1097 */
1098 u16 pio_mhf2 = 0;
1099 struct brcms_hardware *wlc_hw = wlc->hw;
1100 uint unit = wlc_hw->unit;
1101 struct wiphy *wiphy = wlc->wiphy;
1102
1103 /* name and offsets for dma_attach */
1104 snprintf(name, sizeof(name), "wl%d", unit);
1105
1106 if (wlc_hw->di[0] == NULL) { /* Init FIFOs */
1107 int dma_attach_err = 0;
1108
1109 /*
1110 * FIFO 0
1111 * TX: TX_AC_BK_FIFO (TX AC Background data packets)
1112 * RX: RX_FIFO (RX data packets)
1113 */
Arend van Spriel2e81b9b2011-12-08 15:06:52 -08001114 wlc_hw->di[0] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core,
Arend van Spriele81da652011-12-08 15:06:53 -08001115 (wme ? dmareg(DMA_TX, 0) : 0),
1116 dmareg(DMA_RX, 0),
Arend van Spriel5b435de2011-10-05 13:19:03 +02001117 (wme ? NTXD : 0), NRXD,
1118 RXBUFSZ, -1, NRXBUFPOST,
1119 BRCMS_HWRXOFF, &brcm_msg_level);
1120 dma_attach_err |= (NULL == wlc_hw->di[0]);
1121
1122 /*
1123 * FIFO 1
1124 * TX: TX_AC_BE_FIFO (TX AC Best-Effort data packets)
1125 * (legacy) TX_DATA_FIFO (TX data packets)
1126 * RX: UNUSED
1127 */
Arend van Spriel2e81b9b2011-12-08 15:06:52 -08001128 wlc_hw->di[1] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core,
Arend van Spriele81da652011-12-08 15:06:53 -08001129 dmareg(DMA_TX, 1), 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02001130 NTXD, 0, 0, -1, 0, 0,
1131 &brcm_msg_level);
1132 dma_attach_err |= (NULL == wlc_hw->di[1]);
1133
1134 /*
1135 * FIFO 2
1136 * TX: TX_AC_VI_FIFO (TX AC Video data packets)
1137 * RX: UNUSED
1138 */
Arend van Spriel2e81b9b2011-12-08 15:06:52 -08001139 wlc_hw->di[2] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core,
Arend van Spriele81da652011-12-08 15:06:53 -08001140 dmareg(DMA_TX, 2), 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02001141 NTXD, 0, 0, -1, 0, 0,
1142 &brcm_msg_level);
1143 dma_attach_err |= (NULL == wlc_hw->di[2]);
1144 /*
1145 * FIFO 3
1146 * TX: TX_AC_VO_FIFO (TX AC Voice data packets)
1147 * (legacy) TX_CTL_FIFO (TX control & mgmt packets)
1148 */
Arend van Spriel2e81b9b2011-12-08 15:06:52 -08001149 wlc_hw->di[3] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core,
Arend van Spriele81da652011-12-08 15:06:53 -08001150 dmareg(DMA_TX, 3),
1151 0, NTXD, 0, 0, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02001152 0, 0, &brcm_msg_level);
1153 dma_attach_err |= (NULL == wlc_hw->di[3]);
1154/* Cleaner to leave this as if with AP defined */
1155
1156 if (dma_attach_err) {
1157 wiphy_err(wiphy, "wl%d: wlc_attach: dma_attach failed"
1158 "\n", unit);
1159 return false;
1160 }
1161
1162 /* get pointer to dma engine tx flow control variable */
1163 for (i = 0; i < NFIFO; i++)
1164 if (wlc_hw->di[i])
1165 wlc_hw->txavail[i] =
1166 (uint *) dma_getvar(wlc_hw->di[i],
1167 "&txavail");
1168 }
1169
1170 /* initial ucode host flags */
1171 brcms_c_mhfdef(wlc, wlc_hw->band->mhfs, pio_mhf2);
1172
1173 return true;
1174}
1175
1176static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw)
1177{
1178 uint j;
1179
1180 for (j = 0; j < NFIFO; j++) {
1181 if (wlc_hw->di[j]) {
1182 dma_detach(wlc_hw->di[j]);
1183 wlc_hw->di[j] = NULL;
1184 }
1185 }
1186}
1187
1188/*
1189 * Initialize brcms_c_info default values ...
1190 * may get overrides later in this function
1191 * BMAC_NOTES, move low out and resolve the dangling ones
1192 */
1193static void brcms_b_info_init(struct brcms_hardware *wlc_hw)
1194{
1195 struct brcms_c_info *wlc = wlc_hw->wlc;
1196
1197 /* set default sw macintmask value */
1198 wlc->defmacintmask = DEF_MACINTMASK;
1199
1200 /* various 802.11g modes */
1201 wlc_hw->shortslot = false;
1202
1203 wlc_hw->SFBL = RETRY_SHORT_FB;
1204 wlc_hw->LFBL = RETRY_LONG_FB;
1205
1206 /* default mac retry limits */
1207 wlc_hw->SRL = RETRY_SHORT_DEF;
1208 wlc_hw->LRL = RETRY_LONG_DEF;
1209 wlc_hw->chanspec = ch20mhz_chspec(1);
1210}
1211
1212static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
1213{
1214 /* delay before first read of ucode state */
1215 udelay(40);
1216
1217 /* wait until ucode is no longer asleep */
1218 SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==
1219 DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
1220}
1221
1222/* control chip clock to save power, enable dynamic clock or force fast clock */
1223static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
1224{
Arend van Sprielb2ffec42011-12-08 15:06:45 -08001225 if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001226 /* new chips with PMU, CCS_FORCEHT will distribute the HT clock
1227 * on backplane, but mac core will still run on ALP(not HT) when
1228 * it enters powersave mode, which means the FCA bit may not be
1229 * set. Should wakeup mac if driver wants it to run on HT.
1230 */
1231
1232 if (wlc_hw->clk) {
1233 if (mode == CLK_FAST) {
Arend van Spriel16d28122011-12-08 15:06:51 -08001234 bcma_set32(wlc_hw->d11core,
1235 D11REGOFFS(clk_ctl_st),
1236 CCS_FORCEHT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001237
1238 udelay(64);
1239
Arend van Spriel16d28122011-12-08 15:06:51 -08001240 SPINWAIT(
1241 ((bcma_read32(wlc_hw->d11core,
1242 D11REGOFFS(clk_ctl_st)) &
1243 CCS_HTAVAIL) == 0),
1244 PMU_MAX_TRANSITION_DLY);
1245 WARN_ON(!(bcma_read32(wlc_hw->d11core,
1246 D11REGOFFS(clk_ctl_st)) &
1247 CCS_HTAVAIL));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001248 } else {
Arend van Sprielb2ffec42011-12-08 15:06:45 -08001249 if ((ai_get_pmurev(wlc_hw->sih) == 0) &&
Arend van Spriel16d28122011-12-08 15:06:51 -08001250 (bcma_read32(wlc_hw->d11core,
1251 D11REGOFFS(clk_ctl_st)) &
1252 (CCS_FORCEHT | CCS_HTAREQ)))
1253 SPINWAIT(
1254 ((bcma_read32(wlc_hw->d11core,
1255 offsetof(struct d11regs,
1256 clk_ctl_st)) &
1257 CCS_HTAVAIL) == 0),
1258 PMU_MAX_TRANSITION_DLY);
1259 bcma_mask32(wlc_hw->d11core,
1260 D11REGOFFS(clk_ctl_st),
Arend van Spriel5b435de2011-10-05 13:19:03 +02001261 ~CCS_FORCEHT);
1262 }
1263 }
1264 wlc_hw->forcefastclk = (mode == CLK_FAST);
1265 } else {
1266
1267 /* old chips w/o PMU, force HT through cc,
1268 * then use FCA to verify mac is running fast clock
1269 */
1270
1271 wlc_hw->forcefastclk = ai_clkctl_cc(wlc_hw->sih, mode);
1272
1273 /* check fast clock is available (if core is not in reset) */
1274 if (wlc_hw->forcefastclk && wlc_hw->clk)
Arend van Spriela8779e42011-12-08 15:06:58 -08001275 WARN_ON(!(bcma_aread32(wlc_hw->d11core, BCMA_IOST) &
Arend van Spriel5b435de2011-10-05 13:19:03 +02001276 SISF_FCLKA));
1277
1278 /*
1279 * keep the ucode wake bit on if forcefastclk is on since we
1280 * do not want ucode to put us back to slow clock when it dozes
1281 * for PM mode. Code below matches the wake override bit with
1282 * current forcefastclk state. Only setting bit in wake_override
1283 * instead of waking ucode immediately since old code had this
1284 * behavior. Older code set wlc->forcefastclk but only had the
1285 * wake happen if the wakup_ucode work (protected by an up
1286 * check) was executed just below.
1287 */
1288 if (wlc_hw->forcefastclk)
1289 mboolset(wlc_hw->wake_override,
1290 BRCMS_WAKE_OVERRIDE_FORCEFAST);
1291 else
1292 mboolclr(wlc_hw->wake_override,
1293 BRCMS_WAKE_OVERRIDE_FORCEFAST);
1294 }
1295}
1296
1297/* set or clear ucode host flag bits
1298 * it has an optimization for no-change write
1299 * it only writes through shared memory when the core has clock;
1300 * pre-CLK changes should use wlc_write_mhf to get around the optimization
1301 *
1302 *
1303 * bands values are: BRCM_BAND_AUTO <--- Current band only
1304 * BRCM_BAND_5G <--- 5G band only
1305 * BRCM_BAND_2G <--- 2G band only
1306 * BRCM_BAND_ALL <--- All bands
1307 */
1308void
1309brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val,
1310 int bands)
1311{
1312 u16 save;
1313 u16 addr[MHFMAX] = {
1314 M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
1315 M_HOST_FLAGS5
1316 };
1317 struct brcms_hw_band *band;
1318
1319 if ((val & ~mask) || idx >= MHFMAX)
1320 return; /* error condition */
1321
1322 switch (bands) {
1323 /* Current band only or all bands,
1324 * then set the band to current band
1325 */
1326 case BRCM_BAND_AUTO:
1327 case BRCM_BAND_ALL:
1328 band = wlc_hw->band;
1329 break;
1330 case BRCM_BAND_5G:
1331 band = wlc_hw->bandstate[BAND_5G_INDEX];
1332 break;
1333 case BRCM_BAND_2G:
1334 band = wlc_hw->bandstate[BAND_2G_INDEX];
1335 break;
1336 default:
1337 band = NULL; /* error condition */
1338 }
1339
1340 if (band) {
1341 save = band->mhfs[idx];
1342 band->mhfs[idx] = (band->mhfs[idx] & ~mask) | val;
1343
1344 /* optimization: only write through if changed, and
1345 * changed band is the current band
1346 */
1347 if (wlc_hw->clk && (band->mhfs[idx] != save)
1348 && (band == wlc_hw->band))
1349 brcms_b_write_shm(wlc_hw, addr[idx],
1350 (u16) band->mhfs[idx]);
1351 }
1352
1353 if (bands == BRCM_BAND_ALL) {
1354 wlc_hw->bandstate[0]->mhfs[idx] =
1355 (wlc_hw->bandstate[0]->mhfs[idx] & ~mask) | val;
1356 wlc_hw->bandstate[1]->mhfs[idx] =
1357 (wlc_hw->bandstate[1]->mhfs[idx] & ~mask) | val;
1358 }
1359}
1360
1361/* set the maccontrol register to desired reset state and
1362 * initialize the sw cache of the register
1363 */
1364static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw)
1365{
1366 /* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */
1367 wlc_hw->maccontrol = 0;
1368 wlc_hw->suspended_fifos = 0;
1369 wlc_hw->wake_override = 0;
1370 wlc_hw->mute_override = 0;
1371 brcms_b_mctrl(wlc_hw, ~0, MCTL_IHR_EN | MCTL_WAKE);
1372}
1373
1374/*
1375 * write the software state of maccontrol and
1376 * overrides to the maccontrol register
1377 */
1378static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw)
1379{
1380 u32 maccontrol = wlc_hw->maccontrol;
1381
1382 /* OR in the wake bit if overridden */
1383 if (wlc_hw->wake_override)
1384 maccontrol |= MCTL_WAKE;
1385
1386 /* set AP and INFRA bits for mute if needed */
1387 if (wlc_hw->mute_override) {
1388 maccontrol &= ~(MCTL_AP);
1389 maccontrol |= MCTL_INFRA;
1390 }
1391
Arend van Spriel16d28122011-12-08 15:06:51 -08001392 bcma_write32(wlc_hw->d11core, D11REGOFFS(maccontrol),
1393 maccontrol);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001394}
1395
1396/* set or clear maccontrol bits */
1397void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val)
1398{
1399 u32 maccontrol;
1400 u32 new_maccontrol;
1401
1402 if (val & ~mask)
1403 return; /* error condition */
1404 maccontrol = wlc_hw->maccontrol;
1405 new_maccontrol = (maccontrol & ~mask) | val;
1406
1407 /* if the new maccontrol value is the same as the old, nothing to do */
1408 if (new_maccontrol == maccontrol)
1409 return;
1410
1411 /* something changed, cache the new value */
1412 wlc_hw->maccontrol = new_maccontrol;
1413
1414 /* write the new values with overrides applied */
1415 brcms_c_mctrl_write(wlc_hw);
1416}
1417
1418void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw,
1419 u32 override_bit)
1420{
1421 if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) {
1422 mboolset(wlc_hw->wake_override, override_bit);
1423 return;
1424 }
1425
1426 mboolset(wlc_hw->wake_override, override_bit);
1427
1428 brcms_c_mctrl_write(wlc_hw);
1429 brcms_b_wait_for_wake(wlc_hw);
1430}
1431
1432void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw,
1433 u32 override_bit)
1434{
1435 mboolclr(wlc_hw->wake_override, override_bit);
1436
1437 if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE))
1438 return;
1439
1440 brcms_c_mctrl_write(wlc_hw);
1441}
1442
1443/* When driver needs ucode to stop beaconing, it has to make sure that
1444 * MCTL_AP is clear and MCTL_INFRA is set
1445 * Mode MCTL_AP MCTL_INFRA
1446 * AP 1 1
1447 * STA 0 1 <--- This will ensure no beacons
1448 * IBSS 0 0
1449 */
1450static void brcms_c_ucode_mute_override_set(struct brcms_hardware *wlc_hw)
1451{
1452 wlc_hw->mute_override = 1;
1453
1454 /* if maccontrol already has AP == 0 and INFRA == 1 without this
1455 * override, then there is no change to write
1456 */
1457 if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
1458 return;
1459
1460 brcms_c_mctrl_write(wlc_hw);
1461}
1462
1463/* Clear the override on AP and INFRA bits */
1464static void brcms_c_ucode_mute_override_clear(struct brcms_hardware *wlc_hw)
1465{
1466 if (wlc_hw->mute_override == 0)
1467 return;
1468
1469 wlc_hw->mute_override = 0;
1470
1471 /* if maccontrol already has AP == 0 and INFRA == 1 without this
1472 * override, then there is no change to write
1473 */
1474 if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
1475 return;
1476
1477 brcms_c_mctrl_write(wlc_hw);
1478}
1479
1480/*
1481 * Write a MAC address to the given match reg offset in the RXE match engine.
1482 */
1483static void
1484brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset,
1485 const u8 *addr)
1486{
Arend van Spriel16d28122011-12-08 15:06:51 -08001487 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001488 u16 mac_l;
1489 u16 mac_m;
1490 u16 mac_h;
1491
1492 BCMMSG(wlc_hw->wlc->wiphy, "wl%d: brcms_b_set_addrmatch\n",
1493 wlc_hw->unit);
1494
Arend van Spriel5b435de2011-10-05 13:19:03 +02001495 mac_l = addr[0] | (addr[1] << 8);
1496 mac_m = addr[2] | (addr[3] << 8);
1497 mac_h = addr[4] | (addr[5] << 8);
1498
1499 /* enter the MAC addr into the RXE match registers */
Arend van Spriel16d28122011-12-08 15:06:51 -08001500 bcma_write16(core, D11REGOFFS(rcm_ctl),
1501 RCM_INC_DATA | match_reg_offset);
1502 bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_l);
1503 bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_m);
1504 bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_h);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001505}
1506
1507void
1508brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len,
1509 void *buf)
1510{
Arend van Spriel16d28122011-12-08 15:06:51 -08001511 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001512 u32 word;
1513 __le32 word_le;
1514 __be32 word_be;
1515 bool be_bit;
1516 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
1517
Arend van Spriel16d28122011-12-08 15:06:51 -08001518 bcma_write32(core, D11REGOFFS(tplatewrptr), offset);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001519
1520 /* if MCTL_BIGEND bit set in mac control register,
1521 * the chip swaps data in fifo, as well as data in
1522 * template ram
1523 */
Arend van Spriel16d28122011-12-08 15:06:51 -08001524 be_bit = (bcma_read32(core, D11REGOFFS(maccontrol)) & MCTL_BIGEND) != 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001525
1526 while (len > 0) {
1527 memcpy(&word, buf, sizeof(u32));
1528
1529 if (be_bit) {
1530 word_be = cpu_to_be32(word);
1531 word = *(u32 *)&word_be;
1532 } else {
1533 word_le = cpu_to_le32(word);
1534 word = *(u32 *)&word_le;
1535 }
1536
Arend van Spriel16d28122011-12-08 15:06:51 -08001537 bcma_write32(core, D11REGOFFS(tplatewrdata), word);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001538
1539 buf = (u8 *) buf + sizeof(u32);
1540 len -= sizeof(u32);
1541 }
1542}
1543
1544static void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin)
1545{
1546 wlc_hw->band->CWmin = newmin;
1547
Arend van Spriel16d28122011-12-08 15:06:51 -08001548 bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),
1549 OBJADDR_SCR_SEL | S_DOT11_CWMIN);
1550 (void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));
1551 bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), newmin);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001552}
1553
1554static void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax)
1555{
1556 wlc_hw->band->CWmax = newmax;
1557
Arend van Spriel16d28122011-12-08 15:06:51 -08001558 bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),
1559 OBJADDR_SCR_SEL | S_DOT11_CWMAX);
1560 (void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));
1561 bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), newmax);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001562}
1563
1564void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)
1565{
1566 bool fastclk;
1567
1568 /* request FAST clock if not on */
1569 fastclk = wlc_hw->forcefastclk;
1570 if (!fastclk)
1571 brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
1572
1573 wlc_phy_bw_state_set(wlc_hw->band->pi, bw);
1574
1575 brcms_b_phy_reset(wlc_hw);
1576 wlc_phy_init(wlc_hw->band->pi, wlc_phy_chanspec_get(wlc_hw->band->pi));
1577
1578 /* restore the clk */
1579 if (!fastclk)
1580 brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
1581}
1582
1583static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw)
1584{
1585 u16 v;
1586 struct brcms_c_info *wlc = wlc_hw->wlc;
1587 /* update SYNTHPU_DLY */
1588
1589 if (BRCMS_ISLCNPHY(wlc->band))
1590 v = SYNTHPU_DLY_LPPHY_US;
1591 else if (BRCMS_ISNPHY(wlc->band) && (NREV_GE(wlc->band->phyrev, 3)))
1592 v = SYNTHPU_DLY_NPHY_US;
1593 else
1594 v = SYNTHPU_DLY_BPHY_US;
1595
1596 brcms_b_write_shm(wlc_hw, M_SYNTHPU_DLY, v);
1597}
1598
1599static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw)
1600{
1601 u16 phyctl;
1602 u16 phytxant = wlc_hw->bmac_phytxant;
1603 u16 mask = PHY_TXC_ANT_MASK;
1604
1605 /* set the Probe Response frame phy control word */
1606 phyctl = brcms_b_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS);
1607 phyctl = (phyctl & ~mask) | phytxant;
1608 brcms_b_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl);
1609
1610 /* set the Response (ACK/CTS) frame phy control word */
1611 phyctl = brcms_b_read_shm(wlc_hw, M_RSP_PCTLWD);
1612 phyctl = (phyctl & ~mask) | phytxant;
1613 brcms_b_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl);
1614}
1615
1616static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw,
1617 u8 rate)
1618{
1619 uint i;
1620 u8 plcp_rate = 0;
1621 struct plcp_signal_rate_lookup {
1622 u8 rate;
1623 u8 signal_rate;
1624 };
1625 /* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */
1626 const struct plcp_signal_rate_lookup rate_lookup[] = {
1627 {BRCM_RATE_6M, 0xB},
1628 {BRCM_RATE_9M, 0xF},
1629 {BRCM_RATE_12M, 0xA},
1630 {BRCM_RATE_18M, 0xE},
1631 {BRCM_RATE_24M, 0x9},
1632 {BRCM_RATE_36M, 0xD},
1633 {BRCM_RATE_48M, 0x8},
1634 {BRCM_RATE_54M, 0xC}
1635 };
1636
1637 for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) {
1638 if (rate == rate_lookup[i].rate) {
1639 plcp_rate = rate_lookup[i].signal_rate;
1640 break;
1641 }
1642 }
1643
1644 /* Find the SHM pointer to the rate table entry by looking in the
1645 * Direct-map Table
1646 */
1647 return 2 * brcms_b_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2));
1648}
1649
1650static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw)
1651{
1652 u8 rate;
1653 u8 rates[8] = {
1654 BRCM_RATE_6M, BRCM_RATE_9M, BRCM_RATE_12M, BRCM_RATE_18M,
1655 BRCM_RATE_24M, BRCM_RATE_36M, BRCM_RATE_48M, BRCM_RATE_54M
1656 };
1657 u16 entry_ptr;
1658 u16 pctl1;
1659 uint i;
1660
1661 if (!BRCMS_PHY_11N_CAP(wlc_hw->band))
1662 return;
1663
1664 /* walk the phy rate table and update the entries */
1665 for (i = 0; i < ARRAY_SIZE(rates); i++) {
1666 rate = rates[i];
1667
1668 entry_ptr = brcms_b_ofdm_ratetable_offset(wlc_hw, rate);
1669
1670 /* read the SHM Rate Table entry OFDM PCTL1 values */
1671 pctl1 =
1672 brcms_b_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS);
1673
1674 /* modify the value */
1675 pctl1 &= ~PHY_TXC1_MODE_MASK;
1676 pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT);
1677
1678 /* Update the SHM Rate Table entry OFDM PCTL1 values */
1679 brcms_b_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS,
1680 pctl1);
1681 }
1682}
1683
1684/* band-specific init */
1685static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec)
1686{
1687 struct brcms_hardware *wlc_hw = wlc->hw;
1688
1689 BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
1690 wlc_hw->band->bandunit);
1691
1692 brcms_c_ucode_bsinit(wlc_hw);
1693
1694 wlc_phy_init(wlc_hw->band->pi, chanspec);
1695
1696 brcms_c_ucode_txant_set(wlc_hw);
1697
1698 /*
1699 * cwmin is band-specific, update hardware
1700 * with value for current band
1701 */
1702 brcms_b_set_cwmin(wlc_hw, wlc_hw->band->CWmin);
1703 brcms_b_set_cwmax(wlc_hw, wlc_hw->band->CWmax);
1704
1705 brcms_b_update_slot_timing(wlc_hw,
1706 wlc_hw->band->bandtype == BRCM_BAND_5G ?
1707 true : wlc_hw->shortslot);
1708
1709 /* write phytype and phyvers */
1710 brcms_b_write_shm(wlc_hw, M_PHYTYPE, (u16) wlc_hw->band->phytype);
1711 brcms_b_write_shm(wlc_hw, M_PHYVER, (u16) wlc_hw->band->phyrev);
1712
1713 /*
1714 * initialize the txphyctl1 rate table since
1715 * shmem is shared between bands
1716 */
1717 brcms_upd_ofdm_pctl1_table(wlc_hw);
1718
1719 brcms_b_upd_synthpu(wlc_hw);
1720}
1721
1722/* Perform a soft reset of the PHY PLL */
1723void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw)
1724{
1725 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
1726
Arend van Spriel7d8e18e2011-12-08 15:06:56 -08001727 ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_addr),
1728 ~0, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001729 udelay(1);
Arend van Spriel7d8e18e2011-12-08 15:06:56 -08001730 ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data),
1731 0x4, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001732 udelay(1);
Arend van Spriel7d8e18e2011-12-08 15:06:56 -08001733 ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data),
1734 0x4, 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001735 udelay(1);
Arend van Spriel7d8e18e2011-12-08 15:06:56 -08001736 ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data),
1737 0x4, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001738 udelay(1);
1739}
1740
1741/* light way to turn on phy clock without reset for NPHY only
1742 * refer to brcms_b_core_phy_clk for full version
1743 */
1744void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk)
1745{
1746 /* support(necessary for NPHY and HYPHY) only */
1747 if (!BRCMS_ISNPHY(wlc_hw->band))
1748 return;
1749
1750 if (ON == clk)
Arend van Spriela8779e42011-12-08 15:06:58 -08001751 brcms_b_core_ioctl(wlc_hw, SICF_FGC, SICF_FGC);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001752 else
Arend van Spriela8779e42011-12-08 15:06:58 -08001753 brcms_b_core_ioctl(wlc_hw, SICF_FGC, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001754
1755}
1756
1757void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk)
1758{
1759 if (ON == clk)
Arend van Spriela8779e42011-12-08 15:06:58 -08001760 brcms_b_core_ioctl(wlc_hw, SICF_MPCLKE, SICF_MPCLKE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001761 else
Arend van Spriela8779e42011-12-08 15:06:58 -08001762 brcms_b_core_ioctl(wlc_hw, SICF_MPCLKE, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001763}
1764
1765void brcms_b_phy_reset(struct brcms_hardware *wlc_hw)
1766{
1767 struct brcms_phy_pub *pih = wlc_hw->band->pi;
1768 u32 phy_bw_clkbits;
1769 bool phy_in_reset = false;
1770
1771 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
1772
1773 if (pih == NULL)
1774 return;
1775
1776 phy_bw_clkbits = wlc_phy_clk_bwbits(wlc_hw->band->pi);
1777
1778 /* Specific reset sequence required for NPHY rev 3 and 4 */
1779 if (BRCMS_ISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) &&
1780 NREV_LE(wlc_hw->band->phyrev, 4)) {
1781 /* Set the PHY bandwidth */
Arend van Spriela8779e42011-12-08 15:06:58 -08001782 brcms_b_core_ioctl(wlc_hw, SICF_BWMASK, phy_bw_clkbits);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001783
1784 udelay(1);
1785
1786 /* Perform a soft reset of the PHY PLL */
1787 brcms_b_core_phypll_reset(wlc_hw);
1788
1789 /* reset the PHY */
Arend van Spriela8779e42011-12-08 15:06:58 -08001790 brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_PCLKE),
1791 (SICF_PRST | SICF_PCLKE));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001792 phy_in_reset = true;
1793 } else {
Arend van Spriela8779e42011-12-08 15:06:58 -08001794 brcms_b_core_ioctl(wlc_hw,
1795 (SICF_PRST | SICF_PCLKE | SICF_BWMASK),
1796 (SICF_PRST | SICF_PCLKE | phy_bw_clkbits));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001797 }
1798
1799 udelay(2);
1800 brcms_b_core_phy_clk(wlc_hw, ON);
1801
1802 if (pih)
1803 wlc_phy_anacore(pih, ON);
1804}
1805
1806/* switch to and initialize new band */
1807static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit,
1808 u16 chanspec) {
1809 struct brcms_c_info *wlc = wlc_hw->wlc;
1810 u32 macintmask;
1811
1812 /* Enable the d11 core before accessing it */
Arend van Spriela8779e42011-12-08 15:06:58 -08001813 if (!bcma_core_is_enabled(wlc_hw->d11core)) {
1814 bcma_core_enable(wlc_hw->d11core, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001815 brcms_c_mctrl_reset(wlc_hw);
1816 }
1817
1818 macintmask = brcms_c_setband_inact(wlc, bandunit);
1819
1820 if (!wlc_hw->up)
1821 return;
1822
1823 brcms_b_core_phy_clk(wlc_hw, ON);
1824
1825 /* band-specific initializations */
1826 brcms_b_bsinit(wlc, chanspec);
1827
1828 /*
1829 * If there are any pending software interrupt bits,
1830 * then replace these with a harmless nonzero value
1831 * so brcms_c_dpc() will re-enable interrupts when done.
1832 */
1833 if (wlc->macintstatus)
1834 wlc->macintstatus = MI_DMAINT;
1835
1836 /* restore macintmask */
1837 brcms_intrsrestore(wlc->wl, macintmask);
1838
1839 /* ucode should still be suspended.. */
Arend van Spriel16d28122011-12-08 15:06:51 -08001840 WARN_ON((bcma_read32(wlc_hw->d11core, D11REGOFFS(maccontrol)) &
1841 MCTL_EN_MAC) != 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001842}
1843
Arend van Spriel5b435de2011-10-05 13:19:03 +02001844static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw)
1845{
1846
1847 /* reject unsupported corerev */
1848 if (!CONF_HAS(D11CONF, wlc_hw->corerev)) {
1849 wiphy_err(wlc_hw->wlc->wiphy, "unsupported core rev %d\n",
1850 wlc_hw->corerev);
1851 return false;
1852 }
1853
1854 return true;
1855}
1856
1857/* Validate some board info parameters */
1858static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw)
1859{
1860 uint boardrev = wlc_hw->boardrev;
1861
1862 /* 4 bits each for board type, major, minor, and tiny version */
1863 uint brt = (boardrev & 0xf000) >> 12;
1864 uint b0 = (boardrev & 0xf00) >> 8;
1865 uint b1 = (boardrev & 0xf0) >> 4;
1866 uint b2 = boardrev & 0xf;
1867
1868 /* voards from other vendors are always considered valid */
Arend van Sprielb2ffec42011-12-08 15:06:45 -08001869 if (ai_get_boardvendor(wlc_hw->sih) != PCI_VENDOR_ID_BROADCOM)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001870 return true;
1871
1872 /* do some boardrev sanity checks when boardvendor is Broadcom */
1873 if (boardrev == 0)
1874 return false;
1875
1876 if (boardrev <= 0xff)
1877 return true;
1878
1879 if ((brt > 2) || (brt == 0) || (b0 > 9) || (b0 == 0) || (b1 > 9)
1880 || (b2 > 9))
1881 return false;
1882
1883 return true;
1884}
1885
1886static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw)
1887{
1888 enum brcms_srom_id var_id = BRCMS_SROM_MACADDR;
1889 char *macaddr;
1890
1891 /* If macaddr exists, use it (Sromrev4, CIS, ...). */
1892 macaddr = getvar(wlc_hw->sih, var_id);
1893 if (macaddr != NULL)
1894 return macaddr;
1895
1896 if (wlc_hw->_nbands > 1)
1897 var_id = BRCMS_SROM_ET1MACADDR;
1898 else
1899 var_id = BRCMS_SROM_IL0MACADDR;
1900
1901 macaddr = getvar(wlc_hw->sih, var_id);
1902 if (macaddr == NULL)
1903 wiphy_err(wlc_hw->wlc->wiphy, "wl%d: wlc_get_macaddr: macaddr "
1904 "getvar(%d) not found\n", wlc_hw->unit, var_id);
1905
1906 return macaddr;
1907}
1908
1909/* power both the pll and external oscillator on/off */
1910static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)
1911{
1912 BCMMSG(wlc_hw->wlc->wiphy, "wl%d: want %d\n", wlc_hw->unit, want);
1913
1914 /*
1915 * dont power down if plldown is false or
1916 * we must poll hw radio disable
1917 */
1918 if (!want && wlc_hw->pllreq)
1919 return;
1920
1921 if (wlc_hw->sih)
1922 ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want);
1923
1924 wlc_hw->sbclk = want;
1925 if (!wlc_hw->sbclk) {
1926 wlc_hw->clk = false;
1927 if (wlc_hw->band && wlc_hw->band->pi)
1928 wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
1929 }
1930}
1931
1932/*
1933 * Return true if radio is disabled, otherwise false.
1934 * hw radio disable signal is an external pin, users activate it asynchronously
1935 * this function could be called when driver is down and w/o clock
1936 * it operates on different registers depending on corerev and boardflag.
1937 */
1938static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw)
1939{
1940 bool v, clk, xtal;
Arend van Spriela8779e42011-12-08 15:06:58 -08001941 u32 flags = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001942
1943 xtal = wlc_hw->sbclk;
1944 if (!xtal)
1945 brcms_b_xtal(wlc_hw, ON);
1946
1947 /* may need to take core out of reset first */
1948 clk = wlc_hw->clk;
1949 if (!clk) {
1950 /*
1951 * mac no longer enables phyclk automatically when driver
1952 * accesses phyreg throughput mac. This can be skipped since
1953 * only mac reg is accessed below
1954 */
1955 flags |= SICF_PCLKE;
1956
1957 /*
Arend van Spriel3b758a62011-12-12 15:15:09 -08001958 * TODO: test suspend/resume
1959 *
Arend van Spriel5b435de2011-10-05 13:19:03 +02001960 * AI chip doesn't restore bar0win2 on
1961 * hibernation/resume, need sw fixup
1962 */
Arend van Spriel16d28122011-12-08 15:06:51 -08001963
Arend van Spriela8779e42011-12-08 15:06:58 -08001964 bcma_core_enable(wlc_hw->d11core, flags);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001965 brcms_c_mctrl_reset(wlc_hw);
1966 }
1967
Arend van Spriel16d28122011-12-08 15:06:51 -08001968 v = ((bcma_read32(wlc_hw->d11core,
1969 D11REGOFFS(phydebug)) & PDBG_RFD) != 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001970
1971 /* put core back into reset */
1972 if (!clk)
Arend van Spriela8779e42011-12-08 15:06:58 -08001973 bcma_core_disable(wlc_hw->d11core, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001974
1975 if (!xtal)
1976 brcms_b_xtal(wlc_hw, OFF);
1977
1978 return v;
1979}
1980
1981static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo)
1982{
1983 struct dma_pub *di = wlc_hw->di[fifo];
1984 return dma_rxreset(di);
1985}
1986
1987/* d11 core reset
1988 * ensure fask clock during reset
1989 * reset dma
1990 * reset d11(out of reset)
1991 * reset phy(out of reset)
1992 * clear software macintstatus for fresh new start
1993 * one testing hack wlc_hw->noreset will bypass the d11/phy reset
1994 */
1995void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
1996{
Arend van Spriel5b435de2011-10-05 13:19:03 +02001997 uint i;
1998 bool fastclk;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001999
2000 if (flags == BRCMS_USE_COREFLAGS)
2001 flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0);
2002
2003 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
2004
Arend van Spriel5b435de2011-10-05 13:19:03 +02002005 /* request FAST clock if not on */
2006 fastclk = wlc_hw->forcefastclk;
2007 if (!fastclk)
2008 brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
2009
2010 /* reset the dma engines except first time thru */
Arend van Spriela8779e42011-12-08 15:06:58 -08002011 if (bcma_core_is_enabled(wlc_hw->d11core)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002012 for (i = 0; i < NFIFO; i++)
2013 if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i])))
2014 wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: "
2015 "dma_txreset[%d]: cannot stop dma\n",
2016 wlc_hw->unit, __func__, i);
2017
2018 if ((wlc_hw->di[RX_FIFO])
2019 && (!wlc_dma_rxreset(wlc_hw, RX_FIFO)))
2020 wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: dma_rxreset"
2021 "[%d]: cannot stop dma\n",
2022 wlc_hw->unit, __func__, RX_FIFO);
2023 }
2024 /* if noreset, just stop the psm and return */
2025 if (wlc_hw->noreset) {
2026 wlc_hw->wlc->macintstatus = 0; /* skip wl_dpc after down */
2027 brcms_b_mctrl(wlc_hw, MCTL_PSM_RUN | MCTL_EN_MAC, 0);
2028 return;
2029 }
2030
2031 /*
2032 * mac no longer enables phyclk automatically when driver accesses
2033 * phyreg throughput mac, AND phy_reset is skipped at early stage when
2034 * band->pi is invalid. need to enable PHY CLK
2035 */
2036 flags |= SICF_PCLKE;
2037
2038 /*
2039 * reset the core
2040 * In chips with PMU, the fastclk request goes through d11 core
2041 * reg 0x1e0, which is cleared by the core_reset. have to re-request it.
2042 *
2043 * This adds some delay and we can optimize it by also requesting
2044 * fastclk through chipcommon during this period if necessary. But
2045 * that has to work coordinate with other driver like mips/arm since
2046 * they may touch chipcommon as well.
2047 */
2048 wlc_hw->clk = false;
Arend van Spriela8779e42011-12-08 15:06:58 -08002049 bcma_core_enable(wlc_hw->d11core, flags);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002050 wlc_hw->clk = true;
2051 if (wlc_hw->band && wlc_hw->band->pi)
2052 wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, true);
2053
2054 brcms_c_mctrl_reset(wlc_hw);
2055
Arend van Sprielb2ffec42011-12-08 15:06:45 -08002056 if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002057 brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
2058
2059 brcms_b_phy_reset(wlc_hw);
2060
2061 /* turn on PHY_PLL */
2062 brcms_b_core_phypll_ctl(wlc_hw, true);
2063
2064 /* clear sw intstatus */
2065 wlc_hw->wlc->macintstatus = 0;
2066
2067 /* restore the clk setting */
2068 if (!fastclk)
2069 brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
2070}
2071
2072/* txfifo sizes needs to be modified(increased) since the newer cores
2073 * have more memory.
2074 */
2075static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw)
2076{
Arend van Spriel16d28122011-12-08 15:06:51 -08002077 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002078 u16 fifo_nu;
2079 u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk;
2080 u16 txfifo_def, txfifo_def1;
2081 u16 txfifo_cmd;
2082
2083 /* tx fifos start at TXFIFO_START_BLK from the Base address */
2084 txfifo_startblk = TXFIFO_START_BLK;
2085
2086 /* sequence of operations: reset fifo, set fifo size, reset fifo */
2087 for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) {
2088
2089 txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu];
2090 txfifo_def = (txfifo_startblk & 0xff) |
2091 (((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT);
2092 txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) |
2093 ((((txfifo_endblk -
2094 1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT);
2095 txfifo_cmd =
2096 TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT);
2097
Arend van Spriel16d28122011-12-08 15:06:51 -08002098 bcma_write16(core, D11REGOFFS(xmtfifocmd), txfifo_cmd);
2099 bcma_write16(core, D11REGOFFS(xmtfifodef), txfifo_def);
2100 bcma_write16(core, D11REGOFFS(xmtfifodef1), txfifo_def1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002101
Arend van Spriel16d28122011-12-08 15:06:51 -08002102 bcma_write16(core, D11REGOFFS(xmtfifocmd), txfifo_cmd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002103
2104 txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu];
2105 }
2106 /*
2107 * need to propagate to shm location to be in sync since ucode/hw won't
2108 * do this
2109 */
2110 brcms_b_write_shm(wlc_hw, M_FIFOSIZE0,
2111 wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]);
2112 brcms_b_write_shm(wlc_hw, M_FIFOSIZE1,
2113 wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]);
2114 brcms_b_write_shm(wlc_hw, M_FIFOSIZE2,
2115 ((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw->
2116 xmtfifo_sz[TX_AC_BK_FIFO]));
2117 brcms_b_write_shm(wlc_hw, M_FIFOSIZE3,
2118 ((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw->
2119 xmtfifo_sz[TX_BCMC_FIFO]));
2120}
2121
2122/* This function is used for changing the tsf frac register
2123 * If spur avoidance mode is off, the mac freq will be 80/120/160Mhz
2124 * If spur avoidance mode is on1, the mac freq will be 82/123/164Mhz
2125 * If spur avoidance mode is on2, the mac freq will be 84/126/168Mhz
2126 * HTPHY Formula is 2^26/freq(MHz) e.g.
2127 * For spuron2 - 126MHz -> 2^26/126 = 532610.0
2128 * - 532610 = 0x82082 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x2082
2129 * For spuron: 123MHz -> 2^26/123 = 545600.5
2130 * - 545601 = 0x85341 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x5341
2131 * For spur off: 120MHz -> 2^26/120 = 559240.5
2132 * - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889
2133 */
2134
2135void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode)
2136{
Arend van Spriel16d28122011-12-08 15:06:51 -08002137 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002138
Arend van Sprielb2ffec42011-12-08 15:06:45 -08002139 if ((ai_get_chip_id(wlc_hw->sih) == BCM43224_CHIP_ID) ||
2140 (ai_get_chip_id(wlc_hw->sih) == BCM43225_CHIP_ID)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002141 if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */
Arend van Spriel16d28122011-12-08 15:06:51 -08002142 bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x2082);
2143 bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002144 } else if (spurmode == WL_SPURAVOID_ON1) { /* 123Mhz */
Arend van Spriel16d28122011-12-08 15:06:51 -08002145 bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x5341);
2146 bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002147 } else { /* 120Mhz */
Arend van Spriel16d28122011-12-08 15:06:51 -08002148 bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x8889);
2149 bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002150 }
2151 } else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
2152 if (spurmode == WL_SPURAVOID_ON1) { /* 82Mhz */
Arend van Spriel16d28122011-12-08 15:06:51 -08002153 bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x7CE0);
2154 bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0xC);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002155 } else { /* 80Mhz */
Arend van Spriel16d28122011-12-08 15:06:51 -08002156 bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0xCCCD);
2157 bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0xC);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002158 }
2159 }
2160}
2161
2162/* Initialize GPIOs that are controlled by D11 core */
2163static void brcms_c_gpio_init(struct brcms_c_info *wlc)
2164{
2165 struct brcms_hardware *wlc_hw = wlc->hw;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002166 u32 gc, gm;
2167
Arend van Spriel5b435de2011-10-05 13:19:03 +02002168 /* use GPIO select 0 to get all gpio signals from the gpio out reg */
2169 brcms_b_mctrl(wlc_hw, MCTL_GPOUT_SEL_MASK, 0);
2170
2171 /*
2172 * Common GPIO setup:
2173 * G0 = LED 0 = WLAN Activity
2174 * G1 = LED 1 = WLAN 2.4 GHz Radio State
2175 * G2 = LED 2 = WLAN 5 GHz Radio State
2176 * G4 = radio disable input (HI enabled, LO disabled)
2177 */
2178
2179 gc = gm = 0;
2180
2181 /* Allocate GPIOs for mimo antenna diversity feature */
2182 if (wlc_hw->antsel_type == ANTSEL_2x3) {
2183 /* Enable antenna diversity, use 2x3 mode */
2184 brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
2185 MHF3_ANTSEL_EN, BRCM_BAND_ALL);
2186 brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE,
2187 MHF3_ANTSEL_MODE, BRCM_BAND_ALL);
2188
2189 /* init superswitch control */
2190 wlc_phy_antsel_init(wlc_hw->band->pi, false);
2191
2192 } else if (wlc_hw->antsel_type == ANTSEL_2x4) {
2193 gm |= gc |= (BOARD_GPIO_12 | BOARD_GPIO_13);
2194 /*
2195 * The board itself is powered by these GPIOs
2196 * (when not sending pattern) so set them high
2197 */
Arend van Spriel16d28122011-12-08 15:06:51 -08002198 bcma_set16(wlc_hw->d11core, D11REGOFFS(psm_gpio_oe),
2199 (BOARD_GPIO_12 | BOARD_GPIO_13));
2200 bcma_set16(wlc_hw->d11core, D11REGOFFS(psm_gpio_out),
2201 (BOARD_GPIO_12 | BOARD_GPIO_13));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002202
2203 /* Enable antenna diversity, use 2x4 mode */
2204 brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
2205 MHF3_ANTSEL_EN, BRCM_BAND_ALL);
2206 brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, 0,
2207 BRCM_BAND_ALL);
2208
2209 /* Configure the desired clock to be 4Mhz */
2210 brcms_b_write_shm(wlc_hw, M_ANTSEL_CLKDIV,
2211 ANTSEL_CLKDIV_4MHZ);
2212 }
2213
2214 /*
2215 * gpio 9 controls the PA. ucode is responsible
2216 * for wiggling out and oe
2217 */
2218 if (wlc_hw->boardflags & BFL_PACTRL)
2219 gm |= gc |= BOARD_GPIO_PACTRL;
2220
2221 /* apply to gpiocontrol register */
2222 ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY);
2223}
2224
2225static void brcms_ucode_write(struct brcms_hardware *wlc_hw,
2226 const __le32 ucode[], const size_t nbytes)
2227{
Arend van Spriel16d28122011-12-08 15:06:51 -08002228 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002229 uint i;
2230 uint count;
2231
2232 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
2233
2234 count = (nbytes / sizeof(u32));
2235
Arend van Spriel16d28122011-12-08 15:06:51 -08002236 bcma_write32(core, D11REGOFFS(objaddr),
2237 OBJADDR_AUTO_INC | OBJADDR_UCM_SEL);
2238 (void)bcma_read32(core, D11REGOFFS(objaddr));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002239 for (i = 0; i < count; i++)
Arend van Spriel16d28122011-12-08 15:06:51 -08002240 bcma_write32(core, D11REGOFFS(objdata), le32_to_cpu(ucode[i]));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002241
2242}
2243
2244static void brcms_ucode_download(struct brcms_hardware *wlc_hw)
2245{
2246 struct brcms_c_info *wlc;
2247 struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
2248
2249 wlc = wlc_hw->wlc;
2250
2251 if (wlc_hw->ucode_loaded)
2252 return;
2253
2254 if (D11REV_IS(wlc_hw->corerev, 23)) {
2255 if (BRCMS_ISNPHY(wlc_hw->band)) {
2256 brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo,
2257 ucode->bcm43xx_16_mimosz);
2258 wlc_hw->ucode_loaded = true;
2259 } else
2260 wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in "
2261 "corerev %d\n",
2262 __func__, wlc_hw->unit, wlc_hw->corerev);
2263 } else if (D11REV_IS(wlc_hw->corerev, 24)) {
2264 if (BRCMS_ISLCNPHY(wlc_hw->band)) {
2265 brcms_ucode_write(wlc_hw, ucode->bcm43xx_24_lcn,
2266 ucode->bcm43xx_24_lcnsz);
2267 wlc_hw->ucode_loaded = true;
2268 } else {
2269 wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in "
2270 "corerev %d\n",
2271 __func__, wlc_hw->unit, wlc_hw->corerev);
2272 }
2273 }
2274}
2275
2276void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant)
2277{
2278 /* update sw state */
2279 wlc_hw->bmac_phytxant = phytxant;
2280
2281 /* push to ucode if up */
2282 if (!wlc_hw->up)
2283 return;
2284 brcms_c_ucode_txant_set(wlc_hw);
2285
2286}
2287
2288u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw)
2289{
2290 return (u16) wlc_hw->wlc->stf->txant;
2291}
2292
2293void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type)
2294{
2295 wlc_hw->antsel_type = antsel_type;
2296
2297 /* Update the antsel type for phy module to use */
2298 wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);
2299}
2300
2301static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
2302{
2303 bool fatal = false;
2304 uint unit;
2305 uint intstatus, idx;
Arend van Spriel16d28122011-12-08 15:06:51 -08002306 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002307 struct wiphy *wiphy = wlc_hw->wlc->wiphy;
2308
2309 unit = wlc_hw->unit;
2310
2311 for (idx = 0; idx < NFIFO; idx++) {
2312 /* read intstatus register and ignore any non-error bits */
2313 intstatus =
Arend van Spriel16d28122011-12-08 15:06:51 -08002314 bcma_read32(core,
2315 D11REGOFFS(intctrlregs[idx].intstatus)) &
2316 I_ERRORS;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002317 if (!intstatus)
2318 continue;
2319
2320 BCMMSG(wlc_hw->wlc->wiphy, "wl%d: intstatus%d 0x%x\n",
2321 unit, idx, intstatus);
2322
2323 if (intstatus & I_RO) {
2324 wiphy_err(wiphy, "wl%d: fifo %d: receive fifo "
2325 "overflow\n", unit, idx);
2326 fatal = true;
2327 }
2328
2329 if (intstatus & I_PC) {
2330 wiphy_err(wiphy, "wl%d: fifo %d: descriptor error\n",
2331 unit, idx);
2332 fatal = true;
2333 }
2334
2335 if (intstatus & I_PD) {
2336 wiphy_err(wiphy, "wl%d: fifo %d: data error\n", unit,
2337 idx);
2338 fatal = true;
2339 }
2340
2341 if (intstatus & I_DE) {
2342 wiphy_err(wiphy, "wl%d: fifo %d: descriptor protocol "
2343 "error\n", unit, idx);
2344 fatal = true;
2345 }
2346
2347 if (intstatus & I_RU)
2348 wiphy_err(wiphy, "wl%d: fifo %d: receive descriptor "
2349 "underflow\n", idx, unit);
2350
2351 if (intstatus & I_XU) {
2352 wiphy_err(wiphy, "wl%d: fifo %d: transmit fifo "
2353 "underflow\n", idx, unit);
2354 fatal = true;
2355 }
2356
2357 if (fatal) {
Roland Vossenc261bdf2011-10-18 14:03:04 +02002358 brcms_fatal_error(wlc_hw->wlc->wl); /* big hammer */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002359 break;
2360 } else
Arend van Spriel16d28122011-12-08 15:06:51 -08002361 bcma_write32(core,
2362 D11REGOFFS(intctrlregs[idx].intstatus),
2363 intstatus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002364 }
2365}
2366
2367void brcms_c_intrson(struct brcms_c_info *wlc)
2368{
2369 struct brcms_hardware *wlc_hw = wlc->hw;
2370 wlc->macintmask = wlc->defmacintmask;
Arend van Spriel16d28122011-12-08 15:06:51 -08002371 bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), wlc->macintmask);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002372}
2373
Arend van Spriel5b435de2011-10-05 13:19:03 +02002374u32 brcms_c_intrsoff(struct brcms_c_info *wlc)
2375{
2376 struct brcms_hardware *wlc_hw = wlc->hw;
2377 u32 macintmask;
2378
2379 if (!wlc_hw->clk)
2380 return 0;
2381
2382 macintmask = wlc->macintmask; /* isr can still happen */
2383
Arend van Spriel16d28122011-12-08 15:06:51 -08002384 bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), 0);
2385 (void)bcma_read32(wlc_hw->d11core, D11REGOFFS(macintmask));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002386 udelay(1); /* ensure int line is no longer driven */
2387 wlc->macintmask = 0;
2388
2389 /* return previous macintmask; resolve race between us and our isr */
2390 return wlc->macintstatus ? 0 : macintmask;
2391}
2392
2393void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask)
2394{
2395 struct brcms_hardware *wlc_hw = wlc->hw;
2396 if (!wlc_hw->clk)
2397 return;
2398
2399 wlc->macintmask = macintmask;
Arend van Spriel16d28122011-12-08 15:06:51 -08002400 bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), wlc->macintmask);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002401}
2402
Roland Vossendc460122011-10-21 16:16:28 +02002403/* assumes that the d11 MAC is enabled */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002404static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
2405 uint tx_fifo)
2406{
2407 u8 fifo = 1 << tx_fifo;
2408
2409 /* Two clients of this code, 11h Quiet period and scanning. */
2410
2411 /* only suspend if not already suspended */
2412 if ((wlc_hw->suspended_fifos & fifo) == fifo)
2413 return;
2414
2415 /* force the core awake only if not already */
2416 if (wlc_hw->suspended_fifos == 0)
2417 brcms_c_ucode_wake_override_set(wlc_hw,
2418 BRCMS_WAKE_OVERRIDE_TXFIFO);
2419
2420 wlc_hw->suspended_fifos |= fifo;
2421
2422 if (wlc_hw->di[tx_fifo]) {
2423 /*
2424 * Suspending AMPDU transmissions in the middle can cause
2425 * underflow which may result in mismatch between ucode and
2426 * driver so suspend the mac before suspending the FIFO
2427 */
2428 if (BRCMS_PHY_11N_CAP(wlc_hw->band))
2429 brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
2430
2431 dma_txsuspend(wlc_hw->di[tx_fifo]);
2432
2433 if (BRCMS_PHY_11N_CAP(wlc_hw->band))
2434 brcms_c_enable_mac(wlc_hw->wlc);
2435 }
2436}
2437
2438static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
2439 uint tx_fifo)
2440{
2441 /* BMAC_NOTE: BRCMS_TX_FIFO_ENAB is done in brcms_c_dpc() for DMA case
2442 * but need to be done here for PIO otherwise the watchdog will catch
2443 * the inconsistency and fire
2444 */
2445 /* Two clients of this code, 11h Quiet period and scanning. */
2446 if (wlc_hw->di[tx_fifo])
2447 dma_txresume(wlc_hw->di[tx_fifo]);
2448
2449 /* allow core to sleep again */
2450 if (wlc_hw->suspended_fifos == 0)
2451 return;
2452 else {
2453 wlc_hw->suspended_fifos &= ~(1 << tx_fifo);
2454 if (wlc_hw->suspended_fifos == 0)
2455 brcms_c_ucode_wake_override_clear(wlc_hw,
2456 BRCMS_WAKE_OVERRIDE_TXFIFO);
2457 }
2458}
2459
Roland Vossena8bc4912011-10-21 16:16:25 +02002460/* precondition: requires the mac core to be enabled */
Roland Vossenc6c44892011-10-21 16:16:26 +02002461static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002462{
2463 static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
2464
Roland Vossenc6c44892011-10-21 16:16:26 +02002465 if (mute_tx) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002466 /* suspend tx fifos */
2467 brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO);
2468 brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO);
2469 brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_BK_FIFO);
2470 brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO);
2471
2472 /* zero the address match register so we do not send ACKs */
2473 brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
2474 null_ether_addr);
2475 } else {
2476 /* resume tx fifos */
2477 brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO);
2478 brcms_b_tx_fifo_resume(wlc_hw, TX_CTL_FIFO);
2479 brcms_b_tx_fifo_resume(wlc_hw, TX_AC_BK_FIFO);
2480 brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO);
2481
2482 /* Restore address */
2483 brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
2484 wlc_hw->etheraddr);
2485 }
2486
Roland Vossenc6c44892011-10-21 16:16:26 +02002487 wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002488
Roland Vossenc6c44892011-10-21 16:16:26 +02002489 if (mute_tx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002490 brcms_c_ucode_mute_override_set(wlc_hw);
2491 else
2492 brcms_c_ucode_mute_override_clear(wlc_hw);
2493}
2494
Roland Vossendc460122011-10-21 16:16:28 +02002495void
2496brcms_c_mute(struct brcms_c_info *wlc, bool mute_tx)
2497{
2498 brcms_b_mute(wlc->hw, mute_tx);
2499}
2500
Arend van Spriel5b435de2011-10-05 13:19:03 +02002501/*
2502 * Read and clear macintmask and macintstatus and intstatus registers.
2503 * This routine should be called with interrupts off
2504 * Return:
2505 * -1 if brcms_deviceremoved(wlc) evaluates to true;
2506 * 0 if the interrupt is not for us, or we are in some special cases;
2507 * device interrupt status bits otherwise.
2508 */
2509static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr)
2510{
2511 struct brcms_hardware *wlc_hw = wlc->hw;
Arend van Spriel16d28122011-12-08 15:06:51 -08002512 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002513 u32 macintstatus;
2514
2515 /* macintstatus includes a DMA interrupt summary bit */
Arend van Spriel16d28122011-12-08 15:06:51 -08002516 macintstatus = bcma_read32(core, D11REGOFFS(macintstatus));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002517
2518 BCMMSG(wlc->wiphy, "wl%d: macintstatus: 0x%x\n", wlc_hw->unit,
2519 macintstatus);
2520
2521 /* detect cardbus removed, in power down(suspend) and in reset */
2522 if (brcms_deviceremoved(wlc))
2523 return -1;
2524
2525 /* brcms_deviceremoved() succeeds even when the core is still resetting,
2526 * handle that case here.
2527 */
2528 if (macintstatus == 0xffffffff)
2529 return 0;
2530
2531 /* defer unsolicited interrupts */
2532 macintstatus &= (in_isr ? wlc->macintmask : wlc->defmacintmask);
2533
2534 /* if not for us */
2535 if (macintstatus == 0)
2536 return 0;
2537
2538 /* interrupts are already turned off for CFE build
2539 * Caution: For CFE Turning off the interrupts again has some undesired
2540 * consequences
2541 */
2542 /* turn off the interrupts */
Arend van Spriel16d28122011-12-08 15:06:51 -08002543 bcma_write32(core, D11REGOFFS(macintmask), 0);
2544 (void)bcma_read32(core, D11REGOFFS(macintmask));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002545 wlc->macintmask = 0;
2546
2547 /* clear device interrupts */
Arend van Spriel16d28122011-12-08 15:06:51 -08002548 bcma_write32(core, D11REGOFFS(macintstatus), macintstatus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002549
2550 /* MI_DMAINT is indication of non-zero intstatus */
2551 if (macintstatus & MI_DMAINT)
2552 /*
2553 * only fifo interrupt enabled is I_RI in
2554 * RX_FIFO. If MI_DMAINT is set, assume it
2555 * is set and clear the interrupt.
2556 */
Arend van Spriel16d28122011-12-08 15:06:51 -08002557 bcma_write32(core, D11REGOFFS(intctrlregs[RX_FIFO].intstatus),
2558 DEF_RXINTMASK);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002559
2560 return macintstatus;
2561}
2562
2563/* Update wlc->macintstatus and wlc->intstatus[]. */
2564/* Return true if they are updated successfully. false otherwise */
2565bool brcms_c_intrsupd(struct brcms_c_info *wlc)
2566{
2567 u32 macintstatus;
2568
2569 /* read and clear macintstatus and intstatus registers */
2570 macintstatus = wlc_intstatus(wlc, false);
2571
2572 /* device is removed */
2573 if (macintstatus == 0xffffffff)
2574 return false;
2575
2576 /* update interrupt status in software */
2577 wlc->macintstatus |= macintstatus;
2578
2579 return true;
2580}
2581
2582/*
2583 * First-level interrupt processing.
2584 * Return true if this was our interrupt, false otherwise.
2585 * *wantdpc will be set to true if further brcms_c_dpc() processing is required,
2586 * false otherwise.
2587 */
2588bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc)
2589{
2590 struct brcms_hardware *wlc_hw = wlc->hw;
2591 u32 macintstatus;
2592
2593 *wantdpc = false;
2594
2595 if (!wlc_hw->up || !wlc->macintmask)
2596 return false;
2597
2598 /* read and clear macintstatus and intstatus registers */
2599 macintstatus = wlc_intstatus(wlc, true);
2600
2601 if (macintstatus == 0xffffffff)
2602 wiphy_err(wlc->wiphy, "DEVICEREMOVED detected in the ISR code"
2603 " path\n");
2604
2605 /* it is not for us */
2606 if (macintstatus == 0)
2607 return false;
2608
2609 *wantdpc = true;
2610
2611 /* save interrupt status bits */
2612 wlc->macintstatus = macintstatus;
2613
2614 return true;
2615
2616}
2617
2618void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)
2619{
2620 struct brcms_hardware *wlc_hw = wlc->hw;
Arend van Spriel16d28122011-12-08 15:06:51 -08002621 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002622 u32 mc, mi;
2623 struct wiphy *wiphy = wlc->wiphy;
2624
2625 BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
2626 wlc_hw->band->bandunit);
2627
2628 /*
2629 * Track overlapping suspend requests
2630 */
2631 wlc_hw->mac_suspend_depth++;
2632 if (wlc_hw->mac_suspend_depth > 1)
2633 return;
2634
2635 /* force the core awake */
2636 brcms_c_ucode_wake_override_set(wlc_hw, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
2637
Arend van Spriel16d28122011-12-08 15:06:51 -08002638 mc = bcma_read32(core, D11REGOFFS(maccontrol));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002639
2640 if (mc == 0xffffffff) {
2641 wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
2642 __func__);
2643 brcms_down(wlc->wl);
2644 return;
2645 }
2646 WARN_ON(mc & MCTL_PSM_JMP_0);
2647 WARN_ON(!(mc & MCTL_PSM_RUN));
2648 WARN_ON(!(mc & MCTL_EN_MAC));
2649
Arend van Spriel16d28122011-12-08 15:06:51 -08002650 mi = bcma_read32(core, D11REGOFFS(macintstatus));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002651 if (mi == 0xffffffff) {
2652 wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
2653 __func__);
2654 brcms_down(wlc->wl);
2655 return;
2656 }
2657 WARN_ON(mi & MI_MACSSPNDD);
2658
2659 brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, 0);
2660
Arend van Spriel16d28122011-12-08 15:06:51 -08002661 SPINWAIT(!(bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD),
Arend van Spriel5b435de2011-10-05 13:19:03 +02002662 BRCMS_MAX_MAC_SUSPEND);
2663
Arend van Spriel16d28122011-12-08 15:06:51 -08002664 if (!(bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002665 wiphy_err(wiphy, "wl%d: wlc_suspend_mac_and_wait: waited %d uS"
2666 " and MI_MACSSPNDD is still not on.\n",
2667 wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND);
2668 wiphy_err(wiphy, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, "
2669 "psm_brc 0x%04x\n", wlc_hw->unit,
Arend van Spriel16d28122011-12-08 15:06:51 -08002670 bcma_read32(core, D11REGOFFS(psmdebug)),
2671 bcma_read32(core, D11REGOFFS(phydebug)),
2672 bcma_read16(core, D11REGOFFS(psm_brc)));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002673 }
2674
Arend van Spriel16d28122011-12-08 15:06:51 -08002675 mc = bcma_read32(core, D11REGOFFS(maccontrol));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002676 if (mc == 0xffffffff) {
2677 wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
2678 __func__);
2679 brcms_down(wlc->wl);
2680 return;
2681 }
2682 WARN_ON(mc & MCTL_PSM_JMP_0);
2683 WARN_ON(!(mc & MCTL_PSM_RUN));
2684 WARN_ON(mc & MCTL_EN_MAC);
2685}
2686
2687void brcms_c_enable_mac(struct brcms_c_info *wlc)
2688{
2689 struct brcms_hardware *wlc_hw = wlc->hw;
Arend van Spriel16d28122011-12-08 15:06:51 -08002690 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002691 u32 mc, mi;
2692
2693 BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
2694 wlc->band->bandunit);
2695
2696 /*
2697 * Track overlapping suspend requests
2698 */
2699 wlc_hw->mac_suspend_depth--;
2700 if (wlc_hw->mac_suspend_depth > 0)
2701 return;
2702
Arend van Spriel16d28122011-12-08 15:06:51 -08002703 mc = bcma_read32(core, D11REGOFFS(maccontrol));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002704 WARN_ON(mc & MCTL_PSM_JMP_0);
2705 WARN_ON(mc & MCTL_EN_MAC);
2706 WARN_ON(!(mc & MCTL_PSM_RUN));
2707
2708 brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, MCTL_EN_MAC);
Arend van Spriel16d28122011-12-08 15:06:51 -08002709 bcma_write32(core, D11REGOFFS(macintstatus), MI_MACSSPNDD);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002710
Arend van Spriel16d28122011-12-08 15:06:51 -08002711 mc = bcma_read32(core, D11REGOFFS(maccontrol));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002712 WARN_ON(mc & MCTL_PSM_JMP_0);
2713 WARN_ON(!(mc & MCTL_EN_MAC));
2714 WARN_ON(!(mc & MCTL_PSM_RUN));
2715
Arend van Spriel16d28122011-12-08 15:06:51 -08002716 mi = bcma_read32(core, D11REGOFFS(macintstatus));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002717 WARN_ON(mi & MI_MACSSPNDD);
2718
2719 brcms_c_ucode_wake_override_clear(wlc_hw,
2720 BRCMS_WAKE_OVERRIDE_MACSUSPEND);
2721}
2722
2723void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode)
2724{
2725 wlc_hw->hw_stf_ss_opmode = stf_mode;
2726
2727 if (wlc_hw->clk)
2728 brcms_upd_ofdm_pctl1_table(wlc_hw);
2729}
2730
2731static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw)
2732{
Arend van Spriel16d28122011-12-08 15:06:51 -08002733 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002734 u32 w, val;
2735 struct wiphy *wiphy = wlc_hw->wlc->wiphy;
2736
2737 BCMMSG(wiphy, "wl%d\n", wlc_hw->unit);
2738
Arend van Spriel5b435de2011-10-05 13:19:03 +02002739 /* Validate dchip register access */
2740
Arend van Spriel16d28122011-12-08 15:06:51 -08002741 bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2742 (void)bcma_read32(core, D11REGOFFS(objaddr));
2743 w = bcma_read32(core, D11REGOFFS(objdata));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002744
2745 /* Can we write and read back a 32bit register? */
Arend van Spriel16d28122011-12-08 15:06:51 -08002746 bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2747 (void)bcma_read32(core, D11REGOFFS(objaddr));
2748 bcma_write32(core, D11REGOFFS(objdata), (u32) 0xaa5555aa);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002749
Arend van Spriel16d28122011-12-08 15:06:51 -08002750 bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2751 (void)bcma_read32(core, D11REGOFFS(objaddr));
2752 val = bcma_read32(core, D11REGOFFS(objdata));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002753 if (val != (u32) 0xaa5555aa) {
2754 wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "
2755 "expected 0xaa5555aa\n", wlc_hw->unit, val);
2756 return false;
2757 }
2758
Arend van Spriel16d28122011-12-08 15:06:51 -08002759 bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2760 (void)bcma_read32(core, D11REGOFFS(objaddr));
2761 bcma_write32(core, D11REGOFFS(objdata), (u32) 0x55aaaa55);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002762
Arend van Spriel16d28122011-12-08 15:06:51 -08002763 bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2764 (void)bcma_read32(core, D11REGOFFS(objaddr));
2765 val = bcma_read32(core, D11REGOFFS(objdata));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002766 if (val != (u32) 0x55aaaa55) {
2767 wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "
2768 "expected 0x55aaaa55\n", wlc_hw->unit, val);
2769 return false;
2770 }
2771
Arend van Spriel16d28122011-12-08 15:06:51 -08002772 bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2773 (void)bcma_read32(core, D11REGOFFS(objaddr));
2774 bcma_write32(core, D11REGOFFS(objdata), w);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002775
2776 /* clear CFPStart */
Arend van Spriel16d28122011-12-08 15:06:51 -08002777 bcma_write32(core, D11REGOFFS(tsf_cfpstart), 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002778
Arend van Spriel16d28122011-12-08 15:06:51 -08002779 w = bcma_read32(core, D11REGOFFS(maccontrol));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002780 if ((w != (MCTL_IHR_EN | MCTL_WAKE)) &&
2781 (w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) {
2782 wiphy_err(wiphy, "wl%d: validate_chip_access: maccontrol = "
2783 "0x%x, expected 0x%x or 0x%x\n", wlc_hw->unit, w,
2784 (MCTL_IHR_EN | MCTL_WAKE),
2785 (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE));
2786 return false;
2787 }
2788
2789 return true;
2790}
2791
2792#define PHYPLL_WAIT_US 100000
2793
2794void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on)
2795{
Arend van Spriel16d28122011-12-08 15:06:51 -08002796 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002797 u32 tmp;
2798
2799 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
2800
2801 tmp = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002802
2803 if (on) {
Arend van Sprielb2ffec42011-12-08 15:06:45 -08002804 if ((ai_get_chip_id(wlc_hw->sih) == BCM4313_CHIP_ID)) {
Arend van Spriel16d28122011-12-08 15:06:51 -08002805 bcma_set32(core, D11REGOFFS(clk_ctl_st),
2806 CCS_ERSRC_REQ_HT |
2807 CCS_ERSRC_REQ_D11PLL |
2808 CCS_ERSRC_REQ_PHYPLL);
2809 SPINWAIT((bcma_read32(core, D11REGOFFS(clk_ctl_st)) &
2810 CCS_ERSRC_AVAIL_HT) != CCS_ERSRC_AVAIL_HT,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002811 PHYPLL_WAIT_US);
2812
Arend van Spriel16d28122011-12-08 15:06:51 -08002813 tmp = bcma_read32(core, D11REGOFFS(clk_ctl_st));
2814 if ((tmp & CCS_ERSRC_AVAIL_HT) != CCS_ERSRC_AVAIL_HT)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002815 wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on PHY"
2816 " PLL failed\n", __func__);
2817 } else {
Arend van Spriel16d28122011-12-08 15:06:51 -08002818 bcma_set32(core, D11REGOFFS(clk_ctl_st),
2819 tmp | CCS_ERSRC_REQ_D11PLL |
2820 CCS_ERSRC_REQ_PHYPLL);
2821 SPINWAIT((bcma_read32(core, D11REGOFFS(clk_ctl_st)) &
Arend van Spriel5b435de2011-10-05 13:19:03 +02002822 (CCS_ERSRC_AVAIL_D11PLL |
2823 CCS_ERSRC_AVAIL_PHYPLL)) !=
2824 (CCS_ERSRC_AVAIL_D11PLL |
2825 CCS_ERSRC_AVAIL_PHYPLL), PHYPLL_WAIT_US);
2826
Arend van Spriel16d28122011-12-08 15:06:51 -08002827 tmp = bcma_read32(core, D11REGOFFS(clk_ctl_st));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002828 if ((tmp &
2829 (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
2830 !=
2831 (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
2832 wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on "
2833 "PHY PLL failed\n", __func__);
2834 }
2835 } else {
2836 /*
2837 * Since the PLL may be shared, other cores can still
2838 * be requesting it; so we'll deassert the request but
2839 * not wait for status to comply.
2840 */
Arend van Spriel16d28122011-12-08 15:06:51 -08002841 bcma_mask32(core, D11REGOFFS(clk_ctl_st),
2842 ~CCS_ERSRC_REQ_PHYPLL);
2843 (void)bcma_read32(core, D11REGOFFS(clk_ctl_st));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002844 }
2845}
2846
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02002847static void brcms_c_coredisable(struct brcms_hardware *wlc_hw)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002848{
2849 bool dev_gone;
2850
2851 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
2852
2853 dev_gone = brcms_deviceremoved(wlc_hw->wlc);
2854
2855 if (dev_gone)
2856 return;
2857
2858 if (wlc_hw->noreset)
2859 return;
2860
2861 /* radio off */
2862 wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
2863
2864 /* turn off analog core */
2865 wlc_phy_anacore(wlc_hw->band->pi, OFF);
2866
2867 /* turn off PHYPLL to save power */
2868 brcms_b_core_phypll_ctl(wlc_hw, false);
2869
2870 wlc_hw->clk = false;
Arend van Spriela8779e42011-12-08 15:06:58 -08002871 bcma_core_disable(wlc_hw->d11core, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002872 wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
2873}
2874
2875static void brcms_c_flushqueues(struct brcms_c_info *wlc)
2876{
2877 struct brcms_hardware *wlc_hw = wlc->hw;
2878 uint i;
2879
2880 /* free any posted tx packets */
2881 for (i = 0; i < NFIFO; i++)
2882 if (wlc_hw->di[i]) {
2883 dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL);
2884 wlc->core->txpktpend[i] = 0;
2885 BCMMSG(wlc->wiphy, "pktpend fifo %d clrd\n", i);
2886 }
2887
2888 /* free any posted rx packets */
2889 dma_rxreclaim(wlc_hw->di[RX_FIFO]);
2890}
2891
2892static u16
2893brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel)
2894{
Arend van Spriel16d28122011-12-08 15:06:51 -08002895 struct bcma_device *core = wlc_hw->d11core;
2896 u16 objoff = D11REGOFFS(objdata);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002897
Arend van Spriel16d28122011-12-08 15:06:51 -08002898 bcma_write32(core, D11REGOFFS(objaddr), sel | (offset >> 2));
2899 (void)bcma_read32(core, D11REGOFFS(objaddr));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002900 if (offset & 2)
Arend van Spriel16d28122011-12-08 15:06:51 -08002901 objoff += 2;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002902
Arend van Spriel16d28122011-12-08 15:06:51 -08002903 return bcma_read16(core, objoff);
2904;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002905}
2906
2907static void
2908brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset, u16 v,
2909 u32 sel)
2910{
Arend van Spriel16d28122011-12-08 15:06:51 -08002911 struct bcma_device *core = wlc_hw->d11core;
2912 u16 objoff = D11REGOFFS(objdata);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002913
Arend van Spriel16d28122011-12-08 15:06:51 -08002914 bcma_write32(core, D11REGOFFS(objaddr), sel | (offset >> 2));
2915 (void)bcma_read32(core, D11REGOFFS(objaddr));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002916 if (offset & 2)
Arend van Spriel16d28122011-12-08 15:06:51 -08002917 objoff += 2;
2918
2919 bcma_write16(core, objoff, v);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002920}
2921
2922/*
2923 * Read a single u16 from shared memory.
2924 * SHM 'offset' needs to be an even address
2925 */
2926u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset)
2927{
2928 return brcms_b_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL);
2929}
2930
2931/*
2932 * Write a single u16 to shared memory.
2933 * SHM 'offset' needs to be an even address
2934 */
2935void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v)
2936{
2937 brcms_b_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL);
2938}
2939
2940/*
2941 * Copy a buffer to shared memory of specified type .
2942 * SHM 'offset' needs to be an even address and
2943 * Buffer length 'len' must be an even number of bytes
2944 * 'sel' selects the type of memory
2945 */
2946void
2947brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, uint offset,
2948 const void *buf, int len, u32 sel)
2949{
2950 u16 v;
2951 const u8 *p = (const u8 *)buf;
2952 int i;
2953
2954 if (len <= 0 || (offset & 1) || (len & 1))
2955 return;
2956
2957 for (i = 0; i < len; i += 2) {
2958 v = p[i] | (p[i + 1] << 8);
2959 brcms_b_write_objmem(wlc_hw, offset + i, v, sel);
2960 }
2961}
2962
2963/*
2964 * Copy a piece of shared memory of specified type to a buffer .
2965 * SHM 'offset' needs to be an even address and
2966 * Buffer length 'len' must be an even number of bytes
2967 * 'sel' selects the type of memory
2968 */
2969void
2970brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, void *buf,
2971 int len, u32 sel)
2972{
2973 u16 v;
2974 u8 *p = (u8 *) buf;
2975 int i;
2976
2977 if (len <= 0 || (offset & 1) || (len & 1))
2978 return;
2979
2980 for (i = 0; i < len; i += 2) {
2981 v = brcms_b_read_objmem(wlc_hw, offset + i, sel);
2982 p[i] = v & 0xFF;
2983 p[i + 1] = (v >> 8) & 0xFF;
2984 }
2985}
2986
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02002987/* Copy a buffer to shared memory.
2988 * SHM 'offset' needs to be an even address and
2989 * Buffer length 'len' must be an even number of bytes
2990 */
2991static void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset,
2992 const void *buf, int len)
2993{
2994 brcms_b_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL);
2995}
2996
Arend van Spriel5b435de2011-10-05 13:19:03 +02002997static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw,
2998 u16 SRL, u16 LRL)
2999{
3000 wlc_hw->SRL = SRL;
3001 wlc_hw->LRL = LRL;
3002
3003 /* write retry limit to SCR, shouldn't need to suspend */
3004 if (wlc_hw->up) {
Arend van Spriel16d28122011-12-08 15:06:51 -08003005 bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),
3006 OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
3007 (void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));
3008 bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), wlc_hw->SRL);
3009 bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),
3010 OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
3011 (void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));
3012 bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), wlc_hw->LRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003013 }
3014}
3015
3016static void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, u32 req_bit)
3017{
3018 if (set) {
3019 if (mboolisset(wlc_hw->pllreq, req_bit))
3020 return;
3021
3022 mboolset(wlc_hw->pllreq, req_bit);
3023
3024 if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {
3025 if (!wlc_hw->sbclk)
3026 brcms_b_xtal(wlc_hw, ON);
3027 }
3028 } else {
3029 if (!mboolisset(wlc_hw->pllreq, req_bit))
3030 return;
3031
3032 mboolclr(wlc_hw->pllreq, req_bit);
3033
3034 if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {
3035 if (wlc_hw->sbclk)
3036 brcms_b_xtal(wlc_hw, OFF);
3037 }
3038 }
3039}
3040
3041static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
3042{
3043 wlc_hw->antsel_avail = antsel_avail;
3044}
3045
3046/*
3047 * conditions under which the PM bit should be set in outgoing frames
3048 * and STAY_AWAKE is meaningful
3049 */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003050static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003051{
3052 struct brcms_bss_cfg *cfg = wlc->bsscfg;
3053
3054 /* disallow PS when one of the following global conditions meets */
3055 if (!wlc->pub->associated)
3056 return false;
3057
3058 /* disallow PS when one of these meets when not scanning */
Alwin Beukersbe667662011-11-22 17:21:43 -08003059 if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003060 return false;
3061
3062 if (cfg->associated) {
3063 /*
3064 * disallow PS when one of the following
3065 * bsscfg specific conditions meets
3066 */
3067 if (!cfg->BSS)
3068 return false;
3069
3070 return false;
3071 }
3072
3073 return true;
3074}
3075
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003076static void brcms_c_statsupd(struct brcms_c_info *wlc)
3077{
3078 int i;
3079 struct macstat macstats;
Joe Perches8ae74652012-01-15 00:38:38 -08003080#ifdef DEBUG
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003081 u16 delta;
3082 u16 rxf0ovfl;
3083 u16 txfunfl[NFIFO];
Joe Perches8ae74652012-01-15 00:38:38 -08003084#endif /* DEBUG */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003085
3086 /* if driver down, make no sense to update stats */
3087 if (!wlc->pub->up)
3088 return;
3089
Joe Perches8ae74652012-01-15 00:38:38 -08003090#ifdef DEBUG
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003091 /* save last rx fifo 0 overflow count */
3092 rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl;
3093
3094 /* save last tx fifo underflow count */
3095 for (i = 0; i < NFIFO; i++)
3096 txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i];
Joe Perches8ae74652012-01-15 00:38:38 -08003097#endif /* DEBUG */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003098
3099 /* Read mac stats from contiguous shared memory */
3100 brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, &macstats,
3101 sizeof(struct macstat), OBJADDR_SHM_SEL);
3102
Joe Perches8ae74652012-01-15 00:38:38 -08003103#ifdef DEBUG
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003104 /* check for rx fifo 0 overflow */
3105 delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
3106 if (delta)
3107 wiphy_err(wlc->wiphy, "wl%d: %u rx fifo 0 overflows!\n",
3108 wlc->pub->unit, delta);
3109
3110 /* check for tx fifo underflows */
3111 for (i = 0; i < NFIFO; i++) {
3112 delta =
3113 (u16) (wlc->core->macstat_snapshot->txfunfl[i] -
3114 txfunfl[i]);
3115 if (delta)
3116 wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!"
3117 "\n", wlc->pub->unit, delta, i);
3118 }
Joe Perches8ae74652012-01-15 00:38:38 -08003119#endif /* DEBUG */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003120
3121 /* merge counters from dma module */
3122 for (i = 0; i < NFIFO; i++) {
3123 if (wlc->hw->di[i])
3124 dma_counterreset(wlc->hw->di[i]);
3125 }
3126}
3127
Arend van Spriel5b435de2011-10-05 13:19:03 +02003128static void brcms_b_reset(struct brcms_hardware *wlc_hw)
3129{
3130 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
3131
3132 /* reset the core */
3133 if (!brcms_deviceremoved(wlc_hw->wlc))
3134 brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
3135
3136 /* purge the dma rings */
3137 brcms_c_flushqueues(wlc_hw->wlc);
3138}
3139
3140void brcms_c_reset(struct brcms_c_info *wlc)
3141{
3142 BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
3143
3144 /* slurp up hw mac counters before core reset */
3145 brcms_c_statsupd(wlc);
3146
3147 /* reset our snapshot of macstat counters */
3148 memset((char *)wlc->core->macstat_snapshot, 0,
3149 sizeof(struct macstat));
3150
3151 brcms_b_reset(wlc->hw);
3152}
3153
Arend van Spriel5b435de2011-10-05 13:19:03 +02003154/* Return the channel the driver should initialize during brcms_c_init.
3155 * the channel may have to be changed from the currently configured channel
3156 * if other configurations are in conflict (bandlocked, 11n mode disabled,
3157 * invalid channel for current country, etc.)
3158 */
3159static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc)
3160{
3161 u16 chanspec =
3162 1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE |
3163 WL_CHANSPEC_BAND_2G;
3164
3165 return chanspec;
3166}
3167
3168void brcms_c_init_scb(struct scb *scb)
3169{
3170 int i;
3171
3172 memset(scb, 0, sizeof(struct scb));
3173 scb->flags = SCB_WMECAP | SCB_HTCAP;
3174 for (i = 0; i < NUMPRIO; i++) {
3175 scb->seqnum[i] = 0;
3176 scb->seqctl[i] = 0xFFFF;
3177 }
3178
3179 scb->seqctl_nonqos = 0xFFFF;
3180 scb->magic = SCB_MAGIC;
3181}
3182
3183/* d11 core init
3184 * reset PSM
3185 * download ucode/PCM
3186 * let ucode run to suspended
3187 * download ucode inits
3188 * config other core registers
3189 * init dma
3190 */
3191static void brcms_b_coreinit(struct brcms_c_info *wlc)
3192{
3193 struct brcms_hardware *wlc_hw = wlc->hw;
Arend van Spriel16d28122011-12-08 15:06:51 -08003194 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003195 u32 sflags;
Arend van Spriel16d28122011-12-08 15:06:51 -08003196 u32 bcnint_us;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003197 uint i = 0;
3198 bool fifosz_fixup = false;
3199 int err = 0;
3200 u16 buf[NFIFO];
3201 struct wiphy *wiphy = wlc->wiphy;
3202 struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
3203
Arend van Spriel5b435de2011-10-05 13:19:03 +02003204 BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
3205
3206 /* reset PSM */
3207 brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE));
3208
3209 brcms_ucode_download(wlc_hw);
3210 /*
3211 * FIFOSZ fixup. driver wants to controls the fifo allocation.
3212 */
3213 fifosz_fixup = true;
3214
3215 /* let the PSM run to the suspended state, set mode to BSS STA */
Arend van Spriel16d28122011-12-08 15:06:51 -08003216 bcma_write32(core, D11REGOFFS(macintstatus), -1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003217 brcms_b_mctrl(wlc_hw, ~0,
3218 (MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE));
3219
3220 /* wait for ucode to self-suspend after auto-init */
Arend van Spriel16d28122011-12-08 15:06:51 -08003221 SPINWAIT(((bcma_read32(core, D11REGOFFS(macintstatus)) &
3222 MI_MACSSPNDD) == 0), 1000 * 1000);
3223 if ((bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD) == 0)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003224 wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-"
3225 "suspend!\n", wlc_hw->unit);
3226
3227 brcms_c_gpio_init(wlc);
3228
Arend van Spriela8779e42011-12-08 15:06:58 -08003229 sflags = bcma_aread32(core, BCMA_IOST);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003230
3231 if (D11REV_IS(wlc_hw->corerev, 23)) {
3232 if (BRCMS_ISNPHY(wlc_hw->band))
3233 brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);
3234 else
3235 wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
3236 " %d\n", __func__, wlc_hw->unit,
3237 wlc_hw->corerev);
3238 } else if (D11REV_IS(wlc_hw->corerev, 24)) {
3239 if (BRCMS_ISLCNPHY(wlc_hw->band))
3240 brcms_c_write_inits(wlc_hw, ucode->d11lcn0initvals24);
3241 else
3242 wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
3243 " %d\n", __func__, wlc_hw->unit,
3244 wlc_hw->corerev);
3245 } else {
3246 wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
3247 __func__, wlc_hw->unit, wlc_hw->corerev);
3248 }
3249
3250 /* For old ucode, txfifo sizes needs to be modified(increased) */
3251 if (fifosz_fixup == true)
3252 brcms_b_corerev_fifofixup(wlc_hw);
3253
3254 /* check txfifo allocations match between ucode and driver */
3255 buf[TX_AC_BE_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE0);
3256 if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) {
3257 i = TX_AC_BE_FIFO;
3258 err = -1;
3259 }
3260 buf[TX_AC_VI_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE1);
3261 if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) {
3262 i = TX_AC_VI_FIFO;
3263 err = -1;
3264 }
3265 buf[TX_AC_BK_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE2);
3266 buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff;
3267 buf[TX_AC_BK_FIFO] &= 0xff;
3268 if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) {
3269 i = TX_AC_BK_FIFO;
3270 err = -1;
3271 }
3272 if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) {
3273 i = TX_AC_VO_FIFO;
3274 err = -1;
3275 }
3276 buf[TX_BCMC_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE3);
3277 buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff;
3278 buf[TX_BCMC_FIFO] &= 0xff;
3279 if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) {
3280 i = TX_BCMC_FIFO;
3281 err = -1;
3282 }
3283 if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) {
3284 i = TX_ATIM_FIFO;
3285 err = -1;
3286 }
3287 if (err != 0)
3288 wiphy_err(wiphy, "wlc_coreinit: txfifo mismatch: ucode size %d"
3289 " driver size %d index %d\n", buf[i],
3290 wlc_hw->xmtfifo_sz[i], i);
3291
3292 /* make sure we can still talk to the mac */
Arend van Spriel16d28122011-12-08 15:06:51 -08003293 WARN_ON(bcma_read32(core, D11REGOFFS(maccontrol)) == 0xffffffff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003294
3295 /* band-specific inits done by wlc_bsinit() */
3296
3297 /* Set up frame burst size and antenna swap threshold init values */
3298 brcms_b_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST);
3299 brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT);
3300
3301 /* enable one rx interrupt per received frame */
Arend van Spriel16d28122011-12-08 15:06:51 -08003302 bcma_write32(core, D11REGOFFS(intrcvlazy[0]), (1 << IRL_FC_SHIFT));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003303
3304 /* set the station mode (BSS STA) */
3305 brcms_b_mctrl(wlc_hw,
3306 (MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP),
3307 (MCTL_INFRA | MCTL_DISCARD_PMQ));
3308
3309 /* set up Beacon interval */
3310 bcnint_us = 0x8000 << 10;
Arend van Spriel16d28122011-12-08 15:06:51 -08003311 bcma_write32(core, D11REGOFFS(tsf_cfprep),
3312 (bcnint_us << CFPREP_CBI_SHIFT));
3313 bcma_write32(core, D11REGOFFS(tsf_cfpstart), bcnint_us);
3314 bcma_write32(core, D11REGOFFS(macintstatus), MI_GP1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003315
3316 /* write interrupt mask */
Arend van Spriel16d28122011-12-08 15:06:51 -08003317 bcma_write32(core, D11REGOFFS(intctrlregs[RX_FIFO].intmask),
3318 DEF_RXINTMASK);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003319
3320 /* allow the MAC to control the PHY clock (dynamic on/off) */
3321 brcms_b_macphyclk_set(wlc_hw, ON);
3322
3323 /* program dynamic clock control fast powerup delay register */
3324 wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih);
Arend van Spriel16d28122011-12-08 15:06:51 -08003325 bcma_write16(core, D11REGOFFS(scc_fastpwrup_dly), wlc->fastpwrup_dly);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003326
3327 /* tell the ucode the corerev */
3328 brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev);
3329
3330 /* tell the ucode MAC capabilities */
3331 brcms_b_write_shm(wlc_hw, M_MACHW_CAP_L,
3332 (u16) (wlc_hw->machwcap & 0xffff));
3333 brcms_b_write_shm(wlc_hw, M_MACHW_CAP_H,
3334 (u16) ((wlc_hw->
3335 machwcap >> 16) & 0xffff));
3336
3337 /* write retry limits to SCR, this done after PSM init */
Arend van Spriel16d28122011-12-08 15:06:51 -08003338 bcma_write32(core, D11REGOFFS(objaddr),
3339 OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
3340 (void)bcma_read32(core, D11REGOFFS(objaddr));
3341 bcma_write32(core, D11REGOFFS(objdata), wlc_hw->SRL);
3342 bcma_write32(core, D11REGOFFS(objaddr),
3343 OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
3344 (void)bcma_read32(core, D11REGOFFS(objaddr));
3345 bcma_write32(core, D11REGOFFS(objdata), wlc_hw->LRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003346
3347 /* write rate fallback retry limits */
3348 brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL);
3349 brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL);
3350
Arend van Spriel16d28122011-12-08 15:06:51 -08003351 bcma_mask16(core, D11REGOFFS(ifs_ctl), 0x0FFF);
3352 bcma_write16(core, D11REGOFFS(ifs_aifsn), EDCF_AIFSN_MIN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003353
3354 /* init the tx dma engines */
3355 for (i = 0; i < NFIFO; i++) {
3356 if (wlc_hw->di[i])
3357 dma_txinit(wlc_hw->di[i]);
3358 }
3359
3360 /* init the rx dma engine(s) and post receive buffers */
3361 dma_rxinit(wlc_hw->di[RX_FIFO]);
3362 dma_rxfill(wlc_hw->di[RX_FIFO]);
3363}
3364
3365void
Roland Vossena8bc4912011-10-21 16:16:25 +02003366static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003367 u32 macintmask;
3368 bool fastclk;
3369 struct brcms_c_info *wlc = wlc_hw->wlc;
3370
3371 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
3372
3373 /* request FAST clock if not on */
3374 fastclk = wlc_hw->forcefastclk;
3375 if (!fastclk)
3376 brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
3377
3378 /* disable interrupts */
3379 macintmask = brcms_intrsoff(wlc->wl);
3380
3381 /* set up the specified band and chanspec */
3382 brcms_c_setxband(wlc_hw, chspec_bandunit(chanspec));
3383 wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
3384
3385 /* do one-time phy inits and calibration */
3386 wlc_phy_cal_init(wlc_hw->band->pi);
3387
3388 /* core-specific initialization */
3389 brcms_b_coreinit(wlc);
3390
Arend van Spriel5b435de2011-10-05 13:19:03 +02003391 /* band-specific inits */
3392 brcms_b_bsinit(wlc, chanspec);
3393
3394 /* restore macintmask */
3395 brcms_intrsrestore(wlc->wl, macintmask);
3396
3397 /* seed wake_override with BRCMS_WAKE_OVERRIDE_MACSUSPEND since the mac
3398 * is suspended and brcms_c_enable_mac() will clear this override bit.
3399 */
3400 mboolset(wlc_hw->wake_override, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
3401
3402 /*
3403 * initialize mac_suspend_depth to 1 to match ucode
3404 * initial suspended state
3405 */
3406 wlc_hw->mac_suspend_depth = 1;
3407
3408 /* restore the clk */
3409 if (!fastclk)
3410 brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
3411}
3412
3413static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
3414 u16 chanspec)
3415{
3416 /* Save our copy of the chanspec */
3417 wlc->chanspec = chanspec;
3418
3419 /* Set the chanspec and power limits for this locale */
3420 brcms_c_channel_set_chanspec(wlc->cmi, chanspec, BRCMS_TXPWR_MAX);
3421
3422 if (wlc->stf->ss_algosel_auto)
3423 brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel,
3424 chanspec);
3425
3426 brcms_c_stf_ss_update(wlc, wlc->band);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003427}
Arend van Spriel5b435de2011-10-05 13:19:03 +02003428
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003429static void
3430brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs)
3431{
3432 brcms_c_rateset_default(rs, NULL, wlc->band->phytype,
3433 wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL,
3434 (bool) (wlc->pub->_n_enab & SUPPORT_11N),
3435 brcms_chspec_bw(wlc->default_bss->chanspec),
3436 wlc->stf->txstreams);
3437}
3438
3439/* derive wlc->band->basic_rate[] table from 'rateset' */
3440static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
3441 struct brcms_c_rateset *rateset)
3442{
3443 u8 rate;
3444 u8 mandatory;
3445 u8 cck_basic = 0;
3446 u8 ofdm_basic = 0;
3447 u8 *br = wlc->band->basic_rate;
3448 uint i;
3449
3450 /* incoming rates are in 500kbps units as in 802.11 Supported Rates */
3451 memset(br, 0, BRCM_MAXRATE + 1);
3452
3453 /* For each basic rate in the rates list, make an entry in the
3454 * best basic lookup.
3455 */
3456 for (i = 0; i < rateset->count; i++) {
3457 /* only make an entry for a basic rate */
3458 if (!(rateset->rates[i] & BRCMS_RATE_FLAG))
3459 continue;
3460
3461 /* mask off basic bit */
3462 rate = (rateset->rates[i] & BRCMS_RATE_MASK);
3463
3464 if (rate > BRCM_MAXRATE) {
3465 wiphy_err(wlc->wiphy, "brcms_c_rate_lookup_init: "
3466 "invalid rate 0x%X in rate set\n",
3467 rateset->rates[i]);
3468 continue;
3469 }
3470
3471 br[rate] = rate;
3472 }
3473
3474 /* The rate lookup table now has non-zero entries for each
3475 * basic rate, equal to the basic rate: br[basicN] = basicN
3476 *
3477 * To look up the best basic rate corresponding to any
3478 * particular rate, code can use the basic_rate table
3479 * like this
3480 *
3481 * basic_rate = wlc->band->basic_rate[tx_rate]
3482 *
3483 * Make sure there is a best basic rate entry for
3484 * every rate by walking up the table from low rates
3485 * to high, filling in holes in the lookup table
3486 */
3487
3488 for (i = 0; i < wlc->band->hw_rateset.count; i++) {
3489 rate = wlc->band->hw_rateset.rates[i];
3490
3491 if (br[rate] != 0) {
3492 /* This rate is a basic rate.
3493 * Keep track of the best basic rate so far by
3494 * modulation type.
3495 */
3496 if (is_ofdm_rate(rate))
3497 ofdm_basic = rate;
3498 else
3499 cck_basic = rate;
3500
3501 continue;
3502 }
3503
3504 /* This rate is not a basic rate so figure out the
3505 * best basic rate less than this rate and fill in
3506 * the hole in the table
3507 */
3508
3509 br[rate] = is_ofdm_rate(rate) ? ofdm_basic : cck_basic;
3510
3511 if (br[rate] != 0)
3512 continue;
3513
3514 if (is_ofdm_rate(rate)) {
3515 /*
3516 * In 11g and 11a, the OFDM mandatory rates
3517 * are 6, 12, and 24 Mbps
3518 */
3519 if (rate >= BRCM_RATE_24M)
3520 mandatory = BRCM_RATE_24M;
3521 else if (rate >= BRCM_RATE_12M)
3522 mandatory = BRCM_RATE_12M;
3523 else
3524 mandatory = BRCM_RATE_6M;
3525 } else {
3526 /* In 11b, all CCK rates are mandatory 1 - 11 Mbps */
3527 mandatory = rate;
3528 }
3529
3530 br[rate] = mandatory;
3531 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003532}
3533
3534static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
3535 u16 chanspec)
3536{
3537 struct brcms_c_rateset default_rateset;
3538 uint parkband;
3539 uint i, band_order[2];
3540
3541 BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
3542 /*
3543 * We might have been bandlocked during down and the chip
3544 * power-cycled (hibernate). Figure out the right band to park on
3545 */
3546 if (wlc->bandlocked || wlc->pub->_nbands == 1) {
3547 /* updated in brcms_c_bandlock() */
3548 parkband = wlc->band->bandunit;
3549 band_order[0] = band_order[1] = parkband;
3550 } else {
3551 /* park on the band of the specified chanspec */
3552 parkband = chspec_bandunit(chanspec);
3553
3554 /* order so that parkband initialize last */
3555 band_order[0] = parkband ^ 1;
3556 band_order[1] = parkband;
3557 }
3558
3559 /* make each band operational, software state init */
3560 for (i = 0; i < wlc->pub->_nbands; i++) {
3561 uint j = band_order[i];
3562
3563 wlc->band = wlc->bandstate[j];
3564
3565 brcms_default_rateset(wlc, &default_rateset);
3566
3567 /* fill in hw_rate */
3568 brcms_c_rateset_filter(&default_rateset, &wlc->band->hw_rateset,
3569 false, BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
3570 (bool) (wlc->pub->_n_enab & SUPPORT_11N));
3571
3572 /* init basic rate lookup */
3573 brcms_c_rate_lookup_init(wlc, &default_rateset);
3574 }
3575
3576 /* sync up phy/radio chanspec */
3577 brcms_c_set_phy_chanspec(wlc, chanspec);
3578}
3579
Alwin Beukers02a588a2011-11-10 20:30:28 +01003580/*
Alwin Beukersbe667662011-11-22 17:21:43 -08003581 * Set or clear filtering related maccontrol bits based on
3582 * specified filter flags
Alwin Beukers02a588a2011-11-10 20:30:28 +01003583 */
Alwin Beukersbe667662011-11-22 17:21:43 -08003584void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags)
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003585{
Alwin Beukers02a588a2011-11-10 20:30:28 +01003586 u32 promisc_bits = 0;
3587
Alwin Beukersbe667662011-11-22 17:21:43 -08003588 wlc->filter_flags = filter_flags;
3589
3590 if (filter_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
3591 promisc_bits |= MCTL_PROMISC;
3592
3593 if (filter_flags & FIF_BCN_PRBRESP_PROMISC)
Alwin Beukers02a588a2011-11-10 20:30:28 +01003594 promisc_bits |= MCTL_BCNS_PROMISC;
3595
Alwin Beukersbe667662011-11-22 17:21:43 -08003596 if (filter_flags & FIF_FCSFAIL)
3597 promisc_bits |= MCTL_KEEPBADFCS;
3598
3599 if (filter_flags & (FIF_CONTROL | FIF_PSPOLL))
3600 promisc_bits |= MCTL_KEEPCONTROL;
Alwin Beukers02a588a2011-11-10 20:30:28 +01003601
3602 brcms_b_mctrl(wlc->hw,
Alwin Beukersbe667662011-11-22 17:21:43 -08003603 MCTL_PROMISC | MCTL_BCNS_PROMISC |
3604 MCTL_KEEPCONTROL | MCTL_KEEPBADFCS,
3605 promisc_bits);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003606}
3607
Arend van Spriel5b435de2011-10-05 13:19:03 +02003608/*
3609 * ucode, hwmac update
3610 * Channel dependent updates for ucode and hw
3611 */
3612static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
3613{
3614 /* enable or disable any active IBSSs depending on whether or not
3615 * we are on the home channel
3616 */
3617 if (wlc->home_chanspec == wlc_phy_chanspec_get(wlc->band->pi)) {
3618 if (wlc->pub->associated) {
3619 /*
3620 * BMAC_NOTE: This is something that should be fixed
3621 * in ucode inits. I think that the ucode inits set
3622 * up the bcn templates and shm values with a bogus
3623 * beacon. This should not be done in the inits. If
3624 * ucode needs to set up a beacon for testing, the
3625 * test routines should write it down, not expect the
3626 * inits to populate a bogus beacon.
3627 */
3628 if (BRCMS_PHY_11N_CAP(wlc->band))
3629 brcms_b_write_shm(wlc->hw,
3630 M_BCN_TXTSF_OFFSET, 0);
3631 }
3632 } else {
3633 /* disable an active IBSS if we are not on the home channel */
3634 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003635}
3636
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003637static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate,
3638 u8 basic_rate)
3639{
3640 u8 phy_rate, index;
3641 u8 basic_phy_rate, basic_index;
3642 u16 dir_table, basic_table;
3643 u16 basic_ptr;
3644
3645 /* Shared memory address for the table we are reading */
3646 dir_table = is_ofdm_rate(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B;
3647
3648 /* Shared memory address for the table we are writing */
3649 basic_table = is_ofdm_rate(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B;
3650
3651 /*
3652 * for a given rate, the LS-nibble of the PLCP SIGNAL field is
3653 * the index into the rate table.
3654 */
3655 phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
3656 basic_phy_rate = rate_info[basic_rate] & BRCMS_RATE_MASK;
3657 index = phy_rate & 0xf;
3658 basic_index = basic_phy_rate & 0xf;
3659
3660 /* Find the SHM pointer to the ACK rate entry by looking in the
3661 * Direct-map Table
3662 */
3663 basic_ptr = brcms_b_read_shm(wlc->hw, (dir_table + basic_index * 2));
3664
3665 /* Update the SHM BSS-basic-rate-set mapping table with the pointer
3666 * to the correct basic rate for the given incoming rate
3667 */
3668 brcms_b_write_shm(wlc->hw, (basic_table + index * 2), basic_ptr);
3669}
3670
3671static const struct brcms_c_rateset *
3672brcms_c_rateset_get_hwrs(struct brcms_c_info *wlc)
3673{
3674 const struct brcms_c_rateset *rs_dflt;
3675
3676 if (BRCMS_PHY_11N_CAP(wlc->band)) {
3677 if (wlc->band->bandtype == BRCM_BAND_5G)
3678 rs_dflt = &ofdm_mimo_rates;
3679 else
3680 rs_dflt = &cck_ofdm_mimo_rates;
3681 } else if (wlc->band->gmode)
3682 rs_dflt = &cck_ofdm_rates;
3683 else
3684 rs_dflt = &cck_rates;
3685
3686 return rs_dflt;
3687}
3688
3689static void brcms_c_set_ratetable(struct brcms_c_info *wlc)
3690{
3691 const struct brcms_c_rateset *rs_dflt;
3692 struct brcms_c_rateset rs;
3693 u8 rate, basic_rate;
3694 uint i;
3695
3696 rs_dflt = brcms_c_rateset_get_hwrs(wlc);
3697
3698 brcms_c_rateset_copy(rs_dflt, &rs);
3699 brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
3700
3701 /* walk the phy rate table and update SHM basic rate lookup table */
3702 for (i = 0; i < rs.count; i++) {
3703 rate = rs.rates[i] & BRCMS_RATE_MASK;
3704
3705 /* for a given rate brcms_basic_rate returns the rate at
3706 * which a response ACK/CTS should be sent.
3707 */
3708 basic_rate = brcms_basic_rate(wlc, rate);
3709 if (basic_rate == 0)
3710 /* This should only happen if we are using a
3711 * restricted rateset.
3712 */
3713 basic_rate = rs.rates[0] & BRCMS_RATE_MASK;
3714
3715 brcms_c_write_rate_shm(wlc, rate, basic_rate);
3716 }
3717}
3718
Arend van Spriel5b435de2011-10-05 13:19:03 +02003719/* band-specific init */
3720static void brcms_c_bsinit(struct brcms_c_info *wlc)
3721{
3722 BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n",
3723 wlc->pub->unit, wlc->band->bandunit);
3724
3725 /* write ucode ACK/CTS rate table */
3726 brcms_c_set_ratetable(wlc);
3727
3728 /* update some band specific mac configuration */
3729 brcms_c_ucode_mac_upd(wlc);
3730
3731 /* init antenna selection */
3732 brcms_c_antsel_init(wlc->asi);
3733
3734}
3735
3736/* formula: IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */
3737static int
3738brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
3739 bool writeToShm)
3740{
3741 int idle_busy_ratio_x_16 = 0;
3742 uint offset =
3743 isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM :
3744 M_TX_IDLE_BUSY_RATIO_X_16_CCK;
3745 if (duty_cycle > 100 || duty_cycle < 0) {
3746 wiphy_err(wlc->wiphy, "wl%d: duty cycle value off limit\n",
3747 wlc->pub->unit);
3748 return -EINVAL;
3749 }
3750 if (duty_cycle)
3751 idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle;
3752 /* Only write to shared memory when wl is up */
3753 if (writeToShm)
3754 brcms_b_write_shm(wlc->hw, offset, (u16) idle_busy_ratio_x_16);
3755
3756 if (isOFDM)
3757 wlc->tx_duty_cycle_ofdm = (u16) duty_cycle;
3758 else
3759 wlc->tx_duty_cycle_cck = (u16) duty_cycle;
3760
3761 return 0;
3762}
3763
3764/*
3765 * Initialize the base precedence map for dequeueing
3766 * from txq based on WME settings
3767 */
3768static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc)
3769{
3770 wlc->tx_prec_map = BRCMS_PREC_BMP_ALL;
3771 memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16));
3772
3773 wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK;
3774 wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE;
3775 wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI;
3776 wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO;
3777}
3778
3779static void
3780brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc,
3781 struct brcms_txq_info *qi, bool on, int prio)
3782{
3783 /* transmit flowcontrol is not yet implemented */
3784}
3785
3786static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc)
3787{
3788 struct brcms_txq_info *qi;
3789
3790 for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) {
3791 if (qi->stopped) {
3792 brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO);
3793 qi->stopped = 0;
3794 }
3795 }
3796}
3797
Arend van Spriel5b435de2011-10-05 13:19:03 +02003798/* push sw hps and wake state through hardware */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003799static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003800{
3801 u32 v1, v2;
3802 bool hps;
3803 bool awake_before;
3804
3805 hps = brcms_c_ps_allowed(wlc);
3806
3807 BCMMSG(wlc->wiphy, "wl%d: hps %d\n", wlc->pub->unit, hps);
3808
Arend van Spriel16d28122011-12-08 15:06:51 -08003809 v1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003810 v2 = MCTL_WAKE;
3811 if (hps)
3812 v2 |= MCTL_HPS;
3813
3814 brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2);
3815
3816 awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));
3817
3818 if (!awake_before)
3819 brcms_b_wait_for_wake(wlc->hw);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003820}
3821
3822/*
3823 * Write this BSS config's MAC address to core.
3824 * Updates RXE match engine.
3825 */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003826static int brcms_c_set_mac(struct brcms_bss_cfg *bsscfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003827{
3828 int err = 0;
3829 struct brcms_c_info *wlc = bsscfg->wlc;
3830
3831 /* enter the MAC addr into the RXE match registers */
3832 brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, bsscfg->cur_etheraddr);
3833
3834 brcms_c_ampdu_macaddr_upd(wlc);
3835
3836 return err;
3837}
3838
3839/* Write the BSS config's BSSID address to core (set_bssid in d11procs.tcl).
3840 * Updates RXE match engine.
3841 */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003842static void brcms_c_set_bssid(struct brcms_bss_cfg *bsscfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003843{
3844 /* we need to update BSSID in RXE match registers */
3845 brcms_c_set_addrmatch(bsscfg->wlc, RCM_BSSID_OFFSET, bsscfg->BSSID);
3846}
3847
3848static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)
3849{
3850 wlc_hw->shortslot = shortslot;
3851
3852 if (wlc_hw->band->bandtype == BRCM_BAND_2G && wlc_hw->up) {
3853 brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
3854 brcms_b_update_slot_timing(wlc_hw, shortslot);
3855 brcms_c_enable_mac(wlc_hw->wlc);
3856 }
3857}
3858
3859/*
3860 * Suspend the the MAC and update the slot timing
3861 * for standard 11b/g (20us slots) or shortslot 11g (9us slots).
3862 */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003863static void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003864{
3865 /* use the override if it is set */
3866 if (wlc->shortslot_override != BRCMS_SHORTSLOT_AUTO)
3867 shortslot = (wlc->shortslot_override == BRCMS_SHORTSLOT_ON);
3868
3869 if (wlc->shortslot == shortslot)
3870 return;
3871
3872 wlc->shortslot = shortslot;
3873
3874 brcms_b_set_shortslot(wlc->hw, shortslot);
3875}
3876
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003877static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003878{
3879 if (wlc->home_chanspec != chanspec) {
3880 wlc->home_chanspec = chanspec;
3881
3882 if (wlc->bsscfg->associated)
3883 wlc->bsscfg->current_bss->chanspec = chanspec;
3884 }
3885}
3886
3887void
3888brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
Roland Vossenc6c44892011-10-21 16:16:26 +02003889 bool mute_tx, struct txpwr_limits *txpwr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003890{
3891 uint bandunit;
3892
3893 BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec);
3894
3895 wlc_hw->chanspec = chanspec;
3896
3897 /* Switch bands if necessary */
3898 if (wlc_hw->_nbands > 1) {
3899 bandunit = chspec_bandunit(chanspec);
3900 if (wlc_hw->band->bandunit != bandunit) {
3901 /* brcms_b_setband disables other bandunit,
3902 * use light band switch if not up yet
3903 */
3904 if (wlc_hw->up) {
3905 wlc_phy_chanspec_radio_set(wlc_hw->
3906 bandstate[bandunit]->
3907 pi, chanspec);
3908 brcms_b_setband(wlc_hw, bandunit, chanspec);
3909 } else {
3910 brcms_c_setxband(wlc_hw, bandunit);
3911 }
3912 }
3913 }
3914
Roland Vossenc6c44892011-10-21 16:16:26 +02003915 wlc_phy_initcal_enable(wlc_hw->band->pi, !mute_tx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003916
3917 if (!wlc_hw->up) {
3918 if (wlc_hw->clk)
3919 wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr,
3920 chanspec);
3921 wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
3922 } else {
3923 wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec);
3924 wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);
3925
3926 /* Update muting of the channel */
Roland Vossenc6c44892011-10-21 16:16:26 +02003927 brcms_b_mute(wlc_hw, mute_tx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003928 }
3929}
3930
3931/* switch to and initialize new band */
3932static void brcms_c_setband(struct brcms_c_info *wlc,
3933 uint bandunit)
3934{
3935 wlc->band = wlc->bandstate[bandunit];
3936
3937 if (!wlc->pub->up)
3938 return;
3939
3940 /* wait for at least one beacon before entering sleeping state */
3941 brcms_c_set_ps_ctrl(wlc);
3942
3943 /* band-specific initializations */
3944 brcms_c_bsinit(wlc);
3945}
3946
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02003947static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003948{
3949 uint bandunit;
3950 bool switchband = false;
3951 u16 old_chanspec = wlc->chanspec;
3952
3953 if (!brcms_c_valid_chanspec_db(wlc->cmi, chanspec)) {
3954 wiphy_err(wlc->wiphy, "wl%d: %s: Bad channel %d\n",
3955 wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec));
3956 return;
3957 }
3958
3959 /* Switch bands if necessary */
3960 if (wlc->pub->_nbands > 1) {
3961 bandunit = chspec_bandunit(chanspec);
3962 if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) {
3963 switchband = true;
3964 if (wlc->bandlocked) {
3965 wiphy_err(wlc->wiphy, "wl%d: %s: chspec %d "
3966 "band is locked!\n",
3967 wlc->pub->unit, __func__,
3968 CHSPEC_CHANNEL(chanspec));
3969 return;
3970 }
3971 /*
3972 * should the setband call come after the
3973 * brcms_b_chanspec() ? if the setband updates
3974 * (brcms_c_bsinit) use low level calls to inspect and
3975 * set state, the state inspected may be from the wrong
3976 * band, or the following brcms_b_set_chanspec() may
3977 * undo the work.
3978 */
3979 brcms_c_setband(wlc, bandunit);
3980 }
3981 }
3982
3983 /* sync up phy/radio chanspec */
3984 brcms_c_set_phy_chanspec(wlc, chanspec);
3985
3986 /* init antenna selection */
3987 if (brcms_chspec_bw(old_chanspec) != brcms_chspec_bw(chanspec)) {
3988 brcms_c_antsel_init(wlc->asi);
3989
3990 /* Fix the hardware rateset based on bw.
3991 * Mainly add MCS32 for 40Mhz, remove MCS 32 for 20Mhz
3992 */
3993 brcms_c_rateset_bw_mcs_filter(&wlc->band->hw_rateset,
3994 wlc->band->mimo_cap_40 ? brcms_chspec_bw(chanspec) : 0);
3995 }
3996
3997 /* update some mac configuration since chanspec changed */
3998 brcms_c_ucode_mac_upd(wlc);
3999}
4000
Arend van Spriel5b435de2011-10-05 13:19:03 +02004001/*
4002 * This function changes the phytxctl for beacon based on current
4003 * beacon ratespec AND txant setting as per this table:
4004 * ratespec CCK ant = wlc->stf->txant
4005 * OFDM ant = 3
4006 */
4007void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
4008 u32 bcn_rspec)
4009{
4010 u16 phyctl;
4011 u16 phytxant = wlc->stf->phytxant;
4012 u16 mask = PHY_TXC_ANT_MASK;
4013
4014 /* for non-siso rates or default setting, use the available chains */
4015 if (BRCMS_PHY_11N_CAP(wlc->band))
4016 phytxant = brcms_c_stf_phytxchain_sel(wlc, bcn_rspec);
4017
4018 phyctl = brcms_b_read_shm(wlc->hw, M_BCN_PCTLWD);
4019 phyctl = (phyctl & ~mask) | phytxant;
4020 brcms_b_write_shm(wlc->hw, M_BCN_PCTLWD, phyctl);
4021}
4022
4023/*
4024 * centralized protection config change function to simplify debugging, no
4025 * consistency checking this should be called only on changes to avoid overhead
4026 * in periodic function
4027 */
4028void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val)
4029{
4030 BCMMSG(wlc->wiphy, "idx %d, val %d\n", idx, val);
4031
4032 switch (idx) {
4033 case BRCMS_PROT_G_SPEC:
4034 wlc->protection->_g = (bool) val;
4035 break;
4036 case BRCMS_PROT_G_OVR:
4037 wlc->protection->g_override = (s8) val;
4038 break;
4039 case BRCMS_PROT_G_USER:
4040 wlc->protection->gmode_user = (u8) val;
4041 break;
4042 case BRCMS_PROT_OVERLAP:
4043 wlc->protection->overlap = (s8) val;
4044 break;
4045 case BRCMS_PROT_N_USER:
4046 wlc->protection->nmode_user = (s8) val;
4047 break;
4048 case BRCMS_PROT_N_CFG:
4049 wlc->protection->n_cfg = (s8) val;
4050 break;
4051 case BRCMS_PROT_N_CFG_OVR:
4052 wlc->protection->n_cfg_override = (s8) val;
4053 break;
4054 case BRCMS_PROT_N_NONGF:
4055 wlc->protection->nongf = (bool) val;
4056 break;
4057 case BRCMS_PROT_N_NONGF_OVR:
4058 wlc->protection->nongf_override = (s8) val;
4059 break;
4060 case BRCMS_PROT_N_PAM_OVR:
4061 wlc->protection->n_pam_override = (s8) val;
4062 break;
4063 case BRCMS_PROT_N_OBSS:
4064 wlc->protection->n_obss = (bool) val;
4065 break;
4066
4067 default:
4068 break;
4069 }
4070
4071}
4072
4073static void brcms_c_ht_update_sgi_rx(struct brcms_c_info *wlc, int val)
4074{
4075 if (wlc->pub->up) {
4076 brcms_c_update_beacon(wlc);
4077 brcms_c_update_probe_resp(wlc, true);
4078 }
4079}
4080
4081static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val)
4082{
4083 wlc->stf->ldpc = val;
4084
4085 if (wlc->pub->up) {
4086 brcms_c_update_beacon(wlc);
4087 brcms_c_update_probe_resp(wlc, true);
4088 wlc_phy_ldpc_override_set(wlc->band->pi, (val ? true : false));
4089 }
4090}
4091
4092void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
4093 const struct ieee80211_tx_queue_params *params,
4094 bool suspend)
4095{
4096 int i;
4097 struct shm_acparams acp_shm;
4098 u16 *shm_entry;
4099
4100 /* Only apply params if the core is out of reset and has clocks */
4101 if (!wlc->clk) {
4102 wiphy_err(wlc->wiphy, "wl%d: %s : no-clock\n", wlc->pub->unit,
4103 __func__);
4104 return;
4105 }
4106
4107 memset((char *)&acp_shm, 0, sizeof(struct shm_acparams));
4108 /* fill in shm ac params struct */
4109 acp_shm.txop = params->txop;
4110 /* convert from units of 32us to us for ucode */
4111 wlc->edcf_txop[aci & 0x3] = acp_shm.txop =
4112 EDCF_TXOP2USEC(acp_shm.txop);
4113 acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK);
4114
Arend van Sprielb7eec422011-11-10 20:30:18 +01004115 if (aci == IEEE80211_AC_VI && acp_shm.txop == 0
Arend van Spriel5b435de2011-10-05 13:19:03 +02004116 && acp_shm.aifs < EDCF_AIFSN_MAX)
4117 acp_shm.aifs++;
4118
4119 if (acp_shm.aifs < EDCF_AIFSN_MIN
4120 || acp_shm.aifs > EDCF_AIFSN_MAX) {
4121 wiphy_err(wlc->wiphy, "wl%d: edcf_setparams: bad "
4122 "aifs %d\n", wlc->pub->unit, acp_shm.aifs);
4123 } else {
4124 acp_shm.cwmin = params->cw_min;
4125 acp_shm.cwmax = params->cw_max;
4126 acp_shm.cwcur = acp_shm.cwmin;
4127 acp_shm.bslots =
Arend van Spriel16d28122011-12-08 15:06:51 -08004128 bcma_read16(wlc->hw->d11core, D11REGOFFS(tsf_random)) &
4129 acp_shm.cwcur;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004130 acp_shm.reggap = acp_shm.bslots + acp_shm.aifs;
4131 /* Indicate the new params to the ucode */
4132 acp_shm.status = brcms_b_read_shm(wlc->hw, (M_EDCF_QINFO +
4133 wme_ac2fifo[aci] *
4134 M_EDCF_QLEN +
4135 M_EDCF_STATUS_OFF));
4136 acp_shm.status |= WME_STATUS_NEWAC;
4137
4138 /* Fill in shm acparam table */
4139 shm_entry = (u16 *) &acp_shm;
4140 for (i = 0; i < (int)sizeof(struct shm_acparams); i += 2)
4141 brcms_b_write_shm(wlc->hw,
4142 M_EDCF_QINFO +
4143 wme_ac2fifo[aci] * M_EDCF_QLEN + i,
4144 *shm_entry++);
4145 }
4146
4147 if (suspend) {
4148 brcms_c_suspend_mac_and_wait(wlc);
4149 brcms_c_enable_mac(wlc);
4150 }
4151}
4152
Arend van Spriel094b1992011-10-18 14:03:07 +02004153static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004154{
4155 u16 aci;
4156 int i_ac;
4157 struct ieee80211_tx_queue_params txq_pars;
4158 static const struct edcf_acparam default_edcf_acparams[] = {
4159 {EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA, EDCF_AC_BE_TXOP_STA},
4160 {EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA, EDCF_AC_BK_TXOP_STA},
4161 {EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA, EDCF_AC_VI_TXOP_STA},
4162 {EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA, EDCF_AC_VO_TXOP_STA}
4163 }; /* ucode needs these parameters during its initialization */
4164 const struct edcf_acparam *edcf_acp = &default_edcf_acparams[0];
4165
Arend van Sprielb7eec422011-11-10 20:30:18 +01004166 for (i_ac = 0; i_ac < IEEE80211_NUM_ACS; i_ac++, edcf_acp++) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004167 /* find out which ac this set of params applies to */
4168 aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;
4169
4170 /* fill in shm ac params struct */
4171 txq_pars.txop = edcf_acp->TXOP;
4172 txq_pars.aifs = edcf_acp->ACI;
4173
4174 /* CWmin = 2^(ECWmin) - 1 */
4175 txq_pars.cw_min = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK);
4176 /* CWmax = 2^(ECWmax) - 1 */
4177 txq_pars.cw_max = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK)
4178 >> EDCF_ECWMAX_SHIFT);
4179 brcms_c_wme_setparams(wlc, aci, &txq_pars, suspend);
4180 }
4181
4182 if (suspend) {
4183 brcms_c_suspend_mac_and_wait(wlc);
4184 brcms_c_enable_mac(wlc);
4185 }
4186}
4187
Arend van Spriel5b435de2011-10-05 13:19:03 +02004188static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
4189{
4190 /* Don't start the timer if HWRADIO feature is disabled */
4191 if (wlc->radio_monitor)
4192 return;
4193
4194 wlc->radio_monitor = true;
4195 brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_RADIO_MON);
Roland Vossenbe69c4e2011-10-12 20:51:11 +02004196 brcms_add_timer(wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004197}
4198
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02004199static bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004200{
4201 if (!wlc->radio_monitor)
4202 return true;
4203
4204 wlc->radio_monitor = false;
4205 brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_RADIO_MON);
Roland Vossenbe69c4e2011-10-12 20:51:11 +02004206 return brcms_del_timer(wlc->radio_timer);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004207}
4208
4209/* read hwdisable state and propagate to wlc flag */
4210static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc)
4211{
4212 if (wlc->pub->hw_off)
4213 return;
4214
4215 if (brcms_b_radio_read_hwdisabled(wlc->hw))
4216 mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
4217 else
4218 mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
4219}
4220
Arend van Spriel5b435de2011-10-05 13:19:03 +02004221/* update hwradio status and return it */
4222bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc)
4223{
4224 brcms_c_radio_hwdisable_upd(wlc);
4225
4226 return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ?
4227 true : false;
4228}
4229
4230/* periodical query hw radio button while driver is "down" */
4231static void brcms_c_radio_timer(void *arg)
4232{
4233 struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
4234
4235 if (brcms_deviceremoved(wlc)) {
4236 wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
4237 __func__);
4238 brcms_down(wlc->wl);
4239 return;
4240 }
4241
Arend van Spriel5b435de2011-10-05 13:19:03 +02004242 brcms_c_radio_hwdisable_upd(wlc);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004243}
4244
4245/* common low-level watchdog code */
4246static void brcms_b_watchdog(void *arg)
4247{
4248 struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
4249 struct brcms_hardware *wlc_hw = wlc->hw;
4250
4251 BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
4252
4253 if (!wlc_hw->up)
4254 return;
4255
4256 /* increment second count */
4257 wlc_hw->now++;
4258
4259 /* Check for FIFO error interrupts */
4260 brcms_b_fifoerrors(wlc_hw);
4261
4262 /* make sure RX dma has buffers */
4263 dma_rxfill(wlc->hw->di[RX_FIFO]);
4264
4265 wlc_phy_watchdog(wlc_hw->band->pi);
4266}
4267
4268/* common watchdog code */
4269static void brcms_c_watchdog(void *arg)
4270{
4271 struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
4272
4273 BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
4274
4275 if (!wlc->pub->up)
4276 return;
4277
4278 if (brcms_deviceremoved(wlc)) {
4279 wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
4280 __func__);
4281 brcms_down(wlc->wl);
4282 return;
4283 }
4284
4285 /* increment second count */
4286 wlc->pub->now++;
4287
Arend van Spriel5b435de2011-10-05 13:19:03 +02004288 brcms_c_radio_hwdisable_upd(wlc);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004289 /* if radio is disable, driver may be down, quit here */
4290 if (wlc->pub->radio_disabled)
4291 return;
4292
4293 brcms_b_watchdog(wlc);
4294
4295 /*
4296 * occasionally sample mac stat counters to
4297 * detect 16-bit counter wrap
4298 */
4299 if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0)
4300 brcms_c_statsupd(wlc);
4301
4302 if (BRCMS_ISNPHY(wlc->band) &&
4303 ((wlc->pub->now - wlc->tempsense_lasttime) >=
4304 BRCMS_TEMPSENSE_PERIOD)) {
4305 wlc->tempsense_lasttime = wlc->pub->now;
4306 brcms_c_tempsense_upd(wlc);
4307 }
4308}
4309
4310static void brcms_c_watchdog_by_timer(void *arg)
4311{
4312 brcms_c_watchdog(arg);
4313}
4314
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02004315static bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004316{
4317 wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer,
4318 wlc, "watchdog");
4319 if (!wlc->wdtimer) {
4320 wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for wdtimer "
4321 "failed\n", unit);
4322 goto fail;
4323 }
4324
4325 wlc->radio_timer = brcms_init_timer(wlc->wl, brcms_c_radio_timer,
4326 wlc, "radio");
4327 if (!wlc->radio_timer) {
4328 wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for radio_timer "
4329 "failed\n", unit);
4330 goto fail;
4331 }
4332
4333 return true;
4334
4335 fail:
4336 return false;
4337}
4338
4339/*
4340 * Initialize brcms_c_info default values ...
4341 * may get overrides later in this function
4342 */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02004343static void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004344{
4345 int i;
4346
4347 /* Save our copy of the chanspec */
4348 wlc->chanspec = ch20mhz_chspec(1);
4349
4350 /* various 802.11g modes */
4351 wlc->shortslot = false;
4352 wlc->shortslot_override = BRCMS_SHORTSLOT_AUTO;
4353
4354 brcms_c_protection_upd(wlc, BRCMS_PROT_G_OVR, BRCMS_PROTECTION_AUTO);
4355 brcms_c_protection_upd(wlc, BRCMS_PROT_G_SPEC, false);
4356
4357 brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG_OVR,
4358 BRCMS_PROTECTION_AUTO);
4359 brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG, BRCMS_N_PROTECTION_OFF);
4360 brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF_OVR,
4361 BRCMS_PROTECTION_AUTO);
4362 brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF, false);
4363 brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, AUTO);
4364
4365 brcms_c_protection_upd(wlc, BRCMS_PROT_OVERLAP,
4366 BRCMS_PROTECTION_CTL_OVERLAP);
4367
4368 /* 802.11g draft 4.0 NonERP elt advertisement */
4369 wlc->include_legacy_erp = true;
4370
4371 wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF;
4372 wlc->stf->txant = ANT_TX_DEF;
4373
4374 wlc->prb_resp_timeout = BRCMS_PRB_RESP_TIMEOUT;
4375
4376 wlc->usr_fragthresh = DOT11_DEFAULT_FRAG_LEN;
4377 for (i = 0; i < NFIFO; i++)
4378 wlc->fragthresh[i] = DOT11_DEFAULT_FRAG_LEN;
4379 wlc->RTSThresh = DOT11_DEFAULT_RTS_LEN;
4380
4381 /* default rate fallback retry limits */
4382 wlc->SFBL = RETRY_SHORT_FB;
4383 wlc->LFBL = RETRY_LONG_FB;
4384
4385 /* default mac retry limits */
4386 wlc->SRL = RETRY_SHORT_DEF;
4387 wlc->LRL = RETRY_LONG_DEF;
4388
4389 /* WME QoS mode is Auto by default */
4390 wlc->pub->_ampdu = AMPDU_AGG_HOST;
4391 wlc->pub->bcmerror = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004392}
4393
4394static uint brcms_c_attach_module(struct brcms_c_info *wlc)
4395{
4396 uint err = 0;
4397 uint unit;
4398 unit = wlc->pub->unit;
4399
4400 wlc->asi = brcms_c_antsel_attach(wlc);
4401 if (wlc->asi == NULL) {
4402 wiphy_err(wlc->wiphy, "wl%d: attach: antsel_attach "
4403 "failed\n", unit);
4404 err = 44;
4405 goto fail;
4406 }
4407
4408 wlc->ampdu = brcms_c_ampdu_attach(wlc);
4409 if (wlc->ampdu == NULL) {
4410 wiphy_err(wlc->wiphy, "wl%d: attach: ampdu_attach "
4411 "failed\n", unit);
4412 err = 50;
4413 goto fail;
4414 }
4415
4416 if ((brcms_c_stf_attach(wlc) != 0)) {
4417 wiphy_err(wlc->wiphy, "wl%d: attach: stf_attach "
4418 "failed\n", unit);
4419 err = 68;
4420 goto fail;
4421 }
4422 fail:
4423 return err;
4424}
4425
4426struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc)
4427{
4428 return wlc->pub;
4429}
4430
4431/* low level attach
4432 * run backplane attach, init nvram
4433 * run phy attach
4434 * initialize software state for each core and band
4435 * put the whole chip in reset(driver down state), no clock
4436 */
Arend van Sprielb63337a2011-12-08 15:06:47 -08004437static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
4438 uint unit, bool piomode)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004439{
4440 struct brcms_hardware *wlc_hw;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004441 char *macaddr = NULL;
4442 uint err = 0;
4443 uint j;
4444 bool wme = false;
4445 struct shared_phy_params sha_params;
4446 struct wiphy *wiphy = wlc->wiphy;
Arend van Sprielb63337a2011-12-08 15:06:47 -08004447 struct pci_dev *pcidev = core->bus->host_pci;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004448
Arend van Sprielb63337a2011-12-08 15:06:47 -08004449 BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
4450 pcidev->vendor,
4451 pcidev->device);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004452
4453 wme = true;
4454
4455 wlc_hw = wlc->hw;
4456 wlc_hw->wlc = wlc;
4457 wlc_hw->unit = unit;
4458 wlc_hw->band = wlc_hw->bandstate[0];
4459 wlc_hw->_piomode = piomode;
4460
4461 /* populate struct brcms_hardware with default values */
4462 brcms_b_info_init(wlc_hw);
4463
4464 /*
4465 * Do the hardware portion of the attach. Also initialize software
4466 * state that depends on the particular hardware we are running.
4467 */
Arend van Spriel28a53442011-12-08 15:06:49 -08004468 wlc_hw->sih = ai_attach(core->bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004469 if (wlc_hw->sih == NULL) {
4470 wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n",
4471 unit);
4472 err = 11;
4473 goto fail;
4474 }
4475
4476 /* verify again the device is supported */
Arend van Sprielb63337a2011-12-08 15:06:47 -08004477 if (!brcms_c_chipmatch(pcidev->vendor, pcidev->device)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004478 wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported "
4479 "vendor/device (0x%x/0x%x)\n",
Arend van Sprielb63337a2011-12-08 15:06:47 -08004480 unit, pcidev->vendor, pcidev->device);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004481 err = 12;
4482 goto fail;
4483 }
4484
Arend van Sprielb63337a2011-12-08 15:06:47 -08004485 wlc_hw->vendorid = pcidev->vendor;
4486 wlc_hw->deviceid = pcidev->device;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004487
Arend van Spriel16d28122011-12-08 15:06:51 -08004488 wlc_hw->d11core = core;
4489 wlc_hw->corerev = core->id.rev;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004490
4491 /* validate chip, chiprev and corerev */
4492 if (!brcms_c_isgoodchip(wlc_hw)) {
4493 err = 13;
4494 goto fail;
4495 }
4496
4497 /* initialize power control registers */
4498 ai_clkctl_init(wlc_hw->sih);
4499
4500 /* request fastclock and force fastclock for the rest of attach
4501 * bring the d11 core out of reset.
4502 * For PMU chips, the first wlc_clkctl_clk is no-op since core-clk
4503 * is still false; But it will be called again inside wlc_corereset,
4504 * after d11 is out of reset.
4505 */
4506 brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
4507 brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
4508
4509 if (!brcms_b_validate_chip_access(wlc_hw)) {
4510 wiphy_err(wiphy, "wl%d: brcms_b_attach: validate_chip_access "
4511 "failed\n", unit);
4512 err = 14;
4513 goto fail;
4514 }
4515
4516 /* get the board rev, used just below */
4517 j = getintvar(wlc_hw->sih, BRCMS_SROM_BOARDREV);
4518 /* promote srom boardrev of 0xFF to 1 */
4519 if (j == BOARDREV_PROMOTABLE)
4520 j = BOARDREV_PROMOTED;
4521 wlc_hw->boardrev = (u16) j;
4522 if (!brcms_c_validboardtype(wlc_hw)) {
4523 wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom "
Arend van Sprielb2ffec42011-12-08 15:06:45 -08004524 "board type (0x%x)" " or revision level (0x%x)\n",
4525 unit, ai_get_boardtype(wlc_hw->sih),
4526 wlc_hw->boardrev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004527 err = 15;
4528 goto fail;
4529 }
4530 wlc_hw->sromrev = (u8) getintvar(wlc_hw->sih, BRCMS_SROM_REV);
4531 wlc_hw->boardflags = (u32) getintvar(wlc_hw->sih,
4532 BRCMS_SROM_BOARDFLAGS);
4533 wlc_hw->boardflags2 = (u32) getintvar(wlc_hw->sih,
4534 BRCMS_SROM_BOARDFLAGS2);
4535
4536 if (wlc_hw->boardflags & BFL_NOPLLDOWN)
4537 brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED);
4538
4539 /* check device id(srom, nvram etc.) to set bands */
4540 if (wlc_hw->deviceid == BCM43224_D11N_ID ||
4541 wlc_hw->deviceid == BCM43224_D11N_ID_VEN1)
4542 /* Dualband boards */
4543 wlc_hw->_nbands = 2;
4544 else
4545 wlc_hw->_nbands = 1;
4546
Arend van Sprielb2ffec42011-12-08 15:06:45 -08004547 if ((ai_get_chip_id(wlc_hw->sih) == BCM43225_CHIP_ID))
Arend van Spriel5b435de2011-10-05 13:19:03 +02004548 wlc_hw->_nbands = 1;
4549
4550 /* BMAC_NOTE: remove init of pub values when brcms_c_attach()
4551 * unconditionally does the init of these values
4552 */
4553 wlc->vendorid = wlc_hw->vendorid;
4554 wlc->deviceid = wlc_hw->deviceid;
4555 wlc->pub->sih = wlc_hw->sih;
4556 wlc->pub->corerev = wlc_hw->corerev;
4557 wlc->pub->sromrev = wlc_hw->sromrev;
4558 wlc->pub->boardrev = wlc_hw->boardrev;
4559 wlc->pub->boardflags = wlc_hw->boardflags;
4560 wlc->pub->boardflags2 = wlc_hw->boardflags2;
4561 wlc->pub->_nbands = wlc_hw->_nbands;
4562
4563 wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc);
4564
4565 if (wlc_hw->physhim == NULL) {
4566 wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_shim_attach "
4567 "failed\n", unit);
4568 err = 25;
4569 goto fail;
4570 }
4571
4572 /* pass all the parameters to wlc_phy_shared_attach in one struct */
4573 sha_params.sih = wlc_hw->sih;
4574 sha_params.physhim = wlc_hw->physhim;
4575 sha_params.unit = unit;
4576 sha_params.corerev = wlc_hw->corerev;
4577 sha_params.vid = wlc_hw->vendorid;
4578 sha_params.did = wlc_hw->deviceid;
Arend van Sprielb2ffec42011-12-08 15:06:45 -08004579 sha_params.chip = ai_get_chip_id(wlc_hw->sih);
4580 sha_params.chiprev = ai_get_chiprev(wlc_hw->sih);
4581 sha_params.chippkg = ai_get_chippkg(wlc_hw->sih);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004582 sha_params.sromrev = wlc_hw->sromrev;
Arend van Sprielb2ffec42011-12-08 15:06:45 -08004583 sha_params.boardtype = ai_get_boardtype(wlc_hw->sih);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004584 sha_params.boardrev = wlc_hw->boardrev;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004585 sha_params.boardflags = wlc_hw->boardflags;
4586 sha_params.boardflags2 = wlc_hw->boardflags2;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004587
4588 /* alloc and save pointer to shared phy state area */
4589 wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params);
4590 if (!wlc_hw->phy_sh) {
4591 err = 16;
4592 goto fail;
4593 }
4594
4595 /* initialize software state for each core and band */
4596 for (j = 0; j < wlc_hw->_nbands; j++) {
4597 /*
4598 * band0 is always 2.4Ghz
4599 * band1, if present, is 5Ghz
4600 */
4601
4602 brcms_c_setxband(wlc_hw, j);
4603
4604 wlc_hw->band->bandunit = j;
4605 wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
4606 wlc->band->bandunit = j;
4607 wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
Arend van Spriel3b758a62011-12-12 15:15:09 -08004608 wlc->core->coreidx = core->core_index;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004609
Arend van Spriel16d28122011-12-08 15:06:51 -08004610 wlc_hw->machwcap = bcma_read32(core, D11REGOFFS(machwcap));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004611 wlc_hw->machwcap_backup = wlc_hw->machwcap;
4612
4613 /* init tx fifo size */
4614 wlc_hw->xmtfifo_sz =
4615 xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)];
4616
4617 /* Get a phy for this band */
4618 wlc_hw->band->pi =
Arend van Spriel4b006b12011-12-08 15:06:54 -08004619 wlc_phy_attach(wlc_hw->phy_sh, core,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004620 wlc_hw->band->bandtype,
4621 wlc->wiphy);
4622 if (wlc_hw->band->pi == NULL) {
4623 wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_"
4624 "attach failed\n", unit);
4625 err = 17;
4626 goto fail;
4627 }
4628
4629 wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap);
4630
4631 wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype,
4632 &wlc_hw->band->phyrev,
4633 &wlc_hw->band->radioid,
4634 &wlc_hw->band->radiorev);
4635 wlc_hw->band->abgphy_encore =
4636 wlc_phy_get_encore(wlc_hw->band->pi);
4637 wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi);
4638 wlc_hw->band->core_flags =
4639 wlc_phy_get_coreflags(wlc_hw->band->pi);
4640
4641 /* verify good phy_type & supported phy revision */
4642 if (BRCMS_ISNPHY(wlc_hw->band)) {
4643 if (NCONF_HAS(wlc_hw->band->phyrev))
4644 goto good_phy;
4645 else
4646 goto bad_phy;
4647 } else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
4648 if (LCNCONF_HAS(wlc_hw->band->phyrev))
4649 goto good_phy;
4650 else
4651 goto bad_phy;
4652 } else {
4653 bad_phy:
4654 wiphy_err(wiphy, "wl%d: brcms_b_attach: unsupported "
4655 "phy type/rev (%d/%d)\n", unit,
4656 wlc_hw->band->phytype, wlc_hw->band->phyrev);
4657 err = 18;
4658 goto fail;
4659 }
4660
4661 good_phy:
4662 /*
4663 * BMAC_NOTE: wlc->band->pi should not be set below and should
4664 * be done in the high level attach. However we can not make
4665 * that change until all low level access is changed to
4666 * wlc_hw->band->pi. Instead do the wlc->band->pi init below,
4667 * keeping wlc_hw->band->pi as well for incremental update of
4668 * low level fns, and cut over low only init when all fns
4669 * updated.
4670 */
4671 wlc->band->pi = wlc_hw->band->pi;
4672 wlc->band->phytype = wlc_hw->band->phytype;
4673 wlc->band->phyrev = wlc_hw->band->phyrev;
4674 wlc->band->radioid = wlc_hw->band->radioid;
4675 wlc->band->radiorev = wlc_hw->band->radiorev;
4676
4677 /* default contention windows size limits */
4678 wlc_hw->band->CWmin = APHY_CWMIN;
4679 wlc_hw->band->CWmax = PHY_CWMAX;
4680
4681 if (!brcms_b_attach_dmapio(wlc, j, wme)) {
4682 err = 19;
4683 goto fail;
4684 }
4685 }
4686
4687 /* disable core to match driver "down" state */
4688 brcms_c_coredisable(wlc_hw);
4689
4690 /* Match driver "down" state */
4691 ai_pci_down(wlc_hw->sih);
4692
Arend van Spriel5b435de2011-10-05 13:19:03 +02004693 /* turn off pll and xtal to match driver "down" state */
4694 brcms_b_xtal(wlc_hw, OFF);
4695
4696 /* *******************************************************************
4697 * The hardware is in the DOWN state at this point. D11 core
4698 * or cores are in reset with clocks off, and the board PLLs
4699 * are off if possible.
4700 *
4701 * Beyond this point, wlc->sbclk == false and chip registers
4702 * should not be touched.
4703 *********************************************************************
4704 */
4705
4706 /* init etheraddr state variables */
4707 macaddr = brcms_c_get_macaddr(wlc_hw);
4708 if (macaddr == NULL) {
4709 wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n",
4710 unit);
4711 err = 21;
4712 goto fail;
4713 }
4714 if (!mac_pton(macaddr, wlc_hw->etheraddr) ||
4715 is_broadcast_ether_addr(wlc_hw->etheraddr) ||
4716 is_zero_ether_addr(wlc_hw->etheraddr)) {
4717 wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n",
4718 unit, macaddr);
4719 err = 22;
4720 goto fail;
4721 }
4722
Arend van Sprielb2ffec42011-12-08 15:06:45 -08004723 BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
4724 wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih),
4725 macaddr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004726
4727 return err;
4728
4729 fail:
4730 wiphy_err(wiphy, "wl%d: brcms_b_attach: failed with err %d\n", unit,
4731 err);
4732 return err;
4733}
4734
4735static void brcms_c_attach_antgain_init(struct brcms_c_info *wlc)
4736{
4737 uint unit;
4738 unit = wlc->pub->unit;
4739
4740 if ((wlc->band->antgain == -1) && (wlc->pub->sromrev == 1)) {
4741 /* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */
4742 wlc->band->antgain = 8;
4743 } else if (wlc->band->antgain == -1) {
4744 wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
4745 " srom, using 2dB\n", unit, __func__);
4746 wlc->band->antgain = 8;
4747 } else {
4748 s8 gain, fract;
4749 /* Older sroms specified gain in whole dbm only. In order
4750 * be able to specify qdbm granularity and remain backward
4751 * compatible the whole dbms are now encoded in only
4752 * low 6 bits and remaining qdbms are encoded in the hi 2 bits.
4753 * 6 bit signed number ranges from -32 - 31.
4754 *
4755 * Examples:
4756 * 0x1 = 1 db,
4757 * 0xc1 = 1.75 db (1 + 3 quarters),
4758 * 0x3f = -1 (-1 + 0 quarters),
4759 * 0x7f = -.75 (-1 + 1 quarters) = -3 qdbm.
4760 * 0xbf = -.50 (-1 + 2 quarters) = -2 qdbm.
4761 */
4762 gain = wlc->band->antgain & 0x3f;
4763 gain <<= 2; /* Sign extend */
4764 gain >>= 2;
4765 fract = (wlc->band->antgain & 0xc0) >> 6;
4766 wlc->band->antgain = 4 * gain + fract;
4767 }
4768}
4769
4770static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
4771{
4772 int aa;
4773 uint unit;
4774 int bandtype;
4775 struct si_pub *sih = wlc->hw->sih;
4776
4777 unit = wlc->pub->unit;
4778 bandtype = wlc->band->bandtype;
4779
4780 /* get antennas available */
4781 if (bandtype == BRCM_BAND_5G)
4782 aa = (s8) getintvar(sih, BRCMS_SROM_AA5G);
4783 else
4784 aa = (s8) getintvar(sih, BRCMS_SROM_AA2G);
4785
4786 if ((aa < 1) || (aa > 15)) {
4787 wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
4788 " srom (0x%x), using 3\n", unit, __func__, aa);
4789 aa = 3;
4790 }
4791
4792 /* reset the defaults if we have a single antenna */
4793 if (aa == 1) {
4794 wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_0;
4795 wlc->stf->txant = ANT_TX_FORCE_0;
4796 } else if (aa == 2) {
4797 wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_1;
4798 wlc->stf->txant = ANT_TX_FORCE_1;
4799 } else {
4800 }
4801
4802 /* Compute Antenna Gain */
4803 if (bandtype == BRCM_BAND_5G)
4804 wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG1);
4805 else
4806 wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG0);
4807
4808 brcms_c_attach_antgain_init(wlc);
4809
4810 return true;
4811}
4812
4813static void brcms_c_bss_default_init(struct brcms_c_info *wlc)
4814{
4815 u16 chanspec;
4816 struct brcms_band *band;
4817 struct brcms_bss_info *bi = wlc->default_bss;
4818
4819 /* init default and target BSS with some sane initial values */
4820 memset((char *)(bi), 0, sizeof(struct brcms_bss_info));
4821 bi->beacon_period = BEACON_INTERVAL_DEFAULT;
4822
4823 /* fill the default channel as the first valid channel
4824 * starting from the 2G channels
4825 */
4826 chanspec = ch20mhz_chspec(1);
4827 wlc->home_chanspec = bi->chanspec = chanspec;
4828
4829 /* find the band of our default channel */
4830 band = wlc->band;
4831 if (wlc->pub->_nbands > 1 &&
4832 band->bandunit != chspec_bandunit(chanspec))
4833 band = wlc->bandstate[OTHERBANDUNIT(wlc)];
4834
4835 /* init bss rates to the band specific default rate set */
4836 brcms_c_rateset_default(&bi->rateset, NULL, band->phytype,
4837 band->bandtype, false, BRCMS_RATE_MASK_FULL,
4838 (bool) (wlc->pub->_n_enab & SUPPORT_11N),
4839 brcms_chspec_bw(chanspec), wlc->stf->txstreams);
4840
4841 if (wlc->pub->_n_enab & SUPPORT_11N)
4842 bi->flags |= BRCMS_BSS_HT;
4843}
4844
4845static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc)
4846{
4847 struct brcms_txq_info *qi, *p;
4848
4849 qi = kzalloc(sizeof(struct brcms_txq_info), GFP_ATOMIC);
4850 if (qi != NULL) {
4851 /*
4852 * Have enough room for control packets along with HI watermark
4853 * Also, add room to txq for total psq packets if all the SCBs
4854 * leave PS mode. The watermark for flowcontrol to OS packets
4855 * will remain the same
4856 */
4857 brcmu_pktq_init(&qi->q, BRCMS_PREC_COUNT,
4858 2 * BRCMS_DATAHIWAT + PKTQ_LEN_DEFAULT);
4859
4860 /* add this queue to the the global list */
4861 p = wlc->tx_queues;
4862 if (p == NULL) {
4863 wlc->tx_queues = qi;
4864 } else {
4865 while (p->next != NULL)
4866 p = p->next;
4867 p->next = qi;
4868 }
4869 }
4870 return qi;
4871}
4872
4873static void brcms_c_txq_free(struct brcms_c_info *wlc,
4874 struct brcms_txq_info *qi)
4875{
4876 struct brcms_txq_info *p;
4877
4878 if (qi == NULL)
4879 return;
4880
4881 /* remove the queue from the linked list */
4882 p = wlc->tx_queues;
4883 if (p == qi)
4884 wlc->tx_queues = p->next;
4885 else {
4886 while (p != NULL && p->next != qi)
4887 p = p->next;
4888 if (p != NULL)
4889 p->next = p->next->next;
4890 }
4891
4892 kfree(qi);
4893}
4894
4895static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap)
4896{
4897 uint i;
4898 struct brcms_band *band;
4899
4900 for (i = 0; i < wlc->pub->_nbands; i++) {
4901 band = wlc->bandstate[i];
4902 if (band->bandtype == BRCM_BAND_5G) {
4903 if ((bwcap == BRCMS_N_BW_40ALL)
4904 || (bwcap == BRCMS_N_BW_20IN2G_40IN5G))
4905 band->mimo_cap_40 = true;
4906 else
4907 band->mimo_cap_40 = false;
4908 } else {
4909 if (bwcap == BRCMS_N_BW_40ALL)
4910 band->mimo_cap_40 = true;
4911 else
4912 band->mimo_cap_40 = false;
4913 }
4914 }
4915}
4916
Arend van Spriel5b435de2011-10-05 13:19:03 +02004917static void brcms_c_timers_deinit(struct brcms_c_info *wlc)
4918{
4919 /* free timer state */
4920 if (wlc->wdtimer) {
Roland Vossenbe69c4e2011-10-12 20:51:11 +02004921 brcms_free_timer(wlc->wdtimer);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004922 wlc->wdtimer = NULL;
4923 }
4924 if (wlc->radio_timer) {
Roland Vossenbe69c4e2011-10-12 20:51:11 +02004925 brcms_free_timer(wlc->radio_timer);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004926 wlc->radio_timer = NULL;
4927 }
4928}
4929
4930static void brcms_c_detach_module(struct brcms_c_info *wlc)
4931{
4932 if (wlc->asi) {
4933 brcms_c_antsel_detach(wlc->asi);
4934 wlc->asi = NULL;
4935 }
4936
4937 if (wlc->ampdu) {
4938 brcms_c_ampdu_detach(wlc->ampdu);
4939 wlc->ampdu = NULL;
4940 }
4941
4942 brcms_c_stf_detach(wlc);
4943}
4944
4945/*
4946 * low level detach
4947 */
4948static int brcms_b_detach(struct brcms_c_info *wlc)
4949{
4950 uint i;
4951 struct brcms_hw_band *band;
4952 struct brcms_hardware *wlc_hw = wlc->hw;
4953 int callbacks;
4954
4955 callbacks = 0;
4956
4957 if (wlc_hw->sih) {
4958 /*
4959 * detach interrupt sync mechanism since interrupt is disabled
4960 * and per-port interrupt object may has been freed. this must
4961 * be done before sb core switch
4962 */
Arend van Spriel5b435de2011-10-05 13:19:03 +02004963 ai_pci_sleep(wlc_hw->sih);
4964 }
4965
4966 brcms_b_detach_dmapio(wlc_hw);
4967
4968 band = wlc_hw->band;
4969 for (i = 0; i < wlc_hw->_nbands; i++) {
4970 if (band->pi) {
4971 /* Detach this band's phy */
4972 wlc_phy_detach(band->pi);
4973 band->pi = NULL;
4974 }
4975 band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)];
4976 }
4977
4978 /* Free shared phy state */
4979 kfree(wlc_hw->phy_sh);
4980
4981 wlc_phy_shim_detach(wlc_hw->physhim);
4982
4983 if (wlc_hw->sih) {
4984 ai_detach(wlc_hw->sih);
4985 wlc_hw->sih = NULL;
4986 }
4987
4988 return callbacks;
4989
4990}
4991
4992/*
4993 * Return a count of the number of driver callbacks still pending.
4994 *
4995 * General policy is that brcms_c_detach can only dealloc/free software states.
4996 * It can NOT touch hardware registers since the d11core may be in reset and
4997 * clock may not be available.
4998 * One exception is sb register access, which is possible if crystal is turned
4999 * on after "down" state, driver should avoid software timer with the exception
5000 * of radio_monitor.
5001 */
5002uint brcms_c_detach(struct brcms_c_info *wlc)
5003{
5004 uint callbacks = 0;
5005
5006 if (wlc == NULL)
5007 return 0;
5008
5009 BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
5010
5011 callbacks += brcms_b_detach(wlc);
5012
5013 /* delete software timers */
5014 if (!brcms_c_radio_monitor_stop(wlc))
5015 callbacks++;
5016
5017 brcms_c_channel_mgr_detach(wlc->cmi);
5018
5019 brcms_c_timers_deinit(wlc);
5020
5021 brcms_c_detach_module(wlc);
5022
5023
5024 while (wlc->tx_queues != NULL)
5025 brcms_c_txq_free(wlc, wlc->tx_queues);
5026
5027 brcms_c_detach_mfree(wlc);
5028 return callbacks;
5029}
5030
5031/* update state that depends on the current value of "ap" */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02005032static void brcms_c_ap_upd(struct brcms_c_info *wlc)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005033{
5034 /* STA-BSS; short capable */
5035 wlc->PLCPHdr_override = BRCMS_PLCP_SHORT;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005036}
5037
Arend van Spriel5b435de2011-10-05 13:19:03 +02005038/* Initialize just the hardware when coming out of POR or S3/S5 system states */
5039static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
5040{
5041 if (wlc_hw->wlc->pub->hw_up)
5042 return;
5043
5044 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
5045
5046 /*
5047 * Enable pll and xtal, initialize the power control registers,
5048 * and force fastclock for the remainder of brcms_c_up().
5049 */
5050 brcms_b_xtal(wlc_hw, ON);
5051 ai_clkctl_init(wlc_hw->sih);
5052 brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
5053
5054 ai_pci_fixcfg(wlc_hw->sih);
5055
5056 /*
Arend van Spriel3b758a62011-12-12 15:15:09 -08005057 * TODO: test suspend/resume
5058 *
Arend van Spriel5b435de2011-10-05 13:19:03 +02005059 * AI chip doesn't restore bar0win2 on
5060 * hibernation/resume, need sw fixup
5061 */
Arend van Spriel5b435de2011-10-05 13:19:03 +02005062
5063 /*
5064 * Inform phy that a POR reset has occurred so
5065 * it does a complete phy init
5066 */
5067 wlc_phy_por_inform(wlc_hw->band->pi);
5068
5069 wlc_hw->ucode_loaded = false;
5070 wlc_hw->wlc->pub->hw_up = true;
5071
5072 if ((wlc_hw->boardflags & BFL_FEM)
Arend van Sprielb2ffec42011-12-08 15:06:45 -08005073 && (ai_get_chip_id(wlc_hw->sih) == BCM4313_CHIP_ID)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005074 if (!
5075 (wlc_hw->boardrev >= 0x1250
5076 && (wlc_hw->boardflags & BFL_FEM_BT)))
5077 ai_epa_4313war(wlc_hw->sih);
5078 }
5079}
5080
5081static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
5082{
5083 uint coremask;
5084
5085 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
5086
5087 /*
5088 * Enable pll and xtal, initialize the power control registers,
5089 * and force fastclock for the remainder of brcms_c_up().
5090 */
5091 brcms_b_xtal(wlc_hw, ON);
5092 ai_clkctl_init(wlc_hw->sih);
5093 brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
5094
5095 /*
5096 * Configure pci/pcmcia here instead of in brcms_c_attach()
5097 * to allow mfg hotswap: down, hotswap (chip power cycle), up.
5098 */
5099 coremask = (1 << wlc_hw->wlc->core->coreidx);
5100
5101 ai_pci_setup(wlc_hw->sih, coremask);
5102
5103 /*
5104 * Need to read the hwradio status here to cover the case where the
5105 * system is loaded with the hw radio disabled. We do not want to
5106 * bring the driver up in this case.
5107 */
5108 if (brcms_b_radio_read_hwdisabled(wlc_hw)) {
5109 /* put SB PCI in down state again */
5110 ai_pci_down(wlc_hw->sih);
5111 brcms_b_xtal(wlc_hw, OFF);
5112 return -ENOMEDIUM;
5113 }
5114
5115 ai_pci_up(wlc_hw->sih);
5116
5117 /* reset the d11 core */
5118 brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
5119
5120 return 0;
5121}
5122
5123static int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
5124{
5125 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
5126
5127 wlc_hw->up = true;
5128 wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
5129
5130 /* FULLY enable dynamic power control and d11 core interrupt */
5131 brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
5132 brcms_intrson(wlc_hw->wlc->wl);
5133 return 0;
5134}
5135
5136/*
5137 * Write WME tunable parameters for retransmit/max rate
5138 * from wlc struct to ucode
5139 */
5140static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
5141{
5142 int ac;
5143
5144 /* Need clock to do this */
5145 if (!wlc->clk)
5146 return;
5147
Arend van Sprielb7eec422011-11-10 20:30:18 +01005148 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005149 brcms_b_write_shm(wlc->hw, M_AC_TXLMT_ADDR(ac),
5150 wlc->wme_retries[ac]);
5151}
5152
5153/* make interface operational */
5154int brcms_c_up(struct brcms_c_info *wlc)
5155{
5156 BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
5157
5158 /* HW is turned off so don't try to access it */
5159 if (wlc->pub->hw_off || brcms_deviceremoved(wlc))
5160 return -ENOMEDIUM;
5161
5162 if (!wlc->pub->hw_up) {
5163 brcms_b_hw_up(wlc->hw);
5164 wlc->pub->hw_up = true;
5165 }
5166
5167 if ((wlc->pub->boardflags & BFL_FEM)
Arend van Sprielb2ffec42011-12-08 15:06:45 -08005168 && (ai_get_chip_id(wlc->hw->sih) == BCM4313_CHIP_ID)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005169 if (wlc->pub->boardrev >= 0x1250
5170 && (wlc->pub->boardflags & BFL_FEM_BT))
5171 brcms_b_mhf(wlc->hw, MHF5, MHF5_4313_GPIOCTRL,
5172 MHF5_4313_GPIOCTRL, BRCM_BAND_ALL);
5173 else
5174 brcms_b_mhf(wlc->hw, MHF4, MHF4_EXTPA_ENABLE,
5175 MHF4_EXTPA_ENABLE, BRCM_BAND_ALL);
5176 }
5177
5178 /*
5179 * Need to read the hwradio status here to cover the case where the
5180 * system is loaded with the hw radio disabled. We do not want to bring
5181 * the driver up in this case. If radio is disabled, abort up, lower
5182 * power, start radio timer and return 0(for NDIS) don't call
5183 * radio_update to avoid looping brcms_c_up.
5184 *
5185 * brcms_b_up_prep() returns either 0 or -BCME_RADIOOFF only
5186 */
5187 if (!wlc->pub->radio_disabled) {
5188 int status = brcms_b_up_prep(wlc->hw);
5189 if (status == -ENOMEDIUM) {
5190 if (!mboolisset
5191 (wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE)) {
5192 struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
5193 mboolset(wlc->pub->radio_disabled,
5194 WL_RADIO_HW_DISABLE);
5195
5196 if (bsscfg->enable && bsscfg->BSS)
5197 wiphy_err(wlc->wiphy, "wl%d: up"
5198 ": rfdisable -> "
5199 "bsscfg_disable()\n",
5200 wlc->pub->unit);
5201 }
5202 }
5203 }
5204
5205 if (wlc->pub->radio_disabled) {
5206 brcms_c_radio_monitor_start(wlc);
5207 return 0;
5208 }
5209
5210 /* brcms_b_up_prep has done brcms_c_corereset(). so clk is on, set it */
5211 wlc->clk = true;
5212
5213 brcms_c_radio_monitor_stop(wlc);
5214
5215 /* Set EDCF hostflags */
5216 brcms_b_mhf(wlc->hw, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL);
5217
5218 brcms_init(wlc->wl);
5219 wlc->pub->up = true;
5220
5221 if (wlc->bandinit_pending) {
5222 brcms_c_suspend_mac_and_wait(wlc);
5223 brcms_c_set_chanspec(wlc, wlc->default_bss->chanspec);
5224 wlc->bandinit_pending = false;
5225 brcms_c_enable_mac(wlc);
5226 }
5227
5228 brcms_b_up_finish(wlc->hw);
5229
5230 /* Program the TX wme params with the current settings */
5231 brcms_c_wme_retries_write(wlc);
5232
5233 /* start one second watchdog timer */
Roland Vossenbe69c4e2011-10-12 20:51:11 +02005234 brcms_add_timer(wlc->wdtimer, TIMER_INTERVAL_WATCHDOG, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005235 wlc->WDarmed = true;
5236
5237 /* ensure antenna config is up to date */
5238 brcms_c_stf_phy_txant_upd(wlc);
5239 /* ensure LDPC config is in sync */
5240 brcms_c_ht_update_ldpc(wlc, wlc->stf->ldpc);
5241
5242 return 0;
5243}
5244
5245static uint brcms_c_down_del_timer(struct brcms_c_info *wlc)
5246{
5247 uint callbacks = 0;
5248
5249 return callbacks;
5250}
5251
5252static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
5253{
5254 bool dev_gone;
5255 uint callbacks = 0;
5256
5257 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
5258
5259 if (!wlc_hw->up)
5260 return callbacks;
5261
5262 dev_gone = brcms_deviceremoved(wlc_hw->wlc);
5263
5264 /* disable interrupts */
5265 if (dev_gone)
5266 wlc_hw->wlc->macintmask = 0;
5267 else {
5268 /* now disable interrupts */
5269 brcms_intrsoff(wlc_hw->wlc->wl);
5270
5271 /* ensure we're running on the pll clock again */
5272 brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
5273 }
5274 /* down phy at the last of this stage */
5275 callbacks += wlc_phy_down(wlc_hw->band->pi);
5276
5277 return callbacks;
5278}
5279
5280static int brcms_b_down_finish(struct brcms_hardware *wlc_hw)
5281{
5282 uint callbacks = 0;
5283 bool dev_gone;
5284
5285 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
5286
5287 if (!wlc_hw->up)
5288 return callbacks;
5289
5290 wlc_hw->up = false;
5291 wlc_phy_hw_state_upd(wlc_hw->band->pi, false);
5292
5293 dev_gone = brcms_deviceremoved(wlc_hw->wlc);
5294
5295 if (dev_gone) {
5296 wlc_hw->sbclk = false;
5297 wlc_hw->clk = false;
5298 wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
5299
5300 /* reclaim any posted packets */
5301 brcms_c_flushqueues(wlc_hw->wlc);
5302 } else {
5303
5304 /* Reset and disable the core */
Arend van Spriela8779e42011-12-08 15:06:58 -08005305 if (bcma_core_is_enabled(wlc_hw->d11core)) {
Arend van Spriel16d28122011-12-08 15:06:51 -08005306 if (bcma_read32(wlc_hw->d11core,
5307 D11REGOFFS(maccontrol)) & MCTL_EN_MAC)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005308 brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
5309 callbacks += brcms_reset(wlc_hw->wlc->wl);
5310 brcms_c_coredisable(wlc_hw);
5311 }
5312
5313 /* turn off primary xtal and pll */
5314 if (!wlc_hw->noreset) {
5315 ai_pci_down(wlc_hw->sih);
5316 brcms_b_xtal(wlc_hw, OFF);
5317 }
5318 }
5319
5320 return callbacks;
5321}
5322
5323/*
5324 * Mark the interface nonoperational, stop the software mechanisms,
5325 * disable the hardware, free any transient buffer state.
5326 * Return a count of the number of driver callbacks still pending.
5327 */
5328uint brcms_c_down(struct brcms_c_info *wlc)
5329{
5330
5331 uint callbacks = 0;
5332 int i;
5333 bool dev_gone = false;
5334 struct brcms_txq_info *qi;
5335
5336 BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
5337
5338 /* check if we are already in the going down path */
5339 if (wlc->going_down) {
5340 wiphy_err(wlc->wiphy, "wl%d: %s: Driver going down so return"
5341 "\n", wlc->pub->unit, __func__);
5342 return 0;
5343 }
5344 if (!wlc->pub->up)
5345 return callbacks;
5346
Arend van Spriel5b435de2011-10-05 13:19:03 +02005347 wlc->going_down = true;
5348
5349 callbacks += brcms_b_bmac_down_prep(wlc->hw);
5350
5351 dev_gone = brcms_deviceremoved(wlc);
5352
5353 /* Call any registered down handlers */
5354 for (i = 0; i < BRCMS_MAXMODULES; i++) {
5355 if (wlc->modulecb[i].down_fn)
5356 callbacks +=
5357 wlc->modulecb[i].down_fn(wlc->modulecb[i].hdl);
5358 }
5359
5360 /* cancel the watchdog timer */
5361 if (wlc->WDarmed) {
Roland Vossenbe69c4e2011-10-12 20:51:11 +02005362 if (!brcms_del_timer(wlc->wdtimer))
Arend van Spriel5b435de2011-10-05 13:19:03 +02005363 callbacks++;
5364 wlc->WDarmed = false;
5365 }
5366 /* cancel all other timers */
5367 callbacks += brcms_c_down_del_timer(wlc);
5368
5369 wlc->pub->up = false;
5370
5371 wlc_phy_mute_upd(wlc->band->pi, false, PHY_MUTE_ALL);
5372
5373 /* clear txq flow control */
5374 brcms_c_txflowcontrol_reset(wlc);
5375
5376 /* flush tx queues */
5377 for (qi = wlc->tx_queues; qi != NULL; qi = qi->next)
5378 brcmu_pktq_flush(&qi->q, true, NULL, NULL);
5379
5380 callbacks += brcms_b_down_finish(wlc->hw);
5381
5382 /* brcms_b_down_finish has done brcms_c_coredisable(). so clk is off */
5383 wlc->clk = false;
5384
5385 wlc->going_down = false;
5386 return callbacks;
5387}
5388
5389/* Set the current gmode configuration */
5390int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
5391{
5392 int ret = 0;
5393 uint i;
5394 struct brcms_c_rateset rs;
5395 /* Default to 54g Auto */
5396 /* Advertise and use shortslot (-1/0/1 Auto/Off/On) */
5397 s8 shortslot = BRCMS_SHORTSLOT_AUTO;
5398 bool shortslot_restrict = false; /* Restrict association to stations
5399 * that support shortslot
5400 */
5401 bool ofdm_basic = false; /* Make 6, 12, and 24 basic rates */
5402 /* Advertise and use short preambles (-1/0/1 Auto/Off/On) */
5403 int preamble = BRCMS_PLCP_LONG;
5404 bool preamble_restrict = false; /* Restrict association to stations
5405 * that support short preambles
5406 */
5407 struct brcms_band *band;
5408
5409 /* if N-support is enabled, allow Gmode set as long as requested
5410 * Gmode is not GMODE_LEGACY_B
5411 */
5412 if ((wlc->pub->_n_enab & SUPPORT_11N) && gmode == GMODE_LEGACY_B)
5413 return -ENOTSUPP;
5414
5415 /* verify that we are dealing with 2G band and grab the band pointer */
5416 if (wlc->band->bandtype == BRCM_BAND_2G)
5417 band = wlc->band;
5418 else if ((wlc->pub->_nbands > 1) &&
5419 (wlc->bandstate[OTHERBANDUNIT(wlc)]->bandtype == BRCM_BAND_2G))
5420 band = wlc->bandstate[OTHERBANDUNIT(wlc)];
5421 else
5422 return -EINVAL;
5423
5424 /* Legacy or bust when no OFDM is supported by regulatory */
5425 if ((brcms_c_channel_locale_flags_in_band(wlc->cmi, band->bandunit) &
5426 BRCMS_NO_OFDM) && (gmode != GMODE_LEGACY_B))
5427 return -EINVAL;
5428
5429 /* update configuration value */
5430 if (config == true)
5431 brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode);
5432
5433 /* Clear rateset override */
5434 memset(&rs, 0, sizeof(struct brcms_c_rateset));
5435
5436 switch (gmode) {
5437 case GMODE_LEGACY_B:
5438 shortslot = BRCMS_SHORTSLOT_OFF;
5439 brcms_c_rateset_copy(&gphy_legacy_rates, &rs);
5440
5441 break;
5442
5443 case GMODE_LRS:
5444 break;
5445
5446 case GMODE_AUTO:
5447 /* Accept defaults */
5448 break;
5449
5450 case GMODE_ONLY:
5451 ofdm_basic = true;
5452 preamble = BRCMS_PLCP_SHORT;
5453 preamble_restrict = true;
5454 break;
5455
5456 case GMODE_PERFORMANCE:
5457 shortslot = BRCMS_SHORTSLOT_ON;
5458 shortslot_restrict = true;
5459 ofdm_basic = true;
5460 preamble = BRCMS_PLCP_SHORT;
5461 preamble_restrict = true;
5462 break;
5463
5464 default:
5465 /* Error */
5466 wiphy_err(wlc->wiphy, "wl%d: %s: invalid gmode %d\n",
5467 wlc->pub->unit, __func__, gmode);
5468 return -ENOTSUPP;
5469 }
5470
5471 band->gmode = gmode;
5472
5473 wlc->shortslot_override = shortslot;
5474
5475 /* Use the default 11g rateset */
5476 if (!rs.count)
5477 brcms_c_rateset_copy(&cck_ofdm_rates, &rs);
5478
5479 if (ofdm_basic) {
5480 for (i = 0; i < rs.count; i++) {
5481 if (rs.rates[i] == BRCM_RATE_6M
5482 || rs.rates[i] == BRCM_RATE_12M
5483 || rs.rates[i] == BRCM_RATE_24M)
5484 rs.rates[i] |= BRCMS_RATE_FLAG;
5485 }
5486 }
5487
5488 /* Set default bss rateset */
5489 wlc->default_bss->rateset.count = rs.count;
5490 memcpy(wlc->default_bss->rateset.rates, rs.rates,
5491 sizeof(wlc->default_bss->rateset.rates));
5492
5493 return ret;
5494}
5495
5496int brcms_c_set_nmode(struct brcms_c_info *wlc)
5497{
5498 uint i;
5499 s32 nmode = AUTO;
5500
5501 if (wlc->stf->txstreams == WL_11N_3x3)
5502 nmode = WL_11N_3x3;
5503 else
5504 nmode = WL_11N_2x2;
5505
5506 /* force GMODE_AUTO if NMODE is ON */
5507 brcms_c_set_gmode(wlc, GMODE_AUTO, true);
5508 if (nmode == WL_11N_3x3)
5509 wlc->pub->_n_enab = SUPPORT_HT;
5510 else
5511 wlc->pub->_n_enab = SUPPORT_11N;
5512 wlc->default_bss->flags |= BRCMS_BSS_HT;
5513 /* add the mcs rates to the default and hw ratesets */
5514 brcms_c_rateset_mcs_build(&wlc->default_bss->rateset,
5515 wlc->stf->txstreams);
5516 for (i = 0; i < wlc->pub->_nbands; i++)
5517 memcpy(wlc->bandstate[i]->hw_rateset.mcs,
5518 wlc->default_bss->rateset.mcs, MCSSET_LEN);
5519
5520 return 0;
5521}
5522
5523static int
5524brcms_c_set_internal_rateset(struct brcms_c_info *wlc,
5525 struct brcms_c_rateset *rs_arg)
5526{
5527 struct brcms_c_rateset rs, new;
5528 uint bandunit;
5529
5530 memcpy(&rs, rs_arg, sizeof(struct brcms_c_rateset));
5531
5532 /* check for bad count value */
5533 if ((rs.count == 0) || (rs.count > BRCMS_NUMRATES))
5534 return -EINVAL;
5535
5536 /* try the current band */
5537 bandunit = wlc->band->bandunit;
5538 memcpy(&new, &rs, sizeof(struct brcms_c_rateset));
5539 if (brcms_c_rate_hwrs_filter_sort_validate
5540 (&new, &wlc->bandstate[bandunit]->hw_rateset, true,
5541 wlc->stf->txstreams))
5542 goto good;
5543
5544 /* try the other band */
5545 if (brcms_is_mband_unlocked(wlc)) {
5546 bandunit = OTHERBANDUNIT(wlc);
5547 memcpy(&new, &rs, sizeof(struct brcms_c_rateset));
5548 if (brcms_c_rate_hwrs_filter_sort_validate(&new,
5549 &wlc->
5550 bandstate[bandunit]->
5551 hw_rateset, true,
5552 wlc->stf->txstreams))
5553 goto good;
5554 }
5555
5556 return -EBADE;
5557
5558 good:
5559 /* apply new rateset */
5560 memcpy(&wlc->default_bss->rateset, &new,
5561 sizeof(struct brcms_c_rateset));
5562 memcpy(&wlc->bandstate[bandunit]->defrateset, &new,
5563 sizeof(struct brcms_c_rateset));
5564 return 0;
5565}
5566
5567static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)
5568{
5569 u8 r;
5570 bool war = false;
5571
5572 if (wlc->bsscfg->associated)
5573 r = wlc->bsscfg->current_bss->rateset.rates[0];
5574 else
5575 r = wlc->default_bss->rateset.rates[0];
5576
5577 wlc_phy_ofdm_rateset_war(wlc->band->pi, war);
5578}
5579
5580int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)
5581{
5582 u16 chspec = ch20mhz_chspec(channel);
5583
5584 if (channel < 0 || channel > MAXCHANNEL)
5585 return -EINVAL;
5586
5587 if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec))
5588 return -EINVAL;
5589
5590
5591 if (!wlc->pub->up && brcms_is_mband_unlocked(wlc)) {
5592 if (wlc->band->bandunit != chspec_bandunit(chspec))
5593 wlc->bandinit_pending = true;
5594 else
5595 wlc->bandinit_pending = false;
5596 }
5597
5598 wlc->default_bss->chanspec = chspec;
5599 /* brcms_c_BSSinit() will sanitize the rateset before
5600 * using it.. */
5601 if (wlc->pub->up && (wlc_phy_chanspec_get(wlc->band->pi) != chspec)) {
5602 brcms_c_set_home_chanspec(wlc, chspec);
5603 brcms_c_suspend_mac_and_wait(wlc);
5604 brcms_c_set_chanspec(wlc, chspec);
5605 brcms_c_enable_mac(wlc);
5606 }
5607 return 0;
5608}
5609
5610int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl)
5611{
5612 int ac;
5613
5614 if (srl < 1 || srl > RETRY_SHORT_MAX ||
5615 lrl < 1 || lrl > RETRY_SHORT_MAX)
5616 return -EINVAL;
5617
5618 wlc->SRL = srl;
5619 wlc->LRL = lrl;
5620
5621 brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
5622
Arend van Sprielb7eec422011-11-10 20:30:18 +01005623 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005624 wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac],
5625 EDCF_SHORT, wlc->SRL);
5626 wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac],
5627 EDCF_LONG, wlc->LRL);
5628 }
5629 brcms_c_wme_retries_write(wlc);
5630
5631 return 0;
5632}
5633
5634void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
5635 struct brcm_rateset *currs)
5636{
5637 struct brcms_c_rateset *rs;
5638
5639 if (wlc->pub->associated)
5640 rs = &wlc->bsscfg->current_bss->rateset;
5641 else
5642 rs = &wlc->default_bss->rateset;
5643
5644 /* Copy only legacy rateset section */
5645 currs->count = rs->count;
5646 memcpy(&currs->rates, &rs->rates, rs->count);
5647}
5648
5649int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
5650{
5651 struct brcms_c_rateset internal_rs;
5652 int bcmerror;
5653
5654 if (rs->count > BRCMS_NUMRATES)
5655 return -ENOBUFS;
5656
5657 memset(&internal_rs, 0, sizeof(struct brcms_c_rateset));
5658
5659 /* Copy only legacy rateset section */
5660 internal_rs.count = rs->count;
5661 memcpy(&internal_rs.rates, &rs->rates, internal_rs.count);
5662
5663 /* merge rateset coming in with the current mcsset */
5664 if (wlc->pub->_n_enab & SUPPORT_11N) {
5665 struct brcms_bss_info *mcsset_bss;
5666 if (wlc->bsscfg->associated)
5667 mcsset_bss = wlc->bsscfg->current_bss;
5668 else
5669 mcsset_bss = wlc->default_bss;
5670 memcpy(internal_rs.mcs, &mcsset_bss->rateset.mcs[0],
5671 MCSSET_LEN);
5672 }
5673
5674 bcmerror = brcms_c_set_internal_rateset(wlc, &internal_rs);
5675 if (!bcmerror)
5676 brcms_c_ofdm_rateset_war(wlc);
5677
5678 return bcmerror;
5679}
5680
5681int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
5682{
5683 if (period < DOT11_MIN_BEACON_PERIOD ||
5684 period > DOT11_MAX_BEACON_PERIOD)
5685 return -EINVAL;
5686
5687 wlc->default_bss->beacon_period = period;
5688 return 0;
5689}
5690
5691u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx)
5692{
5693 return wlc->band->phytype;
5694}
5695
5696void brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override)
5697{
5698 wlc->shortslot_override = sslot_override;
5699
5700 /*
5701 * shortslot is an 11g feature, so no more work if we are
5702 * currently on the 5G band
5703 */
5704 if (wlc->band->bandtype == BRCM_BAND_5G)
5705 return;
5706
5707 if (wlc->pub->up && wlc->pub->associated) {
5708 /* let watchdog or beacon processing update shortslot */
5709 } else if (wlc->pub->up) {
5710 /* unassociated shortslot is off */
5711 brcms_c_switch_shortslot(wlc, false);
5712 } else {
5713 /* driver is down, so just update the brcms_c_info
5714 * value */
5715 if (wlc->shortslot_override == BRCMS_SHORTSLOT_AUTO)
5716 wlc->shortslot = false;
5717 else
5718 wlc->shortslot =
5719 (wlc->shortslot_override ==
5720 BRCMS_SHORTSLOT_ON);
5721 }
5722}
5723
5724/*
5725 * register watchdog and down handlers.
5726 */
5727int brcms_c_module_register(struct brcms_pub *pub,
5728 const char *name, struct brcms_info *hdl,
5729 int (*d_fn)(void *handle))
5730{
5731 struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc;
5732 int i;
5733
5734 /* find an empty entry and just add, no duplication check! */
5735 for (i = 0; i < BRCMS_MAXMODULES; i++) {
5736 if (wlc->modulecb[i].name[0] == '\0') {
5737 strncpy(wlc->modulecb[i].name, name,
5738 sizeof(wlc->modulecb[i].name) - 1);
5739 wlc->modulecb[i].hdl = hdl;
5740 wlc->modulecb[i].down_fn = d_fn;
5741 return 0;
5742 }
5743 }
5744
5745 return -ENOSR;
5746}
5747
5748/* unregister module callbacks */
5749int brcms_c_module_unregister(struct brcms_pub *pub, const char *name,
5750 struct brcms_info *hdl)
5751{
5752 struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc;
5753 int i;
5754
5755 if (wlc == NULL)
5756 return -ENODATA;
5757
5758 for (i = 0; i < BRCMS_MAXMODULES; i++) {
5759 if (!strcmp(wlc->modulecb[i].name, name) &&
5760 (wlc->modulecb[i].hdl == hdl)) {
5761 memset(&wlc->modulecb[i], 0, sizeof(struct modulecb));
5762 return 0;
5763 }
5764 }
5765
5766 /* table not found! */
5767 return -ENODATA;
5768}
5769
Arend van Spriel5b435de2011-10-05 13:19:03 +02005770void brcms_c_print_txstatus(struct tx_status *txs)
5771{
Joe Perches18aad4f2012-01-15 00:38:42 -08005772 pr_debug("\ntxpkt (MPDU) Complete\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005773
Joe Perches18aad4f2012-01-15 00:38:42 -08005774 pr_debug("FrameID: %04x TxStatus: %04x\n", txs->frameid, txs->status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005775
Joe Perches18aad4f2012-01-15 00:38:42 -08005776 pr_debug("[15:12] %d frame attempts\n",
5777 (txs->status & TX_STATUS_FRM_RTX_MASK) >>
5778 TX_STATUS_FRM_RTX_SHIFT);
5779 pr_debug(" [11:8] %d rts attempts\n",
5780 (txs->status & TX_STATUS_RTS_RTX_MASK) >>
5781 TX_STATUS_RTS_RTX_SHIFT);
5782 pr_debug(" [7] %d PM mode indicated\n",
5783 txs->status & TX_STATUS_PMINDCTD ? 1 : 0);
5784 pr_debug(" [6] %d intermediate status\n",
5785 txs->status & TX_STATUS_INTERMEDIATE ? 1 : 0);
5786 pr_debug(" [5] %d AMPDU\n",
5787 txs->status & TX_STATUS_AMPDU ? 1 : 0);
5788 pr_debug(" [4:2] %d Frame Suppressed Reason (%s)\n",
5789 (txs->status & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT,
5790 (const char *[]) {
5791 "None",
5792 "PMQ Entry",
5793 "Flush request",
5794 "Previous frag failure",
5795 "Channel mismatch",
5796 "Lifetime Expiry",
5797 "Underflow"
5798 } [(txs->status & TX_STATUS_SUPR_MASK) >>
5799 TX_STATUS_SUPR_SHIFT]);
5800 pr_debug(" [1] %d acked\n",
5801 txs->status & TX_STATUS_ACK_RCV ? 1 : 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005802
Joe Perches18aad4f2012-01-15 00:38:42 -08005803 pr_debug("LastTxTime: %04x Seq: %04x PHYTxStatus: %04x RxAckRSSI: %04x RxAckSQ: %04x\n",
5804 txs->lasttxtime, txs->sequence, txs->phyerr,
5805 (txs->ackphyrxsh & PRXS1_JSSI_MASK) >> PRXS1_JSSI_SHIFT,
5806 (txs->ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005807}
5808
Arend van Spriel5b435de2011-10-05 13:19:03 +02005809bool brcms_c_chipmatch(u16 vendor, u16 device)
5810{
5811 if (vendor != PCI_VENDOR_ID_BROADCOM) {
Joe Perches02f77192012-01-15 00:38:44 -08005812 pr_err("unknown vendor id %04x\n", vendor);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005813 return false;
5814 }
5815
5816 if (device == BCM43224_D11N_ID_VEN1)
5817 return true;
5818 if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID))
5819 return true;
5820 if (device == BCM4313_D11N2G_ID)
5821 return true;
5822 if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID))
5823 return true;
5824
Joe Perches02f77192012-01-15 00:38:44 -08005825 pr_err("unknown device id %04x\n", device);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005826 return false;
5827}
5828
Joe Perches8ae74652012-01-15 00:38:38 -08005829#if defined(DEBUG)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005830void brcms_c_print_txdesc(struct d11txh *txh)
5831{
5832 u16 mtcl = le16_to_cpu(txh->MacTxControlLow);
5833 u16 mtch = le16_to_cpu(txh->MacTxControlHigh);
5834 u16 mfc = le16_to_cpu(txh->MacFrameControl);
5835 u16 tfest = le16_to_cpu(txh->TxFesTimeNormal);
5836 u16 ptcw = le16_to_cpu(txh->PhyTxControlWord);
5837 u16 ptcw_1 = le16_to_cpu(txh->PhyTxControlWord_1);
5838 u16 ptcw_1_Fbr = le16_to_cpu(txh->PhyTxControlWord_1_Fbr);
5839 u16 ptcw_1_Rts = le16_to_cpu(txh->PhyTxControlWord_1_Rts);
5840 u16 ptcw_1_FbrRts = le16_to_cpu(txh->PhyTxControlWord_1_FbrRts);
5841 u16 mainrates = le16_to_cpu(txh->MainRates);
5842 u16 xtraft = le16_to_cpu(txh->XtraFrameTypes);
5843 u8 *iv = txh->IV;
5844 u8 *ra = txh->TxFrameRA;
5845 u16 tfestfb = le16_to_cpu(txh->TxFesTimeFallback);
5846 u8 *rtspfb = txh->RTSPLCPFallback;
5847 u16 rtsdfb = le16_to_cpu(txh->RTSDurFallback);
5848 u8 *fragpfb = txh->FragPLCPFallback;
5849 u16 fragdfb = le16_to_cpu(txh->FragDurFallback);
5850 u16 mmodelen = le16_to_cpu(txh->MModeLen);
5851 u16 mmodefbrlen = le16_to_cpu(txh->MModeFbrLen);
5852 u16 tfid = le16_to_cpu(txh->TxFrameID);
5853 u16 txs = le16_to_cpu(txh->TxStatus);
5854 u16 mnmpdu = le16_to_cpu(txh->MaxNMpdus);
5855 u16 mabyte = le16_to_cpu(txh->MaxABytes_MRT);
5856 u16 mabyte_f = le16_to_cpu(txh->MaxABytes_FBR);
5857 u16 mmbyte = le16_to_cpu(txh->MinMBytes);
5858
5859 u8 *rtsph = txh->RTSPhyHeader;
5860 struct ieee80211_rts rts = txh->rts_frame;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005861
5862 /* add plcp header along with txh descriptor */
Joe Perchesc2e6d5a2012-01-15 00:38:43 -08005863 brcmu_dbg_hex_dump(txh, sizeof(struct d11txh) + 48,
5864 "Raw TxDesc + plcp header:\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005865
Joe Perches18aad4f2012-01-15 00:38:42 -08005866 pr_debug("TxCtlLow: %04x ", mtcl);
5867 pr_debug("TxCtlHigh: %04x ", mtch);
5868 pr_debug("FC: %04x ", mfc);
5869 pr_debug("FES Time: %04x\n", tfest);
5870 pr_debug("PhyCtl: %04x%s ", ptcw,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005871 (ptcw & PHY_TXC_SHORT_HDR) ? " short" : "");
Joe Perches18aad4f2012-01-15 00:38:42 -08005872 pr_debug("PhyCtl_1: %04x ", ptcw_1);
5873 pr_debug("PhyCtl_1_Fbr: %04x\n", ptcw_1_Fbr);
5874 pr_debug("PhyCtl_1_Rts: %04x ", ptcw_1_Rts);
5875 pr_debug("PhyCtl_1_Fbr_Rts: %04x\n", ptcw_1_FbrRts);
5876 pr_debug("MainRates: %04x ", mainrates);
5877 pr_debug("XtraFrameTypes: %04x ", xtraft);
5878 pr_debug("\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005879
Arend van Spriel09c7dfa2011-10-18 14:03:10 +02005880 print_hex_dump_bytes("SecIV:", DUMP_PREFIX_OFFSET, iv, sizeof(txh->IV));
5881 print_hex_dump_bytes("RA:", DUMP_PREFIX_OFFSET,
5882 ra, sizeof(txh->TxFrameRA));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005883
Joe Perches18aad4f2012-01-15 00:38:42 -08005884 pr_debug("Fb FES Time: %04x ", tfestfb);
Arend van Spriel09c7dfa2011-10-18 14:03:10 +02005885 print_hex_dump_bytes("Fb RTS PLCP:", DUMP_PREFIX_OFFSET,
5886 rtspfb, sizeof(txh->RTSPLCPFallback));
Joe Perches18aad4f2012-01-15 00:38:42 -08005887 pr_debug("RTS DUR: %04x ", rtsdfb);
Arend van Spriel09c7dfa2011-10-18 14:03:10 +02005888 print_hex_dump_bytes("PLCP:", DUMP_PREFIX_OFFSET,
5889 fragpfb, sizeof(txh->FragPLCPFallback));
Joe Perches18aad4f2012-01-15 00:38:42 -08005890 pr_debug("DUR: %04x", fragdfb);
5891 pr_debug("\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005892
Joe Perches18aad4f2012-01-15 00:38:42 -08005893 pr_debug("MModeLen: %04x ", mmodelen);
5894 pr_debug("MModeFbrLen: %04x\n", mmodefbrlen);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005895
Joe Perches18aad4f2012-01-15 00:38:42 -08005896 pr_debug("FrameID: %04x\n", tfid);
5897 pr_debug("TxStatus: %04x\n", txs);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005898
Joe Perches18aad4f2012-01-15 00:38:42 -08005899 pr_debug("MaxNumMpdu: %04x\n", mnmpdu);
5900 pr_debug("MaxAggbyte: %04x\n", mabyte);
5901 pr_debug("MaxAggbyte_fb: %04x\n", mabyte_f);
5902 pr_debug("MinByte: %04x\n", mmbyte);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005903
Arend van Spriel09c7dfa2011-10-18 14:03:10 +02005904 print_hex_dump_bytes("RTS PLCP:", DUMP_PREFIX_OFFSET,
5905 rtsph, sizeof(txh->RTSPhyHeader));
5906 print_hex_dump_bytes("RTS Frame:", DUMP_PREFIX_OFFSET,
5907 (u8 *)&rts, sizeof(txh->rts_frame));
Joe Perches18aad4f2012-01-15 00:38:42 -08005908 pr_debug("\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005909}
Joe Perches8ae74652012-01-15 00:38:38 -08005910#endif /* defined(DEBUG) */
Arend van Spriel5b435de2011-10-05 13:19:03 +02005911
Joe Perches8ae74652012-01-15 00:38:38 -08005912#if defined(DEBUG)
Arend van Spriel094b1992011-10-18 14:03:07 +02005913static int
Alwin Beukers44760652011-10-12 20:51:31 +02005914brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf,
Arend van Spriel094b1992011-10-18 14:03:07 +02005915 int len)
Alwin Beukers44760652011-10-12 20:51:31 +02005916{
5917 int i;
5918 char *p = buf;
5919 char hexstr[16];
5920 int slen = 0, nlen = 0;
5921 u32 bit;
5922 const char *name;
5923
5924 if (len < 2 || !buf)
5925 return 0;
5926
5927 buf[0] = '\0';
5928
5929 for (i = 0; flags != 0; i++) {
5930 bit = bd[i].bit;
5931 name = bd[i].name;
5932 if (bit == 0 && flags != 0) {
5933 /* print any unnamed bits */
5934 snprintf(hexstr, 16, "0x%X", flags);
5935 name = hexstr;
5936 flags = 0; /* exit loop */
5937 } else if ((flags & bit) == 0)
5938 continue;
5939 flags &= ~bit;
5940 nlen = strlen(name);
5941 slen += nlen;
5942 /* count btwn flag space */
5943 if (flags != 0)
5944 slen += 1;
5945 /* need NULL char as well */
5946 if (len <= slen)
5947 break;
5948 /* copy NULL char but don't count it */
5949 strncpy(p, name, nlen + 1);
5950 p += nlen;
5951 /* copy btwn flag space and NULL char */
5952 if (flags != 0)
5953 p += snprintf(p, 2, " ");
5954 len -= slen;
5955 }
5956
5957 /* indicate the str was too short */
5958 if (flags != 0) {
5959 if (len < 2)
5960 p -= 2 - len; /* overwrite last char */
5961 p += snprintf(p, 2, ">");
5962 }
5963
5964 return (int)(p - buf);
5965}
Joe Perches8ae74652012-01-15 00:38:38 -08005966#endif /* defined(DEBUG) */
Alwin Beukers44760652011-10-12 20:51:31 +02005967
Joe Perches8ae74652012-01-15 00:38:38 -08005968#if defined(DEBUG)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005969void brcms_c_print_rxh(struct d11rxhdr *rxh)
5970{
5971 u16 len = rxh->RxFrameSize;
5972 u16 phystatus_0 = rxh->PhyRxStatus_0;
5973 u16 phystatus_1 = rxh->PhyRxStatus_1;
5974 u16 phystatus_2 = rxh->PhyRxStatus_2;
5975 u16 phystatus_3 = rxh->PhyRxStatus_3;
5976 u16 macstatus1 = rxh->RxStatus1;
5977 u16 macstatus2 = rxh->RxStatus2;
5978 char flagstr[64];
5979 char lenbuf[20];
Alwin Beukers44760652011-10-12 20:51:31 +02005980 static const struct brcms_c_bit_desc macstat_flags[] = {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005981 {RXS_FCSERR, "FCSErr"},
5982 {RXS_RESPFRAMETX, "Reply"},
5983 {RXS_PBPRES, "PADDING"},
5984 {RXS_DECATMPT, "DeCr"},
5985 {RXS_DECERR, "DeCrErr"},
5986 {RXS_BCNSENT, "Bcn"},
5987 {0, NULL}
5988 };
5989
Joe Perchesc2e6d5a2012-01-15 00:38:43 -08005990 brcmu_dbg_hex_dump(rxh, sizeof(struct d11rxhdr), "Raw RxDesc:\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005991
Alwin Beukers44760652011-10-12 20:51:31 +02005992 brcms_c_format_flags(macstat_flags, macstatus1, flagstr, 64);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005993
5994 snprintf(lenbuf, sizeof(lenbuf), "0x%x", len);
5995
Joe Perches18aad4f2012-01-15 00:38:42 -08005996 pr_debug("RxFrameSize: %6s (%d)%s\n", lenbuf, len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005997 (rxh->PhyRxStatus_0 & PRXS0_SHORTH) ? " short preamble" : "");
Joe Perches18aad4f2012-01-15 00:38:42 -08005998 pr_debug("RxPHYStatus: %04x %04x %04x %04x\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02005999 phystatus_0, phystatus_1, phystatus_2, phystatus_3);
Joe Perches18aad4f2012-01-15 00:38:42 -08006000 pr_debug("RxMACStatus: %x %s\n", macstatus1, flagstr);
6001 pr_debug("RXMACaggtype: %x\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02006002 (macstatus2 & RXS_AGGTYPE_MASK));
Joe Perches18aad4f2012-01-15 00:38:42 -08006003 pr_debug("RxTSFTime: %04x\n", rxh->RxTSFTime);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006004}
Joe Perches8ae74652012-01-15 00:38:38 -08006005#endif /* defined(DEBUG) */
Arend van Spriel5b435de2011-10-05 13:19:03 +02006006
6007u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)
6008{
6009 u16 table_ptr;
6010 u8 phy_rate, index;
6011
6012 /* get the phy specific rate encoding for the PLCP SIGNAL field */
6013 if (is_ofdm_rate(rate))
6014 table_ptr = M_RT_DIRMAP_A;
6015 else
6016 table_ptr = M_RT_DIRMAP_B;
6017
6018 /* for a given rate, the LS-nibble of the PLCP SIGNAL field is
6019 * the index into the rate table.
6020 */
6021 phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
6022 index = phy_rate & 0xf;
6023
6024 /* Find the SHM pointer to the rate table entry by looking in the
6025 * Direct-map Table
6026 */
6027 return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2));
6028}
6029
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02006030static bool
Arend van Spriel5b435de2011-10-05 13:19:03 +02006031brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q,
6032 struct sk_buff *pkt, int prec, bool head)
6033{
6034 struct sk_buff *p;
6035 int eprec = -1; /* precedence to evict from */
6036
6037 /* Determine precedence from which to evict packet, if any */
6038 if (pktq_pfull(q, prec))
6039 eprec = prec;
6040 else if (pktq_full(q)) {
6041 p = brcmu_pktq_peek_tail(q, &eprec);
6042 if (eprec > prec) {
6043 wiphy_err(wlc->wiphy, "%s: Failing: eprec %d > prec %d"
6044 "\n", __func__, eprec, prec);
6045 return false;
6046 }
6047 }
6048
6049 /* Evict if needed */
6050 if (eprec >= 0) {
6051 bool discard_oldest;
6052
6053 discard_oldest = ac_bitmap_tst(0, eprec);
6054
6055 /* Refuse newer packet unless configured to discard oldest */
6056 if (eprec == prec && !discard_oldest) {
6057 wiphy_err(wlc->wiphy, "%s: No where to go, prec == %d"
6058 "\n", __func__, prec);
6059 return false;
6060 }
6061
6062 /* Evict packet according to discard policy */
6063 p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) :
6064 brcmu_pktq_pdeq_tail(q, eprec);
6065 brcmu_pkt_buf_free_skb(p);
6066 }
6067
6068 /* Enqueue */
6069 if (head)
6070 p = brcmu_pktq_penq_head(q, prec, pkt);
6071 else
6072 p = brcmu_pktq_penq(q, prec, pkt);
6073
6074 return true;
6075}
6076
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02006077/*
6078 * Attempts to queue a packet onto a multiple-precedence queue,
6079 * if necessary evicting a lower precedence packet from the queue.
6080 *
6081 * 'prec' is the precedence number that has already been mapped
6082 * from the packet priority.
6083 *
6084 * Returns true if packet consumed (queued), false if not.
6085 */
6086static bool brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q,
6087 struct sk_buff *pkt, int prec)
6088{
6089 return brcms_c_prec_enq_head(wlc, q, pkt, prec, false);
6090}
6091
Arend van Spriel5b435de2011-10-05 13:19:03 +02006092void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
6093 struct sk_buff *sdu, uint prec)
6094{
6095 struct brcms_txq_info *qi = wlc->pkt_queue; /* Check me */
6096 struct pktq *q = &qi->q;
6097 int prio;
6098
6099 prio = sdu->priority;
6100
6101 if (!brcms_c_prec_enq(wlc, q, sdu, prec)) {
6102 /*
6103 * we might hit this condtion in case
6104 * packet flooding from mac80211 stack
6105 */
6106 brcmu_pkt_buf_free_skb(sdu);
6107 }
6108}
6109
6110/*
6111 * bcmc_fid_generate:
6112 * Generate frame ID for a BCMC packet. The frag field is not used
6113 * for MC frames so is used as part of the sequence number.
6114 */
6115static inline u16
6116bcmc_fid_generate(struct brcms_c_info *wlc, struct brcms_bss_cfg *bsscfg,
6117 struct d11txh *txh)
6118{
6119 u16 frameid;
6120
6121 frameid = le16_to_cpu(txh->TxFrameID) & ~(TXFID_SEQ_MASK |
6122 TXFID_QUEUE_MASK);
6123 frameid |=
6124 (((wlc->
6125 mc_fid_counter++) << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
6126 TX_BCMC_FIFO;
6127
6128 return frameid;
6129}
6130
6131static uint
6132brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec,
6133 u8 preamble_type)
6134{
6135 uint dur = 0;
6136
6137 BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d\n",
6138 wlc->pub->unit, rspec, preamble_type);
6139 /*
6140 * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
6141 * is less than or equal to the rate of the immediately previous
6142 * frame in the FES
6143 */
6144 rspec = brcms_basic_rate(wlc, rspec);
6145 /* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */
6146 dur =
6147 brcms_c_calc_frame_time(wlc, rspec, preamble_type,
6148 (DOT11_ACK_LEN + FCS_LEN));
6149 return dur;
6150}
6151
6152static uint
6153brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec,
6154 u8 preamble_type)
6155{
6156 BCMMSG(wlc->wiphy, "wl%d: ratespec 0x%x, preamble_type %d\n",
6157 wlc->pub->unit, rspec, preamble_type);
6158 return brcms_c_calc_ack_time(wlc, rspec, preamble_type);
6159}
6160
6161static uint
6162brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec,
6163 u8 preamble_type)
6164{
6165 BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, "
6166 "preamble_type %d\n", wlc->pub->unit, rspec, preamble_type);
6167 /*
6168 * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
6169 * is less than or equal to the rate of the immediately previous
6170 * frame in the FES
6171 */
6172 rspec = brcms_basic_rate(wlc, rspec);
6173 /* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */
6174 return brcms_c_calc_frame_time(wlc, rspec, preamble_type,
6175 (DOT11_BA_LEN + DOT11_BA_BITMAP_LEN +
6176 FCS_LEN));
6177}
6178
6179/* brcms_c_compute_frame_dur()
6180 *
6181 * Calculate the 802.11 MAC header DUR field for MPDU
6182 * DUR for a single frame = 1 SIFS + 1 ACK
6183 * DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time
6184 *
6185 * rate MPDU rate in unit of 500kbps
6186 * next_frag_len next MPDU length in bytes
6187 * preamble_type use short/GF or long/MM PLCP header
6188 */
6189static u16
6190brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate,
6191 u8 preamble_type, uint next_frag_len)
6192{
6193 u16 dur, sifs;
6194
6195 sifs = get_sifs(wlc->band);
6196
6197 dur = sifs;
6198 dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type);
6199
6200 if (next_frag_len) {
6201 /* Double the current DUR to get 2 SIFS + 2 ACKs */
6202 dur *= 2;
6203 /* add another SIFS and the frag time */
6204 dur += sifs;
6205 dur +=
6206 (u16) brcms_c_calc_frame_time(wlc, rate, preamble_type,
6207 next_frag_len);
6208 }
6209 return dur;
6210}
6211
6212/* The opposite of brcms_c_calc_frame_time */
6213static uint
6214brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec,
6215 u8 preamble_type, uint dur)
6216{
6217 uint nsyms, mac_len, Ndps, kNdps;
6218 uint rate = rspec2rate(ratespec);
6219
6220 BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n",
6221 wlc->pub->unit, ratespec, preamble_type, dur);
6222
6223 if (is_mcs_rate(ratespec)) {
6224 uint mcs = ratespec & RSPEC_RATE_MASK;
6225 int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
6226 dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
6227 /* payload calculation matches that of regular ofdm */
6228 if (wlc->band->bandtype == BRCM_BAND_2G)
6229 dur -= DOT11_OFDM_SIGNAL_EXTENSION;
6230 /* kNdbps = kbps * 4 */
6231 kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
6232 rspec_issgi(ratespec)) * 4;
6233 nsyms = dur / APHY_SYMBOL_TIME;
6234 mac_len =
6235 ((nsyms * kNdps) -
6236 ((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000;
6237 } else if (is_ofdm_rate(ratespec)) {
6238 dur -= APHY_PREAMBLE_TIME;
6239 dur -= APHY_SIGNAL_TIME;
6240 /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
6241 Ndps = rate * 2;
6242 nsyms = dur / APHY_SYMBOL_TIME;
6243 mac_len =
6244 ((nsyms * Ndps) -
6245 (APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8;
6246 } else {
6247 if (preamble_type & BRCMS_SHORT_PREAMBLE)
6248 dur -= BPHY_PLCP_SHORT_TIME;
6249 else
6250 dur -= BPHY_PLCP_TIME;
6251 mac_len = dur * rate;
6252 /* divide out factor of 2 in rate (1/2 mbps) */
6253 mac_len = mac_len / 8 / 2;
6254 }
6255 return mac_len;
6256}
6257
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02006258/*
6259 * Return true if the specified rate is supported by the specified band.
6260 * BRCM_BAND_AUTO indicates the current band.
6261 */
6262static bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band,
6263 bool verbose)
6264{
6265 struct brcms_c_rateset *hw_rateset;
6266 uint i;
6267
6268 if ((band == BRCM_BAND_AUTO) || (band == wlc->band->bandtype))
6269 hw_rateset = &wlc->band->hw_rateset;
6270 else if (wlc->pub->_nbands > 1)
6271 hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset;
6272 else
6273 /* other band specified and we are a single band device */
6274 return false;
6275
6276 /* check if this is a mimo rate */
6277 if (is_mcs_rate(rspec)) {
6278 if ((rspec & RSPEC_RATE_MASK) >= MCS_TABLE_SIZE)
6279 goto error;
6280
6281 return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK));
6282 }
6283
6284 for (i = 0; i < hw_rateset->count; i++)
6285 if (hw_rateset->rates[i] == rspec2rate(rspec))
6286 return true;
6287 error:
6288 if (verbose)
6289 wiphy_err(wlc->wiphy, "wl%d: valid_rate: rate spec 0x%x "
6290 "not in hw_rateset\n", wlc->pub->unit, rspec);
6291
6292 return false;
6293}
6294
Arend van Spriel5b435de2011-10-05 13:19:03 +02006295static u32
6296mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
6297 u32 int_val)
6298{
6299 u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT;
6300 u8 rate = int_val & NRATE_RATE_MASK;
6301 u32 rspec;
6302 bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE);
6303 bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT);
6304 bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY)
6305 == NRATE_OVERRIDE_MCS_ONLY);
6306 int bcmerror = 0;
6307
6308 if (!ismcs)
6309 return (u32) rate;
6310
6311 /* validate the combination of rate/mcs/stf is allowed */
6312 if ((wlc->pub->_n_enab & SUPPORT_11N) && ismcs) {
6313 /* mcs only allowed when nmode */
6314 if (stf > PHY_TXC1_MODE_SDM) {
6315 wiphy_err(wlc->wiphy, "wl%d: %s: Invalid stf\n",
6316 wlc->pub->unit, __func__);
6317 bcmerror = -EINVAL;
6318 goto done;
6319 }
6320
6321 /* mcs 32 is a special case, DUP mode 40 only */
6322 if (rate == 32) {
6323 if (!CHSPEC_IS40(wlc->home_chanspec) ||
6324 ((stf != PHY_TXC1_MODE_SISO)
6325 && (stf != PHY_TXC1_MODE_CDD))) {
6326 wiphy_err(wlc->wiphy, "wl%d: %s: Invalid mcs "
6327 "32\n", wlc->pub->unit, __func__);
6328 bcmerror = -EINVAL;
6329 goto done;
6330 }
6331 /* mcs > 7 must use stf SDM */
6332 } else if (rate > HIGHEST_SINGLE_STREAM_MCS) {
6333 /* mcs > 7 must use stf SDM */
6334 if (stf != PHY_TXC1_MODE_SDM) {
6335 BCMMSG(wlc->wiphy, "wl%d: enabling "
6336 "SDM mode for mcs %d\n",
6337 wlc->pub->unit, rate);
6338 stf = PHY_TXC1_MODE_SDM;
6339 }
6340 } else {
6341 /*
6342 * MCS 0-7 may use SISO, CDD, and for
6343 * phy_rev >= 3 STBC
6344 */
6345 if ((stf > PHY_TXC1_MODE_STBC) ||
6346 (!BRCMS_STBC_CAP_PHY(wlc)
6347 && (stf == PHY_TXC1_MODE_STBC))) {
6348 wiphy_err(wlc->wiphy, "wl%d: %s: Invalid STBC"
6349 "\n", wlc->pub->unit, __func__);
6350 bcmerror = -EINVAL;
6351 goto done;
6352 }
6353 }
6354 } else if (is_ofdm_rate(rate)) {
6355 if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {
6356 wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n",
6357 wlc->pub->unit, __func__);
6358 bcmerror = -EINVAL;
6359 goto done;
6360 }
6361 } else if (is_cck_rate(rate)) {
6362 if ((cur_band->bandtype != BRCM_BAND_2G)
6363 || (stf != PHY_TXC1_MODE_SISO)) {
6364 wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n",
6365 wlc->pub->unit, __func__);
6366 bcmerror = -EINVAL;
6367 goto done;
6368 }
6369 } else {
6370 wiphy_err(wlc->wiphy, "wl%d: %s: Unknown rate type\n",
6371 wlc->pub->unit, __func__);
6372 bcmerror = -EINVAL;
6373 goto done;
6374 }
6375 /* make sure multiple antennae are available for non-siso rates */
6376 if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) {
6377 wiphy_err(wlc->wiphy, "wl%d: %s: SISO antenna but !SISO "
6378 "request\n", wlc->pub->unit, __func__);
6379 bcmerror = -EINVAL;
6380 goto done;
6381 }
6382
6383 rspec = rate;
6384 if (ismcs) {
6385 rspec |= RSPEC_MIMORATE;
6386 /* For STBC populate the STC field of the ratespec */
6387 if (stf == PHY_TXC1_MODE_STBC) {
6388 u8 stc;
6389 stc = 1; /* Nss for single stream is always 1 */
6390 rspec |= (stc << RSPEC_STC_SHIFT);
6391 }
6392 }
6393
6394 rspec |= (stf << RSPEC_STF_SHIFT);
6395
6396 if (override_mcs_only)
6397 rspec |= RSPEC_OVERRIDE_MCS_ONLY;
6398
6399 if (issgi)
6400 rspec |= RSPEC_SHORT_GI;
6401
6402 if ((rate != 0)
6403 && !brcms_c_valid_rate(wlc, rspec, cur_band->bandtype, true))
6404 return rate;
6405
6406 return rspec;
6407done:
6408 return rate;
6409}
6410
6411/*
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02006412 * Compute PLCP, but only requires actual rate and length of pkt.
6413 * Rate is given in the driver standard multiple of 500 kbps.
6414 * le is set for 11 Mbps rate if necessary.
6415 * Broken out for PRQ.
6416 */
6417
6418static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500,
6419 uint length, u8 *plcp)
6420{
6421 u16 usec = 0;
6422 u8 le = 0;
6423
6424 switch (rate_500) {
6425 case BRCM_RATE_1M:
6426 usec = length << 3;
6427 break;
6428 case BRCM_RATE_2M:
6429 usec = length << 2;
6430 break;
6431 case BRCM_RATE_5M5:
6432 usec = (length << 4) / 11;
6433 if ((length << 4) - (usec * 11) > 0)
6434 usec++;
6435 break;
6436 case BRCM_RATE_11M:
6437 usec = (length << 3) / 11;
6438 if ((length << 3) - (usec * 11) > 0) {
6439 usec++;
6440 if ((usec * 11) - (length << 3) >= 8)
6441 le = D11B_PLCP_SIGNAL_LE;
6442 }
6443 break;
6444
6445 default:
6446 wiphy_err(wlc->wiphy,
6447 "brcms_c_cck_plcp_set: unsupported rate %d\n",
6448 rate_500);
6449 rate_500 = BRCM_RATE_1M;
6450 usec = length << 3;
6451 break;
6452 }
6453 /* PLCP signal byte */
6454 plcp[0] = rate_500 * 5; /* r (500kbps) * 5 == r (100kbps) */
6455 /* PLCP service byte */
6456 plcp[1] = (u8) (le | D11B_PLCP_SIGNAL_LOCKED);
6457 /* PLCP length u16, little endian */
6458 plcp[2] = usec & 0xff;
6459 plcp[3] = (usec >> 8) & 0xff;
6460 /* PLCP CRC16 */
6461 plcp[4] = 0;
6462 plcp[5] = 0;
6463}
6464
6465/* Rate: 802.11 rate code, length: PSDU length in octets */
6466static void brcms_c_compute_mimo_plcp(u32 rspec, uint length, u8 *plcp)
6467{
6468 u8 mcs = (u8) (rspec & RSPEC_RATE_MASK);
6469 plcp[0] = mcs;
6470 if (rspec_is40mhz(rspec) || (mcs == 32))
6471 plcp[0] |= MIMO_PLCP_40MHZ;
6472 BRCMS_SET_MIMO_PLCP_LEN(plcp, length);
6473 plcp[3] = rspec_mimoplcp3(rspec); /* rspec already holds this byte */
6474 plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */
6475 plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */
6476 plcp[5] = 0;
6477}
6478
6479/* Rate: 802.11 rate code, length: PSDU length in octets */
6480static void
6481brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp)
6482{
6483 u8 rate_signal;
6484 u32 tmp = 0;
6485 int rate = rspec2rate(rspec);
6486
6487 /*
6488 * encode rate per 802.11a-1999 sec 17.3.4.1, with lsb
6489 * transmitted first
6490 */
6491 rate_signal = rate_info[rate] & BRCMS_RATE_MASK;
6492 memset(plcp, 0, D11_PHY_HDR_LEN);
6493 D11A_PHY_HDR_SRATE((struct ofdm_phy_hdr *) plcp, rate_signal);
6494
6495 tmp = (length & 0xfff) << 5;
6496 plcp[2] |= (tmp >> 16) & 0xff;
6497 plcp[1] |= (tmp >> 8) & 0xff;
6498 plcp[0] |= tmp & 0xff;
6499}
6500
6501/* Rate: 802.11 rate code, length: PSDU length in octets */
6502static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rspec,
6503 uint length, u8 *plcp)
6504{
6505 int rate = rspec2rate(rspec);
6506
6507 brcms_c_cck_plcp_set(wlc, rate, length, plcp);
6508}
6509
6510static void
6511brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec,
6512 uint length, u8 *plcp)
6513{
6514 if (is_mcs_rate(rspec))
6515 brcms_c_compute_mimo_plcp(rspec, length, plcp);
6516 else if (is_ofdm_rate(rspec))
6517 brcms_c_compute_ofdm_plcp(rspec, length, plcp);
6518 else
6519 brcms_c_compute_cck_plcp(wlc, rspec, length, plcp);
6520}
6521
6522/* brcms_c_compute_rtscts_dur()
6523 *
6524 * Calculate the 802.11 MAC header DUR field for an RTS or CTS frame
6525 * DUR for normal RTS/CTS w/ frame = 3 SIFS + 1 CTS + next frame time + 1 ACK
6526 * DUR for CTS-TO-SELF w/ frame = 2 SIFS + next frame time + 1 ACK
6527 *
6528 * cts cts-to-self or rts/cts
6529 * rts_rate rts or cts rate in unit of 500kbps
6530 * rate next MPDU rate in unit of 500kbps
6531 * frame_len next MPDU frame length in bytes
6532 */
6533u16
6534brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
6535 u32 rts_rate,
6536 u32 frame_rate, u8 rts_preamble_type,
6537 u8 frame_preamble_type, uint frame_len, bool ba)
6538{
6539 u16 dur, sifs;
6540
6541 sifs = get_sifs(wlc->band);
6542
6543 if (!cts_only) {
6544 /* RTS/CTS */
6545 dur = 3 * sifs;
6546 dur +=
6547 (u16) brcms_c_calc_cts_time(wlc, rts_rate,
6548 rts_preamble_type);
6549 } else {
6550 /* CTS-TO-SELF */
6551 dur = 2 * sifs;
6552 }
6553
6554 dur +=
6555 (u16) brcms_c_calc_frame_time(wlc, frame_rate, frame_preamble_type,
6556 frame_len);
6557 if (ba)
6558 dur +=
6559 (u16) brcms_c_calc_ba_time(wlc, frame_rate,
6560 BRCMS_SHORT_PREAMBLE);
6561 else
6562 dur +=
6563 (u16) brcms_c_calc_ack_time(wlc, frame_rate,
6564 frame_preamble_type);
6565 return dur;
6566}
6567
6568static u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
6569{
6570 u16 phyctl1 = 0;
6571 u16 bw;
6572
6573 if (BRCMS_ISLCNPHY(wlc->band)) {
6574 bw = PHY_TXC1_BW_20MHZ;
6575 } else {
6576 bw = rspec_get_bw(rspec);
6577 /* 10Mhz is not supported yet */
6578 if (bw < PHY_TXC1_BW_20MHZ) {
6579 wiphy_err(wlc->wiphy, "phytxctl1_calc: bw %d is "
6580 "not supported yet, set to 20L\n", bw);
6581 bw = PHY_TXC1_BW_20MHZ;
6582 }
6583 }
6584
6585 if (is_mcs_rate(rspec)) {
6586 uint mcs = rspec & RSPEC_RATE_MASK;
6587
6588 /* bw, stf, coding-type is part of rspec_phytxbyte2 returns */
6589 phyctl1 = rspec_phytxbyte2(rspec);
6590 /* set the upper byte of phyctl1 */
6591 phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8);
6592 } else if (is_cck_rate(rspec) && !BRCMS_ISLCNPHY(wlc->band)
6593 && !BRCMS_ISSSLPNPHY(wlc->band)) {
6594 /*
6595 * In CCK mode LPPHY overloads OFDM Modulation bits with CCK
6596 * Data Rate. Eventually MIMOPHY would also be converted to
6597 * this format
6598 */
6599 /* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */
6600 phyctl1 = (bw | (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));
6601 } else { /* legacy OFDM/CCK */
6602 s16 phycfg;
6603 /* get the phyctl byte from rate phycfg table */
6604 phycfg = brcms_c_rate_legacy_phyctl(rspec2rate(rspec));
6605 if (phycfg == -1) {
6606 wiphy_err(wlc->wiphy, "phytxctl1_calc: wrong "
6607 "legacy OFDM/CCK rate\n");
6608 phycfg = 0;
6609 }
6610 /* set the upper byte of phyctl1 */
6611 phyctl1 =
6612 (bw | (phycfg << 8) |
6613 (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));
6614 }
6615 return phyctl1;
6616}
6617
6618/*
Arend van Spriel5b435de2011-10-05 13:19:03 +02006619 * Add struct d11txh, struct cck_phy_hdr.
6620 *
6621 * 'p' data must start with 802.11 MAC header
6622 * 'p' must allow enough bytes of local headers to be "pushed" onto the packet
6623 *
6624 * headroom == D11_PHY_HDR_LEN + D11_TXH_LEN (D11_TXH_LEN is now 104 bytes)
6625 *
6626 */
6627static u16
6628brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
6629 struct sk_buff *p, struct scb *scb, uint frag,
6630 uint nfrags, uint queue, uint next_frag_len)
6631{
6632 struct ieee80211_hdr *h;
6633 struct d11txh *txh;
6634 u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN];
6635 int len, phylen, rts_phylen;
6636 u16 mch, phyctl, xfts, mainrates;
6637 u16 seq = 0, mcl = 0, status = 0, frameid = 0;
6638 u32 rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
6639 u32 rts_rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
6640 bool use_rts = false;
6641 bool use_cts = false;
6642 bool use_rifs = false;
6643 bool short_preamble[2] = { false, false };
6644 u8 preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };
6645 u8 rts_preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };
6646 u8 *rts_plcp, rts_plcp_fallback[D11_PHY_HDR_LEN];
6647 struct ieee80211_rts *rts = NULL;
6648 bool qos;
6649 uint ac;
6650 bool hwtkmic = false;
6651 u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
6652#define ANTCFG_NONE 0xFF
6653 u8 antcfg = ANTCFG_NONE;
6654 u8 fbantcfg = ANTCFG_NONE;
6655 uint phyctl1_stf = 0;
6656 u16 durid = 0;
6657 struct ieee80211_tx_rate *txrate[2];
6658 int k;
6659 struct ieee80211_tx_info *tx_info;
6660 bool is_mcs;
6661 u16 mimo_txbw;
6662 u8 mimo_preamble_type;
6663
6664 /* locate 802.11 MAC header */
6665 h = (struct ieee80211_hdr *)(p->data);
6666 qos = ieee80211_is_data_qos(h->frame_control);
6667
6668 /* compute length of frame in bytes for use in PLCP computations */
Arend van Sprielad4d71f2011-11-10 20:30:26 +01006669 len = p->len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006670 phylen = len + FCS_LEN;
6671
6672 /* Get tx_info */
6673 tx_info = IEEE80211_SKB_CB(p);
6674
6675 /* add PLCP */
6676 plcp = skb_push(p, D11_PHY_HDR_LEN);
6677
6678 /* add Broadcom tx descriptor header */
6679 txh = (struct d11txh *) skb_push(p, D11_TXH_LEN);
6680 memset(txh, 0, D11_TXH_LEN);
6681
6682 /* setup frameid */
6683 if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
6684 /* non-AP STA should never use BCMC queue */
6685 if (queue == TX_BCMC_FIFO) {
6686 wiphy_err(wlc->wiphy, "wl%d: %s: ASSERT queue == "
6687 "TX_BCMC!\n", wlc->pub->unit, __func__);
6688 frameid = bcmc_fid_generate(wlc, NULL, txh);
6689 } else {
6690 /* Increment the counter for first fragment */
6691 if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
6692 scb->seqnum[p->priority]++;
6693
6694 /* extract fragment number from frame first */
6695 seq = le16_to_cpu(h->seq_ctrl) & FRAGNUM_MASK;
6696 seq |= (scb->seqnum[p->priority] << SEQNUM_SHIFT);
6697 h->seq_ctrl = cpu_to_le16(seq);
6698
6699 frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
6700 (queue & TXFID_QUEUE_MASK);
6701 }
6702 }
6703 frameid |= queue & TXFID_QUEUE_MASK;
6704
6705 /* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */
6706 if (ieee80211_is_beacon(h->frame_control))
6707 mcl |= TXC_IGNOREPMQ;
6708
6709 txrate[0] = tx_info->control.rates;
6710 txrate[1] = txrate[0] + 1;
6711
6712 /*
6713 * if rate control algorithm didn't give us a fallback
6714 * rate, use the primary rate
6715 */
6716 if (txrate[1]->idx < 0)
6717 txrate[1] = txrate[0];
6718
6719 for (k = 0; k < hw->max_rates; k++) {
6720 is_mcs = txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false;
6721 if (!is_mcs) {
6722 if ((txrate[k]->idx >= 0)
6723 && (txrate[k]->idx <
6724 hw->wiphy->bands[tx_info->band]->n_bitrates)) {
6725 rspec[k] =
6726 hw->wiphy->bands[tx_info->band]->
6727 bitrates[txrate[k]->idx].hw_value;
6728 short_preamble[k] =
6729 txrate[k]->
6730 flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ?
6731 true : false;
6732 } else {
6733 rspec[k] = BRCM_RATE_1M;
6734 }
6735 } else {
6736 rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band,
6737 NRATE_MCS_INUSE | txrate[k]->idx);
6738 }
6739
6740 /*
6741 * Currently only support same setting for primay and
6742 * fallback rates. Unify flags for each rate into a
6743 * single value for the frame
6744 */
6745 use_rts |=
6746 txrate[k]->
6747 flags & IEEE80211_TX_RC_USE_RTS_CTS ? true : false;
6748 use_cts |=
6749 txrate[k]->
6750 flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? true : false;
6751
6752
6753 /*
6754 * (1) RATE:
6755 * determine and validate primary rate
6756 * and fallback rates
6757 */
6758 if (!rspec_active(rspec[k])) {
6759 rspec[k] = BRCM_RATE_1M;
6760 } else {
6761 if (!is_multicast_ether_addr(h->addr1)) {
6762 /* set tx antenna config */
6763 brcms_c_antsel_antcfg_get(wlc->asi, false,
6764 false, 0, 0, &antcfg, &fbantcfg);
6765 }
6766 }
6767 }
6768
6769 phyctl1_stf = wlc->stf->ss_opmode;
6770
6771 if (wlc->pub->_n_enab & SUPPORT_11N) {
6772 for (k = 0; k < hw->max_rates; k++) {
6773 /*
6774 * apply siso/cdd to single stream mcs's or ofdm
6775 * if rspec is auto selected
6776 */
6777 if (((is_mcs_rate(rspec[k]) &&
6778 is_single_stream(rspec[k] & RSPEC_RATE_MASK)) ||
6779 is_ofdm_rate(rspec[k]))
6780 && ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY)
6781 || !(rspec[k] & RSPEC_OVERRIDE))) {
6782 rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK);
6783
6784 /* For SISO MCS use STBC if possible */
6785 if (is_mcs_rate(rspec[k])
6786 && BRCMS_STF_SS_STBC_TX(wlc, scb)) {
6787 u8 stc;
6788
6789 /* Nss for single stream is always 1 */
6790 stc = 1;
6791 rspec[k] |= (PHY_TXC1_MODE_STBC <<
6792 RSPEC_STF_SHIFT) |
6793 (stc << RSPEC_STC_SHIFT);
6794 } else
6795 rspec[k] |=
6796 (phyctl1_stf << RSPEC_STF_SHIFT);
6797 }
6798
6799 /*
6800 * Is the phy configured to use 40MHZ frames? If
6801 * so then pick the desired txbw
6802 */
6803 if (brcms_chspec_bw(wlc->chanspec) == BRCMS_40_MHZ) {
6804 /* default txbw is 20in40 SB */
6805 mimo_ctlchbw = mimo_txbw =
6806 CHSPEC_SB_UPPER(wlc_phy_chanspec_get(
6807 wlc->band->pi))
6808 ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
6809
6810 if (is_mcs_rate(rspec[k])) {
6811 /* mcs 32 must be 40b/w DUP */
6812 if ((rspec[k] & RSPEC_RATE_MASK)
6813 == 32) {
6814 mimo_txbw =
6815 PHY_TXC1_BW_40MHZ_DUP;
6816 /* use override */
6817 } else if (wlc->mimo_40txbw != AUTO)
6818 mimo_txbw = wlc->mimo_40txbw;
6819 /* else check if dst is using 40 Mhz */
6820 else if (scb->flags & SCB_IS40)
6821 mimo_txbw = PHY_TXC1_BW_40MHZ;
6822 } else if (is_ofdm_rate(rspec[k])) {
6823 if (wlc->ofdm_40txbw != AUTO)
6824 mimo_txbw = wlc->ofdm_40txbw;
6825 } else if (wlc->cck_40txbw != AUTO) {
6826 mimo_txbw = wlc->cck_40txbw;
6827 }
6828 } else {
6829 /*
6830 * mcs32 is 40 b/w only.
6831 * This is possible for probe packets on
6832 * a STA during SCAN
6833 */
6834 if ((rspec[k] & RSPEC_RATE_MASK) == 32)
6835 /* mcs 0 */
6836 rspec[k] = RSPEC_MIMORATE;
6837
6838 mimo_txbw = PHY_TXC1_BW_20MHZ;
6839 }
6840
6841 /* Set channel width */
6842 rspec[k] &= ~RSPEC_BW_MASK;
6843 if ((k == 0) || ((k > 0) && is_mcs_rate(rspec[k])))
6844 rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT);
6845 else
6846 rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
6847
6848 /* Disable short GI, not supported yet */
6849 rspec[k] &= ~RSPEC_SHORT_GI;
6850
6851 mimo_preamble_type = BRCMS_MM_PREAMBLE;
6852 if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD)
6853 mimo_preamble_type = BRCMS_GF_PREAMBLE;
6854
6855 if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
6856 && (!is_mcs_rate(rspec[k]))) {
6857 wiphy_err(wlc->wiphy, "wl%d: %s: IEEE80211_TX_"
6858 "RC_MCS != is_mcs_rate(rspec)\n",
6859 wlc->pub->unit, __func__);
6860 }
6861
6862 if (is_mcs_rate(rspec[k])) {
6863 preamble_type[k] = mimo_preamble_type;
6864
6865 /*
6866 * if SGI is selected, then forced mm
6867 * for single stream
6868 */
6869 if ((rspec[k] & RSPEC_SHORT_GI)
6870 && is_single_stream(rspec[k] &
6871 RSPEC_RATE_MASK))
6872 preamble_type[k] = BRCMS_MM_PREAMBLE;
6873 }
6874
6875 /* should be better conditionalized */
6876 if (!is_mcs_rate(rspec[0])
6877 && (tx_info->control.rates[0].
6878 flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE))
6879 preamble_type[k] = BRCMS_SHORT_PREAMBLE;
6880 }
6881 } else {
6882 for (k = 0; k < hw->max_rates; k++) {
6883 /* Set ctrlchbw as 20Mhz */
6884 rspec[k] &= ~RSPEC_BW_MASK;
6885 rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT);
6886
6887 /* for nphy, stf of ofdm frames must follow policies */
6888 if (BRCMS_ISNPHY(wlc->band) && is_ofdm_rate(rspec[k])) {
6889 rspec[k] &= ~RSPEC_STF_MASK;
6890 rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT;
6891 }
6892 }
6893 }
6894
6895 /* Reset these for use with AMPDU's */
6896 txrate[0]->count = 0;
6897 txrate[1]->count = 0;
6898
6899 /* (2) PROTECTION, may change rspec */
6900 if ((ieee80211_is_data(h->frame_control) ||
6901 ieee80211_is_mgmt(h->frame_control)) &&
6902 (phylen > wlc->RTSThresh) && !is_multicast_ether_addr(h->addr1))
6903 use_rts = true;
6904
6905 /* (3) PLCP: determine PLCP header and MAC duration,
6906 * fill struct d11txh */
6907 brcms_c_compute_plcp(wlc, rspec[0], phylen, plcp);
6908 brcms_c_compute_plcp(wlc, rspec[1], phylen, plcp_fallback);
6909 memcpy(&txh->FragPLCPFallback,
6910 plcp_fallback, sizeof(txh->FragPLCPFallback));
6911
6912 /* Length field now put in CCK FBR CRC field */
6913 if (is_cck_rate(rspec[1])) {
6914 txh->FragPLCPFallback[4] = phylen & 0xff;
6915 txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8;
6916 }
6917
6918 /* MIMO-RATE: need validation ?? */
6919 mainrates = is_ofdm_rate(rspec[0]) ?
6920 D11A_PHY_HDR_GRATE((struct ofdm_phy_hdr *) plcp) :
6921 plcp[0];
6922
6923 /* DUR field for main rate */
6924 if (!ieee80211_is_pspoll(h->frame_control) &&
6925 !is_multicast_ether_addr(h->addr1) && !use_rifs) {
6926 durid =
6927 brcms_c_compute_frame_dur(wlc, rspec[0], preamble_type[0],
6928 next_frag_len);
6929 h->duration_id = cpu_to_le16(durid);
6930 } else if (use_rifs) {
6931 /* NAV protect to end of next max packet size */
6932 durid =
6933 (u16) brcms_c_calc_frame_time(wlc, rspec[0],
6934 preamble_type[0],
6935 DOT11_MAX_FRAG_LEN);
6936 durid += RIFS_11N_TIME;
6937 h->duration_id = cpu_to_le16(durid);
6938 }
6939
6940 /* DUR field for fallback rate */
6941 if (ieee80211_is_pspoll(h->frame_control))
6942 txh->FragDurFallback = h->duration_id;
6943 else if (is_multicast_ether_addr(h->addr1) || use_rifs)
6944 txh->FragDurFallback = 0;
6945 else {
6946 durid = brcms_c_compute_frame_dur(wlc, rspec[1],
6947 preamble_type[1], next_frag_len);
6948 txh->FragDurFallback = cpu_to_le16(durid);
6949 }
6950
6951 /* (4) MAC-HDR: MacTxControlLow */
6952 if (frag == 0)
6953 mcl |= TXC_STARTMSDU;
6954
6955 if (!is_multicast_ether_addr(h->addr1))
6956 mcl |= TXC_IMMEDACK;
6957
6958 if (wlc->band->bandtype == BRCM_BAND_5G)
6959 mcl |= TXC_FREQBAND_5G;
6960
6961 if (CHSPEC_IS40(wlc_phy_chanspec_get(wlc->band->pi)))
6962 mcl |= TXC_BW_40;
6963
6964 /* set AMIC bit if using hardware TKIP MIC */
6965 if (hwtkmic)
6966 mcl |= TXC_AMIC;
6967
6968 txh->MacTxControlLow = cpu_to_le16(mcl);
6969
6970 /* MacTxControlHigh */
6971 mch = 0;
6972
6973 /* Set fallback rate preamble type */
6974 if ((preamble_type[1] == BRCMS_SHORT_PREAMBLE) ||
6975 (preamble_type[1] == BRCMS_GF_PREAMBLE)) {
6976 if (rspec2rate(rspec[1]) != BRCM_RATE_1M)
6977 mch |= TXC_PREAMBLE_DATA_FB_SHORT;
6978 }
6979
6980 /* MacFrameControl */
6981 memcpy(&txh->MacFrameControl, &h->frame_control, sizeof(u16));
6982 txh->TxFesTimeNormal = cpu_to_le16(0);
6983
6984 txh->TxFesTimeFallback = cpu_to_le16(0);
6985
6986 /* TxFrameRA */
6987 memcpy(&txh->TxFrameRA, &h->addr1, ETH_ALEN);
6988
6989 /* TxFrameID */
6990 txh->TxFrameID = cpu_to_le16(frameid);
6991
6992 /*
6993 * TxStatus, Note the case of recreating the first frag of a suppressed
6994 * frame then we may need to reset the retry cnt's via the status reg
6995 */
6996 txh->TxStatus = cpu_to_le16(status);
6997
6998 /*
6999 * extra fields for ucode AMPDU aggregation, the new fields are added to
7000 * the END of previous structure so that it's compatible in driver.
7001 */
7002 txh->MaxNMpdus = cpu_to_le16(0);
7003 txh->MaxABytes_MRT = cpu_to_le16(0);
7004 txh->MaxABytes_FBR = cpu_to_le16(0);
7005 txh->MinMBytes = cpu_to_le16(0);
7006
7007 /* (5) RTS/CTS: determine RTS/CTS PLCP header and MAC duration,
7008 * furnish struct d11txh */
7009 /* RTS PLCP header and RTS frame */
7010 if (use_rts || use_cts) {
7011 if (use_rts && use_cts)
7012 use_cts = false;
7013
7014 for (k = 0; k < 2; k++) {
7015 rts_rspec[k] = brcms_c_rspec_to_rts_rspec(wlc, rspec[k],
7016 false,
7017 mimo_ctlchbw);
7018 }
7019
7020 if (!is_ofdm_rate(rts_rspec[0]) &&
7021 !((rspec2rate(rts_rspec[0]) == BRCM_RATE_1M) ||
7022 (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
7023 rts_preamble_type[0] = BRCMS_SHORT_PREAMBLE;
7024 mch |= TXC_PREAMBLE_RTS_MAIN_SHORT;
7025 }
7026
7027 if (!is_ofdm_rate(rts_rspec[1]) &&
7028 !((rspec2rate(rts_rspec[1]) == BRCM_RATE_1M) ||
7029 (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
7030 rts_preamble_type[1] = BRCMS_SHORT_PREAMBLE;
7031 mch |= TXC_PREAMBLE_RTS_FB_SHORT;
7032 }
7033
7034 /* RTS/CTS additions to MacTxControlLow */
7035 if (use_cts) {
7036 txh->MacTxControlLow |= cpu_to_le16(TXC_SENDCTS);
7037 } else {
7038 txh->MacTxControlLow |= cpu_to_le16(TXC_SENDRTS);
7039 txh->MacTxControlLow |= cpu_to_le16(TXC_LONGFRAME);
7040 }
7041
7042 /* RTS PLCP header */
7043 rts_plcp = txh->RTSPhyHeader;
7044 if (use_cts)
7045 rts_phylen = DOT11_CTS_LEN + FCS_LEN;
7046 else
7047 rts_phylen = DOT11_RTS_LEN + FCS_LEN;
7048
7049 brcms_c_compute_plcp(wlc, rts_rspec[0], rts_phylen, rts_plcp);
7050
7051 /* fallback rate version of RTS PLCP header */
7052 brcms_c_compute_plcp(wlc, rts_rspec[1], rts_phylen,
7053 rts_plcp_fallback);
7054 memcpy(&txh->RTSPLCPFallback, rts_plcp_fallback,
7055 sizeof(txh->RTSPLCPFallback));
7056
7057 /* RTS frame fields... */
7058 rts = (struct ieee80211_rts *)&txh->rts_frame;
7059
7060 durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec[0],
7061 rspec[0], rts_preamble_type[0],
7062 preamble_type[0], phylen, false);
7063 rts->duration = cpu_to_le16(durid);
7064 /* fallback rate version of RTS DUR field */
7065 durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
7066 rts_rspec[1], rspec[1],
7067 rts_preamble_type[1],
7068 preamble_type[1], phylen, false);
7069 txh->RTSDurFallback = cpu_to_le16(durid);
7070
7071 if (use_cts) {
7072 rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
7073 IEEE80211_STYPE_CTS);
7074
7075 memcpy(&rts->ra, &h->addr2, ETH_ALEN);
7076 } else {
7077 rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
7078 IEEE80211_STYPE_RTS);
7079
7080 memcpy(&rts->ra, &h->addr1, 2 * ETH_ALEN);
7081 }
7082
7083 /* mainrate
7084 * low 8 bits: main frag rate/mcs,
7085 * high 8 bits: rts/cts rate/mcs
7086 */
7087 mainrates |= (is_ofdm_rate(rts_rspec[0]) ?
7088 D11A_PHY_HDR_GRATE(
7089 (struct ofdm_phy_hdr *) rts_plcp) :
7090 rts_plcp[0]) << 8;
7091 } else {
7092 memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);
7093 memset((char *)&txh->rts_frame, 0,
7094 sizeof(struct ieee80211_rts));
7095 memset((char *)txh->RTSPLCPFallback, 0,
7096 sizeof(txh->RTSPLCPFallback));
7097 txh->RTSDurFallback = 0;
7098 }
7099
7100#ifdef SUPPORT_40MHZ
7101 /* add null delimiter count */
7102 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && is_mcs_rate(rspec))
7103 txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] =
7104 brcm_c_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen);
7105
7106#endif
7107
7108 /*
7109 * Now that RTS/RTS FB preamble types are updated, write
7110 * the final value
7111 */
7112 txh->MacTxControlHigh = cpu_to_le16(mch);
7113
7114 /*
7115 * MainRates (both the rts and frag plcp rates have
7116 * been calculated now)
7117 */
7118 txh->MainRates = cpu_to_le16(mainrates);
7119
7120 /* XtraFrameTypes */
7121 xfts = frametype(rspec[1], wlc->mimoft);
7122 xfts |= (frametype(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);
7123 xfts |= (frametype(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);
7124 xfts |= CHSPEC_CHANNEL(wlc_phy_chanspec_get(wlc->band->pi)) <<
7125 XFTS_CHANNEL_SHIFT;
7126 txh->XtraFrameTypes = cpu_to_le16(xfts);
7127
7128 /* PhyTxControlWord */
7129 phyctl = frametype(rspec[0], wlc->mimoft);
7130 if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) ||
7131 (preamble_type[0] == BRCMS_GF_PREAMBLE)) {
7132 if (rspec2rate(rspec[0]) != BRCM_RATE_1M)
7133 phyctl |= PHY_TXC_SHORT_HDR;
7134 }
7135
7136 /* phytxant is properly bit shifted */
7137 phyctl |= brcms_c_stf_d11hdrs_phyctl_txant(wlc, rspec[0]);
7138 txh->PhyTxControlWord = cpu_to_le16(phyctl);
7139
7140 /* PhyTxControlWord_1 */
7141 if (BRCMS_PHY_11N_CAP(wlc->band)) {
7142 u16 phyctl1 = 0;
7143
7144 phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[0]);
7145 txh->PhyTxControlWord_1 = cpu_to_le16(phyctl1);
7146 phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[1]);
7147 txh->PhyTxControlWord_1_Fbr = cpu_to_le16(phyctl1);
7148
7149 if (use_rts || use_cts) {
7150 phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[0]);
7151 txh->PhyTxControlWord_1_Rts = cpu_to_le16(phyctl1);
7152 phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[1]);
7153 txh->PhyTxControlWord_1_FbrRts = cpu_to_le16(phyctl1);
7154 }
7155
7156 /*
7157 * For mcs frames, if mixedmode(overloaded with long preamble)
7158 * is going to be set, fill in non-zero MModeLen and/or
7159 * MModeFbrLen it will be unnecessary if they are separated
7160 */
7161 if (is_mcs_rate(rspec[0]) &&
7162 (preamble_type[0] == BRCMS_MM_PREAMBLE)) {
7163 u16 mmodelen =
7164 brcms_c_calc_lsig_len(wlc, rspec[0], phylen);
7165 txh->MModeLen = cpu_to_le16(mmodelen);
7166 }
7167
7168 if (is_mcs_rate(rspec[1]) &&
7169 (preamble_type[1] == BRCMS_MM_PREAMBLE)) {
7170 u16 mmodefbrlen =
7171 brcms_c_calc_lsig_len(wlc, rspec[1], phylen);
7172 txh->MModeFbrLen = cpu_to_le16(mmodefbrlen);
7173 }
7174 }
7175
7176 ac = skb_get_queue_mapping(p);
7177 if ((scb->flags & SCB_WMECAP) && qos && wlc->edcf_txop[ac]) {
7178 uint frag_dur, dur, dur_fallback;
7179
7180 /* WME: Update TXOP threshold */
7181 if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) && frag == 0) {
7182 frag_dur =
7183 brcms_c_calc_frame_time(wlc, rspec[0],
7184 preamble_type[0], phylen);
7185
7186 if (rts) {
7187 /* 1 RTS or CTS-to-self frame */
7188 dur =
7189 brcms_c_calc_cts_time(wlc, rts_rspec[0],
7190 rts_preamble_type[0]);
7191 dur_fallback =
7192 brcms_c_calc_cts_time(wlc, rts_rspec[1],
7193 rts_preamble_type[1]);
7194 /* (SIFS + CTS) + SIFS + frame + SIFS + ACK */
7195 dur += le16_to_cpu(rts->duration);
7196 dur_fallback +=
7197 le16_to_cpu(txh->RTSDurFallback);
7198 } else if (use_rifs) {
7199 dur = frag_dur;
7200 dur_fallback = 0;
7201 } else {
7202 /* frame + SIFS + ACK */
7203 dur = frag_dur;
7204 dur +=
7205 brcms_c_compute_frame_dur(wlc, rspec[0],
7206 preamble_type[0], 0);
7207
7208 dur_fallback =
7209 brcms_c_calc_frame_time(wlc, rspec[1],
7210 preamble_type[1],
7211 phylen);
7212 dur_fallback +=
7213 brcms_c_compute_frame_dur(wlc, rspec[1],
7214 preamble_type[1], 0);
7215 }
7216 /* NEED to set TxFesTimeNormal (hard) */
7217 txh->TxFesTimeNormal = cpu_to_le16((u16) dur);
7218 /*
7219 * NEED to set fallback rate version of
7220 * TxFesTimeNormal (hard)
7221 */
7222 txh->TxFesTimeFallback =
7223 cpu_to_le16((u16) dur_fallback);
7224
7225 /*
7226 * update txop byte threshold (txop minus intraframe
7227 * overhead)
7228 */
7229 if (wlc->edcf_txop[ac] >= (dur - frag_dur)) {
7230 uint newfragthresh;
7231
7232 newfragthresh =
7233 brcms_c_calc_frame_len(wlc,
7234 rspec[0], preamble_type[0],
7235 (wlc->edcf_txop[ac] -
7236 (dur - frag_dur)));
7237 /* range bound the fragthreshold */
7238 if (newfragthresh < DOT11_MIN_FRAG_LEN)
7239 newfragthresh =
7240 DOT11_MIN_FRAG_LEN;
7241 else if (newfragthresh >
7242 wlc->usr_fragthresh)
7243 newfragthresh =
7244 wlc->usr_fragthresh;
7245 /* update the fragthresh and do txc update */
7246 if (wlc->fragthresh[queue] !=
7247 (u16) newfragthresh)
7248 wlc->fragthresh[queue] =
7249 (u16) newfragthresh;
7250 } else {
7251 wiphy_err(wlc->wiphy, "wl%d: %s txop invalid "
7252 "for rate %d\n",
7253 wlc->pub->unit, fifo_names[queue],
7254 rspec2rate(rspec[0]));
7255 }
7256
7257 if (dur > wlc->edcf_txop[ac])
7258 wiphy_err(wlc->wiphy, "wl%d: %s: %s txop "
7259 "exceeded phylen %d/%d dur %d/%d\n",
7260 wlc->pub->unit, __func__,
7261 fifo_names[queue],
7262 phylen, wlc->fragthresh[queue],
7263 dur, wlc->edcf_txop[ac]);
7264 }
7265 }
7266
7267 return 0;
7268}
7269
7270void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu,
7271 struct ieee80211_hw *hw)
7272{
7273 u8 prio;
7274 uint fifo;
7275 struct scb *scb = &wlc->pri_scb;
7276 struct ieee80211_hdr *d11_header = (struct ieee80211_hdr *)(sdu->data);
7277
7278 /*
7279 * 802.11 standard requires management traffic
7280 * to go at highest priority
7281 */
7282 prio = ieee80211_is_data(d11_header->frame_control) ? sdu->priority :
7283 MAXPRIO;
7284 fifo = prio2fifo[prio];
7285 if (brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0))
7286 return;
7287 brcms_c_txq_enq(wlc, scb, sdu, BRCMS_PRIO_TO_PREC(prio));
7288 brcms_c_send_q(wlc);
7289}
7290
7291void brcms_c_send_q(struct brcms_c_info *wlc)
7292{
7293 struct sk_buff *pkt[DOT11_MAXNUMFRAGS];
7294 int prec;
7295 u16 prec_map;
7296 int err = 0, i, count;
7297 uint fifo;
7298 struct brcms_txq_info *qi = wlc->pkt_queue;
7299 struct pktq *q = &qi->q;
7300 struct ieee80211_tx_info *tx_info;
7301
7302 prec_map = wlc->tx_prec_map;
7303
7304 /* Send all the enq'd pkts that we can.
7305 * Dequeue packets with precedence with empty HW fifo only
7306 */
7307 while (prec_map && (pkt[0] = brcmu_pktq_mdeq(q, prec_map, &prec))) {
7308 tx_info = IEEE80211_SKB_CB(pkt[0]);
7309 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
7310 err = brcms_c_sendampdu(wlc->ampdu, qi, pkt, prec);
7311 } else {
7312 count = 1;
7313 err = brcms_c_prep_pdu(wlc, pkt[0], &fifo);
7314 if (!err) {
7315 for (i = 0; i < count; i++)
7316 brcms_c_txfifo(wlc, fifo, pkt[i], true,
7317 1);
7318 }
7319 }
7320
7321 if (err == -EBUSY) {
7322 brcmu_pktq_penq_head(q, prec, pkt[0]);
7323 /*
7324 * If send failed due to any other reason than a
7325 * change in HW FIFO condition, quit. Otherwise,
7326 * read the new prec_map!
7327 */
7328 if (prec_map == wlc->tx_prec_map)
7329 break;
7330 prec_map = wlc->tx_prec_map;
7331 }
7332 }
7333}
7334
7335void
7336brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
7337 bool commit, s8 txpktpend)
7338{
7339 u16 frameid = INVALIDFID;
7340 struct d11txh *txh;
7341
7342 txh = (struct d11txh *) (p->data);
7343
7344 /* When a BC/MC frame is being committed to the BCMC fifo
7345 * via DMA (NOT PIO), update ucode or BSS info as appropriate.
7346 */
7347 if (fifo == TX_BCMC_FIFO)
7348 frameid = le16_to_cpu(txh->TxFrameID);
7349
7350 /*
7351 * Bump up pending count for if not using rpc. If rpc is
7352 * used, this will be handled in brcms_b_txfifo()
7353 */
7354 if (commit) {
7355 wlc->core->txpktpend[fifo] += txpktpend;
7356 BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n",
7357 txpktpend, wlc->core->txpktpend[fifo]);
7358 }
7359
7360 /* Commit BCMC sequence number in the SHM frame ID location */
7361 if (frameid != INVALIDFID) {
7362 /*
7363 * To inform the ucode of the last mcast frame posted
7364 * so that it can clear moredata bit
7365 */
7366 brcms_b_write_shm(wlc->hw, M_BCMC_FID, frameid);
7367 }
7368
7369 if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0)
7370 wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n");
7371}
7372
Arend van Spriel5b435de2011-10-05 13:19:03 +02007373u32
7374brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
7375 bool use_rspec, u16 mimo_ctlchbw)
7376{
7377 u32 rts_rspec = 0;
7378
7379 if (use_rspec)
7380 /* use frame rate as rts rate */
7381 rts_rspec = rspec;
7382 else if (wlc->band->gmode && wlc->protection->_g && !is_cck_rate(rspec))
7383 /* Use 11Mbps as the g protection RTS target rate and fallback.
7384 * Use the brcms_basic_rate() lookup to find the best basic rate
7385 * under the target in case 11 Mbps is not Basic.
7386 * 6 and 9 Mbps are not usually selected by rate selection, but
7387 * even if the OFDM rate we are protecting is 6 or 9 Mbps, 11
7388 * is more robust.
7389 */
7390 rts_rspec = brcms_basic_rate(wlc, BRCM_RATE_11M);
7391 else
7392 /* calculate RTS rate and fallback rate based on the frame rate
7393 * RTS must be sent at a basic rate since it is a
7394 * control frame, sec 9.6 of 802.11 spec
7395 */
7396 rts_rspec = brcms_basic_rate(wlc, rspec);
7397
7398 if (BRCMS_PHY_11N_CAP(wlc->band)) {
7399 /* set rts txbw to correct side band */
7400 rts_rspec &= ~RSPEC_BW_MASK;
7401
7402 /*
7403 * if rspec/rspec_fallback is 40MHz, then send RTS on both
7404 * 20MHz channel (DUP), otherwise send RTS on control channel
7405 */
7406 if (rspec_is40mhz(rspec) && !is_cck_rate(rts_rspec))
7407 rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT);
7408 else
7409 rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
7410
7411 /* pick siso/cdd as default for ofdm */
7412 if (is_ofdm_rate(rts_rspec)) {
7413 rts_rspec &= ~RSPEC_STF_MASK;
7414 rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
7415 }
7416 }
7417 return rts_rspec;
7418}
7419
Arend van Spriel5b435de2011-10-05 13:19:03 +02007420void
7421brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, s8 txpktpend)
7422{
7423 wlc->core->txpktpend[fifo] -= txpktpend;
7424 BCMMSG(wlc->wiphy, "pktpend dec %d to %d\n", txpktpend,
7425 wlc->core->txpktpend[fifo]);
7426
7427 /* There is more room; mark precedences related to this FIFO sendable */
7428 wlc->tx_prec_map |= wlc->fifo2prec_map[fifo];
7429
7430 /* figure out which bsscfg is being worked on... */
7431}
7432
7433/* Update beacon listen interval in shared memory */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02007434static void brcms_c_bcn_li_upd(struct brcms_c_info *wlc)
Arend van Spriel5b435de2011-10-05 13:19:03 +02007435{
7436 /* wake up every DTIM is the default */
7437 if (wlc->bcn_li_dtim == 1)
7438 brcms_b_write_shm(wlc->hw, M_BCN_LI, 0);
7439 else
7440 brcms_b_write_shm(wlc->hw, M_BCN_LI,
7441 (wlc->bcn_li_dtim << 8) | wlc->bcn_li_bcn);
7442}
7443
7444static void
7445brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr,
7446 u32 *tsf_h_ptr)
7447{
Arend van Spriel16d28122011-12-08 15:06:51 -08007448 struct bcma_device *core = wlc_hw->d11core;
Arend van Spriel5b435de2011-10-05 13:19:03 +02007449
7450 /* read the tsf timer low, then high to get an atomic read */
Arend van Spriel16d28122011-12-08 15:06:51 -08007451 *tsf_l_ptr = bcma_read32(core, D11REGOFFS(tsf_timerlow));
7452 *tsf_h_ptr = bcma_read32(core, D11REGOFFS(tsf_timerhigh));
Arend van Spriel5b435de2011-10-05 13:19:03 +02007453}
7454
7455/*
7456 * recover 64bit TSF value from the 16bit TSF value in the rx header
7457 * given the assumption that the TSF passed in header is within 65ms
7458 * of the current tsf.
7459 *
7460 * 6 5 4 4 3 2 1
7461 * 3.......6.......8.......0.......2.......4.......6.......8......0
7462 * |<---------- tsf_h ----------->||<--- tsf_l -->||<-RxTSFTime ->|
7463 *
7464 * The RxTSFTime are the lowest 16 bits and provided by the ucode. The
7465 * tsf_l is filled in by brcms_b_recv, which is done earlier in the
7466 * receive call sequence after rx interrupt. Only the higher 16 bits
7467 * are used. Finally, the tsf_h is read from the tsf register.
7468 */
7469static u64 brcms_c_recover_tsf64(struct brcms_c_info *wlc,
7470 struct d11rxhdr *rxh)
7471{
7472 u32 tsf_h, tsf_l;
7473 u16 rx_tsf_0_15, rx_tsf_16_31;
7474
7475 brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h);
7476
7477 rx_tsf_16_31 = (u16)(tsf_l >> 16);
7478 rx_tsf_0_15 = rxh->RxTSFTime;
7479
7480 /*
7481 * a greater tsf time indicates the low 16 bits of
7482 * tsf_l wrapped, so decrement the high 16 bits.
7483 */
7484 if ((u16)tsf_l < rx_tsf_0_15) {
7485 rx_tsf_16_31 -= 1;
7486 if (rx_tsf_16_31 == 0xffff)
7487 tsf_h -= 1;
7488 }
7489
7490 return ((u64)tsf_h << 32) | (((u32)rx_tsf_16_31 << 16) + rx_tsf_0_15);
7491}
7492
7493static void
7494prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
7495 struct sk_buff *p,
7496 struct ieee80211_rx_status *rx_status)
7497{
7498 int preamble;
7499 int channel;
7500 u32 rspec;
7501 unsigned char *plcp;
7502
7503 /* fill in TSF and flag its presence */
7504 rx_status->mactime = brcms_c_recover_tsf64(wlc, rxh);
7505 rx_status->flag |= RX_FLAG_MACTIME_MPDU;
7506
7507 channel = BRCMS_CHAN_CHANNEL(rxh->RxChan);
7508
7509 if (channel > 14) {
7510 rx_status->band = IEEE80211_BAND_5GHZ;
7511 rx_status->freq = ieee80211_ofdm_chan_to_freq(
7512 WF_CHAN_FACTOR_5_G/2, channel);
7513
7514 } else {
7515 rx_status->band = IEEE80211_BAND_2GHZ;
7516 rx_status->freq = ieee80211_dsss_chan_to_freq(channel);
7517 }
7518
7519 rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh);
7520
7521 /* noise */
7522 /* qual */
7523 rx_status->antenna =
7524 (rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0;
7525
7526 plcp = p->data;
7527
7528 rspec = brcms_c_compute_rspec(rxh, plcp);
7529 if (is_mcs_rate(rspec)) {
7530 rx_status->rate_idx = rspec & RSPEC_RATE_MASK;
7531 rx_status->flag |= RX_FLAG_HT;
7532 if (rspec_is40mhz(rspec))
7533 rx_status->flag |= RX_FLAG_40MHZ;
7534 } else {
7535 switch (rspec2rate(rspec)) {
7536 case BRCM_RATE_1M:
7537 rx_status->rate_idx = 0;
7538 break;
7539 case BRCM_RATE_2M:
7540 rx_status->rate_idx = 1;
7541 break;
7542 case BRCM_RATE_5M5:
7543 rx_status->rate_idx = 2;
7544 break;
7545 case BRCM_RATE_11M:
7546 rx_status->rate_idx = 3;
7547 break;
7548 case BRCM_RATE_6M:
7549 rx_status->rate_idx = 4;
7550 break;
7551 case BRCM_RATE_9M:
7552 rx_status->rate_idx = 5;
7553 break;
7554 case BRCM_RATE_12M:
7555 rx_status->rate_idx = 6;
7556 break;
7557 case BRCM_RATE_18M:
7558 rx_status->rate_idx = 7;
7559 break;
7560 case BRCM_RATE_24M:
7561 rx_status->rate_idx = 8;
7562 break;
7563 case BRCM_RATE_36M:
7564 rx_status->rate_idx = 9;
7565 break;
7566 case BRCM_RATE_48M:
7567 rx_status->rate_idx = 10;
7568 break;
7569 case BRCM_RATE_54M:
7570 rx_status->rate_idx = 11;
7571 break;
7572 default:
7573 wiphy_err(wlc->wiphy, "%s: Unknown rate\n", __func__);
7574 }
7575
7576 /*
7577 * For 5GHz, we should decrease the index as it is
7578 * a subset of the 2.4G rates. See bitrates field
7579 * of brcms_band_5GHz_nphy (in mac80211_if.c).
7580 */
7581 if (rx_status->band == IEEE80211_BAND_5GHZ)
7582 rx_status->rate_idx -= BRCMS_LEGACY_5G_RATE_OFFSET;
7583
7584 /* Determine short preamble and rate_idx */
7585 preamble = 0;
7586 if (is_cck_rate(rspec)) {
7587 if (rxh->PhyRxStatus_0 & PRXS0_SHORTH)
7588 rx_status->flag |= RX_FLAG_SHORTPRE;
7589 } else if (is_ofdm_rate(rspec)) {
7590 rx_status->flag |= RX_FLAG_SHORTPRE;
7591 } else {
7592 wiphy_err(wlc->wiphy, "%s: Unknown modulation\n",
7593 __func__);
7594 }
7595 }
7596
7597 if (plcp3_issgi(plcp[3]))
7598 rx_status->flag |= RX_FLAG_SHORT_GI;
7599
7600 if (rxh->RxStatus1 & RXS_DECERR) {
7601 rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC;
7602 wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_PLCP_CRC\n",
7603 __func__);
7604 }
7605 if (rxh->RxStatus1 & RXS_FCSERR) {
7606 rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
7607 wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_FCS_CRC\n",
7608 __func__);
7609 }
7610}
7611
7612static void
7613brcms_c_recvctl(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
7614 struct sk_buff *p)
7615{
7616 int len_mpdu;
7617 struct ieee80211_rx_status rx_status;
7618
7619 memset(&rx_status, 0, sizeof(rx_status));
7620 prep_mac80211_status(wlc, rxh, p, &rx_status);
7621
7622 /* mac header+body length, exclude CRC and plcp header */
7623 len_mpdu = p->len - D11_PHY_HDR_LEN - FCS_LEN;
7624 skb_pull(p, D11_PHY_HDR_LEN);
7625 __skb_trim(p, len_mpdu);
7626
7627 memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status));
7628 ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p);
7629}
7630
Arend van Spriel5b435de2011-10-05 13:19:03 +02007631/* calculate frame duration for Mixed-mode L-SIG spoofing, return
7632 * number of bytes goes in the length field
7633 *
7634 * Formula given by HT PHY Spec v 1.13
7635 * len = 3(nsyms + nstream + 3) - 3
7636 */
7637u16
7638brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
7639 uint mac_len)
7640{
7641 uint nsyms, len = 0, kNdps;
7642
7643 BCMMSG(wlc->wiphy, "wl%d: rate %d, len%d\n",
7644 wlc->pub->unit, rspec2rate(ratespec), mac_len);
7645
7646 if (is_mcs_rate(ratespec)) {
7647 uint mcs = ratespec & RSPEC_RATE_MASK;
7648 int tot_streams = (mcs_2_txstreams(mcs) + 1) +
7649 rspec_stc(ratespec);
7650
7651 /*
7652 * the payload duration calculation matches that
7653 * of regular ofdm
7654 */
7655 /* 1000Ndbps = kbps * 4 */
7656 kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
7657 rspec_issgi(ratespec)) * 4;
7658
7659 if (rspec_stc(ratespec) == 0)
7660 nsyms =
7661 CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
7662 APHY_TAIL_NBITS) * 1000, kNdps);
7663 else
7664 /* STBC needs to have even number of symbols */
7665 nsyms =
7666 2 *
7667 CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
7668 APHY_TAIL_NBITS) * 1000, 2 * kNdps);
7669
7670 /* (+3) account for HT-SIG(2) and HT-STF(1) */
7671 nsyms += (tot_streams + 3);
7672 /*
7673 * 3 bytes/symbol @ legacy 6Mbps rate
7674 * (-3) excluding service bits and tail bits
7675 */
7676 len = (3 * nsyms) - 3;
7677 }
7678
7679 return (u16) len;
7680}
7681
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02007682static void
7683brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
Arend van Spriel5b435de2011-10-05 13:19:03 +02007684{
7685 const struct brcms_c_rateset *rs_dflt;
7686 struct brcms_c_rateset rs;
7687 u8 rate;
7688 u16 entry_ptr;
7689 u8 plcp[D11_PHY_HDR_LEN];
7690 u16 dur, sifs;
7691 uint i;
7692
7693 sifs = get_sifs(wlc->band);
7694
7695 rs_dflt = brcms_c_rateset_get_hwrs(wlc);
7696
7697 brcms_c_rateset_copy(rs_dflt, &rs);
7698 brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
7699
7700 /*
7701 * walk the phy rate table and update MAC core SHM
7702 * basic rate table entries
7703 */
7704 for (i = 0; i < rs.count; i++) {
7705 rate = rs.rates[i] & BRCMS_RATE_MASK;
7706
7707 entry_ptr = brcms_b_rate_shm_offset(wlc->hw, rate);
7708
7709 /* Calculate the Probe Response PLCP for the given rate */
7710 brcms_c_compute_plcp(wlc, rate, frame_len, plcp);
7711
7712 /*
7713 * Calculate the duration of the Probe Response
7714 * frame plus SIFS for the MAC
7715 */
7716 dur = (u16) brcms_c_calc_frame_time(wlc, rate,
7717 BRCMS_LONG_PREAMBLE, frame_len);
7718 dur += sifs;
7719
7720 /* Update the SHM Rate Table entry Probe Response values */
7721 brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS,
7722 (u16) (plcp[0] + (plcp[1] << 8)));
7723 brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS + 2,
7724 (u16) (plcp[2] + (plcp[3] << 8)));
7725 brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_DUR_POS, dur);
7726 }
7727}
7728
7729/* Max buffering needed for beacon template/prb resp template is 142 bytes.
7730 *
7731 * PLCP header is 6 bytes.
7732 * 802.11 A3 header is 24 bytes.
7733 * Max beacon frame body template length is 112 bytes.
7734 * Max probe resp frame body template length is 110 bytes.
7735 *
7736 * *len on input contains the max length of the packet available.
7737 *
7738 * The *len value is set to the number of bytes in buf used, and starts
7739 * with the PLCP and included up to, but not including, the 4 byte FCS.
7740 */
7741static void
7742brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
7743 u32 bcn_rspec,
7744 struct brcms_bss_cfg *cfg, u16 *buf, int *len)
7745{
7746 static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
7747 struct cck_phy_hdr *plcp;
7748 struct ieee80211_mgmt *h;
7749 int hdr_len, body_len;
7750
7751 hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN;
7752
7753 /* calc buffer size provided for frame body */
7754 body_len = *len - hdr_len;
7755 /* return actual size */
7756 *len = hdr_len + body_len;
7757
7758 /* format PHY and MAC headers */
7759 memset((char *)buf, 0, hdr_len);
7760
7761 plcp = (struct cck_phy_hdr *) buf;
7762
7763 /*
7764 * PLCP for Probe Response frames are filled in from
7765 * core's rate table
7766 */
7767 if (type == IEEE80211_STYPE_BEACON)
7768 /* fill in PLCP */
7769 brcms_c_compute_plcp(wlc, bcn_rspec,
7770 (DOT11_MAC_HDR_LEN + body_len + FCS_LEN),
7771 (u8 *) plcp);
7772
7773 /* "Regular" and 16 MBSS but not for 4 MBSS */
7774 /* Update the phytxctl for the beacon based on the rspec */
7775 brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec);
7776
7777 h = (struct ieee80211_mgmt *)&plcp[1];
7778
7779 /* fill in 802.11 header */
7780 h->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | type);
7781
7782 /* DUR is 0 for multicast bcn, or filled in by MAC for prb resp */
7783 /* A1 filled in by MAC for prb resp, broadcast for bcn */
7784 if (type == IEEE80211_STYPE_BEACON)
7785 memcpy(&h->da, &ether_bcast, ETH_ALEN);
7786 memcpy(&h->sa, &cfg->cur_etheraddr, ETH_ALEN);
7787 memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN);
7788
7789 /* SEQ filled in by MAC */
7790}
7791
7792int brcms_c_get_header_len(void)
7793{
7794 return TXOFF;
7795}
7796
7797/*
7798 * Update all beacons for the system.
7799 */
7800void brcms_c_update_beacon(struct brcms_c_info *wlc)
7801{
7802 struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
7803
7804 if (bsscfg->up && !bsscfg->BSS)
7805 /* Clear the soft intmask */
7806 wlc->defmacintmask &= ~MI_BCNTPL;
7807}
7808
7809/* Write ssid into shared memory */
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02007810static void
7811brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02007812{
7813 u8 *ssidptr = cfg->SSID;
7814 u16 base = M_SSID;
7815 u8 ssidbuf[IEEE80211_MAX_SSID_LEN];
7816
7817 /* padding the ssid with zero and copy it into shm */
7818 memset(ssidbuf, 0, IEEE80211_MAX_SSID_LEN);
7819 memcpy(ssidbuf, ssidptr, cfg->SSID_len);
7820
7821 brcms_c_copyto_shm(wlc, base, ssidbuf, IEEE80211_MAX_SSID_LEN);
7822 brcms_b_write_shm(wlc->hw, M_SSIDLEN, (u16) cfg->SSID_len);
7823}
7824
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02007825static void
Arend van Spriel5b435de2011-10-05 13:19:03 +02007826brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
7827 struct brcms_bss_cfg *cfg,
7828 bool suspend)
7829{
7830 u16 prb_resp[BCN_TMPL_LEN / 2];
7831 int len = BCN_TMPL_LEN;
7832
7833 /*
7834 * write the probe response to hardware, or save in
7835 * the config structure
7836 */
7837
7838 /* create the probe response template */
7839 brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0,
7840 cfg, prb_resp, &len);
7841
7842 if (suspend)
7843 brcms_c_suspend_mac_and_wait(wlc);
7844
7845 /* write the probe response into the template region */
7846 brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE,
7847 (len + 3) & ~3, prb_resp);
7848
7849 /* write the length of the probe response frame (+PLCP/-FCS) */
7850 brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len);
7851
7852 /* write the SSID and SSID length */
7853 brcms_c_shm_ssid_upd(wlc, cfg);
7854
7855 /*
7856 * Write PLCP headers and durations for probe response frames
7857 * at all rates. Use the actual frame length covered by the
7858 * PLCP header for the call to brcms_c_mod_prb_rsp_rate_table()
7859 * by subtracting the PLCP len and adding the FCS.
7860 */
7861 len += (-D11_PHY_HDR_LEN + FCS_LEN);
7862 brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len);
7863
7864 if (suspend)
7865 brcms_c_enable_mac(wlc);
7866}
7867
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02007868void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
7869{
7870 struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
7871
7872 /* update AP or IBSS probe responses */
7873 if (bsscfg->up && !bsscfg->BSS)
7874 brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
7875}
7876
Arend van Spriel5b435de2011-10-05 13:19:03 +02007877/* prepares pdu for transmission. returns BCM error codes */
7878int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifop)
7879{
7880 uint fifo;
7881 struct d11txh *txh;
7882 struct ieee80211_hdr *h;
7883 struct scb *scb;
7884
7885 txh = (struct d11txh *) (pdu->data);
7886 h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
7887
7888 /* get the pkt queue info. This was put at brcms_c_sendctl or
7889 * brcms_c_send for PDU */
7890 fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
7891
7892 scb = NULL;
7893
7894 *fifop = fifo;
7895
7896 /* return if insufficient dma resources */
7897 if (*wlc->core->txavail[fifo] < MAX_DMA_SEGS) {
7898 /* Mark precedences related to this FIFO, unsendable */
7899 /* A fifo is full. Clear precedences related to that FIFO */
7900 wlc->tx_prec_map &= ~(wlc->fifo2prec_map[fifo]);
7901 return -EBUSY;
7902 }
7903 return 0;
7904}
7905
Arend van Spriel5b435de2011-10-05 13:19:03 +02007906int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
7907 uint *blocks)
7908{
7909 if (fifo >= NFIFO)
7910 return -EINVAL;
7911
7912 *blocks = wlc_hw->xmtfifo_sz[fifo];
7913
7914 return 0;
7915}
7916
7917void
7918brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset,
7919 const u8 *addr)
7920{
7921 brcms_b_set_addrmatch(wlc->hw, match_reg_offset, addr);
7922 if (match_reg_offset == RCM_BSSID_OFFSET)
7923 memcpy(wlc->bsscfg->BSSID, addr, ETH_ALEN);
7924}
7925
Arend van Spriel5b435de2011-10-05 13:19:03 +02007926/*
7927 * Flag 'scan in progress' to withhold dynamic phy calibration
7928 */
7929void brcms_c_scan_start(struct brcms_c_info *wlc)
7930{
7931 wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true);
7932}
7933
7934void brcms_c_scan_stop(struct brcms_c_info *wlc)
7935{
7936 wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false);
7937}
7938
7939void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state)
7940{
7941 wlc->pub->associated = state;
7942 wlc->bsscfg->associated = state;
7943}
7944
7945/*
7946 * When a remote STA/AP is removed by Mac80211, or when it can no longer accept
7947 * AMPDU traffic, packets pending in hardware have to be invalidated so that
7948 * when later on hardware releases them, they can be handled appropriately.
7949 */
7950void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
7951 struct ieee80211_sta *sta,
7952 void (*dma_callback_fn))
7953{
7954 struct dma_pub *dmah;
7955 int i;
7956 for (i = 0; i < NFIFO; i++) {
7957 dmah = hw->di[i];
7958 if (dmah != NULL)
7959 dma_walk_packets(dmah, dma_callback_fn, sta);
7960 }
7961}
7962
7963int brcms_c_get_curband(struct brcms_c_info *wlc)
7964{
7965 return wlc->band->bandunit;
7966}
7967
7968void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop)
7969{
7970 /* flush packet queue when requested */
7971 if (drop)
7972 brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL);
7973
7974 /* wait for queue and DMA fifos to run dry */
7975 while (!pktq_empty(&wlc->pkt_queue->q) || brcms_txpktpendtot(wlc) > 0)
7976 brcms_msleep(wlc->wl, 1);
7977}
7978
7979void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
7980{
7981 wlc->bcn_li_bcn = interval;
7982 if (wlc->pub->up)
7983 brcms_c_bcn_li_upd(wlc);
7984}
7985
7986int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr)
7987{
7988 uint qdbm;
7989
7990 /* Remove override bit and clip to max qdbm value */
7991 qdbm = min_t(uint, txpwr * BRCMS_TXPWR_DB_FACTOR, 0xff);
7992 return wlc_phy_txpower_set(wlc->band->pi, qdbm, false);
7993}
7994
7995int brcms_c_get_tx_power(struct brcms_c_info *wlc)
7996{
7997 uint qdbm;
7998 bool override;
7999
8000 wlc_phy_txpower_get(wlc->band->pi, &qdbm, &override);
8001
8002 /* Return qdbm units */
8003 return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR);
8004}
8005
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008006/* Process received frames */
8007/*
8008 * Return true if more frames need to be processed. false otherwise.
8009 * Param 'bound' indicates max. # frames to process before break out.
8010 */
8011static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
8012{
8013 struct d11rxhdr *rxh;
8014 struct ieee80211_hdr *h;
8015 uint len;
8016 bool is_amsdu;
8017
8018 BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
8019
8020 /* frame starts with rxhdr */
8021 rxh = (struct d11rxhdr *) (p->data);
8022
8023 /* strip off rxhdr */
8024 skb_pull(p, BRCMS_HWRXOFF);
8025
8026 /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
8027 if (rxh->RxStatus1 & RXS_PBPRES) {
8028 if (p->len < 2) {
8029 wiphy_err(wlc->wiphy, "wl%d: recv: rcvd runt of "
8030 "len %d\n", wlc->pub->unit, p->len);
8031 goto toss;
8032 }
8033 skb_pull(p, 2);
8034 }
8035
8036 h = (struct ieee80211_hdr *)(p->data + D11_PHY_HDR_LEN);
8037 len = p->len;
8038
8039 if (rxh->RxStatus1 & RXS_FCSERR) {
Alwin Beukersbe667662011-11-22 17:21:43 -08008040 if (!(wlc->filter_flags & FIF_FCSFAIL))
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008041 goto toss;
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008042 }
8043
8044 /* check received pkt has at least frame control field */
8045 if (len < D11_PHY_HDR_LEN + sizeof(h->frame_control))
8046 goto toss;
8047
8048 /* not supporting A-MSDU */
8049 is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK;
8050 if (is_amsdu)
8051 goto toss;
8052
8053 brcms_c_recvctl(wlc, rxh, p);
8054 return;
8055
8056 toss:
8057 brcmu_pkt_buf_free_skb(p);
8058}
8059
8060/* Process received frames */
8061/*
8062 * Return true if more frames need to be processed. false otherwise.
8063 * Param 'bound' indicates max. # frames to process before break out.
8064 */
8065static bool
8066brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
8067{
8068 struct sk_buff *p;
Arend van Spriel3fd172d2011-10-21 16:16:31 +02008069 struct sk_buff *next = NULL;
8070 struct sk_buff_head recv_frames;
8071
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008072 uint n = 0;
8073 uint bound_limit = bound ? RXBND : -1;
8074
8075 BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
Arend van Spriel3fd172d2011-10-21 16:16:31 +02008076 skb_queue_head_init(&recv_frames);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008077
Arend van Spriel3fd172d2011-10-21 16:16:31 +02008078 /* gather received frames */
8079 while (dma_rx(wlc_hw->di[fifo], &recv_frames)) {
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008080
8081 /* !give others some time to run! */
8082 if (++n >= bound_limit)
8083 break;
8084 }
8085
8086 /* post more rbufs */
8087 dma_rxfill(wlc_hw->di[fifo]);
8088
8089 /* process each frame */
Arend van Spriel3fd172d2011-10-21 16:16:31 +02008090 skb_queue_walk_safe(&recv_frames, p, next) {
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008091 struct d11rxhdr_le *rxh_le;
8092 struct d11rxhdr *rxh;
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008093
Arend van Spriel3fd172d2011-10-21 16:16:31 +02008094 skb_unlink(p, &recv_frames);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008095 rxh_le = (struct d11rxhdr_le *)p->data;
8096 rxh = (struct d11rxhdr *)p->data;
8097
8098 /* fixup rx header endianness */
8099 rxh->RxFrameSize = le16_to_cpu(rxh_le->RxFrameSize);
8100 rxh->PhyRxStatus_0 = le16_to_cpu(rxh_le->PhyRxStatus_0);
8101 rxh->PhyRxStatus_1 = le16_to_cpu(rxh_le->PhyRxStatus_1);
8102 rxh->PhyRxStatus_2 = le16_to_cpu(rxh_le->PhyRxStatus_2);
8103 rxh->PhyRxStatus_3 = le16_to_cpu(rxh_le->PhyRxStatus_3);
8104 rxh->PhyRxStatus_4 = le16_to_cpu(rxh_le->PhyRxStatus_4);
8105 rxh->PhyRxStatus_5 = le16_to_cpu(rxh_le->PhyRxStatus_5);
8106 rxh->RxStatus1 = le16_to_cpu(rxh_le->RxStatus1);
8107 rxh->RxStatus2 = le16_to_cpu(rxh_le->RxStatus2);
8108 rxh->RxTSFTime = le16_to_cpu(rxh_le->RxTSFTime);
8109 rxh->RxChan = le16_to_cpu(rxh_le->RxChan);
8110
8111 brcms_c_recv(wlc_hw->wlc, p);
8112 }
8113
8114 return n >= bound_limit;
8115}
8116
8117/* second-level interrupt processing
8118 * Return true if another dpc needs to be re-scheduled. false otherwise.
8119 * Param 'bounded' indicates if applicable loops should be bounded.
8120 */
8121bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
8122{
8123 u32 macintstatus;
8124 struct brcms_hardware *wlc_hw = wlc->hw;
Arend van Spriel16d28122011-12-08 15:06:51 -08008125 struct bcma_device *core = wlc_hw->d11core;
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008126 struct wiphy *wiphy = wlc->wiphy;
8127
8128 if (brcms_deviceremoved(wlc)) {
8129 wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
8130 __func__);
8131 brcms_down(wlc->wl);
8132 return false;
8133 }
8134
8135 /* grab and clear the saved software intstatus bits */
8136 macintstatus = wlc->macintstatus;
8137 wlc->macintstatus = 0;
8138
8139 BCMMSG(wlc->wiphy, "wl%d: macintstatus 0x%x\n",
8140 wlc_hw->unit, macintstatus);
8141
8142 WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */
8143
8144 /* tx status */
8145 if (macintstatus & MI_TFS) {
8146 bool fatal;
8147 if (brcms_b_txstatus(wlc->hw, bounded, &fatal))
8148 wlc->macintstatus |= MI_TFS;
8149 if (fatal) {
8150 wiphy_err(wiphy, "MI_TFS: fatal\n");
8151 goto fatal;
8152 }
8153 }
8154
8155 if (macintstatus & (MI_TBTT | MI_DTIM_TBTT))
8156 brcms_c_tbtt(wlc);
8157
8158 /* ATIM window end */
8159 if (macintstatus & MI_ATIMWINEND) {
8160 BCMMSG(wlc->wiphy, "end of ATIM window\n");
Arend van Spriel16d28122011-12-08 15:06:51 -08008161 bcma_set32(core, D11REGOFFS(maccommand), wlc->qvalid);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008162 wlc->qvalid = 0;
8163 }
8164
8165 /*
8166 * received data or control frame, MI_DMAINT is
8167 * indication of RX_FIFO interrupt
8168 */
8169 if (macintstatus & MI_DMAINT)
8170 if (brcms_b_recv(wlc_hw, RX_FIFO, bounded))
8171 wlc->macintstatus |= MI_DMAINT;
8172
8173 /* noise sample collected */
8174 if (macintstatus & MI_BG_NOISE)
8175 wlc_phy_noise_sample_intr(wlc_hw->band->pi);
8176
8177 if (macintstatus & MI_GP0) {
8178 wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d "
Arend van Sprielb2ffec42011-12-08 15:06:45 -08008179 "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008180
8181 printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
Arend van Sprielb2ffec42011-12-08 15:06:45 -08008182 __func__, ai_get_chip_id(wlc_hw->sih),
8183 ai_get_chiprev(wlc_hw->sih));
Roland Vossenc261bdf2011-10-18 14:03:04 +02008184 brcms_fatal_error(wlc_hw->wlc->wl);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008185 }
8186
8187 /* gptimer timeout */
8188 if (macintstatus & MI_TO)
Arend van Spriel16d28122011-12-08 15:06:51 -08008189 bcma_write32(core, D11REGOFFS(gptimer), 0);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008190
8191 if (macintstatus & MI_RFDISABLE) {
8192 BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the"
8193 " RF Disable Input\n", wlc_hw->unit);
8194 brcms_rfkill_set_hw_state(wlc->wl);
8195 }
8196
8197 /* send any enq'd tx packets. Just makes sure to jump start tx */
8198 if (!pktq_empty(&wlc->pkt_queue->q))
8199 brcms_c_send_q(wlc);
8200
8201 /* it isn't done and needs to be resched if macintstatus is non-zero */
8202 return wlc->macintstatus != 0;
8203
8204 fatal:
Roland Vossenc261bdf2011-10-18 14:03:04 +02008205 brcms_fatal_error(wlc_hw->wlc->wl);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008206 return wlc->macintstatus != 0;
8207}
8208
Roland Vossendc460122011-10-21 16:16:28 +02008209void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008210{
Arend van Spriel16d28122011-12-08 15:06:51 -08008211 struct bcma_device *core = wlc->hw->d11core;
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008212 u16 chanspec;
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008213
8214 BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
8215
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008216 /*
8217 * This will happen if a big-hammer was executed. In
8218 * that case, we want to go back to the channel that
8219 * we were on and not new channel
8220 */
8221 if (wlc->pub->associated)
8222 chanspec = wlc->home_chanspec;
8223 else
8224 chanspec = brcms_c_init_chanspec(wlc);
8225
Roland Vossena8bc4912011-10-21 16:16:25 +02008226 brcms_b_init(wlc->hw, chanspec);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008227
8228 /* update beacon listen interval */
8229 brcms_c_bcn_li_upd(wlc);
8230
8231 /* write ethernet address to core */
8232 brcms_c_set_mac(wlc->bsscfg);
8233 brcms_c_set_bssid(wlc->bsscfg);
8234
8235 /* Update tsf_cfprep if associated and up */
8236 if (wlc->pub->associated && wlc->bsscfg->up) {
8237 u32 bi;
8238
8239 /* get beacon period and convert to uS */
8240 bi = wlc->bsscfg->current_bss->beacon_period << 10;
8241 /*
8242 * update since init path would reset
8243 * to default value
8244 */
Arend van Spriel16d28122011-12-08 15:06:51 -08008245 bcma_write32(core, D11REGOFFS(tsf_cfprep),
8246 bi << CFPREP_CBI_SHIFT);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008247
8248 /* Update maccontrol PM related bits */
8249 brcms_c_set_ps_ctrl(wlc);
8250 }
8251
8252 brcms_c_bandinit_ordered(wlc, chanspec);
8253
8254 /* init probe response timeout */
8255 brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);
8256
8257 /* init max burst txop (framebursting) */
8258 brcms_b_write_shm(wlc->hw, M_MBURST_TXOP,
8259 (wlc->
8260 _rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP));
8261
8262 /* initialize maximum allowed duty cycle */
8263 brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, true, true);
8264 brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, false, true);
8265
8266 /*
8267 * Update some shared memory locations related to
8268 * max AMPDU size allowed to received
8269 */
8270 brcms_c_ampdu_shm_upd(wlc->ampdu);
8271
8272 /* band-specific inits */
8273 brcms_c_bsinit(wlc);
8274
8275 /* Enable EDCF mode (while the MAC is suspended) */
Arend van Spriel16d28122011-12-08 15:06:51 -08008276 bcma_set16(core, D11REGOFFS(ifs_ctl), IFS_USEEDCF);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008277 brcms_c_edcf_setparams(wlc, false);
8278
8279 /* Init precedence maps for empty FIFOs */
8280 brcms_c_tx_prec_map_init(wlc);
8281
8282 /* read the ucode version if we have not yet done so */
8283 if (wlc->ucode_rev == 0) {
8284 wlc->ucode_rev =
8285 brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR) << NBITS(u16);
8286 wlc->ucode_rev |= brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR);
8287 }
8288
8289 /* ..now really unleash hell (allow the MAC out of suspend) */
8290 brcms_c_enable_mac(wlc);
8291
Roland Vossena8bc4912011-10-21 16:16:25 +02008292 /* suspend the tx fifos and mute the phy for preism cac time */
8293 if (mute_tx)
Roland Vossenc6c44892011-10-21 16:16:26 +02008294 brcms_b_mute(wlc->hw, true);
Roland Vossena8bc4912011-10-21 16:16:25 +02008295
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008296 /* clear tx flow control */
8297 brcms_c_txflowcontrol_reset(wlc);
8298
8299 /* enable the RF Disable Delay timer */
Arend van Spriel16d28122011-12-08 15:06:51 -08008300 bcma_write32(core, D11REGOFFS(rfdisabledly), RFDISABLE_DEFAULT);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008301
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008302 /*
8303 * Initialize WME parameters; if they haven't been set by some other
8304 * mechanism (IOVar, etc) then read them from the hardware.
8305 */
8306 if (GFIELD(wlc->wme_retries[0], EDCF_SHORT) == 0) {
8307 /* Uninitialized; read from HW */
8308 int ac;
8309
Arend van Sprielb7eec422011-11-10 20:30:18 +01008310 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008311 wlc->wme_retries[ac] =
8312 brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac));
8313 }
8314}
8315
8316/*
8317 * The common driver entry routine. Error codes should be unique
8318 */
8319struct brcms_c_info *
Arend van Sprielb63337a2011-12-08 15:06:47 -08008320brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit,
8321 bool piomode, uint *perr)
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008322{
8323 struct brcms_c_info *wlc;
8324 uint err = 0;
8325 uint i, j;
8326 struct brcms_pub *pub;
8327
8328 /* allocate struct brcms_c_info state and its substructures */
Arend van Sprielb63337a2011-12-08 15:06:47 -08008329 wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, 0);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008330 if (wlc == NULL)
8331 goto fail;
8332 wlc->wiphy = wl->wiphy;
8333 pub = wlc->pub;
8334
Joe Perches8ae74652012-01-15 00:38:38 -08008335#if defined(DEBUG)
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008336 wlc_info_dbg = wlc;
8337#endif
8338
8339 wlc->band = wlc->bandstate[0];
8340 wlc->core = wlc->corestate;
8341 wlc->wl = wl;
8342 pub->unit = unit;
8343 pub->_piomode = piomode;
8344 wlc->bandinit_pending = false;
8345
8346 /* populate struct brcms_c_info with default values */
8347 brcms_c_info_init(wlc, unit);
8348
8349 /* update sta/ap related parameters */
8350 brcms_c_ap_upd(wlc);
8351
8352 /*
8353 * low level attach steps(all hw accesses go
8354 * inside, no more in rest of the attach)
8355 */
Arend van Sprielb63337a2011-12-08 15:06:47 -08008356 err = brcms_b_attach(wlc, core, unit, piomode);
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008357 if (err)
8358 goto fail;
8359
8360 brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, OFF);
8361
8362 pub->phy_11ncapable = BRCMS_PHY_11N_CAP(wlc->band);
8363
8364 /* disable allowed duty cycle */
8365 wlc->tx_duty_cycle_ofdm = 0;
8366 wlc->tx_duty_cycle_cck = 0;
8367
8368 brcms_c_stf_phy_chain_calc(wlc);
8369
8370 /* txchain 1: txant 0, txchain 2: txant 1 */
8371 if (BRCMS_ISNPHY(wlc->band) && (wlc->stf->txstreams == 1))
8372 wlc->stf->txant = wlc->stf->hw_txchain - 1;
8373
8374 /* push to BMAC driver */
8375 wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain,
8376 wlc->stf->hw_rxchain);
8377
8378 /* pull up some info resulting from the low attach */
8379 for (i = 0; i < NFIFO; i++)
8380 wlc->core->txavail[i] = wlc->hw->txavail[i];
8381
8382 memcpy(&wlc->perm_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
8383 memcpy(&pub->cur_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
8384
8385 for (j = 0; j < wlc->pub->_nbands; j++) {
8386 wlc->band = wlc->bandstate[j];
8387
8388 if (!brcms_c_attach_stf_ant_init(wlc)) {
8389 err = 24;
8390 goto fail;
8391 }
8392
8393 /* default contention windows size limits */
8394 wlc->band->CWmin = APHY_CWMIN;
8395 wlc->band->CWmax = PHY_CWMAX;
8396
8397 /* init gmode value */
8398 if (wlc->band->bandtype == BRCM_BAND_2G) {
8399 wlc->band->gmode = GMODE_AUTO;
8400 brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER,
8401 wlc->band->gmode);
8402 }
8403
8404 /* init _n_enab supported mode */
8405 if (BRCMS_PHY_11N_CAP(wlc->band)) {
8406 pub->_n_enab = SUPPORT_11N;
8407 brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER,
8408 ((pub->_n_enab ==
8409 SUPPORT_11N) ? WL_11N_2x2 :
8410 WL_11N_3x3));
8411 }
8412
8413 /* init per-band default rateset, depend on band->gmode */
8414 brcms_default_rateset(wlc, &wlc->band->defrateset);
8415
8416 /* fill in hw_rateset */
8417 brcms_c_rateset_filter(&wlc->band->defrateset,
8418 &wlc->band->hw_rateset, false,
8419 BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
8420 (bool) (wlc->pub->_n_enab & SUPPORT_11N));
8421 }
8422
8423 /*
8424 * update antenna config due to
8425 * wlc->stf->txant/txchain/ant_rx_ovr change
8426 */
8427 brcms_c_stf_phy_txant_upd(wlc);
8428
8429 /* attach each modules */
8430 err = brcms_c_attach_module(wlc);
8431 if (err != 0)
8432 goto fail;
8433
8434 if (!brcms_c_timers_init(wlc, unit)) {
8435 wiphy_err(wl->wiphy, "wl%d: %s: init_timer failed\n", unit,
8436 __func__);
8437 err = 32;
8438 goto fail;
8439 }
8440
8441 /* depend on rateset, gmode */
8442 wlc->cmi = brcms_c_channel_mgr_attach(wlc);
8443 if (!wlc->cmi) {
8444 wiphy_err(wl->wiphy, "wl%d: %s: channel_mgr_attach failed"
8445 "\n", unit, __func__);
8446 err = 33;
8447 goto fail;
8448 }
8449
8450 /* init default when all parameters are ready, i.e. ->rateset */
8451 brcms_c_bss_default_init(wlc);
8452
8453 /*
8454 * Complete the wlc default state initializations..
8455 */
8456
8457 /* allocate our initial queue */
8458 wlc->pkt_queue = brcms_c_txq_alloc(wlc);
8459 if (wlc->pkt_queue == NULL) {
8460 wiphy_err(wl->wiphy, "wl%d: %s: failed to malloc tx queue\n",
8461 unit, __func__);
8462 err = 100;
8463 goto fail;
8464 }
8465
8466 wlc->bsscfg->wlc = wlc;
8467
8468 wlc->mimoft = FT_HT;
8469 wlc->mimo_40txbw = AUTO;
8470 wlc->ofdm_40txbw = AUTO;
8471 wlc->cck_40txbw = AUTO;
8472 brcms_c_update_mimo_band_bwcap(wlc, BRCMS_N_BW_20IN2G_40IN5G);
8473
8474 /* Set default values of SGI */
8475 if (BRCMS_SGI_CAP_PHY(wlc)) {
8476 brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
8477 BRCMS_N_SGI_40));
8478 } else if (BRCMS_ISSSLPNPHY(wlc->band)) {
8479 brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
8480 BRCMS_N_SGI_40));
8481 } else {
8482 brcms_c_ht_update_sgi_rx(wlc, 0);
8483 }
8484
Alwin Beukers94bdc2a2011-10-12 20:51:13 +02008485 brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail);
8486
8487 if (perr)
8488 *perr = 0;
8489
8490 return wlc;
8491
8492 fail:
8493 wiphy_err(wl->wiphy, "wl%d: %s: failed with err %d\n",
8494 unit, __func__, err);
8495 if (wlc)
8496 brcms_c_detach(wlc);
8497
8498 if (perr)
8499 *perr = err;
8500 return NULL;
8501}