xref: /freebsd/sys/contrib/dev/broadcom/brcm80211/brcmsmac/main.c (revision b4c3e9b5b09c829b4135aff738bd2893ed052377)
1*b4c3e9b5SBjoern A. Zeeb /*
2*b4c3e9b5SBjoern A. Zeeb  * Copyright (c) 2010 Broadcom Corporation
3*b4c3e9b5SBjoern A. Zeeb  * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
4*b4c3e9b5SBjoern A. Zeeb  *
5*b4c3e9b5SBjoern A. Zeeb  * Permission to use, copy, modify, and/or distribute this software for any
6*b4c3e9b5SBjoern A. Zeeb  * purpose with or without fee is hereby granted, provided that the above
7*b4c3e9b5SBjoern A. Zeeb  * copyright notice and this permission notice appear in all copies.
8*b4c3e9b5SBjoern A. Zeeb  *
9*b4c3e9b5SBjoern A. Zeeb  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*b4c3e9b5SBjoern A. Zeeb  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*b4c3e9b5SBjoern A. Zeeb  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
12*b4c3e9b5SBjoern A. Zeeb  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*b4c3e9b5SBjoern A. Zeeb  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
14*b4c3e9b5SBjoern A. Zeeb  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15*b4c3e9b5SBjoern A. Zeeb  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*b4c3e9b5SBjoern A. Zeeb  */
17*b4c3e9b5SBjoern A. Zeeb 
18*b4c3e9b5SBjoern A. Zeeb #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19*b4c3e9b5SBjoern A. Zeeb 
20*b4c3e9b5SBjoern A. Zeeb #include <linux/pci_ids.h>
21*b4c3e9b5SBjoern A. Zeeb #include <linux/if_ether.h>
22*b4c3e9b5SBjoern A. Zeeb #include <net/cfg80211.h>
23*b4c3e9b5SBjoern A. Zeeb #include <net/mac80211.h>
24*b4c3e9b5SBjoern A. Zeeb #include <brcm_hw_ids.h>
25*b4c3e9b5SBjoern A. Zeeb #include <aiutils.h>
26*b4c3e9b5SBjoern A. Zeeb #include <chipcommon.h>
27*b4c3e9b5SBjoern A. Zeeb #include "rate.h"
28*b4c3e9b5SBjoern A. Zeeb #include "scb.h"
29*b4c3e9b5SBjoern A. Zeeb #include "phy/phy_hal.h"
30*b4c3e9b5SBjoern A. Zeeb #include "channel.h"
31*b4c3e9b5SBjoern A. Zeeb #include "antsel.h"
32*b4c3e9b5SBjoern A. Zeeb #include "stf.h"
33*b4c3e9b5SBjoern A. Zeeb #include "ampdu.h"
34*b4c3e9b5SBjoern A. Zeeb #include "mac80211_if.h"
35*b4c3e9b5SBjoern A. Zeeb #include "ucode_loader.h"
36*b4c3e9b5SBjoern A. Zeeb #include "main.h"
37*b4c3e9b5SBjoern A. Zeeb #include "soc.h"
38*b4c3e9b5SBjoern A. Zeeb #include "dma.h"
39*b4c3e9b5SBjoern A. Zeeb #include "debug.h"
40*b4c3e9b5SBjoern A. Zeeb #include "brcms_trace_events.h"
41*b4c3e9b5SBjoern A. Zeeb 
42*b4c3e9b5SBjoern A. Zeeb /* watchdog timer, in unit of ms */
43*b4c3e9b5SBjoern A. Zeeb #define TIMER_INTERVAL_WATCHDOG		1000
44*b4c3e9b5SBjoern A. Zeeb /* radio monitor timer, in unit of ms */
45*b4c3e9b5SBjoern A. Zeeb #define TIMER_INTERVAL_RADIOCHK		800
46*b4c3e9b5SBjoern A. Zeeb 
47*b4c3e9b5SBjoern A. Zeeb /* beacon interval, in unit of 1024TU */
48*b4c3e9b5SBjoern A. Zeeb #define BEACON_INTERVAL_DEFAULT		100
49*b4c3e9b5SBjoern A. Zeeb 
50*b4c3e9b5SBjoern A. Zeeb /* n-mode support capability */
51*b4c3e9b5SBjoern A. Zeeb /* 2x2 includes both 1x1 & 2x2 devices
52*b4c3e9b5SBjoern A. Zeeb  * reserved #define 2 for future when we want to separate 1x1 & 2x2 and
53*b4c3e9b5SBjoern A. Zeeb  * control it independently
54*b4c3e9b5SBjoern A. Zeeb  */
55*b4c3e9b5SBjoern A. Zeeb #define WL_11N_2x2			1
56*b4c3e9b5SBjoern A. Zeeb #define WL_11N_3x3			3
57*b4c3e9b5SBjoern A. Zeeb #define WL_11N_4x4			4
58*b4c3e9b5SBjoern A. Zeeb 
59*b4c3e9b5SBjoern A. Zeeb #define EDCF_ACI_MASK			0x60
60*b4c3e9b5SBjoern A. Zeeb #define EDCF_ACI_SHIFT			5
61*b4c3e9b5SBjoern A. Zeeb #define EDCF_ECWMIN_MASK		0x0f
62*b4c3e9b5SBjoern A. Zeeb #define EDCF_ECWMAX_SHIFT		4
63*b4c3e9b5SBjoern A. Zeeb #define EDCF_AIFSN_MASK			0x0f
64*b4c3e9b5SBjoern A. Zeeb #define EDCF_AIFSN_MAX			15
65*b4c3e9b5SBjoern A. Zeeb #define EDCF_ECWMAX_MASK		0xf0
66*b4c3e9b5SBjoern A. Zeeb 
67*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_BE_TXOP_STA		0x0000
68*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_BK_TXOP_STA		0x0000
69*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_VO_ACI_STA		0x62
70*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_VO_ECW_STA		0x32
71*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_VI_ACI_STA		0x42
72*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_VI_ECW_STA		0x43
73*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_BK_ECW_STA		0xA4
74*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_VI_TXOP_STA		0x005e
75*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_VO_TXOP_STA		0x002f
76*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_BE_ACI_STA		0x03
77*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_BE_ECW_STA		0xA4
78*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_BK_ACI_STA		0x27
79*b4c3e9b5SBjoern A. Zeeb #define EDCF_AC_VO_TXOP_AP		0x002f
80*b4c3e9b5SBjoern A. Zeeb 
81*b4c3e9b5SBjoern A. Zeeb #define EDCF_TXOP2USEC(txop)		((txop) << 5)
82*b4c3e9b5SBjoern A. Zeeb #define EDCF_ECW2CW(exp)		((1 << (exp)) - 1)
83*b4c3e9b5SBjoern A. Zeeb 
84*b4c3e9b5SBjoern A. Zeeb #define APHY_SYMBOL_TIME		4
85*b4c3e9b5SBjoern A. Zeeb #define APHY_PREAMBLE_TIME		16
86*b4c3e9b5SBjoern A. Zeeb #define APHY_SIGNAL_TIME		4
87*b4c3e9b5SBjoern A. Zeeb #define APHY_SIFS_TIME			16
88*b4c3e9b5SBjoern A. Zeeb #define APHY_SERVICE_NBITS		16
89*b4c3e9b5SBjoern A. Zeeb #define APHY_TAIL_NBITS			6
90*b4c3e9b5SBjoern A. Zeeb #define BPHY_SIFS_TIME			10
91*b4c3e9b5SBjoern A. Zeeb #define BPHY_PLCP_SHORT_TIME		96
92*b4c3e9b5SBjoern A. Zeeb 
93*b4c3e9b5SBjoern A. Zeeb #define PREN_PREAMBLE			24
94*b4c3e9b5SBjoern A. Zeeb #define PREN_MM_EXT			12
95*b4c3e9b5SBjoern A. Zeeb #define PREN_PREAMBLE_EXT		4
96*b4c3e9b5SBjoern A. Zeeb 
97*b4c3e9b5SBjoern A. Zeeb #define DOT11_MAC_HDR_LEN		24
98*b4c3e9b5SBjoern A. Zeeb #define DOT11_ACK_LEN			10
99*b4c3e9b5SBjoern A. Zeeb #define DOT11_BA_LEN			4
100*b4c3e9b5SBjoern A. Zeeb #define DOT11_OFDM_SIGNAL_EXTENSION	6
101*b4c3e9b5SBjoern A. Zeeb #define DOT11_MIN_FRAG_LEN		256
102*b4c3e9b5SBjoern A. Zeeb #define DOT11_RTS_LEN			16
103*b4c3e9b5SBjoern A. Zeeb #define DOT11_CTS_LEN			10
104*b4c3e9b5SBjoern A. Zeeb #define DOT11_BA_BITMAP_LEN		128
105*b4c3e9b5SBjoern A. Zeeb #define DOT11_MAXNUMFRAGS		16
106*b4c3e9b5SBjoern A. Zeeb #define DOT11_MAX_FRAG_LEN		2346
107*b4c3e9b5SBjoern A. Zeeb 
108*b4c3e9b5SBjoern A. Zeeb #define BPHY_PLCP_TIME			192
109*b4c3e9b5SBjoern A. Zeeb #define RIFS_11N_TIME			2
110*b4c3e9b5SBjoern A. Zeeb 
111*b4c3e9b5SBjoern A. Zeeb /* length of the BCN template area */
112*b4c3e9b5SBjoern A. Zeeb #define BCN_TMPL_LEN			512
113*b4c3e9b5SBjoern A. Zeeb 
114*b4c3e9b5SBjoern A. Zeeb /* brcms_bss_info flag bit values */
115*b4c3e9b5SBjoern A. Zeeb #define BRCMS_BSS_HT			0x0020	/* BSS is HT (MIMO) capable */
116*b4c3e9b5SBjoern A. Zeeb 
117*b4c3e9b5SBjoern A. Zeeb /* chip rx buffer offset */
118*b4c3e9b5SBjoern A. Zeeb #define BRCMS_HWRXOFF			38
119*b4c3e9b5SBjoern A. Zeeb 
120*b4c3e9b5SBjoern A. Zeeb /* rfdisable delay timer 500 ms, runs of ALP clock */
121*b4c3e9b5SBjoern A. Zeeb #define RFDISABLE_DEFAULT		10000000
122*b4c3e9b5SBjoern A. Zeeb 
123*b4c3e9b5SBjoern A. Zeeb #define BRCMS_TEMPSENSE_PERIOD		10	/* 10 second timeout */
124*b4c3e9b5SBjoern A. Zeeb 
125*b4c3e9b5SBjoern A. Zeeb /* synthpu_dly times in us */
126*b4c3e9b5SBjoern A. Zeeb #define SYNTHPU_DLY_APHY_US		3700
127*b4c3e9b5SBjoern A. Zeeb #define SYNTHPU_DLY_BPHY_US		1050
128*b4c3e9b5SBjoern A. Zeeb #define SYNTHPU_DLY_NPHY_US		2048
129*b4c3e9b5SBjoern A. Zeeb #define SYNTHPU_DLY_LPPHY_US		300
130*b4c3e9b5SBjoern A. Zeeb 
131*b4c3e9b5SBjoern A. Zeeb #define ANTCNT				10	/* vanilla M_MAX_ANTCNT val */
132*b4c3e9b5SBjoern A. Zeeb 
133*b4c3e9b5SBjoern A. Zeeb /* Per-AC retry limit register definitions; uses defs.h bitfield macros */
134*b4c3e9b5SBjoern A. Zeeb #define EDCF_SHORT_S			0
135*b4c3e9b5SBjoern A. Zeeb #define EDCF_SFB_S			4
136*b4c3e9b5SBjoern A. Zeeb #define EDCF_LONG_S			8
137*b4c3e9b5SBjoern A. Zeeb #define EDCF_LFB_S			12
138*b4c3e9b5SBjoern A. Zeeb #define EDCF_SHORT_M			BITFIELD_MASK(4)
139*b4c3e9b5SBjoern A. Zeeb #define EDCF_SFB_M			BITFIELD_MASK(4)
140*b4c3e9b5SBjoern A. Zeeb #define EDCF_LONG_M			BITFIELD_MASK(4)
141*b4c3e9b5SBjoern A. Zeeb #define EDCF_LFB_M			BITFIELD_MASK(4)
142*b4c3e9b5SBjoern A. Zeeb 
143*b4c3e9b5SBjoern A. Zeeb #define RETRY_SHORT_DEF			7	/* Default Short retry Limit */
144*b4c3e9b5SBjoern A. Zeeb #define RETRY_SHORT_MAX			255	/* Maximum Short retry Limit */
145*b4c3e9b5SBjoern A. Zeeb #define RETRY_LONG_DEF			4	/* Default Long retry count */
146*b4c3e9b5SBjoern A. Zeeb #define RETRY_SHORT_FB			3	/* Short count for fb rate */
147*b4c3e9b5SBjoern A. Zeeb #define RETRY_LONG_FB			2	/* Long count for fb rate */
148*b4c3e9b5SBjoern A. Zeeb 
149*b4c3e9b5SBjoern A. Zeeb #define APHY_CWMIN			15
150*b4c3e9b5SBjoern A. Zeeb #define PHY_CWMAX			1023
151*b4c3e9b5SBjoern A. Zeeb 
152*b4c3e9b5SBjoern A. Zeeb #define EDCF_AIFSN_MIN			1
153*b4c3e9b5SBjoern A. Zeeb 
154*b4c3e9b5SBjoern A. Zeeb #define FRAGNUM_MASK			0xF
155*b4c3e9b5SBjoern A. Zeeb 
156*b4c3e9b5SBjoern A. Zeeb #define APHY_SLOT_TIME			9
157*b4c3e9b5SBjoern A. Zeeb #define BPHY_SLOT_TIME			20
158*b4c3e9b5SBjoern A. Zeeb 
159*b4c3e9b5SBjoern A. Zeeb #define WL_SPURAVOID_OFF		0
160*b4c3e9b5SBjoern A. Zeeb #define WL_SPURAVOID_ON1		1
161*b4c3e9b5SBjoern A. Zeeb #define WL_SPURAVOID_ON2		2
162*b4c3e9b5SBjoern A. Zeeb 
163*b4c3e9b5SBjoern A. Zeeb /* invalid core flags, use the saved coreflags */
164*b4c3e9b5SBjoern A. Zeeb #define BRCMS_USE_COREFLAGS		0xffffffff
165*b4c3e9b5SBjoern A. Zeeb 
166*b4c3e9b5SBjoern A. Zeeb /* values for PLCPHdr_override */
167*b4c3e9b5SBjoern A. Zeeb #define BRCMS_PLCP_AUTO			-1
168*b4c3e9b5SBjoern A. Zeeb #define BRCMS_PLCP_SHORT		0
169*b4c3e9b5SBjoern A. Zeeb #define BRCMS_PLCP_LONG			1
170*b4c3e9b5SBjoern A. Zeeb 
171*b4c3e9b5SBjoern A. Zeeb /* values for g_protection_override and n_protection_override */
172*b4c3e9b5SBjoern A. Zeeb #define BRCMS_PROTECTION_AUTO		-1
173*b4c3e9b5SBjoern A. Zeeb #define BRCMS_PROTECTION_OFF		0
174*b4c3e9b5SBjoern A. Zeeb #define BRCMS_PROTECTION_ON		1
175*b4c3e9b5SBjoern A. Zeeb #define BRCMS_PROTECTION_MMHDR_ONLY	2
176*b4c3e9b5SBjoern A. Zeeb #define BRCMS_PROTECTION_CTS_ONLY	3
177*b4c3e9b5SBjoern A. Zeeb 
178*b4c3e9b5SBjoern A. Zeeb /* values for g_protection_control and n_protection_control */
179*b4c3e9b5SBjoern A. Zeeb #define BRCMS_PROTECTION_CTL_OFF	0
180*b4c3e9b5SBjoern A. Zeeb #define BRCMS_PROTECTION_CTL_LOCAL	1
181*b4c3e9b5SBjoern A. Zeeb #define BRCMS_PROTECTION_CTL_OVERLAP	2
182*b4c3e9b5SBjoern A. Zeeb 
183*b4c3e9b5SBjoern A. Zeeb /* values for n_protection */
184*b4c3e9b5SBjoern A. Zeeb #define BRCMS_N_PROTECTION_OFF		0
185*b4c3e9b5SBjoern A. Zeeb #define BRCMS_N_PROTECTION_OPTIONAL	1
186*b4c3e9b5SBjoern A. Zeeb #define BRCMS_N_PROTECTION_20IN40	2
187*b4c3e9b5SBjoern A. Zeeb #define BRCMS_N_PROTECTION_MIXEDMODE	3
188*b4c3e9b5SBjoern A. Zeeb 
189*b4c3e9b5SBjoern A. Zeeb /* values for band specific 40MHz capabilities */
190*b4c3e9b5SBjoern A. Zeeb #define BRCMS_N_BW_20ALL		0
191*b4c3e9b5SBjoern A. Zeeb #define BRCMS_N_BW_40ALL		1
192*b4c3e9b5SBjoern A. Zeeb #define BRCMS_N_BW_20IN2G_40IN5G	2
193*b4c3e9b5SBjoern A. Zeeb 
194*b4c3e9b5SBjoern A. Zeeb /* bitflags for SGI support (sgi_rx iovar) */
195*b4c3e9b5SBjoern A. Zeeb #define BRCMS_N_SGI_20			0x01
196*b4c3e9b5SBjoern A. Zeeb #define BRCMS_N_SGI_40			0x02
197*b4c3e9b5SBjoern A. Zeeb 
198*b4c3e9b5SBjoern A. Zeeb /* defines used by the nrate iovar */
199*b4c3e9b5SBjoern A. Zeeb /* MSC in use,indicates b0-6 holds an mcs */
200*b4c3e9b5SBjoern A. Zeeb #define NRATE_MCS_INUSE			0x00000080
201*b4c3e9b5SBjoern A. Zeeb /* rate/mcs value */
202*b4c3e9b5SBjoern A. Zeeb #define NRATE_RATE_MASK			0x0000007f
203*b4c3e9b5SBjoern A. Zeeb /* stf mode mask: siso, cdd, stbc, sdm */
204*b4c3e9b5SBjoern A. Zeeb #define NRATE_STF_MASK			0x0000ff00
205*b4c3e9b5SBjoern A. Zeeb /* stf mode shift */
206*b4c3e9b5SBjoern A. Zeeb #define NRATE_STF_SHIFT			8
207*b4c3e9b5SBjoern A. Zeeb /* bit indicate to override mcs only */
208*b4c3e9b5SBjoern A. Zeeb #define NRATE_OVERRIDE_MCS_ONLY		0x40000000
209*b4c3e9b5SBjoern A. Zeeb #define NRATE_SGI_MASK			0x00800000	/* sgi mode */
210*b4c3e9b5SBjoern A. Zeeb #define NRATE_SGI_SHIFT			23		/* sgi mode */
211*b4c3e9b5SBjoern A. Zeeb #define NRATE_LDPC_CODING		0x00400000	/* adv coding in use */
212*b4c3e9b5SBjoern A. Zeeb #define NRATE_LDPC_SHIFT		22		/* ldpc shift */
213*b4c3e9b5SBjoern A. Zeeb 
214*b4c3e9b5SBjoern A. Zeeb #define NRATE_STF_SISO			0		/* stf mode SISO */
215*b4c3e9b5SBjoern A. Zeeb #define NRATE_STF_CDD			1		/* stf mode CDD */
216*b4c3e9b5SBjoern A. Zeeb #define NRATE_STF_STBC			2		/* stf mode STBC */
217*b4c3e9b5SBjoern A. Zeeb #define NRATE_STF_SDM			3		/* stf mode SDM */
218*b4c3e9b5SBjoern A. Zeeb 
219*b4c3e9b5SBjoern A. Zeeb #define MAX_DMA_SEGS			4
220*b4c3e9b5SBjoern A. Zeeb 
221*b4c3e9b5SBjoern A. Zeeb /* # of entries in Tx FIFO */
222*b4c3e9b5SBjoern A. Zeeb #define NTXD				64
223*b4c3e9b5SBjoern A. Zeeb /* Max # of entries in Rx FIFO based on 4kb page size */
224*b4c3e9b5SBjoern A. Zeeb #define NRXD				256
225*b4c3e9b5SBjoern A. Zeeb 
226*b4c3e9b5SBjoern A. Zeeb /* Amount of headroom to leave in Tx FIFO */
227*b4c3e9b5SBjoern A. Zeeb #define TX_HEADROOM			4
228*b4c3e9b5SBjoern A. Zeeb 
229*b4c3e9b5SBjoern A. Zeeb /* try to keep this # rbufs posted to the chip */
230*b4c3e9b5SBjoern A. Zeeb #define NRXBUFPOST			32
231*b4c3e9b5SBjoern A. Zeeb 
232*b4c3e9b5SBjoern A. Zeeb /* max # frames to process in brcms_c_recv() */
233*b4c3e9b5SBjoern A. Zeeb #define RXBND				8
234*b4c3e9b5SBjoern A. Zeeb /* max # tx status to process in wlc_txstatus() */
235*b4c3e9b5SBjoern A. Zeeb #define TXSBND				8
236*b4c3e9b5SBjoern A. Zeeb 
237*b4c3e9b5SBjoern A. Zeeb /*
238*b4c3e9b5SBjoern A. Zeeb  * The following table lists the buffer memory allocated to xmt fifos in HW.
239*b4c3e9b5SBjoern A. Zeeb  * the size is in units of 256bytes(one block), total size is HW dependent
240*b4c3e9b5SBjoern A. Zeeb  * ucode has default fifo partition, sw can overwrite if necessary
241*b4c3e9b5SBjoern A. Zeeb  *
242*b4c3e9b5SBjoern A. Zeeb  * This is documented in twiki under the topic UcodeTxFifo. Please ensure
243*b4c3e9b5SBjoern A. Zeeb  * the twiki is updated before making changes.
244*b4c3e9b5SBjoern A. Zeeb  */
245*b4c3e9b5SBjoern A. Zeeb 
246*b4c3e9b5SBjoern A. Zeeb /* Starting corerev for the fifo size table */
247*b4c3e9b5SBjoern A. Zeeb #define XMTFIFOTBL_STARTREV	17
248*b4c3e9b5SBjoern A. Zeeb 
249*b4c3e9b5SBjoern A. Zeeb struct d11init {
250*b4c3e9b5SBjoern A. Zeeb 	__le16 addr;
251*b4c3e9b5SBjoern A. Zeeb 	__le16 size;
252*b4c3e9b5SBjoern A. Zeeb 	__le32 value;
253*b4c3e9b5SBjoern A. Zeeb };
254*b4c3e9b5SBjoern A. Zeeb 
255*b4c3e9b5SBjoern A. Zeeb struct edcf_acparam {
256*b4c3e9b5SBjoern A. Zeeb 	u8 ACI;
257*b4c3e9b5SBjoern A. Zeeb 	u8 ECW;
258*b4c3e9b5SBjoern A. Zeeb 	u16 TXOP;
259*b4c3e9b5SBjoern A. Zeeb } __packed;
260*b4c3e9b5SBjoern A. Zeeb 
261*b4c3e9b5SBjoern A. Zeeb /* debug/trace */
262*b4c3e9b5SBjoern A. Zeeb uint brcm_msg_level;
263*b4c3e9b5SBjoern A. Zeeb 
264*b4c3e9b5SBjoern A. Zeeb /* TX FIFO number to WME/802.1E Access Category */
265*b4c3e9b5SBjoern A. Zeeb static const u8 wme_fifo2ac[] = {
266*b4c3e9b5SBjoern A. Zeeb 	IEEE80211_AC_BK,
267*b4c3e9b5SBjoern A. Zeeb 	IEEE80211_AC_BE,
268*b4c3e9b5SBjoern A. Zeeb 	IEEE80211_AC_VI,
269*b4c3e9b5SBjoern A. Zeeb 	IEEE80211_AC_VO,
270*b4c3e9b5SBjoern A. Zeeb 	IEEE80211_AC_BE,
271*b4c3e9b5SBjoern A. Zeeb 	IEEE80211_AC_BE
272*b4c3e9b5SBjoern A. Zeeb };
273*b4c3e9b5SBjoern A. Zeeb 
274*b4c3e9b5SBjoern A. Zeeb /* ieee80211 Access Category to TX FIFO number */
275*b4c3e9b5SBjoern A. Zeeb static const u8 wme_ac2fifo[] = {
276*b4c3e9b5SBjoern A. Zeeb 	TX_AC_VO_FIFO,
277*b4c3e9b5SBjoern A. Zeeb 	TX_AC_VI_FIFO,
278*b4c3e9b5SBjoern A. Zeeb 	TX_AC_BE_FIFO,
279*b4c3e9b5SBjoern A. Zeeb 	TX_AC_BK_FIFO
280*b4c3e9b5SBjoern A. Zeeb };
281*b4c3e9b5SBjoern A. Zeeb 
282*b4c3e9b5SBjoern A. Zeeb static const u16 xmtfifo_sz[][NFIFO] = {
283*b4c3e9b5SBjoern A. Zeeb 	/* corerev 17: 5120, 49152, 49152, 5376, 4352, 1280 */
284*b4c3e9b5SBjoern A. Zeeb 	{20, 192, 192, 21, 17, 5},
285*b4c3e9b5SBjoern A. Zeeb 	/* corerev 18: */
286*b4c3e9b5SBjoern A. Zeeb 	{0, 0, 0, 0, 0, 0},
287*b4c3e9b5SBjoern A. Zeeb 	/* corerev 19: */
288*b4c3e9b5SBjoern A. Zeeb 	{0, 0, 0, 0, 0, 0},
289*b4c3e9b5SBjoern A. Zeeb 	/* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */
290*b4c3e9b5SBjoern A. Zeeb 	{20, 192, 192, 21, 17, 5},
291*b4c3e9b5SBjoern A. Zeeb 	/* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */
292*b4c3e9b5SBjoern A. Zeeb 	{9, 58, 22, 14, 14, 5},
293*b4c3e9b5SBjoern A. Zeeb 	/* corerev 22: 5120, 49152, 49152, 5376, 4352, 1280 */
294*b4c3e9b5SBjoern A. Zeeb 	{20, 192, 192, 21, 17, 5},
295*b4c3e9b5SBjoern A. Zeeb 	/* corerev 23: 5120, 49152, 49152, 5376, 4352, 1280 */
296*b4c3e9b5SBjoern A. Zeeb 	{20, 192, 192, 21, 17, 5},
297*b4c3e9b5SBjoern A. Zeeb 	/* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */
298*b4c3e9b5SBjoern A. Zeeb 	{9, 58, 22, 14, 14, 5},
299*b4c3e9b5SBjoern A. Zeeb 	/* corerev 25: */
300*b4c3e9b5SBjoern A. Zeeb 	{0, 0, 0, 0, 0, 0},
301*b4c3e9b5SBjoern A. Zeeb 	/* corerev 26: */
302*b4c3e9b5SBjoern A. Zeeb 	{0, 0, 0, 0, 0, 0},
303*b4c3e9b5SBjoern A. Zeeb 	/* corerev 27: */
304*b4c3e9b5SBjoern A. Zeeb 	{0, 0, 0, 0, 0, 0},
305*b4c3e9b5SBjoern A. Zeeb 	/* corerev 28: 2304, 14848, 5632, 3584, 3584, 1280 */
306*b4c3e9b5SBjoern A. Zeeb 	{9, 58, 22, 14, 14, 5},
307*b4c3e9b5SBjoern A. Zeeb };
308*b4c3e9b5SBjoern A. Zeeb 
309*b4c3e9b5SBjoern A. Zeeb #ifdef DEBUG
310*b4c3e9b5SBjoern A. Zeeb static const char * const fifo_names[] = {
311*b4c3e9b5SBjoern A. Zeeb 	"AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" };
312*b4c3e9b5SBjoern A. Zeeb #else
313*b4c3e9b5SBjoern A. Zeeb static const char fifo_names[6][1];
314*b4c3e9b5SBjoern A. Zeeb #endif
315*b4c3e9b5SBjoern A. Zeeb 
316*b4c3e9b5SBjoern A. Zeeb #ifdef DEBUG
317*b4c3e9b5SBjoern A. Zeeb /* pointer to most recently allocated wl/wlc */
318*b4c3e9b5SBjoern A. Zeeb static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);
319*b4c3e9b5SBjoern A. Zeeb #endif
320*b4c3e9b5SBjoern A. Zeeb 
321*b4c3e9b5SBjoern A. Zeeb /* Mapping of ieee80211 AC numbers to tx fifos */
322*b4c3e9b5SBjoern A. Zeeb static const u8 ac_to_fifo_mapping[IEEE80211_NUM_ACS] = {
323*b4c3e9b5SBjoern A. Zeeb 	[IEEE80211_AC_VO]	= TX_AC_VO_FIFO,
324*b4c3e9b5SBjoern A. Zeeb 	[IEEE80211_AC_VI]	= TX_AC_VI_FIFO,
325*b4c3e9b5SBjoern A. Zeeb 	[IEEE80211_AC_BE]	= TX_AC_BE_FIFO,
326*b4c3e9b5SBjoern A. Zeeb 	[IEEE80211_AC_BK]	= TX_AC_BK_FIFO,
327*b4c3e9b5SBjoern A. Zeeb };
328*b4c3e9b5SBjoern A. Zeeb 
329*b4c3e9b5SBjoern A. Zeeb /* Mapping of tx fifos to ieee80211 AC numbers */
330*b4c3e9b5SBjoern A. Zeeb static const u8 fifo_to_ac_mapping[IEEE80211_NUM_ACS] = {
331*b4c3e9b5SBjoern A. Zeeb 	[TX_AC_BK_FIFO]	= IEEE80211_AC_BK,
332*b4c3e9b5SBjoern A. Zeeb 	[TX_AC_BE_FIFO]	= IEEE80211_AC_BE,
333*b4c3e9b5SBjoern A. Zeeb 	[TX_AC_VI_FIFO]	= IEEE80211_AC_VI,
334*b4c3e9b5SBjoern A. Zeeb 	[TX_AC_VO_FIFO]	= IEEE80211_AC_VO,
335*b4c3e9b5SBjoern A. Zeeb };
336*b4c3e9b5SBjoern A. Zeeb 
brcms_ac_to_fifo(u8 ac)337*b4c3e9b5SBjoern A. Zeeb static u8 brcms_ac_to_fifo(u8 ac)
338*b4c3e9b5SBjoern A. Zeeb {
339*b4c3e9b5SBjoern A. Zeeb 	if (ac >= ARRAY_SIZE(ac_to_fifo_mapping))
340*b4c3e9b5SBjoern A. Zeeb 		return TX_AC_BE_FIFO;
341*b4c3e9b5SBjoern A. Zeeb 	return ac_to_fifo_mapping[ac];
342*b4c3e9b5SBjoern A. Zeeb }
343*b4c3e9b5SBjoern A. Zeeb 
brcms_fifo_to_ac(u8 fifo)344*b4c3e9b5SBjoern A. Zeeb static u8 brcms_fifo_to_ac(u8 fifo)
345*b4c3e9b5SBjoern A. Zeeb {
346*b4c3e9b5SBjoern A. Zeeb 	if (fifo >= ARRAY_SIZE(fifo_to_ac_mapping))
347*b4c3e9b5SBjoern A. Zeeb 		return IEEE80211_AC_BE;
348*b4c3e9b5SBjoern A. Zeeb 	return fifo_to_ac_mapping[fifo];
349*b4c3e9b5SBjoern A. Zeeb }
350*b4c3e9b5SBjoern A. Zeeb 
351*b4c3e9b5SBjoern A. Zeeb /* Find basic rate for a given rate */
brcms_basic_rate(struct brcms_c_info * wlc,u32 rspec)352*b4c3e9b5SBjoern A. Zeeb static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
353*b4c3e9b5SBjoern A. Zeeb {
354*b4c3e9b5SBjoern A. Zeeb 	if (is_mcs_rate(rspec))
355*b4c3e9b5SBjoern A. Zeeb 		return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
356*b4c3e9b5SBjoern A. Zeeb 		       .leg_ofdm];
357*b4c3e9b5SBjoern A. Zeeb 	return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
358*b4c3e9b5SBjoern A. Zeeb }
359*b4c3e9b5SBjoern A. Zeeb 
frametype(u32 rspec,u8 mimoframe)360*b4c3e9b5SBjoern A. Zeeb static u16 frametype(u32 rspec, u8 mimoframe)
361*b4c3e9b5SBjoern A. Zeeb {
362*b4c3e9b5SBjoern A. Zeeb 	if (is_mcs_rate(rspec))
363*b4c3e9b5SBjoern A. Zeeb 		return mimoframe;
364*b4c3e9b5SBjoern A. Zeeb 	return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;
365*b4c3e9b5SBjoern A. Zeeb }
366*b4c3e9b5SBjoern A. Zeeb 
367*b4c3e9b5SBjoern A. Zeeb /* currently the best mechanism for determining SIFS is the band in use */
get_sifs(struct brcms_band * band)368*b4c3e9b5SBjoern A. Zeeb static u16 get_sifs(struct brcms_band *band)
369*b4c3e9b5SBjoern A. Zeeb {
370*b4c3e9b5SBjoern A. Zeeb 	return band->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME :
371*b4c3e9b5SBjoern A. Zeeb 				 BPHY_SIFS_TIME;
372*b4c3e9b5SBjoern A. Zeeb }
373*b4c3e9b5SBjoern A. Zeeb 
374*b4c3e9b5SBjoern A. Zeeb /*
375*b4c3e9b5SBjoern A. Zeeb  * Detect Card removed.
376*b4c3e9b5SBjoern A. Zeeb  * Even checking an sbconfig register read will not false trigger when the core
377*b4c3e9b5SBjoern A. Zeeb  * is in reset it breaks CF address mechanism. Accessing gphy phyversion will
378*b4c3e9b5SBjoern A. Zeeb  * cause SB error if aphy is in reset on 4306B0-DB. Need a simple accessible
379*b4c3e9b5SBjoern A. Zeeb  * reg with fixed 0/1 pattern (some platforms return all 0).
380*b4c3e9b5SBjoern A. Zeeb  * If clocks are present, call the sb routine which will figure out if the
381*b4c3e9b5SBjoern A. Zeeb  * device is removed.
382*b4c3e9b5SBjoern A. Zeeb  */
brcms_deviceremoved(struct brcms_c_info * wlc)383*b4c3e9b5SBjoern A. Zeeb static bool brcms_deviceremoved(struct brcms_c_info *wlc)
384*b4c3e9b5SBjoern A. Zeeb {
385*b4c3e9b5SBjoern A. Zeeb 	u32 macctrl;
386*b4c3e9b5SBjoern A. Zeeb 
387*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->hw->clk)
388*b4c3e9b5SBjoern A. Zeeb 		return ai_deviceremoved(wlc->hw->sih);
389*b4c3e9b5SBjoern A. Zeeb 	macctrl = bcma_read32(wlc->hw->d11core,
390*b4c3e9b5SBjoern A. Zeeb 			      D11REGOFFS(maccontrol));
391*b4c3e9b5SBjoern A. Zeeb 	return (macctrl & (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN;
392*b4c3e9b5SBjoern A. Zeeb }
393*b4c3e9b5SBjoern A. Zeeb 
394*b4c3e9b5SBjoern A. Zeeb /* sum the individual fifo tx pending packet counts */
brcms_txpktpendtot(struct brcms_c_info * wlc)395*b4c3e9b5SBjoern A. Zeeb static int brcms_txpktpendtot(struct brcms_c_info *wlc)
396*b4c3e9b5SBjoern A. Zeeb {
397*b4c3e9b5SBjoern A. Zeeb 	int i;
398*b4c3e9b5SBjoern A. Zeeb 	int pending = 0;
399*b4c3e9b5SBjoern A. Zeeb 
400*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++)
401*b4c3e9b5SBjoern A. Zeeb 		if (wlc->hw->di[i])
402*b4c3e9b5SBjoern A. Zeeb 			pending += dma_txpending(wlc->hw->di[i]);
403*b4c3e9b5SBjoern A. Zeeb 	return pending;
404*b4c3e9b5SBjoern A. Zeeb }
405*b4c3e9b5SBjoern A. Zeeb 
brcms_is_mband_unlocked(struct brcms_c_info * wlc)406*b4c3e9b5SBjoern A. Zeeb static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc)
407*b4c3e9b5SBjoern A. Zeeb {
408*b4c3e9b5SBjoern A. Zeeb 	return wlc->pub->_nbands > 1 && !wlc->bandlocked;
409*b4c3e9b5SBjoern A. Zeeb }
410*b4c3e9b5SBjoern A. Zeeb 
brcms_chspec_bw(u16 chanspec)411*b4c3e9b5SBjoern A. Zeeb static int brcms_chspec_bw(u16 chanspec)
412*b4c3e9b5SBjoern A. Zeeb {
413*b4c3e9b5SBjoern A. Zeeb 	if (CHSPEC_IS40(chanspec))
414*b4c3e9b5SBjoern A. Zeeb 		return BRCMS_40_MHZ;
415*b4c3e9b5SBjoern A. Zeeb 	if (CHSPEC_IS20(chanspec))
416*b4c3e9b5SBjoern A. Zeeb 		return BRCMS_20_MHZ;
417*b4c3e9b5SBjoern A. Zeeb 
418*b4c3e9b5SBjoern A. Zeeb 	return BRCMS_10_MHZ;
419*b4c3e9b5SBjoern A. Zeeb }
420*b4c3e9b5SBjoern A. Zeeb 
brcms_c_bsscfg_mfree(struct brcms_bss_cfg * cfg)421*b4c3e9b5SBjoern A. Zeeb static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg)
422*b4c3e9b5SBjoern A. Zeeb {
423*b4c3e9b5SBjoern A. Zeeb 	if (cfg == NULL)
424*b4c3e9b5SBjoern A. Zeeb 		return;
425*b4c3e9b5SBjoern A. Zeeb 
426*b4c3e9b5SBjoern A. Zeeb 	kfree(cfg->current_bss);
427*b4c3e9b5SBjoern A. Zeeb 	kfree(cfg);
428*b4c3e9b5SBjoern A. Zeeb }
429*b4c3e9b5SBjoern A. Zeeb 
brcms_c_detach_mfree(struct brcms_c_info * wlc)430*b4c3e9b5SBjoern A. Zeeb static void brcms_c_detach_mfree(struct brcms_c_info *wlc)
431*b4c3e9b5SBjoern A. Zeeb {
432*b4c3e9b5SBjoern A. Zeeb 	if (wlc == NULL)
433*b4c3e9b5SBjoern A. Zeeb 		return;
434*b4c3e9b5SBjoern A. Zeeb 
435*b4c3e9b5SBjoern A. Zeeb 	brcms_c_bsscfg_mfree(wlc->bsscfg);
436*b4c3e9b5SBjoern A. Zeeb 	kfree(wlc->pub);
437*b4c3e9b5SBjoern A. Zeeb 	kfree(wlc->modulecb);
438*b4c3e9b5SBjoern A. Zeeb 	kfree(wlc->default_bss);
439*b4c3e9b5SBjoern A. Zeeb 	kfree(wlc->protection);
440*b4c3e9b5SBjoern A. Zeeb 	kfree(wlc->stf);
441*b4c3e9b5SBjoern A. Zeeb 	kfree(wlc->bandstate[0]);
442*b4c3e9b5SBjoern A. Zeeb 	if (wlc->corestate)
443*b4c3e9b5SBjoern A. Zeeb 		kfree(wlc->corestate->macstat_snapshot);
444*b4c3e9b5SBjoern A. Zeeb 	kfree(wlc->corestate);
445*b4c3e9b5SBjoern A. Zeeb 	if (wlc->hw)
446*b4c3e9b5SBjoern A. Zeeb 		kfree(wlc->hw->bandstate[0]);
447*b4c3e9b5SBjoern A. Zeeb 	kfree(wlc->hw);
448*b4c3e9b5SBjoern A. Zeeb 	if (wlc->beacon)
449*b4c3e9b5SBjoern A. Zeeb 		dev_kfree_skb_any(wlc->beacon);
450*b4c3e9b5SBjoern A. Zeeb 	if (wlc->probe_resp)
451*b4c3e9b5SBjoern A. Zeeb 		dev_kfree_skb_any(wlc->probe_resp);
452*b4c3e9b5SBjoern A. Zeeb 
453*b4c3e9b5SBjoern A. Zeeb 	kfree(wlc);
454*b4c3e9b5SBjoern A. Zeeb }
455*b4c3e9b5SBjoern A. Zeeb 
brcms_c_bsscfg_malloc(uint unit)456*b4c3e9b5SBjoern A. Zeeb static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit)
457*b4c3e9b5SBjoern A. Zeeb {
458*b4c3e9b5SBjoern A. Zeeb 	struct brcms_bss_cfg *cfg;
459*b4c3e9b5SBjoern A. Zeeb 
460*b4c3e9b5SBjoern A. Zeeb 	cfg = kzalloc(sizeof(*cfg), GFP_ATOMIC);
461*b4c3e9b5SBjoern A. Zeeb 	if (cfg == NULL)
462*b4c3e9b5SBjoern A. Zeeb 		goto fail;
463*b4c3e9b5SBjoern A. Zeeb 
464*b4c3e9b5SBjoern A. Zeeb 	cfg->current_bss = kzalloc(sizeof(*cfg->current_bss), GFP_ATOMIC);
465*b4c3e9b5SBjoern A. Zeeb 	if (cfg->current_bss == NULL)
466*b4c3e9b5SBjoern A. Zeeb 		goto fail;
467*b4c3e9b5SBjoern A. Zeeb 
468*b4c3e9b5SBjoern A. Zeeb 	return cfg;
469*b4c3e9b5SBjoern A. Zeeb 
470*b4c3e9b5SBjoern A. Zeeb  fail:
471*b4c3e9b5SBjoern A. Zeeb 	brcms_c_bsscfg_mfree(cfg);
472*b4c3e9b5SBjoern A. Zeeb 	return NULL;
473*b4c3e9b5SBjoern A. Zeeb }
474*b4c3e9b5SBjoern A. Zeeb 
475*b4c3e9b5SBjoern A. Zeeb static struct brcms_c_info *
brcms_c_attach_malloc(uint unit,uint * err,uint devid)476*b4c3e9b5SBjoern A. Zeeb brcms_c_attach_malloc(uint unit, uint *err, uint devid)
477*b4c3e9b5SBjoern A. Zeeb {
478*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_info *wlc;
479*b4c3e9b5SBjoern A. Zeeb 
480*b4c3e9b5SBjoern A. Zeeb 	wlc = kzalloc(sizeof(*wlc), GFP_ATOMIC);
481*b4c3e9b5SBjoern A. Zeeb 	if (wlc == NULL) {
482*b4c3e9b5SBjoern A. Zeeb 		*err = 1002;
483*b4c3e9b5SBjoern A. Zeeb 		goto fail;
484*b4c3e9b5SBjoern A. Zeeb 	}
485*b4c3e9b5SBjoern A. Zeeb 
486*b4c3e9b5SBjoern A. Zeeb 	/* allocate struct brcms_c_pub state structure */
487*b4c3e9b5SBjoern A. Zeeb 	wlc->pub = kzalloc(sizeof(*wlc->pub), GFP_ATOMIC);
488*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub == NULL) {
489*b4c3e9b5SBjoern A. Zeeb 		*err = 1003;
490*b4c3e9b5SBjoern A. Zeeb 		goto fail;
491*b4c3e9b5SBjoern A. Zeeb 	}
492*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->wlc = wlc;
493*b4c3e9b5SBjoern A. Zeeb 
494*b4c3e9b5SBjoern A. Zeeb 	/* allocate struct brcms_hardware state structure */
495*b4c3e9b5SBjoern A. Zeeb 
496*b4c3e9b5SBjoern A. Zeeb 	wlc->hw = kzalloc(sizeof(*wlc->hw), GFP_ATOMIC);
497*b4c3e9b5SBjoern A. Zeeb 	if (wlc->hw == NULL) {
498*b4c3e9b5SBjoern A. Zeeb 		*err = 1005;
499*b4c3e9b5SBjoern A. Zeeb 		goto fail;
500*b4c3e9b5SBjoern A. Zeeb 	}
501*b4c3e9b5SBjoern A. Zeeb 	wlc->hw->wlc = wlc;
502*b4c3e9b5SBjoern A. Zeeb 
503*b4c3e9b5SBjoern A. Zeeb 	wlc->hw->bandstate[0] =
504*b4c3e9b5SBjoern A. Zeeb 		kcalloc(MAXBANDS, sizeof(struct brcms_hw_band), GFP_ATOMIC);
505*b4c3e9b5SBjoern A. Zeeb 	if (wlc->hw->bandstate[0] == NULL) {
506*b4c3e9b5SBjoern A. Zeeb 		*err = 1006;
507*b4c3e9b5SBjoern A. Zeeb 		goto fail;
508*b4c3e9b5SBjoern A. Zeeb 	} else {
509*b4c3e9b5SBjoern A. Zeeb 		int i;
510*b4c3e9b5SBjoern A. Zeeb 
511*b4c3e9b5SBjoern A. Zeeb 		for (i = 1; i < MAXBANDS; i++)
512*b4c3e9b5SBjoern A. Zeeb 			wlc->hw->bandstate[i] = (struct brcms_hw_band *)
513*b4c3e9b5SBjoern A. Zeeb 			    ((unsigned long)wlc->hw->bandstate[0] +
514*b4c3e9b5SBjoern A. Zeeb 			     (sizeof(struct brcms_hw_band) * i));
515*b4c3e9b5SBjoern A. Zeeb 	}
516*b4c3e9b5SBjoern A. Zeeb 
517*b4c3e9b5SBjoern A. Zeeb 	wlc->modulecb =
518*b4c3e9b5SBjoern A. Zeeb 		kcalloc(BRCMS_MAXMODULES, sizeof(struct modulecb),
519*b4c3e9b5SBjoern A. Zeeb 			GFP_ATOMIC);
520*b4c3e9b5SBjoern A. Zeeb 	if (wlc->modulecb == NULL) {
521*b4c3e9b5SBjoern A. Zeeb 		*err = 1009;
522*b4c3e9b5SBjoern A. Zeeb 		goto fail;
523*b4c3e9b5SBjoern A. Zeeb 	}
524*b4c3e9b5SBjoern A. Zeeb 
525*b4c3e9b5SBjoern A. Zeeb 	wlc->default_bss = kzalloc(sizeof(*wlc->default_bss), GFP_ATOMIC);
526*b4c3e9b5SBjoern A. Zeeb 	if (wlc->default_bss == NULL) {
527*b4c3e9b5SBjoern A. Zeeb 		*err = 1010;
528*b4c3e9b5SBjoern A. Zeeb 		goto fail;
529*b4c3e9b5SBjoern A. Zeeb 	}
530*b4c3e9b5SBjoern A. Zeeb 
531*b4c3e9b5SBjoern A. Zeeb 	wlc->bsscfg = brcms_c_bsscfg_malloc(unit);
532*b4c3e9b5SBjoern A. Zeeb 	if (wlc->bsscfg == NULL) {
533*b4c3e9b5SBjoern A. Zeeb 		*err = 1011;
534*b4c3e9b5SBjoern A. Zeeb 		goto fail;
535*b4c3e9b5SBjoern A. Zeeb 	}
536*b4c3e9b5SBjoern A. Zeeb 
537*b4c3e9b5SBjoern A. Zeeb 	wlc->protection = kzalloc(sizeof(*wlc->protection), GFP_ATOMIC);
538*b4c3e9b5SBjoern A. Zeeb 	if (wlc->protection == NULL) {
539*b4c3e9b5SBjoern A. Zeeb 		*err = 1016;
540*b4c3e9b5SBjoern A. Zeeb 		goto fail;
541*b4c3e9b5SBjoern A. Zeeb 	}
542*b4c3e9b5SBjoern A. Zeeb 
543*b4c3e9b5SBjoern A. Zeeb 	wlc->stf = kzalloc(sizeof(*wlc->stf), GFP_ATOMIC);
544*b4c3e9b5SBjoern A. Zeeb 	if (wlc->stf == NULL) {
545*b4c3e9b5SBjoern A. Zeeb 		*err = 1017;
546*b4c3e9b5SBjoern A. Zeeb 		goto fail;
547*b4c3e9b5SBjoern A. Zeeb 	}
548*b4c3e9b5SBjoern A. Zeeb 
549*b4c3e9b5SBjoern A. Zeeb 	wlc->bandstate[0] =
550*b4c3e9b5SBjoern A. Zeeb 		kcalloc(MAXBANDS, sizeof(*wlc->bandstate[0]), GFP_ATOMIC);
551*b4c3e9b5SBjoern A. Zeeb 	if (wlc->bandstate[0] == NULL) {
552*b4c3e9b5SBjoern A. Zeeb 		*err = 1025;
553*b4c3e9b5SBjoern A. Zeeb 		goto fail;
554*b4c3e9b5SBjoern A. Zeeb 	} else {
555*b4c3e9b5SBjoern A. Zeeb 		int i;
556*b4c3e9b5SBjoern A. Zeeb 
557*b4c3e9b5SBjoern A. Zeeb 		for (i = 1; i < MAXBANDS; i++)
558*b4c3e9b5SBjoern A. Zeeb 			wlc->bandstate[i] = (struct brcms_band *)
559*b4c3e9b5SBjoern A. Zeeb 				((unsigned long)wlc->bandstate[0]
560*b4c3e9b5SBjoern A. Zeeb 				+ (sizeof(struct brcms_band)*i));
561*b4c3e9b5SBjoern A. Zeeb 	}
562*b4c3e9b5SBjoern A. Zeeb 
563*b4c3e9b5SBjoern A. Zeeb 	wlc->corestate = kzalloc(sizeof(*wlc->corestate), GFP_ATOMIC);
564*b4c3e9b5SBjoern A. Zeeb 	if (wlc->corestate == NULL) {
565*b4c3e9b5SBjoern A. Zeeb 		*err = 1026;
566*b4c3e9b5SBjoern A. Zeeb 		goto fail;
567*b4c3e9b5SBjoern A. Zeeb 	}
568*b4c3e9b5SBjoern A. Zeeb 
569*b4c3e9b5SBjoern A. Zeeb 	wlc->corestate->macstat_snapshot =
570*b4c3e9b5SBjoern A. Zeeb 		kzalloc(sizeof(*wlc->corestate->macstat_snapshot), GFP_ATOMIC);
571*b4c3e9b5SBjoern A. Zeeb 	if (wlc->corestate->macstat_snapshot == NULL) {
572*b4c3e9b5SBjoern A. Zeeb 		*err = 1027;
573*b4c3e9b5SBjoern A. Zeeb 		goto fail;
574*b4c3e9b5SBjoern A. Zeeb 	}
575*b4c3e9b5SBjoern A. Zeeb 
576*b4c3e9b5SBjoern A. Zeeb 	return wlc;
577*b4c3e9b5SBjoern A. Zeeb 
578*b4c3e9b5SBjoern A. Zeeb  fail:
579*b4c3e9b5SBjoern A. Zeeb 	brcms_c_detach_mfree(wlc);
580*b4c3e9b5SBjoern A. Zeeb 	return NULL;
581*b4c3e9b5SBjoern A. Zeeb }
582*b4c3e9b5SBjoern A. Zeeb 
583*b4c3e9b5SBjoern A. Zeeb /*
584*b4c3e9b5SBjoern A. Zeeb  * Update the slot timing for standard 11b/g (20us slots)
585*b4c3e9b5SBjoern A. Zeeb  * or shortslot 11g (9us slots)
586*b4c3e9b5SBjoern A. Zeeb  * The PSM needs to be suspended for this call.
587*b4c3e9b5SBjoern A. Zeeb  */
brcms_b_update_slot_timing(struct brcms_hardware * wlc_hw,bool shortslot)588*b4c3e9b5SBjoern A. Zeeb static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
589*b4c3e9b5SBjoern A. Zeeb 					bool shortslot)
590*b4c3e9b5SBjoern A. Zeeb {
591*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
592*b4c3e9b5SBjoern A. Zeeb 
593*b4c3e9b5SBjoern A. Zeeb 	if (shortslot) {
594*b4c3e9b5SBjoern A. Zeeb 		/* 11g short slot: 11a timing */
595*b4c3e9b5SBjoern A. Zeeb 		bcma_write16(core, D11REGOFFS(ifs_slot), 0x0207);
596*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, APHY_SLOT_TIME);
597*b4c3e9b5SBjoern A. Zeeb 	} else {
598*b4c3e9b5SBjoern A. Zeeb 		/* 11g long slot: 11b timing */
599*b4c3e9b5SBjoern A. Zeeb 		bcma_write16(core, D11REGOFFS(ifs_slot), 0x0212);
600*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, BPHY_SLOT_TIME);
601*b4c3e9b5SBjoern A. Zeeb 	}
602*b4c3e9b5SBjoern A. Zeeb }
603*b4c3e9b5SBjoern A. Zeeb 
604*b4c3e9b5SBjoern A. Zeeb /*
605*b4c3e9b5SBjoern A. Zeeb  * calculate frame duration of a given rate and length, return
606*b4c3e9b5SBjoern A. Zeeb  * time in usec unit
607*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_calc_frame_time(struct brcms_c_info * wlc,u32 ratespec,u8 preamble_type,uint mac_len)608*b4c3e9b5SBjoern A. Zeeb static uint brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
609*b4c3e9b5SBjoern A. Zeeb 				    u8 preamble_type, uint mac_len)
610*b4c3e9b5SBjoern A. Zeeb {
611*b4c3e9b5SBjoern A. Zeeb 	uint nsyms, dur = 0, Ndps, kNdps;
612*b4c3e9b5SBjoern A. Zeeb 	uint rate = rspec2rate(ratespec);
613*b4c3e9b5SBjoern A. Zeeb 
614*b4c3e9b5SBjoern A. Zeeb 	if (rate == 0) {
615*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "wl%d: WAR: using rate of 1 mbps\n",
616*b4c3e9b5SBjoern A. Zeeb 			  wlc->pub->unit);
617*b4c3e9b5SBjoern A. Zeeb 		rate = BRCM_RATE_1M;
618*b4c3e9b5SBjoern A. Zeeb 	}
619*b4c3e9b5SBjoern A. Zeeb 
620*b4c3e9b5SBjoern A. Zeeb 	if (is_mcs_rate(ratespec)) {
621*b4c3e9b5SBjoern A. Zeeb 		uint mcs = ratespec & RSPEC_RATE_MASK;
622*b4c3e9b5SBjoern A. Zeeb 		int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
623*b4c3e9b5SBjoern A. Zeeb 
624*b4c3e9b5SBjoern A. Zeeb 		dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
625*b4c3e9b5SBjoern A. Zeeb 		if (preamble_type == BRCMS_MM_PREAMBLE)
626*b4c3e9b5SBjoern A. Zeeb 			dur += PREN_MM_EXT;
627*b4c3e9b5SBjoern A. Zeeb 		/* 1000Ndbps = kbps * 4 */
628*b4c3e9b5SBjoern A. Zeeb 		kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
629*b4c3e9b5SBjoern A. Zeeb 				   rspec_issgi(ratespec)) * 4;
630*b4c3e9b5SBjoern A. Zeeb 
631*b4c3e9b5SBjoern A. Zeeb 		if (rspec_stc(ratespec) == 0)
632*b4c3e9b5SBjoern A. Zeeb 			nsyms =
633*b4c3e9b5SBjoern A. Zeeb 			    CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
634*b4c3e9b5SBjoern A. Zeeb 				  APHY_TAIL_NBITS) * 1000, kNdps);
635*b4c3e9b5SBjoern A. Zeeb 		else
636*b4c3e9b5SBjoern A. Zeeb 			/* STBC needs to have even number of symbols */
637*b4c3e9b5SBjoern A. Zeeb 			nsyms =
638*b4c3e9b5SBjoern A. Zeeb 			    2 *
639*b4c3e9b5SBjoern A. Zeeb 			    CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
640*b4c3e9b5SBjoern A. Zeeb 				  APHY_TAIL_NBITS) * 1000, 2 * kNdps);
641*b4c3e9b5SBjoern A. Zeeb 
642*b4c3e9b5SBjoern A. Zeeb 		dur += APHY_SYMBOL_TIME * nsyms;
643*b4c3e9b5SBjoern A. Zeeb 		if (wlc->band->bandtype == BRCM_BAND_2G)
644*b4c3e9b5SBjoern A. Zeeb 			dur += DOT11_OFDM_SIGNAL_EXTENSION;
645*b4c3e9b5SBjoern A. Zeeb 	} else if (is_ofdm_rate(rate)) {
646*b4c3e9b5SBjoern A. Zeeb 		dur = APHY_PREAMBLE_TIME;
647*b4c3e9b5SBjoern A. Zeeb 		dur += APHY_SIGNAL_TIME;
648*b4c3e9b5SBjoern A. Zeeb 		/* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
649*b4c3e9b5SBjoern A. Zeeb 		Ndps = rate * 2;
650*b4c3e9b5SBjoern A. Zeeb 		/* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
651*b4c3e9b5SBjoern A. Zeeb 		nsyms =
652*b4c3e9b5SBjoern A. Zeeb 		    CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS),
653*b4c3e9b5SBjoern A. Zeeb 			 Ndps);
654*b4c3e9b5SBjoern A. Zeeb 		dur += APHY_SYMBOL_TIME * nsyms;
655*b4c3e9b5SBjoern A. Zeeb 		if (wlc->band->bandtype == BRCM_BAND_2G)
656*b4c3e9b5SBjoern A. Zeeb 			dur += DOT11_OFDM_SIGNAL_EXTENSION;
657*b4c3e9b5SBjoern A. Zeeb 	} else {
658*b4c3e9b5SBjoern A. Zeeb 		/*
659*b4c3e9b5SBjoern A. Zeeb 		 * calc # bits * 2 so factor of 2 in rate (1/2 mbps)
660*b4c3e9b5SBjoern A. Zeeb 		 * will divide out
661*b4c3e9b5SBjoern A. Zeeb 		 */
662*b4c3e9b5SBjoern A. Zeeb 		mac_len = mac_len * 8 * 2;
663*b4c3e9b5SBjoern A. Zeeb 		/* calc ceiling of bits/rate = microseconds of air time */
664*b4c3e9b5SBjoern A. Zeeb 		dur = (mac_len + rate - 1) / rate;
665*b4c3e9b5SBjoern A. Zeeb 		if (preamble_type & BRCMS_SHORT_PREAMBLE)
666*b4c3e9b5SBjoern A. Zeeb 			dur += BPHY_PLCP_SHORT_TIME;
667*b4c3e9b5SBjoern A. Zeeb 		else
668*b4c3e9b5SBjoern A. Zeeb 			dur += BPHY_PLCP_TIME;
669*b4c3e9b5SBjoern A. Zeeb 	}
670*b4c3e9b5SBjoern A. Zeeb 	return dur;
671*b4c3e9b5SBjoern A. Zeeb }
672*b4c3e9b5SBjoern A. Zeeb 
brcms_c_write_inits(struct brcms_hardware * wlc_hw,const struct d11init * inits)673*b4c3e9b5SBjoern A. Zeeb static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
674*b4c3e9b5SBjoern A. Zeeb 				const struct d11init *inits)
675*b4c3e9b5SBjoern A. Zeeb {
676*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
677*b4c3e9b5SBjoern A. Zeeb 	int i;
678*b4c3e9b5SBjoern A. Zeeb 	uint offset;
679*b4c3e9b5SBjoern A. Zeeb 	u16 size;
680*b4c3e9b5SBjoern A. Zeeb 	u32 value;
681*b4c3e9b5SBjoern A. Zeeb 
682*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);
683*b4c3e9b5SBjoern A. Zeeb 
684*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; inits[i].addr != cpu_to_le16(0xffff); i++) {
685*b4c3e9b5SBjoern A. Zeeb 		size = le16_to_cpu(inits[i].size);
686*b4c3e9b5SBjoern A. Zeeb 		offset = le16_to_cpu(inits[i].addr);
687*b4c3e9b5SBjoern A. Zeeb 		value = le32_to_cpu(inits[i].value);
688*b4c3e9b5SBjoern A. Zeeb 		if (size == 2)
689*b4c3e9b5SBjoern A. Zeeb 			bcma_write16(core, offset, value);
690*b4c3e9b5SBjoern A. Zeeb 		else if (size == 4)
691*b4c3e9b5SBjoern A. Zeeb 			bcma_write32(core, offset, value);
692*b4c3e9b5SBjoern A. Zeeb 		else
693*b4c3e9b5SBjoern A. Zeeb 			break;
694*b4c3e9b5SBjoern A. Zeeb 	}
695*b4c3e9b5SBjoern A. Zeeb }
696*b4c3e9b5SBjoern A. Zeeb 
brcms_c_write_mhf(struct brcms_hardware * wlc_hw,u16 * mhfs)697*b4c3e9b5SBjoern A. Zeeb static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs)
698*b4c3e9b5SBjoern A. Zeeb {
699*b4c3e9b5SBjoern A. Zeeb 	u8 idx;
700*b4c3e9b5SBjoern A. Zeeb 	static const u16 addr[] = {
701*b4c3e9b5SBjoern A. Zeeb 		M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
702*b4c3e9b5SBjoern A. Zeeb 		M_HOST_FLAGS5
703*b4c3e9b5SBjoern A. Zeeb 	};
704*b4c3e9b5SBjoern A. Zeeb 
705*b4c3e9b5SBjoern A. Zeeb 	for (idx = 0; idx < MHFMAX; idx++)
706*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc_hw, addr[idx], mhfs[idx]);
707*b4c3e9b5SBjoern A. Zeeb }
708*b4c3e9b5SBjoern A. Zeeb 
brcms_c_ucode_bsinit(struct brcms_hardware * wlc_hw)709*b4c3e9b5SBjoern A. Zeeb static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw)
710*b4c3e9b5SBjoern A. Zeeb {
711*b4c3e9b5SBjoern A. Zeeb 	struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
712*b4c3e9b5SBjoern A. Zeeb 
713*b4c3e9b5SBjoern A. Zeeb 	/* init microcode host flags */
714*b4c3e9b5SBjoern A. Zeeb 	brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);
715*b4c3e9b5SBjoern A. Zeeb 
716*b4c3e9b5SBjoern A. Zeeb 	/* do band-specific ucode IHR, SHM, and SCR inits */
717*b4c3e9b5SBjoern A. Zeeb 	if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
718*b4c3e9b5SBjoern A. Zeeb 		if (BRCMS_ISNPHY(wlc_hw->band))
719*b4c3e9b5SBjoern A. Zeeb 			brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);
720*b4c3e9b5SBjoern A. Zeeb 		else
721*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc_hw->d11core,
722*b4c3e9b5SBjoern A. Zeeb 				  "%s: wl%d: unsupported phy in corerev %d\n",
723*b4c3e9b5SBjoern A. Zeeb 				  __func__, wlc_hw->unit,
724*b4c3e9b5SBjoern A. Zeeb 				  wlc_hw->corerev);
725*b4c3e9b5SBjoern A. Zeeb 	} else {
726*b4c3e9b5SBjoern A. Zeeb 		if (D11REV_IS(wlc_hw->corerev, 24)) {
727*b4c3e9b5SBjoern A. Zeeb 			if (BRCMS_ISLCNPHY(wlc_hw->band))
728*b4c3e9b5SBjoern A. Zeeb 				brcms_c_write_inits(wlc_hw,
729*b4c3e9b5SBjoern A. Zeeb 						    ucode->d11lcn0bsinitvals24);
730*b4c3e9b5SBjoern A. Zeeb 			else
731*b4c3e9b5SBjoern A. Zeeb 				brcms_err(wlc_hw->d11core,
732*b4c3e9b5SBjoern A. Zeeb 					  "%s: wl%d: unsupported phy in core rev %d\n",
733*b4c3e9b5SBjoern A. Zeeb 					  __func__, wlc_hw->unit,
734*b4c3e9b5SBjoern A. Zeeb 					  wlc_hw->corerev);
735*b4c3e9b5SBjoern A. Zeeb 		} else {
736*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc_hw->d11core,
737*b4c3e9b5SBjoern A. Zeeb 				  "%s: wl%d: unsupported corerev %d\n",
738*b4c3e9b5SBjoern A. Zeeb 				  __func__, wlc_hw->unit, wlc_hw->corerev);
739*b4c3e9b5SBjoern A. Zeeb 		}
740*b4c3e9b5SBjoern A. Zeeb 	}
741*b4c3e9b5SBjoern A. Zeeb }
742*b4c3e9b5SBjoern A. Zeeb 
brcms_b_core_ioctl(struct brcms_hardware * wlc_hw,u32 m,u32 v)743*b4c3e9b5SBjoern A. Zeeb static void brcms_b_core_ioctl(struct brcms_hardware *wlc_hw, u32 m, u32 v)
744*b4c3e9b5SBjoern A. Zeeb {
745*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
746*b4c3e9b5SBjoern A. Zeeb 	u32 ioctl = bcma_aread32(core, BCMA_IOCTL) & ~m;
747*b4c3e9b5SBjoern A. Zeeb 
748*b4c3e9b5SBjoern A. Zeeb 	bcma_awrite32(core, BCMA_IOCTL, ioctl | v);
749*b4c3e9b5SBjoern A. Zeeb }
750*b4c3e9b5SBjoern A. Zeeb 
brcms_b_core_phy_clk(struct brcms_hardware * wlc_hw,bool clk)751*b4c3e9b5SBjoern A. Zeeb static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk)
752*b4c3e9b5SBjoern A. Zeeb {
753*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc_hw->d11core, "wl%d: clk %d\n", wlc_hw->unit, clk);
754*b4c3e9b5SBjoern A. Zeeb 
755*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->phyclk = clk;
756*b4c3e9b5SBjoern A. Zeeb 
757*b4c3e9b5SBjoern A. Zeeb 	if (OFF == clk) {	/* clear gmode bit, put phy into reset */
758*b4c3e9b5SBjoern A. Zeeb 
759*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC | SICF_GMODE),
760*b4c3e9b5SBjoern A. Zeeb 				   (SICF_PRST | SICF_FGC));
761*b4c3e9b5SBjoern A. Zeeb 		udelay(1);
762*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC), SICF_PRST);
763*b4c3e9b5SBjoern A. Zeeb 		udelay(1);
764*b4c3e9b5SBjoern A. Zeeb 
765*b4c3e9b5SBjoern A. Zeeb 	} else {		/* take phy out of reset */
766*b4c3e9b5SBjoern A. Zeeb 
767*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC), SICF_FGC);
768*b4c3e9b5SBjoern A. Zeeb 		udelay(1);
769*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw, SICF_FGC, 0);
770*b4c3e9b5SBjoern A. Zeeb 		udelay(1);
771*b4c3e9b5SBjoern A. Zeeb 
772*b4c3e9b5SBjoern A. Zeeb 	}
773*b4c3e9b5SBjoern A. Zeeb }
774*b4c3e9b5SBjoern A. Zeeb 
775*b4c3e9b5SBjoern A. Zeeb /* low-level band switch utility routine */
brcms_c_setxband(struct brcms_hardware * wlc_hw,uint bandunit)776*b4c3e9b5SBjoern A. Zeeb static void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit)
777*b4c3e9b5SBjoern A. Zeeb {
778*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: bandunit %d\n", wlc_hw->unit,
779*b4c3e9b5SBjoern A. Zeeb 			   bandunit);
780*b4c3e9b5SBjoern A. Zeeb 
781*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->band = wlc_hw->bandstate[bandunit];
782*b4c3e9b5SBjoern A. Zeeb 
783*b4c3e9b5SBjoern A. Zeeb 	/*
784*b4c3e9b5SBjoern A. Zeeb 	 * BMAC_NOTE:
785*b4c3e9b5SBjoern A. Zeeb 	 *   until we eliminate need for wlc->band refs in low level code
786*b4c3e9b5SBjoern A. Zeeb 	 */
787*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit];
788*b4c3e9b5SBjoern A. Zeeb 
789*b4c3e9b5SBjoern A. Zeeb 	/* set gmode core flag */
790*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->sbclk && !wlc_hw->noreset) {
791*b4c3e9b5SBjoern A. Zeeb 		u32 gmode = 0;
792*b4c3e9b5SBjoern A. Zeeb 
793*b4c3e9b5SBjoern A. Zeeb 		if (bandunit == 0)
794*b4c3e9b5SBjoern A. Zeeb 			gmode = SICF_GMODE;
795*b4c3e9b5SBjoern A. Zeeb 
796*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw, SICF_GMODE, gmode);
797*b4c3e9b5SBjoern A. Zeeb 	}
798*b4c3e9b5SBjoern A. Zeeb }
799*b4c3e9b5SBjoern A. Zeeb 
800*b4c3e9b5SBjoern A. Zeeb /* switch to new band but leave it inactive */
brcms_c_setband_inact(struct brcms_c_info * wlc,uint bandunit)801*b4c3e9b5SBjoern A. Zeeb static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)
802*b4c3e9b5SBjoern A. Zeeb {
803*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
804*b4c3e9b5SBjoern A. Zeeb 	u32 macintmask;
805*b4c3e9b5SBjoern A. Zeeb 	u32 macctrl;
806*b4c3e9b5SBjoern A. Zeeb 
807*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_mac80211(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);
808*b4c3e9b5SBjoern A. Zeeb 	macctrl = bcma_read32(wlc_hw->d11core,
809*b4c3e9b5SBjoern A. Zeeb 			      D11REGOFFS(maccontrol));
810*b4c3e9b5SBjoern A. Zeeb 	WARN_ON((macctrl & MCTL_EN_MAC) != 0);
811*b4c3e9b5SBjoern A. Zeeb 
812*b4c3e9b5SBjoern A. Zeeb 	/* disable interrupts */
813*b4c3e9b5SBjoern A. Zeeb 	macintmask = brcms_intrsoff(wlc->wl);
814*b4c3e9b5SBjoern A. Zeeb 
815*b4c3e9b5SBjoern A. Zeeb 	/* radio off */
816*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
817*b4c3e9b5SBjoern A. Zeeb 
818*b4c3e9b5SBjoern A. Zeeb 	brcms_b_core_phy_clk(wlc_hw, OFF);
819*b4c3e9b5SBjoern A. Zeeb 
820*b4c3e9b5SBjoern A. Zeeb 	brcms_c_setxband(wlc_hw, bandunit);
821*b4c3e9b5SBjoern A. Zeeb 
822*b4c3e9b5SBjoern A. Zeeb 	return macintmask;
823*b4c3e9b5SBjoern A. Zeeb }
824*b4c3e9b5SBjoern A. Zeeb 
825*b4c3e9b5SBjoern A. Zeeb /* process an individual struct tx_status */
826*b4c3e9b5SBjoern A. Zeeb static bool
brcms_c_dotxstatus(struct brcms_c_info * wlc,struct tx_status * txs)827*b4c3e9b5SBjoern A. Zeeb brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
828*b4c3e9b5SBjoern A. Zeeb {
829*b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *p = NULL;
830*b4c3e9b5SBjoern A. Zeeb 	uint queue = NFIFO;
831*b4c3e9b5SBjoern A. Zeeb 	struct dma_pub *dma = NULL;
832*b4c3e9b5SBjoern A. Zeeb 	struct d11txh *txh = NULL;
833*b4c3e9b5SBjoern A. Zeeb 	struct scb *scb = NULL;
834*b4c3e9b5SBjoern A. Zeeb 	int tx_frame_count;
835*b4c3e9b5SBjoern A. Zeeb 	uint supr_status;
836*b4c3e9b5SBjoern A. Zeeb 	bool lastframe;
837*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_hdr *h;
838*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_tx_info *tx_info;
839*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_tx_rate *txrate;
840*b4c3e9b5SBjoern A. Zeeb 	int i;
841*b4c3e9b5SBjoern A. Zeeb 	bool fatal = true;
842*b4c3e9b5SBjoern A. Zeeb 
843*b4c3e9b5SBjoern A. Zeeb 	trace_brcms_txstatus(&wlc->hw->d11core->dev, txs->framelen,
844*b4c3e9b5SBjoern A. Zeeb 			     txs->frameid, txs->status, txs->lasttxtime,
845*b4c3e9b5SBjoern A. Zeeb 			     txs->sequence, txs->phyerr, txs->ackphyrxsh);
846*b4c3e9b5SBjoern A. Zeeb 
847*b4c3e9b5SBjoern A. Zeeb 	/* discard intermediate indications for ucode with one legitimate case:
848*b4c3e9b5SBjoern A. Zeeb 	 *   e.g. if "useRTS" is set. ucode did a successful rts/cts exchange,
849*b4c3e9b5SBjoern A. Zeeb 	 *   but the subsequent tx of DATA failed. so it will start rts/cts
850*b4c3e9b5SBjoern A. Zeeb 	 *   from the beginning (resetting the rts transmission count)
851*b4c3e9b5SBjoern A. Zeeb 	 */
852*b4c3e9b5SBjoern A. Zeeb 	if (!(txs->status & TX_STATUS_AMPDU)
853*b4c3e9b5SBjoern A. Zeeb 	    && (txs->status & TX_STATUS_INTERMEDIATE)) {
854*b4c3e9b5SBjoern A. Zeeb 		brcms_dbg_tx(wlc->hw->d11core, "INTERMEDIATE but not AMPDU\n");
855*b4c3e9b5SBjoern A. Zeeb 		fatal = false;
856*b4c3e9b5SBjoern A. Zeeb 		goto out;
857*b4c3e9b5SBjoern A. Zeeb 	}
858*b4c3e9b5SBjoern A. Zeeb 
859*b4c3e9b5SBjoern A. Zeeb 	queue = txs->frameid & TXFID_QUEUE_MASK;
860*b4c3e9b5SBjoern A. Zeeb 	if (queue >= NFIFO) {
861*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "queue %u >= NFIFO\n", queue);
862*b4c3e9b5SBjoern A. Zeeb 		goto out;
863*b4c3e9b5SBjoern A. Zeeb 	}
864*b4c3e9b5SBjoern A. Zeeb 
865*b4c3e9b5SBjoern A. Zeeb 	dma = wlc->hw->di[queue];
866*b4c3e9b5SBjoern A. Zeeb 
867*b4c3e9b5SBjoern A. Zeeb 	p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
868*b4c3e9b5SBjoern A. Zeeb 	if (p == NULL) {
869*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "dma_getnexttxp returned null!\n");
870*b4c3e9b5SBjoern A. Zeeb 		goto out;
871*b4c3e9b5SBjoern A. Zeeb 	}
872*b4c3e9b5SBjoern A. Zeeb 
873*b4c3e9b5SBjoern A. Zeeb 	txh = (struct d11txh *) (p->data);
874*b4c3e9b5SBjoern A. Zeeb 
875*b4c3e9b5SBjoern A. Zeeb 	if (txs->phyerr)
876*b4c3e9b5SBjoern A. Zeeb 		brcms_dbg_tx(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n",
877*b4c3e9b5SBjoern A. Zeeb 			     txs->phyerr, txh->MainRates);
878*b4c3e9b5SBjoern A. Zeeb 
879*b4c3e9b5SBjoern A. Zeeb 	if (txs->frameid != le16_to_cpu(txh->TxFrameID)) {
880*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "frameid != txh->TxFrameID\n");
881*b4c3e9b5SBjoern A. Zeeb 		goto out;
882*b4c3e9b5SBjoern A. Zeeb 	}
883*b4c3e9b5SBjoern A. Zeeb 	tx_info = IEEE80211_SKB_CB(p);
884*b4c3e9b5SBjoern A. Zeeb 	h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
885*b4c3e9b5SBjoern A. Zeeb 
886*b4c3e9b5SBjoern A. Zeeb 	if (tx_info->rate_driver_data[0])
887*b4c3e9b5SBjoern A. Zeeb 		scb = &wlc->pri_scb;
888*b4c3e9b5SBjoern A. Zeeb 
889*b4c3e9b5SBjoern A. Zeeb 	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
890*b4c3e9b5SBjoern A. Zeeb 		brcms_c_ampdu_dotxstatus(wlc->ampdu, scb, p, txs);
891*b4c3e9b5SBjoern A. Zeeb 		fatal = false;
892*b4c3e9b5SBjoern A. Zeeb 		goto out;
893*b4c3e9b5SBjoern A. Zeeb 	}
894*b4c3e9b5SBjoern A. Zeeb 
895*b4c3e9b5SBjoern A. Zeeb 	/*
896*b4c3e9b5SBjoern A. Zeeb 	 * brcms_c_ampdu_dotxstatus() will trace tx descriptors for AMPDU
897*b4c3e9b5SBjoern A. Zeeb 	 * frames; this traces them for the rest.
898*b4c3e9b5SBjoern A. Zeeb 	 */
899*b4c3e9b5SBjoern A. Zeeb 	trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, sizeof(*txh));
900*b4c3e9b5SBjoern A. Zeeb 
901*b4c3e9b5SBjoern A. Zeeb 	supr_status = txs->status & TX_STATUS_SUPR_MASK;
902*b4c3e9b5SBjoern A. Zeeb 	if (supr_status == TX_STATUS_SUPR_BADCH) {
903*b4c3e9b5SBjoern A. Zeeb 		unsigned xfts = le16_to_cpu(txh->XtraFrameTypes);
904*b4c3e9b5SBjoern A. Zeeb 		brcms_dbg_tx(wlc->hw->d11core,
905*b4c3e9b5SBjoern A. Zeeb 			     "Pkt tx suppressed, dest chan %u, current %d\n",
906*b4c3e9b5SBjoern A. Zeeb 			     (xfts >> XFTS_CHANNEL_SHIFT) & 0xff,
907*b4c3e9b5SBjoern A. Zeeb 			     CHSPEC_CHANNEL(wlc->default_bss->chanspec));
908*b4c3e9b5SBjoern A. Zeeb 	}
909*b4c3e9b5SBjoern A. Zeeb 
910*b4c3e9b5SBjoern A. Zeeb 	tx_frame_count =
911*b4c3e9b5SBjoern A. Zeeb 	    (txs->status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT;
912*b4c3e9b5SBjoern A. Zeeb 
913*b4c3e9b5SBjoern A. Zeeb 	lastframe = !ieee80211_has_morefrags(h->frame_control);
914*b4c3e9b5SBjoern A. Zeeb 
915*b4c3e9b5SBjoern A. Zeeb 	if (!lastframe) {
916*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "Not last frame!\n");
917*b4c3e9b5SBjoern A. Zeeb 	} else {
918*b4c3e9b5SBjoern A. Zeeb 		/*
919*b4c3e9b5SBjoern A. Zeeb 		 * Set information to be consumed by Minstrel ht.
920*b4c3e9b5SBjoern A. Zeeb 		 *
921*b4c3e9b5SBjoern A. Zeeb 		 * The "fallback limit" is the number of tx attempts a given
922*b4c3e9b5SBjoern A. Zeeb 		 * MPDU is sent at the "primary" rate. Tx attempts beyond that
923*b4c3e9b5SBjoern A. Zeeb 		 * limit are sent at the "secondary" rate.
924*b4c3e9b5SBjoern A. Zeeb 		 * A 'short frame' does not exceed RTS threshold.
925*b4c3e9b5SBjoern A. Zeeb 		 */
926*b4c3e9b5SBjoern A. Zeeb 		u16 sfbl,	/* Short Frame Rate Fallback Limit */
927*b4c3e9b5SBjoern A. Zeeb 		    lfbl,	/* Long Frame Rate Fallback Limit */
928*b4c3e9b5SBjoern A. Zeeb 		    fbl;
929*b4c3e9b5SBjoern A. Zeeb 
930*b4c3e9b5SBjoern A. Zeeb 		if (queue < IEEE80211_NUM_ACS) {
931*b4c3e9b5SBjoern A. Zeeb 			sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
932*b4c3e9b5SBjoern A. Zeeb 				      EDCF_SFB);
933*b4c3e9b5SBjoern A. Zeeb 			lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
934*b4c3e9b5SBjoern A. Zeeb 				      EDCF_LFB);
935*b4c3e9b5SBjoern A. Zeeb 		} else {
936*b4c3e9b5SBjoern A. Zeeb 			sfbl = wlc->SFBL;
937*b4c3e9b5SBjoern A. Zeeb 			lfbl = wlc->LFBL;
938*b4c3e9b5SBjoern A. Zeeb 		}
939*b4c3e9b5SBjoern A. Zeeb 
940*b4c3e9b5SBjoern A. Zeeb 		txrate = tx_info->status.rates;
941*b4c3e9b5SBjoern A. Zeeb 		if (txrate[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
942*b4c3e9b5SBjoern A. Zeeb 			fbl = lfbl;
943*b4c3e9b5SBjoern A. Zeeb 		else
944*b4c3e9b5SBjoern A. Zeeb 			fbl = sfbl;
945*b4c3e9b5SBjoern A. Zeeb 
946*b4c3e9b5SBjoern A. Zeeb 		ieee80211_tx_info_clear_status(tx_info);
947*b4c3e9b5SBjoern A. Zeeb 
948*b4c3e9b5SBjoern A. Zeeb 		if ((tx_frame_count > fbl) && (txrate[1].idx >= 0)) {
949*b4c3e9b5SBjoern A. Zeeb 			/*
950*b4c3e9b5SBjoern A. Zeeb 			 * rate selection requested a fallback rate
951*b4c3e9b5SBjoern A. Zeeb 			 * and we used it
952*b4c3e9b5SBjoern A. Zeeb 			 */
953*b4c3e9b5SBjoern A. Zeeb 			txrate[0].count = fbl;
954*b4c3e9b5SBjoern A. Zeeb 			txrate[1].count = tx_frame_count - fbl;
955*b4c3e9b5SBjoern A. Zeeb 		} else {
956*b4c3e9b5SBjoern A. Zeeb 			/*
957*b4c3e9b5SBjoern A. Zeeb 			 * rate selection did not request fallback rate, or
958*b4c3e9b5SBjoern A. Zeeb 			 * we didn't need it
959*b4c3e9b5SBjoern A. Zeeb 			 */
960*b4c3e9b5SBjoern A. Zeeb 			txrate[0].count = tx_frame_count;
961*b4c3e9b5SBjoern A. Zeeb 			/*
962*b4c3e9b5SBjoern A. Zeeb 			 * rc80211_minstrel.c:minstrel_tx_status() expects
963*b4c3e9b5SBjoern A. Zeeb 			 * unused rates to be marked with idx = -1
964*b4c3e9b5SBjoern A. Zeeb 			 */
965*b4c3e9b5SBjoern A. Zeeb 			txrate[1].idx = -1;
966*b4c3e9b5SBjoern A. Zeeb 			txrate[1].count = 0;
967*b4c3e9b5SBjoern A. Zeeb 		}
968*b4c3e9b5SBjoern A. Zeeb 
969*b4c3e9b5SBjoern A. Zeeb 		/* clear the rest of the rates */
970*b4c3e9b5SBjoern A. Zeeb 		for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
971*b4c3e9b5SBjoern A. Zeeb 			txrate[i].idx = -1;
972*b4c3e9b5SBjoern A. Zeeb 			txrate[i].count = 0;
973*b4c3e9b5SBjoern A. Zeeb 		}
974*b4c3e9b5SBjoern A. Zeeb 
975*b4c3e9b5SBjoern A. Zeeb 		if (txs->status & TX_STATUS_ACK_RCV)
976*b4c3e9b5SBjoern A. Zeeb 			tx_info->flags |= IEEE80211_TX_STAT_ACK;
977*b4c3e9b5SBjoern A. Zeeb 	}
978*b4c3e9b5SBjoern A. Zeeb 
979*b4c3e9b5SBjoern A. Zeeb 	if (lastframe) {
980*b4c3e9b5SBjoern A. Zeeb 		/* remove PLCP & Broadcom tx descriptor header */
981*b4c3e9b5SBjoern A. Zeeb 		skb_pull(p, D11_PHY_HDR_LEN);
982*b4c3e9b5SBjoern A. Zeeb 		skb_pull(p, D11_TXH_LEN);
983*b4c3e9b5SBjoern A. Zeeb 		ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p);
984*b4c3e9b5SBjoern A. Zeeb 	} else {
985*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core,
986*b4c3e9b5SBjoern A. Zeeb 			  "%s: Not last frame => not calling tx_status\n",
987*b4c3e9b5SBjoern A. Zeeb 			  __func__);
988*b4c3e9b5SBjoern A. Zeeb 	}
989*b4c3e9b5SBjoern A. Zeeb 
990*b4c3e9b5SBjoern A. Zeeb 	fatal = false;
991*b4c3e9b5SBjoern A. Zeeb 
992*b4c3e9b5SBjoern A. Zeeb  out:
993*b4c3e9b5SBjoern A. Zeeb 	if (fatal) {
994*b4c3e9b5SBjoern A. Zeeb 		if (txh)
995*b4c3e9b5SBjoern A. Zeeb 			trace_brcms_txdesc(&wlc->hw->d11core->dev, txh,
996*b4c3e9b5SBjoern A. Zeeb 					   sizeof(*txh));
997*b4c3e9b5SBjoern A. Zeeb 		brcmu_pkt_buf_free_skb(p);
998*b4c3e9b5SBjoern A. Zeeb 	}
999*b4c3e9b5SBjoern A. Zeeb 
1000*b4c3e9b5SBjoern A. Zeeb 	if (dma && queue < NFIFO) {
1001*b4c3e9b5SBjoern A. Zeeb 		u16 ac_queue = brcms_fifo_to_ac(queue);
1002*b4c3e9b5SBjoern A. Zeeb 		if (dma->txavail > TX_HEADROOM && queue < TX_BCMC_FIFO &&
1003*b4c3e9b5SBjoern A. Zeeb 		    ieee80211_queue_stopped(wlc->pub->ieee_hw, ac_queue))
1004*b4c3e9b5SBjoern A. Zeeb 			ieee80211_wake_queue(wlc->pub->ieee_hw, ac_queue);
1005*b4c3e9b5SBjoern A. Zeeb 		dma_kick_tx(dma);
1006*b4c3e9b5SBjoern A. Zeeb 	}
1007*b4c3e9b5SBjoern A. Zeeb 
1008*b4c3e9b5SBjoern A. Zeeb 	return fatal;
1009*b4c3e9b5SBjoern A. Zeeb }
1010*b4c3e9b5SBjoern A. Zeeb 
1011*b4c3e9b5SBjoern A. Zeeb /* process tx completion events in BMAC
1012*b4c3e9b5SBjoern A. Zeeb  * Return true if more tx status need to be processed. false otherwise.
1013*b4c3e9b5SBjoern A. Zeeb  */
1014*b4c3e9b5SBjoern A. Zeeb static bool
brcms_b_txstatus(struct brcms_hardware * wlc_hw,bool bound,bool * fatal)1015*b4c3e9b5SBjoern A. Zeeb brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
1016*b4c3e9b5SBjoern A. Zeeb {
1017*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core;
1018*b4c3e9b5SBjoern A. Zeeb 	struct tx_status txstatus, *txs;
1019*b4c3e9b5SBjoern A. Zeeb 	u32 s1, s2;
1020*b4c3e9b5SBjoern A. Zeeb 	uint n = 0;
1021*b4c3e9b5SBjoern A. Zeeb 	/*
1022*b4c3e9b5SBjoern A. Zeeb 	 * Param 'max_tx_num' indicates max. # tx status to process before
1023*b4c3e9b5SBjoern A. Zeeb 	 * break out.
1024*b4c3e9b5SBjoern A. Zeeb 	 */
1025*b4c3e9b5SBjoern A. Zeeb 	uint max_tx_num = bound ? TXSBND : -1;
1026*b4c3e9b5SBjoern A. Zeeb 
1027*b4c3e9b5SBjoern A. Zeeb 	txs = &txstatus;
1028*b4c3e9b5SBjoern A. Zeeb 	core = wlc_hw->d11core;
1029*b4c3e9b5SBjoern A. Zeeb 	*fatal = false;
1030*b4c3e9b5SBjoern A. Zeeb 
1031*b4c3e9b5SBjoern A. Zeeb 	while (n < max_tx_num) {
1032*b4c3e9b5SBjoern A. Zeeb 		s1 = bcma_read32(core, D11REGOFFS(frmtxstatus));
1033*b4c3e9b5SBjoern A. Zeeb 		if (s1 == 0xffffffff) {
1034*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
1035*b4c3e9b5SBjoern A. Zeeb 				  __func__);
1036*b4c3e9b5SBjoern A. Zeeb 			*fatal = true;
1037*b4c3e9b5SBjoern A. Zeeb 			return false;
1038*b4c3e9b5SBjoern A. Zeeb 		}
1039*b4c3e9b5SBjoern A. Zeeb 		/* only process when valid */
1040*b4c3e9b5SBjoern A. Zeeb 		if (!(s1 & TXS_V))
1041*b4c3e9b5SBjoern A. Zeeb 			break;
1042*b4c3e9b5SBjoern A. Zeeb 
1043*b4c3e9b5SBjoern A. Zeeb 		s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2));
1044*b4c3e9b5SBjoern A. Zeeb 		txs->status = s1 & TXS_STATUS_MASK;
1045*b4c3e9b5SBjoern A. Zeeb 		txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT;
1046*b4c3e9b5SBjoern A. Zeeb 		txs->sequence = s2 & TXS_SEQ_MASK;
1047*b4c3e9b5SBjoern A. Zeeb 		txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT;
1048*b4c3e9b5SBjoern A. Zeeb 		txs->lasttxtime = 0;
1049*b4c3e9b5SBjoern A. Zeeb 
1050*b4c3e9b5SBjoern A. Zeeb 		*fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs);
1051*b4c3e9b5SBjoern A. Zeeb 		if (*fatal)
1052*b4c3e9b5SBjoern A. Zeeb 			return false;
1053*b4c3e9b5SBjoern A. Zeeb 		n++;
1054*b4c3e9b5SBjoern A. Zeeb 	}
1055*b4c3e9b5SBjoern A. Zeeb 
1056*b4c3e9b5SBjoern A. Zeeb 	return n >= max_tx_num;
1057*b4c3e9b5SBjoern A. Zeeb }
1058*b4c3e9b5SBjoern A. Zeeb 
brcms_c_tbtt(struct brcms_c_info * wlc)1059*b4c3e9b5SBjoern A. Zeeb static void brcms_c_tbtt(struct brcms_c_info *wlc)
1060*b4c3e9b5SBjoern A. Zeeb {
1061*b4c3e9b5SBjoern A. Zeeb 	if (wlc->bsscfg->type == BRCMS_TYPE_ADHOC)
1062*b4c3e9b5SBjoern A. Zeeb 		/*
1063*b4c3e9b5SBjoern A. Zeeb 		 * DirFrmQ is now valid...defer setting until end
1064*b4c3e9b5SBjoern A. Zeeb 		 * of ATIM window
1065*b4c3e9b5SBjoern A. Zeeb 		 */
1066*b4c3e9b5SBjoern A. Zeeb 		wlc->qvalid |= MCMD_DIRFRMQVAL;
1067*b4c3e9b5SBjoern A. Zeeb }
1068*b4c3e9b5SBjoern A. Zeeb 
1069*b4c3e9b5SBjoern A. Zeeb /* set initial host flags value */
1070*b4c3e9b5SBjoern A. Zeeb static void
brcms_c_mhfdef(struct brcms_c_info * wlc,u16 * mhfs,u16 mhf2_init)1071*b4c3e9b5SBjoern A. Zeeb brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init)
1072*b4c3e9b5SBjoern A. Zeeb {
1073*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
1074*b4c3e9b5SBjoern A. Zeeb 
1075*b4c3e9b5SBjoern A. Zeeb 	memset(mhfs, 0, MHFMAX * sizeof(u16));
1076*b4c3e9b5SBjoern A. Zeeb 
1077*b4c3e9b5SBjoern A. Zeeb 	mhfs[MHF2] |= mhf2_init;
1078*b4c3e9b5SBjoern A. Zeeb 
1079*b4c3e9b5SBjoern A. Zeeb 	/* prohibit use of slowclock on multifunction boards */
1080*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->boardflags & BFL_NOPLLDOWN)
1081*b4c3e9b5SBjoern A. Zeeb 		mhfs[MHF1] |= MHF1_FORCEFASTCLK;
1082*b4c3e9b5SBjoern A. Zeeb 
1083*b4c3e9b5SBjoern A. Zeeb 	if (BRCMS_ISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) {
1084*b4c3e9b5SBjoern A. Zeeb 		mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR;
1085*b4c3e9b5SBjoern A. Zeeb 		mhfs[MHF1] |= MHF1_IQSWAP_WAR;
1086*b4c3e9b5SBjoern A. Zeeb 	}
1087*b4c3e9b5SBjoern A. Zeeb }
1088*b4c3e9b5SBjoern A. Zeeb 
1089*b4c3e9b5SBjoern A. Zeeb static uint
dmareg(uint direction,uint fifonum)1090*b4c3e9b5SBjoern A. Zeeb dmareg(uint direction, uint fifonum)
1091*b4c3e9b5SBjoern A. Zeeb {
1092*b4c3e9b5SBjoern A. Zeeb 	if (direction == DMA_TX)
1093*b4c3e9b5SBjoern A. Zeeb 		return offsetof(struct d11regs, fifo64regs[fifonum].dmaxmt);
1094*b4c3e9b5SBjoern A. Zeeb 	return offsetof(struct d11regs, fifo64regs[fifonum].dmarcv);
1095*b4c3e9b5SBjoern A. Zeeb }
1096*b4c3e9b5SBjoern A. Zeeb 
brcms_b_attach_dmapio(struct brcms_c_info * wlc,uint j,bool wme)1097*b4c3e9b5SBjoern A. Zeeb static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
1098*b4c3e9b5SBjoern A. Zeeb {
1099*b4c3e9b5SBjoern A. Zeeb 	uint i;
1100*b4c3e9b5SBjoern A. Zeeb 	char name[8];
1101*b4c3e9b5SBjoern A. Zeeb 	/*
1102*b4c3e9b5SBjoern A. Zeeb 	 * ucode host flag 2 needed for pio mode, independent of band and fifo
1103*b4c3e9b5SBjoern A. Zeeb 	 */
1104*b4c3e9b5SBjoern A. Zeeb 	u16 pio_mhf2 = 0;
1105*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
1106*b4c3e9b5SBjoern A. Zeeb 	uint unit = wlc_hw->unit;
1107*b4c3e9b5SBjoern A. Zeeb 
1108*b4c3e9b5SBjoern A. Zeeb 	/* name and offsets for dma_attach */
1109*b4c3e9b5SBjoern A. Zeeb 	snprintf(name, sizeof(name), "wl%d", unit);
1110*b4c3e9b5SBjoern A. Zeeb 
1111*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->di[0] == NULL) {	/* Init FIFOs */
1112*b4c3e9b5SBjoern A. Zeeb 		int dma_attach_err = 0;
1113*b4c3e9b5SBjoern A. Zeeb 
1114*b4c3e9b5SBjoern A. Zeeb 		/*
1115*b4c3e9b5SBjoern A. Zeeb 		 * FIFO 0
1116*b4c3e9b5SBjoern A. Zeeb 		 * TX: TX_AC_BK_FIFO (TX AC Background data packets)
1117*b4c3e9b5SBjoern A. Zeeb 		 * RX: RX_FIFO (RX data packets)
1118*b4c3e9b5SBjoern A. Zeeb 		 */
1119*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->di[0] = dma_attach(name, wlc,
1120*b4c3e9b5SBjoern A. Zeeb 					   (wme ? dmareg(DMA_TX, 0) : 0),
1121*b4c3e9b5SBjoern A. Zeeb 					   dmareg(DMA_RX, 0),
1122*b4c3e9b5SBjoern A. Zeeb 					   (wme ? NTXD : 0), NRXD,
1123*b4c3e9b5SBjoern A. Zeeb 					   RXBUFSZ, -1, NRXBUFPOST,
1124*b4c3e9b5SBjoern A. Zeeb 					   BRCMS_HWRXOFF);
1125*b4c3e9b5SBjoern A. Zeeb 		dma_attach_err |= (NULL == wlc_hw->di[0]);
1126*b4c3e9b5SBjoern A. Zeeb 
1127*b4c3e9b5SBjoern A. Zeeb 		/*
1128*b4c3e9b5SBjoern A. Zeeb 		 * FIFO 1
1129*b4c3e9b5SBjoern A. Zeeb 		 * TX: TX_AC_BE_FIFO (TX AC Best-Effort data packets)
1130*b4c3e9b5SBjoern A. Zeeb 		 *   (legacy) TX_DATA_FIFO (TX data packets)
1131*b4c3e9b5SBjoern A. Zeeb 		 * RX: UNUSED
1132*b4c3e9b5SBjoern A. Zeeb 		 */
1133*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->di[1] = dma_attach(name, wlc,
1134*b4c3e9b5SBjoern A. Zeeb 					   dmareg(DMA_TX, 1), 0,
1135*b4c3e9b5SBjoern A. Zeeb 					   NTXD, 0, 0, -1, 0, 0);
1136*b4c3e9b5SBjoern A. Zeeb 		dma_attach_err |= (NULL == wlc_hw->di[1]);
1137*b4c3e9b5SBjoern A. Zeeb 
1138*b4c3e9b5SBjoern A. Zeeb 		/*
1139*b4c3e9b5SBjoern A. Zeeb 		 * FIFO 2
1140*b4c3e9b5SBjoern A. Zeeb 		 * TX: TX_AC_VI_FIFO (TX AC Video data packets)
1141*b4c3e9b5SBjoern A. Zeeb 		 * RX: UNUSED
1142*b4c3e9b5SBjoern A. Zeeb 		 */
1143*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->di[2] = dma_attach(name, wlc,
1144*b4c3e9b5SBjoern A. Zeeb 					   dmareg(DMA_TX, 2), 0,
1145*b4c3e9b5SBjoern A. Zeeb 					   NTXD, 0, 0, -1, 0, 0);
1146*b4c3e9b5SBjoern A. Zeeb 		dma_attach_err |= (NULL == wlc_hw->di[2]);
1147*b4c3e9b5SBjoern A. Zeeb 		/*
1148*b4c3e9b5SBjoern A. Zeeb 		 * FIFO 3
1149*b4c3e9b5SBjoern A. Zeeb 		 * TX: TX_AC_VO_FIFO (TX AC Voice data packets)
1150*b4c3e9b5SBjoern A. Zeeb 		 *   (legacy) TX_CTL_FIFO (TX control & mgmt packets)
1151*b4c3e9b5SBjoern A. Zeeb 		 */
1152*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->di[3] = dma_attach(name, wlc,
1153*b4c3e9b5SBjoern A. Zeeb 					   dmareg(DMA_TX, 3),
1154*b4c3e9b5SBjoern A. Zeeb 					   0, NTXD, 0, 0, -1,
1155*b4c3e9b5SBjoern A. Zeeb 					   0, 0);
1156*b4c3e9b5SBjoern A. Zeeb 		dma_attach_err |= (NULL == wlc_hw->di[3]);
1157*b4c3e9b5SBjoern A. Zeeb /* Cleaner to leave this as if with AP defined */
1158*b4c3e9b5SBjoern A. Zeeb 
1159*b4c3e9b5SBjoern A. Zeeb 		if (dma_attach_err) {
1160*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc_hw->d11core,
1161*b4c3e9b5SBjoern A. Zeeb 				  "wl%d: wlc_attach: dma_attach failed\n",
1162*b4c3e9b5SBjoern A. Zeeb 				  unit);
1163*b4c3e9b5SBjoern A. Zeeb 			return false;
1164*b4c3e9b5SBjoern A. Zeeb 		}
1165*b4c3e9b5SBjoern A. Zeeb 
1166*b4c3e9b5SBjoern A. Zeeb 		/* get pointer to dma engine tx flow control variable */
1167*b4c3e9b5SBjoern A. Zeeb 		for (i = 0; i < NFIFO; i++)
1168*b4c3e9b5SBjoern A. Zeeb 			if (wlc_hw->di[i])
1169*b4c3e9b5SBjoern A. Zeeb 				wlc_hw->txavail[i] =
1170*b4c3e9b5SBjoern A. Zeeb 				    (uint *) dma_getvar(wlc_hw->di[i],
1171*b4c3e9b5SBjoern A. Zeeb 							"&txavail");
1172*b4c3e9b5SBjoern A. Zeeb 	}
1173*b4c3e9b5SBjoern A. Zeeb 
1174*b4c3e9b5SBjoern A. Zeeb 	/* initial ucode host flags */
1175*b4c3e9b5SBjoern A. Zeeb 	brcms_c_mhfdef(wlc, wlc_hw->band->mhfs, pio_mhf2);
1176*b4c3e9b5SBjoern A. Zeeb 
1177*b4c3e9b5SBjoern A. Zeeb 	return true;
1178*b4c3e9b5SBjoern A. Zeeb }
1179*b4c3e9b5SBjoern A. Zeeb 
brcms_b_detach_dmapio(struct brcms_hardware * wlc_hw)1180*b4c3e9b5SBjoern A. Zeeb static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw)
1181*b4c3e9b5SBjoern A. Zeeb {
1182*b4c3e9b5SBjoern A. Zeeb 	uint j;
1183*b4c3e9b5SBjoern A. Zeeb 
1184*b4c3e9b5SBjoern A. Zeeb 	for (j = 0; j < NFIFO; j++) {
1185*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->di[j]) {
1186*b4c3e9b5SBjoern A. Zeeb 			dma_detach(wlc_hw->di[j]);
1187*b4c3e9b5SBjoern A. Zeeb 			wlc_hw->di[j] = NULL;
1188*b4c3e9b5SBjoern A. Zeeb 		}
1189*b4c3e9b5SBjoern A. Zeeb 	}
1190*b4c3e9b5SBjoern A. Zeeb }
1191*b4c3e9b5SBjoern A. Zeeb 
1192*b4c3e9b5SBjoern A. Zeeb /*
1193*b4c3e9b5SBjoern A. Zeeb  * Initialize brcms_c_info default values ...
1194*b4c3e9b5SBjoern A. Zeeb  * may get overrides later in this function
1195*b4c3e9b5SBjoern A. Zeeb  *  BMAC_NOTES, move low out and resolve the dangling ones
1196*b4c3e9b5SBjoern A. Zeeb  */
brcms_b_info_init(struct brcms_hardware * wlc_hw)1197*b4c3e9b5SBjoern A. Zeeb static void brcms_b_info_init(struct brcms_hardware *wlc_hw)
1198*b4c3e9b5SBjoern A. Zeeb {
1199*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_info *wlc = wlc_hw->wlc;
1200*b4c3e9b5SBjoern A. Zeeb 
1201*b4c3e9b5SBjoern A. Zeeb 	/* set default sw macintmask value */
1202*b4c3e9b5SBjoern A. Zeeb 	wlc->defmacintmask = DEF_MACINTMASK;
1203*b4c3e9b5SBjoern A. Zeeb 
1204*b4c3e9b5SBjoern A. Zeeb 	/* various 802.11g modes */
1205*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->shortslot = false;
1206*b4c3e9b5SBjoern A. Zeeb 
1207*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->SFBL = RETRY_SHORT_FB;
1208*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->LFBL = RETRY_LONG_FB;
1209*b4c3e9b5SBjoern A. Zeeb 
1210*b4c3e9b5SBjoern A. Zeeb 	/* default mac retry limits */
1211*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->SRL = RETRY_SHORT_DEF;
1212*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->LRL = RETRY_LONG_DEF;
1213*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->chanspec = ch20mhz_chspec(1);
1214*b4c3e9b5SBjoern A. Zeeb }
1215*b4c3e9b5SBjoern A. Zeeb 
brcms_b_wait_for_wake(struct brcms_hardware * wlc_hw)1216*b4c3e9b5SBjoern A. Zeeb static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
1217*b4c3e9b5SBjoern A. Zeeb {
1218*b4c3e9b5SBjoern A. Zeeb 	/* delay before first read of ucode state */
1219*b4c3e9b5SBjoern A. Zeeb 	udelay(40);
1220*b4c3e9b5SBjoern A. Zeeb 
1221*b4c3e9b5SBjoern A. Zeeb 	/* wait until ucode is no longer asleep */
1222*b4c3e9b5SBjoern A. Zeeb 	SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==
1223*b4c3e9b5SBjoern A. Zeeb 		  DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
1224*b4c3e9b5SBjoern A. Zeeb }
1225*b4c3e9b5SBjoern A. Zeeb 
1226*b4c3e9b5SBjoern A. Zeeb /* control chip clock to save power, enable dynamic clock or force fast clock */
brcms_b_clkctl_clk(struct brcms_hardware * wlc_hw,enum bcma_clkmode mode)1227*b4c3e9b5SBjoern A. Zeeb static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, enum bcma_clkmode mode)
1228*b4c3e9b5SBjoern A. Zeeb {
1229*b4c3e9b5SBjoern A. Zeeb 	if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU) {
1230*b4c3e9b5SBjoern A. Zeeb 		/* new chips with PMU, CCS_FORCEHT will distribute the HT clock
1231*b4c3e9b5SBjoern A. Zeeb 		 * on backplane, but mac core will still run on ALP(not HT) when
1232*b4c3e9b5SBjoern A. Zeeb 		 * it enters powersave mode, which means the FCA bit may not be
1233*b4c3e9b5SBjoern A. Zeeb 		 * set. Should wakeup mac if driver wants it to run on HT.
1234*b4c3e9b5SBjoern A. Zeeb 		 */
1235*b4c3e9b5SBjoern A. Zeeb 
1236*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->clk) {
1237*b4c3e9b5SBjoern A. Zeeb 			if (mode == BCMA_CLKMODE_FAST) {
1238*b4c3e9b5SBjoern A. Zeeb 				bcma_set32(wlc_hw->d11core,
1239*b4c3e9b5SBjoern A. Zeeb 					   D11REGOFFS(clk_ctl_st),
1240*b4c3e9b5SBjoern A. Zeeb 					   CCS_FORCEHT);
1241*b4c3e9b5SBjoern A. Zeeb 
1242*b4c3e9b5SBjoern A. Zeeb 				udelay(64);
1243*b4c3e9b5SBjoern A. Zeeb 
1244*b4c3e9b5SBjoern A. Zeeb 				SPINWAIT(
1245*b4c3e9b5SBjoern A. Zeeb 				    ((bcma_read32(wlc_hw->d11core,
1246*b4c3e9b5SBjoern A. Zeeb 				      D11REGOFFS(clk_ctl_st)) &
1247*b4c3e9b5SBjoern A. Zeeb 				      CCS_HTAVAIL) == 0),
1248*b4c3e9b5SBjoern A. Zeeb 				      PMU_MAX_TRANSITION_DLY);
1249*b4c3e9b5SBjoern A. Zeeb 				WARN_ON(!(bcma_read32(wlc_hw->d11core,
1250*b4c3e9b5SBjoern A. Zeeb 					D11REGOFFS(clk_ctl_st)) &
1251*b4c3e9b5SBjoern A. Zeeb 					CCS_HTAVAIL));
1252*b4c3e9b5SBjoern A. Zeeb 			} else {
1253*b4c3e9b5SBjoern A. Zeeb 				if ((ai_get_pmurev(wlc_hw->sih) == 0) &&
1254*b4c3e9b5SBjoern A. Zeeb 				    (bcma_read32(wlc_hw->d11core,
1255*b4c3e9b5SBjoern A. Zeeb 					D11REGOFFS(clk_ctl_st)) &
1256*b4c3e9b5SBjoern A. Zeeb 					(CCS_FORCEHT | CCS_HTAREQ)))
1257*b4c3e9b5SBjoern A. Zeeb 					SPINWAIT(
1258*b4c3e9b5SBjoern A. Zeeb 					    ((bcma_read32(wlc_hw->d11core,
1259*b4c3e9b5SBjoern A. Zeeb 					      offsetof(struct d11regs,
1260*b4c3e9b5SBjoern A. Zeeb 						       clk_ctl_st)) &
1261*b4c3e9b5SBjoern A. Zeeb 					      CCS_HTAVAIL) == 0),
1262*b4c3e9b5SBjoern A. Zeeb 					      PMU_MAX_TRANSITION_DLY);
1263*b4c3e9b5SBjoern A. Zeeb 				bcma_mask32(wlc_hw->d11core,
1264*b4c3e9b5SBjoern A. Zeeb 					D11REGOFFS(clk_ctl_st),
1265*b4c3e9b5SBjoern A. Zeeb 					~CCS_FORCEHT);
1266*b4c3e9b5SBjoern A. Zeeb 			}
1267*b4c3e9b5SBjoern A. Zeeb 		}
1268*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->forcefastclk = (mode == BCMA_CLKMODE_FAST);
1269*b4c3e9b5SBjoern A. Zeeb 	} else {
1270*b4c3e9b5SBjoern A. Zeeb 
1271*b4c3e9b5SBjoern A. Zeeb 		/* old chips w/o PMU, force HT through cc,
1272*b4c3e9b5SBjoern A. Zeeb 		 * then use FCA to verify mac is running fast clock
1273*b4c3e9b5SBjoern A. Zeeb 		 */
1274*b4c3e9b5SBjoern A. Zeeb 
1275*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->forcefastclk = ai_clkctl_cc(wlc_hw->sih, mode);
1276*b4c3e9b5SBjoern A. Zeeb 
1277*b4c3e9b5SBjoern A. Zeeb 		/* check fast clock is available (if core is not in reset) */
1278*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->forcefastclk && wlc_hw->clk)
1279*b4c3e9b5SBjoern A. Zeeb 			WARN_ON(!(bcma_aread32(wlc_hw->d11core, BCMA_IOST) &
1280*b4c3e9b5SBjoern A. Zeeb 				  SISF_FCLKA));
1281*b4c3e9b5SBjoern A. Zeeb 
1282*b4c3e9b5SBjoern A. Zeeb 		/*
1283*b4c3e9b5SBjoern A. Zeeb 		 * keep the ucode wake bit on if forcefastclk is on since we
1284*b4c3e9b5SBjoern A. Zeeb 		 * do not want ucode to put us back to slow clock when it dozes
1285*b4c3e9b5SBjoern A. Zeeb 		 * for PM mode. Code below matches the wake override bit with
1286*b4c3e9b5SBjoern A. Zeeb 		 * current forcefastclk state. Only setting bit in wake_override
1287*b4c3e9b5SBjoern A. Zeeb 		 * instead of waking ucode immediately since old code had this
1288*b4c3e9b5SBjoern A. Zeeb 		 * behavior. Older code set wlc->forcefastclk but only had the
1289*b4c3e9b5SBjoern A. Zeeb 		 * wake happen if the wakup_ucode work (protected by an up
1290*b4c3e9b5SBjoern A. Zeeb 		 * check) was executed just below.
1291*b4c3e9b5SBjoern A. Zeeb 		 */
1292*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->forcefastclk)
1293*b4c3e9b5SBjoern A. Zeeb 			mboolset(wlc_hw->wake_override,
1294*b4c3e9b5SBjoern A. Zeeb 				 BRCMS_WAKE_OVERRIDE_FORCEFAST);
1295*b4c3e9b5SBjoern A. Zeeb 		else
1296*b4c3e9b5SBjoern A. Zeeb 			mboolclr(wlc_hw->wake_override,
1297*b4c3e9b5SBjoern A. Zeeb 				 BRCMS_WAKE_OVERRIDE_FORCEFAST);
1298*b4c3e9b5SBjoern A. Zeeb 	}
1299*b4c3e9b5SBjoern A. Zeeb }
1300*b4c3e9b5SBjoern A. Zeeb 
1301*b4c3e9b5SBjoern A. Zeeb /* set or clear ucode host flag bits
1302*b4c3e9b5SBjoern A. Zeeb  * it has an optimization for no-change write
1303*b4c3e9b5SBjoern A. Zeeb  * it only writes through shared memory when the core has clock;
1304*b4c3e9b5SBjoern A. Zeeb  * pre-CLK changes should use wlc_write_mhf to get around the optimization
1305*b4c3e9b5SBjoern A. Zeeb  *
1306*b4c3e9b5SBjoern A. Zeeb  *
1307*b4c3e9b5SBjoern A. Zeeb  * bands values are: BRCM_BAND_AUTO <--- Current band only
1308*b4c3e9b5SBjoern A. Zeeb  *                   BRCM_BAND_5G   <--- 5G band only
1309*b4c3e9b5SBjoern A. Zeeb  *                   BRCM_BAND_2G   <--- 2G band only
1310*b4c3e9b5SBjoern A. Zeeb  *                   BRCM_BAND_ALL  <--- All bands
1311*b4c3e9b5SBjoern A. Zeeb  */
1312*b4c3e9b5SBjoern A. Zeeb void
brcms_b_mhf(struct brcms_hardware * wlc_hw,u8 idx,u16 mask,u16 val,int bands)1313*b4c3e9b5SBjoern A. Zeeb brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val,
1314*b4c3e9b5SBjoern A. Zeeb 	     int bands)
1315*b4c3e9b5SBjoern A. Zeeb {
1316*b4c3e9b5SBjoern A. Zeeb 	u16 save;
1317*b4c3e9b5SBjoern A. Zeeb 	u16 addr[MHFMAX] = {
1318*b4c3e9b5SBjoern A. Zeeb 		M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
1319*b4c3e9b5SBjoern A. Zeeb 		M_HOST_FLAGS5
1320*b4c3e9b5SBjoern A. Zeeb 	};
1321*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hw_band *band;
1322*b4c3e9b5SBjoern A. Zeeb 
1323*b4c3e9b5SBjoern A. Zeeb 	if ((val & ~mask) || idx >= MHFMAX)
1324*b4c3e9b5SBjoern A. Zeeb 		return; /* error condition */
1325*b4c3e9b5SBjoern A. Zeeb 
1326*b4c3e9b5SBjoern A. Zeeb 	switch (bands) {
1327*b4c3e9b5SBjoern A. Zeeb 		/* Current band only or all bands,
1328*b4c3e9b5SBjoern A. Zeeb 		 * then set the band to current band
1329*b4c3e9b5SBjoern A. Zeeb 		 */
1330*b4c3e9b5SBjoern A. Zeeb 	case BRCM_BAND_AUTO:
1331*b4c3e9b5SBjoern A. Zeeb 	case BRCM_BAND_ALL:
1332*b4c3e9b5SBjoern A. Zeeb 		band = wlc_hw->band;
1333*b4c3e9b5SBjoern A. Zeeb 		break;
1334*b4c3e9b5SBjoern A. Zeeb 	case BRCM_BAND_5G:
1335*b4c3e9b5SBjoern A. Zeeb 		band = wlc_hw->bandstate[BAND_5G_INDEX];
1336*b4c3e9b5SBjoern A. Zeeb 		break;
1337*b4c3e9b5SBjoern A. Zeeb 	case BRCM_BAND_2G:
1338*b4c3e9b5SBjoern A. Zeeb 		band = wlc_hw->bandstate[BAND_2G_INDEX];
1339*b4c3e9b5SBjoern A. Zeeb 		break;
1340*b4c3e9b5SBjoern A. Zeeb 	default:
1341*b4c3e9b5SBjoern A. Zeeb 		band = NULL;	/* error condition */
1342*b4c3e9b5SBjoern A. Zeeb 	}
1343*b4c3e9b5SBjoern A. Zeeb 
1344*b4c3e9b5SBjoern A. Zeeb 	if (band) {
1345*b4c3e9b5SBjoern A. Zeeb 		save = band->mhfs[idx];
1346*b4c3e9b5SBjoern A. Zeeb 		band->mhfs[idx] = (band->mhfs[idx] & ~mask) | val;
1347*b4c3e9b5SBjoern A. Zeeb 
1348*b4c3e9b5SBjoern A. Zeeb 		/* optimization: only write through if changed, and
1349*b4c3e9b5SBjoern A. Zeeb 		 * changed band is the current band
1350*b4c3e9b5SBjoern A. Zeeb 		 */
1351*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->clk && (band->mhfs[idx] != save)
1352*b4c3e9b5SBjoern A. Zeeb 		    && (band == wlc_hw->band))
1353*b4c3e9b5SBjoern A. Zeeb 			brcms_b_write_shm(wlc_hw, addr[idx],
1354*b4c3e9b5SBjoern A. Zeeb 					   (u16) band->mhfs[idx]);
1355*b4c3e9b5SBjoern A. Zeeb 	}
1356*b4c3e9b5SBjoern A. Zeeb 
1357*b4c3e9b5SBjoern A. Zeeb 	if (bands == BRCM_BAND_ALL) {
1358*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->bandstate[0]->mhfs[idx] =
1359*b4c3e9b5SBjoern A. Zeeb 		    (wlc_hw->bandstate[0]->mhfs[idx] & ~mask) | val;
1360*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->bandstate[1]->mhfs[idx] =
1361*b4c3e9b5SBjoern A. Zeeb 		    (wlc_hw->bandstate[1]->mhfs[idx] & ~mask) | val;
1362*b4c3e9b5SBjoern A. Zeeb 	}
1363*b4c3e9b5SBjoern A. Zeeb }
1364*b4c3e9b5SBjoern A. Zeeb 
1365*b4c3e9b5SBjoern A. Zeeb /* set the maccontrol register to desired reset state and
1366*b4c3e9b5SBjoern A. Zeeb  * initialize the sw cache of the register
1367*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_mctrl_reset(struct brcms_hardware * wlc_hw)1368*b4c3e9b5SBjoern A. Zeeb static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw)
1369*b4c3e9b5SBjoern A. Zeeb {
1370*b4c3e9b5SBjoern A. Zeeb 	/* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */
1371*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->maccontrol = 0;
1372*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->suspended_fifos = 0;
1373*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->wake_override = 0;
1374*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->mute_override = 0;
1375*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mctrl(wlc_hw, ~0, MCTL_IHR_EN | MCTL_WAKE);
1376*b4c3e9b5SBjoern A. Zeeb }
1377*b4c3e9b5SBjoern A. Zeeb 
1378*b4c3e9b5SBjoern A. Zeeb /*
1379*b4c3e9b5SBjoern A. Zeeb  * write the software state of maccontrol and
1380*b4c3e9b5SBjoern A. Zeeb  * overrides to the maccontrol register
1381*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_mctrl_write(struct brcms_hardware * wlc_hw)1382*b4c3e9b5SBjoern A. Zeeb static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw)
1383*b4c3e9b5SBjoern A. Zeeb {
1384*b4c3e9b5SBjoern A. Zeeb 	u32 maccontrol = wlc_hw->maccontrol;
1385*b4c3e9b5SBjoern A. Zeeb 
1386*b4c3e9b5SBjoern A. Zeeb 	/* OR in the wake bit if overridden */
1387*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->wake_override)
1388*b4c3e9b5SBjoern A. Zeeb 		maccontrol |= MCTL_WAKE;
1389*b4c3e9b5SBjoern A. Zeeb 
1390*b4c3e9b5SBjoern A. Zeeb 	/* set AP and INFRA bits for mute if needed */
1391*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->mute_override) {
1392*b4c3e9b5SBjoern A. Zeeb 		maccontrol &= ~(MCTL_AP);
1393*b4c3e9b5SBjoern A. Zeeb 		maccontrol |= MCTL_INFRA;
1394*b4c3e9b5SBjoern A. Zeeb 	}
1395*b4c3e9b5SBjoern A. Zeeb 
1396*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc_hw->d11core, D11REGOFFS(maccontrol),
1397*b4c3e9b5SBjoern A. Zeeb 		     maccontrol);
1398*b4c3e9b5SBjoern A. Zeeb }
1399*b4c3e9b5SBjoern A. Zeeb 
1400*b4c3e9b5SBjoern A. Zeeb /* set or clear maccontrol bits */
brcms_b_mctrl(struct brcms_hardware * wlc_hw,u32 mask,u32 val)1401*b4c3e9b5SBjoern A. Zeeb void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val)
1402*b4c3e9b5SBjoern A. Zeeb {
1403*b4c3e9b5SBjoern A. Zeeb 	u32 maccontrol;
1404*b4c3e9b5SBjoern A. Zeeb 	u32 new_maccontrol;
1405*b4c3e9b5SBjoern A. Zeeb 
1406*b4c3e9b5SBjoern A. Zeeb 	if (val & ~mask)
1407*b4c3e9b5SBjoern A. Zeeb 		return; /* error condition */
1408*b4c3e9b5SBjoern A. Zeeb 	maccontrol = wlc_hw->maccontrol;
1409*b4c3e9b5SBjoern A. Zeeb 	new_maccontrol = (maccontrol & ~mask) | val;
1410*b4c3e9b5SBjoern A. Zeeb 
1411*b4c3e9b5SBjoern A. Zeeb 	/* if the new maccontrol value is the same as the old, nothing to do */
1412*b4c3e9b5SBjoern A. Zeeb 	if (new_maccontrol == maccontrol)
1413*b4c3e9b5SBjoern A. Zeeb 		return;
1414*b4c3e9b5SBjoern A. Zeeb 
1415*b4c3e9b5SBjoern A. Zeeb 	/* something changed, cache the new value */
1416*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->maccontrol = new_maccontrol;
1417*b4c3e9b5SBjoern A. Zeeb 
1418*b4c3e9b5SBjoern A. Zeeb 	/* write the new values with overrides applied */
1419*b4c3e9b5SBjoern A. Zeeb 	brcms_c_mctrl_write(wlc_hw);
1420*b4c3e9b5SBjoern A. Zeeb }
1421*b4c3e9b5SBjoern A. Zeeb 
brcms_c_ucode_wake_override_set(struct brcms_hardware * wlc_hw,u32 override_bit)1422*b4c3e9b5SBjoern A. Zeeb void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw,
1423*b4c3e9b5SBjoern A. Zeeb 				 u32 override_bit)
1424*b4c3e9b5SBjoern A. Zeeb {
1425*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) {
1426*b4c3e9b5SBjoern A. Zeeb 		mboolset(wlc_hw->wake_override, override_bit);
1427*b4c3e9b5SBjoern A. Zeeb 		return;
1428*b4c3e9b5SBjoern A. Zeeb 	}
1429*b4c3e9b5SBjoern A. Zeeb 
1430*b4c3e9b5SBjoern A. Zeeb 	mboolset(wlc_hw->wake_override, override_bit);
1431*b4c3e9b5SBjoern A. Zeeb 
1432*b4c3e9b5SBjoern A. Zeeb 	brcms_c_mctrl_write(wlc_hw);
1433*b4c3e9b5SBjoern A. Zeeb 	brcms_b_wait_for_wake(wlc_hw);
1434*b4c3e9b5SBjoern A. Zeeb }
1435*b4c3e9b5SBjoern A. Zeeb 
brcms_c_ucode_wake_override_clear(struct brcms_hardware * wlc_hw,u32 override_bit)1436*b4c3e9b5SBjoern A. Zeeb void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw,
1437*b4c3e9b5SBjoern A. Zeeb 				   u32 override_bit)
1438*b4c3e9b5SBjoern A. Zeeb {
1439*b4c3e9b5SBjoern A. Zeeb 	mboolclr(wlc_hw->wake_override, override_bit);
1440*b4c3e9b5SBjoern A. Zeeb 
1441*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE))
1442*b4c3e9b5SBjoern A. Zeeb 		return;
1443*b4c3e9b5SBjoern A. Zeeb 
1444*b4c3e9b5SBjoern A. Zeeb 	brcms_c_mctrl_write(wlc_hw);
1445*b4c3e9b5SBjoern A. Zeeb }
1446*b4c3e9b5SBjoern A. Zeeb 
1447*b4c3e9b5SBjoern A. Zeeb /* When driver needs ucode to stop beaconing, it has to make sure that
1448*b4c3e9b5SBjoern A. Zeeb  * MCTL_AP is clear and MCTL_INFRA is set
1449*b4c3e9b5SBjoern A. Zeeb  * Mode           MCTL_AP        MCTL_INFRA
1450*b4c3e9b5SBjoern A. Zeeb  * AP                1              1
1451*b4c3e9b5SBjoern A. Zeeb  * STA               0              1 <--- This will ensure no beacons
1452*b4c3e9b5SBjoern A. Zeeb  * IBSS              0              0
1453*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_ucode_mute_override_set(struct brcms_hardware * wlc_hw)1454*b4c3e9b5SBjoern A. Zeeb static void brcms_c_ucode_mute_override_set(struct brcms_hardware *wlc_hw)
1455*b4c3e9b5SBjoern A. Zeeb {
1456*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->mute_override = 1;
1457*b4c3e9b5SBjoern A. Zeeb 
1458*b4c3e9b5SBjoern A. Zeeb 	/* if maccontrol already has AP == 0 and INFRA == 1 without this
1459*b4c3e9b5SBjoern A. Zeeb 	 * override, then there is no change to write
1460*b4c3e9b5SBjoern A. Zeeb 	 */
1461*b4c3e9b5SBjoern A. Zeeb 	if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
1462*b4c3e9b5SBjoern A. Zeeb 		return;
1463*b4c3e9b5SBjoern A. Zeeb 
1464*b4c3e9b5SBjoern A. Zeeb 	brcms_c_mctrl_write(wlc_hw);
1465*b4c3e9b5SBjoern A. Zeeb }
1466*b4c3e9b5SBjoern A. Zeeb 
1467*b4c3e9b5SBjoern A. Zeeb /* Clear the override on AP and INFRA bits */
brcms_c_ucode_mute_override_clear(struct brcms_hardware * wlc_hw)1468*b4c3e9b5SBjoern A. Zeeb static void brcms_c_ucode_mute_override_clear(struct brcms_hardware *wlc_hw)
1469*b4c3e9b5SBjoern A. Zeeb {
1470*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->mute_override == 0)
1471*b4c3e9b5SBjoern A. Zeeb 		return;
1472*b4c3e9b5SBjoern A. Zeeb 
1473*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->mute_override = 0;
1474*b4c3e9b5SBjoern A. Zeeb 
1475*b4c3e9b5SBjoern A. Zeeb 	/* if maccontrol already has AP == 0 and INFRA == 1 without this
1476*b4c3e9b5SBjoern A. Zeeb 	 * override, then there is no change to write
1477*b4c3e9b5SBjoern A. Zeeb 	 */
1478*b4c3e9b5SBjoern A. Zeeb 	if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
1479*b4c3e9b5SBjoern A. Zeeb 		return;
1480*b4c3e9b5SBjoern A. Zeeb 
1481*b4c3e9b5SBjoern A. Zeeb 	brcms_c_mctrl_write(wlc_hw);
1482*b4c3e9b5SBjoern A. Zeeb }
1483*b4c3e9b5SBjoern A. Zeeb 
1484*b4c3e9b5SBjoern A. Zeeb /*
1485*b4c3e9b5SBjoern A. Zeeb  * Write a MAC address to the given match reg offset in the RXE match engine.
1486*b4c3e9b5SBjoern A. Zeeb  */
1487*b4c3e9b5SBjoern A. Zeeb static void
brcms_b_set_addrmatch(struct brcms_hardware * wlc_hw,int match_reg_offset,const u8 * addr)1488*b4c3e9b5SBjoern A. Zeeb brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset,
1489*b4c3e9b5SBjoern A. Zeeb 		       const u8 *addr)
1490*b4c3e9b5SBjoern A. Zeeb {
1491*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
1492*b4c3e9b5SBjoern A. Zeeb 	u16 mac_l;
1493*b4c3e9b5SBjoern A. Zeeb 	u16 mac_m;
1494*b4c3e9b5SBjoern A. Zeeb 	u16 mac_h;
1495*b4c3e9b5SBjoern A. Zeeb 
1496*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_rx(core, "wl%d: brcms_b_set_addrmatch\n", wlc_hw->unit);
1497*b4c3e9b5SBjoern A. Zeeb 
1498*b4c3e9b5SBjoern A. Zeeb 	mac_l = addr[0] | (addr[1] << 8);
1499*b4c3e9b5SBjoern A. Zeeb 	mac_m = addr[2] | (addr[3] << 8);
1500*b4c3e9b5SBjoern A. Zeeb 	mac_h = addr[4] | (addr[5] << 8);
1501*b4c3e9b5SBjoern A. Zeeb 
1502*b4c3e9b5SBjoern A. Zeeb 	/* enter the MAC addr into the RXE match registers */
1503*b4c3e9b5SBjoern A. Zeeb 	bcma_write16(core, D11REGOFFS(rcm_ctl),
1504*b4c3e9b5SBjoern A. Zeeb 		     RCM_INC_DATA | match_reg_offset);
1505*b4c3e9b5SBjoern A. Zeeb 	bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_l);
1506*b4c3e9b5SBjoern A. Zeeb 	bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_m);
1507*b4c3e9b5SBjoern A. Zeeb 	bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_h);
1508*b4c3e9b5SBjoern A. Zeeb }
1509*b4c3e9b5SBjoern A. Zeeb 
1510*b4c3e9b5SBjoern A. Zeeb void
brcms_b_write_template_ram(struct brcms_hardware * wlc_hw,int offset,int len,void * buf)1511*b4c3e9b5SBjoern A. Zeeb brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len,
1512*b4c3e9b5SBjoern A. Zeeb 			    void *buf)
1513*b4c3e9b5SBjoern A. Zeeb {
1514*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
1515*b4c3e9b5SBjoern A. Zeeb 	u32 word;
1516*b4c3e9b5SBjoern A. Zeeb 	__le32 word_le;
1517*b4c3e9b5SBjoern A. Zeeb 	__be32 word_be;
1518*b4c3e9b5SBjoern A. Zeeb 	bool be_bit;
1519*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(core, "wl%d\n", wlc_hw->unit);
1520*b4c3e9b5SBjoern A. Zeeb 
1521*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(tplatewrptr), offset);
1522*b4c3e9b5SBjoern A. Zeeb 
1523*b4c3e9b5SBjoern A. Zeeb 	/* if MCTL_BIGEND bit set in mac control register,
1524*b4c3e9b5SBjoern A. Zeeb 	 * the chip swaps data in fifo, as well as data in
1525*b4c3e9b5SBjoern A. Zeeb 	 * template ram
1526*b4c3e9b5SBjoern A. Zeeb 	 */
1527*b4c3e9b5SBjoern A. Zeeb 	be_bit = (bcma_read32(core, D11REGOFFS(maccontrol)) & MCTL_BIGEND) != 0;
1528*b4c3e9b5SBjoern A. Zeeb 
1529*b4c3e9b5SBjoern A. Zeeb 	while (len > 0) {
1530*b4c3e9b5SBjoern A. Zeeb 		memcpy(&word, buf, sizeof(u32));
1531*b4c3e9b5SBjoern A. Zeeb 
1532*b4c3e9b5SBjoern A. Zeeb 		if (be_bit) {
1533*b4c3e9b5SBjoern A. Zeeb 			word_be = cpu_to_be32(word);
1534*b4c3e9b5SBjoern A. Zeeb 			word = *(u32 *)&word_be;
1535*b4c3e9b5SBjoern A. Zeeb 		} else {
1536*b4c3e9b5SBjoern A. Zeeb 			word_le = cpu_to_le32(word);
1537*b4c3e9b5SBjoern A. Zeeb 			word = *(u32 *)&word_le;
1538*b4c3e9b5SBjoern A. Zeeb 		}
1539*b4c3e9b5SBjoern A. Zeeb 
1540*b4c3e9b5SBjoern A. Zeeb 		bcma_write32(core, D11REGOFFS(tplatewrdata), word);
1541*b4c3e9b5SBjoern A. Zeeb 
1542*b4c3e9b5SBjoern A. Zeeb 		buf = (u8 *) buf + sizeof(u32);
1543*b4c3e9b5SBjoern A. Zeeb 		len -= sizeof(u32);
1544*b4c3e9b5SBjoern A. Zeeb 	}
1545*b4c3e9b5SBjoern A. Zeeb }
1546*b4c3e9b5SBjoern A. Zeeb 
brcms_b_set_cwmin(struct brcms_hardware * wlc_hw,u16 newmin)1547*b4c3e9b5SBjoern A. Zeeb static void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin)
1548*b4c3e9b5SBjoern A. Zeeb {
1549*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->band->CWmin = newmin;
1550*b4c3e9b5SBjoern A. Zeeb 
1551*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),
1552*b4c3e9b5SBjoern A. Zeeb 		     OBJADDR_SCR_SEL | S_DOT11_CWMIN);
1553*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));
1554*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), newmin);
1555*b4c3e9b5SBjoern A. Zeeb }
1556*b4c3e9b5SBjoern A. Zeeb 
brcms_b_set_cwmax(struct brcms_hardware * wlc_hw,u16 newmax)1557*b4c3e9b5SBjoern A. Zeeb static void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax)
1558*b4c3e9b5SBjoern A. Zeeb {
1559*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->band->CWmax = newmax;
1560*b4c3e9b5SBjoern A. Zeeb 
1561*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),
1562*b4c3e9b5SBjoern A. Zeeb 		     OBJADDR_SCR_SEL | S_DOT11_CWMAX);
1563*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));
1564*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), newmax);
1565*b4c3e9b5SBjoern A. Zeeb }
1566*b4c3e9b5SBjoern A. Zeeb 
brcms_b_bw_set(struct brcms_hardware * wlc_hw,u16 bw)1567*b4c3e9b5SBjoern A. Zeeb void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)
1568*b4c3e9b5SBjoern A. Zeeb {
1569*b4c3e9b5SBjoern A. Zeeb 	bool fastclk;
1570*b4c3e9b5SBjoern A. Zeeb 
1571*b4c3e9b5SBjoern A. Zeeb 	/* request FAST clock if not on */
1572*b4c3e9b5SBjoern A. Zeeb 	fastclk = wlc_hw->forcefastclk;
1573*b4c3e9b5SBjoern A. Zeeb 	if (!fastclk)
1574*b4c3e9b5SBjoern A. Zeeb 		brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
1575*b4c3e9b5SBjoern A. Zeeb 
1576*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_bw_state_set(wlc_hw->band->pi, bw);
1577*b4c3e9b5SBjoern A. Zeeb 
1578*b4c3e9b5SBjoern A. Zeeb 	brcms_b_phy_reset(wlc_hw);
1579*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_init(wlc_hw->band->pi, wlc_phy_chanspec_get(wlc_hw->band->pi));
1580*b4c3e9b5SBjoern A. Zeeb 
1581*b4c3e9b5SBjoern A. Zeeb 	/* restore the clk */
1582*b4c3e9b5SBjoern A. Zeeb 	if (!fastclk)
1583*b4c3e9b5SBjoern A. Zeeb 		brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
1584*b4c3e9b5SBjoern A. Zeeb }
1585*b4c3e9b5SBjoern A. Zeeb 
brcms_b_upd_synthpu(struct brcms_hardware * wlc_hw)1586*b4c3e9b5SBjoern A. Zeeb static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw)
1587*b4c3e9b5SBjoern A. Zeeb {
1588*b4c3e9b5SBjoern A. Zeeb 	u16 v;
1589*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_info *wlc = wlc_hw->wlc;
1590*b4c3e9b5SBjoern A. Zeeb 	/* update SYNTHPU_DLY */
1591*b4c3e9b5SBjoern A. Zeeb 
1592*b4c3e9b5SBjoern A. Zeeb 	if (BRCMS_ISLCNPHY(wlc->band))
1593*b4c3e9b5SBjoern A. Zeeb 		v = SYNTHPU_DLY_LPPHY_US;
1594*b4c3e9b5SBjoern A. Zeeb 	else if (BRCMS_ISNPHY(wlc->band) && (NREV_GE(wlc->band->phyrev, 3)))
1595*b4c3e9b5SBjoern A. Zeeb 		v = SYNTHPU_DLY_NPHY_US;
1596*b4c3e9b5SBjoern A. Zeeb 	else
1597*b4c3e9b5SBjoern A. Zeeb 		v = SYNTHPU_DLY_BPHY_US;
1598*b4c3e9b5SBjoern A. Zeeb 
1599*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_SYNTHPU_DLY, v);
1600*b4c3e9b5SBjoern A. Zeeb }
1601*b4c3e9b5SBjoern A. Zeeb 
brcms_c_ucode_txant_set(struct brcms_hardware * wlc_hw)1602*b4c3e9b5SBjoern A. Zeeb static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw)
1603*b4c3e9b5SBjoern A. Zeeb {
1604*b4c3e9b5SBjoern A. Zeeb 	u16 phyctl;
1605*b4c3e9b5SBjoern A. Zeeb 	u16 phytxant = wlc_hw->bmac_phytxant;
1606*b4c3e9b5SBjoern A. Zeeb 	u16 mask = PHY_TXC_ANT_MASK;
1607*b4c3e9b5SBjoern A. Zeeb 
1608*b4c3e9b5SBjoern A. Zeeb 	/* set the Probe Response frame phy control word */
1609*b4c3e9b5SBjoern A. Zeeb 	phyctl = brcms_b_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS);
1610*b4c3e9b5SBjoern A. Zeeb 	phyctl = (phyctl & ~mask) | phytxant;
1611*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl);
1612*b4c3e9b5SBjoern A. Zeeb 
1613*b4c3e9b5SBjoern A. Zeeb 	/* set the Response (ACK/CTS) frame phy control word */
1614*b4c3e9b5SBjoern A. Zeeb 	phyctl = brcms_b_read_shm(wlc_hw, M_RSP_PCTLWD);
1615*b4c3e9b5SBjoern A. Zeeb 	phyctl = (phyctl & ~mask) | phytxant;
1616*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl);
1617*b4c3e9b5SBjoern A. Zeeb }
1618*b4c3e9b5SBjoern A. Zeeb 
brcms_b_ofdm_ratetable_offset(struct brcms_hardware * wlc_hw,u8 rate)1619*b4c3e9b5SBjoern A. Zeeb static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw,
1620*b4c3e9b5SBjoern A. Zeeb 					 u8 rate)
1621*b4c3e9b5SBjoern A. Zeeb {
1622*b4c3e9b5SBjoern A. Zeeb 	uint i;
1623*b4c3e9b5SBjoern A. Zeeb 	u8 plcp_rate = 0;
1624*b4c3e9b5SBjoern A. Zeeb 	struct plcp_signal_rate_lookup {
1625*b4c3e9b5SBjoern A. Zeeb 		u8 rate;
1626*b4c3e9b5SBjoern A. Zeeb 		u8 signal_rate;
1627*b4c3e9b5SBjoern A. Zeeb 	};
1628*b4c3e9b5SBjoern A. Zeeb 	/* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */
1629*b4c3e9b5SBjoern A. Zeeb 	const struct plcp_signal_rate_lookup rate_lookup[] = {
1630*b4c3e9b5SBjoern A. Zeeb 		{BRCM_RATE_6M, 0xB},
1631*b4c3e9b5SBjoern A. Zeeb 		{BRCM_RATE_9M, 0xF},
1632*b4c3e9b5SBjoern A. Zeeb 		{BRCM_RATE_12M, 0xA},
1633*b4c3e9b5SBjoern A. Zeeb 		{BRCM_RATE_18M, 0xE},
1634*b4c3e9b5SBjoern A. Zeeb 		{BRCM_RATE_24M, 0x9},
1635*b4c3e9b5SBjoern A. Zeeb 		{BRCM_RATE_36M, 0xD},
1636*b4c3e9b5SBjoern A. Zeeb 		{BRCM_RATE_48M, 0x8},
1637*b4c3e9b5SBjoern A. Zeeb 		{BRCM_RATE_54M, 0xC}
1638*b4c3e9b5SBjoern A. Zeeb 	};
1639*b4c3e9b5SBjoern A. Zeeb 
1640*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) {
1641*b4c3e9b5SBjoern A. Zeeb 		if (rate == rate_lookup[i].rate) {
1642*b4c3e9b5SBjoern A. Zeeb 			plcp_rate = rate_lookup[i].signal_rate;
1643*b4c3e9b5SBjoern A. Zeeb 			break;
1644*b4c3e9b5SBjoern A. Zeeb 		}
1645*b4c3e9b5SBjoern A. Zeeb 	}
1646*b4c3e9b5SBjoern A. Zeeb 
1647*b4c3e9b5SBjoern A. Zeeb 	/* Find the SHM pointer to the rate table entry by looking in the
1648*b4c3e9b5SBjoern A. Zeeb 	 * Direct-map Table
1649*b4c3e9b5SBjoern A. Zeeb 	 */
1650*b4c3e9b5SBjoern A. Zeeb 	return 2 * brcms_b_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2));
1651*b4c3e9b5SBjoern A. Zeeb }
1652*b4c3e9b5SBjoern A. Zeeb 
brcms_upd_ofdm_pctl1_table(struct brcms_hardware * wlc_hw)1653*b4c3e9b5SBjoern A. Zeeb static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw)
1654*b4c3e9b5SBjoern A. Zeeb {
1655*b4c3e9b5SBjoern A. Zeeb 	u8 rate;
1656*b4c3e9b5SBjoern A. Zeeb 	u8 rates[8] = {
1657*b4c3e9b5SBjoern A. Zeeb 		BRCM_RATE_6M, BRCM_RATE_9M, BRCM_RATE_12M, BRCM_RATE_18M,
1658*b4c3e9b5SBjoern A. Zeeb 		BRCM_RATE_24M, BRCM_RATE_36M, BRCM_RATE_48M, BRCM_RATE_54M
1659*b4c3e9b5SBjoern A. Zeeb 	};
1660*b4c3e9b5SBjoern A. Zeeb 	u16 entry_ptr;
1661*b4c3e9b5SBjoern A. Zeeb 	u16 pctl1;
1662*b4c3e9b5SBjoern A. Zeeb 	uint i;
1663*b4c3e9b5SBjoern A. Zeeb 
1664*b4c3e9b5SBjoern A. Zeeb 	if (!BRCMS_PHY_11N_CAP(wlc_hw->band))
1665*b4c3e9b5SBjoern A. Zeeb 		return;
1666*b4c3e9b5SBjoern A. Zeeb 
1667*b4c3e9b5SBjoern A. Zeeb 	/* walk the phy rate table and update the entries */
1668*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(rates); i++) {
1669*b4c3e9b5SBjoern A. Zeeb 		rate = rates[i];
1670*b4c3e9b5SBjoern A. Zeeb 
1671*b4c3e9b5SBjoern A. Zeeb 		entry_ptr = brcms_b_ofdm_ratetable_offset(wlc_hw, rate);
1672*b4c3e9b5SBjoern A. Zeeb 
1673*b4c3e9b5SBjoern A. Zeeb 		/* read the SHM Rate Table entry OFDM PCTL1 values */
1674*b4c3e9b5SBjoern A. Zeeb 		pctl1 =
1675*b4c3e9b5SBjoern A. Zeeb 		    brcms_b_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS);
1676*b4c3e9b5SBjoern A. Zeeb 
1677*b4c3e9b5SBjoern A. Zeeb 		/* modify the value */
1678*b4c3e9b5SBjoern A. Zeeb 		pctl1 &= ~PHY_TXC1_MODE_MASK;
1679*b4c3e9b5SBjoern A. Zeeb 		pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT);
1680*b4c3e9b5SBjoern A. Zeeb 
1681*b4c3e9b5SBjoern A. Zeeb 		/* Update the SHM Rate Table entry OFDM PCTL1 values */
1682*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS,
1683*b4c3e9b5SBjoern A. Zeeb 				   pctl1);
1684*b4c3e9b5SBjoern A. Zeeb 	}
1685*b4c3e9b5SBjoern A. Zeeb }
1686*b4c3e9b5SBjoern A. Zeeb 
1687*b4c3e9b5SBjoern A. Zeeb /* band-specific init */
brcms_b_bsinit(struct brcms_c_info * wlc,u16 chanspec)1688*b4c3e9b5SBjoern A. Zeeb static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec)
1689*b4c3e9b5SBjoern A. Zeeb {
1690*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
1691*b4c3e9b5SBjoern A. Zeeb 
1692*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: bandunit %d\n", wlc_hw->unit,
1693*b4c3e9b5SBjoern A. Zeeb 			   wlc_hw->band->bandunit);
1694*b4c3e9b5SBjoern A. Zeeb 
1695*b4c3e9b5SBjoern A. Zeeb 	brcms_c_ucode_bsinit(wlc_hw);
1696*b4c3e9b5SBjoern A. Zeeb 
1697*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_init(wlc_hw->band->pi, chanspec);
1698*b4c3e9b5SBjoern A. Zeeb 
1699*b4c3e9b5SBjoern A. Zeeb 	brcms_c_ucode_txant_set(wlc_hw);
1700*b4c3e9b5SBjoern A. Zeeb 
1701*b4c3e9b5SBjoern A. Zeeb 	/*
1702*b4c3e9b5SBjoern A. Zeeb 	 * cwmin is band-specific, update hardware
1703*b4c3e9b5SBjoern A. Zeeb 	 * with value for current band
1704*b4c3e9b5SBjoern A. Zeeb 	 */
1705*b4c3e9b5SBjoern A. Zeeb 	brcms_b_set_cwmin(wlc_hw, wlc_hw->band->CWmin);
1706*b4c3e9b5SBjoern A. Zeeb 	brcms_b_set_cwmax(wlc_hw, wlc_hw->band->CWmax);
1707*b4c3e9b5SBjoern A. Zeeb 
1708*b4c3e9b5SBjoern A. Zeeb 	brcms_b_update_slot_timing(wlc_hw,
1709*b4c3e9b5SBjoern A. Zeeb 				   wlc_hw->band->bandtype == BRCM_BAND_5G ?
1710*b4c3e9b5SBjoern A. Zeeb 				   true : wlc_hw->shortslot);
1711*b4c3e9b5SBjoern A. Zeeb 
1712*b4c3e9b5SBjoern A. Zeeb 	/* write phytype and phyvers */
1713*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_PHYTYPE, (u16) wlc_hw->band->phytype);
1714*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_PHYVER, (u16) wlc_hw->band->phyrev);
1715*b4c3e9b5SBjoern A. Zeeb 
1716*b4c3e9b5SBjoern A. Zeeb 	/*
1717*b4c3e9b5SBjoern A. Zeeb 	 * initialize the txphyctl1 rate table since
1718*b4c3e9b5SBjoern A. Zeeb 	 * shmem is shared between bands
1719*b4c3e9b5SBjoern A. Zeeb 	 */
1720*b4c3e9b5SBjoern A. Zeeb 	brcms_upd_ofdm_pctl1_table(wlc_hw);
1721*b4c3e9b5SBjoern A. Zeeb 
1722*b4c3e9b5SBjoern A. Zeeb 	brcms_b_upd_synthpu(wlc_hw);
1723*b4c3e9b5SBjoern A. Zeeb }
1724*b4c3e9b5SBjoern A. Zeeb 
1725*b4c3e9b5SBjoern A. Zeeb /* Perform a soft reset of the PHY PLL */
brcms_b_core_phypll_reset(struct brcms_hardware * wlc_hw)1726*b4c3e9b5SBjoern A. Zeeb void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw)
1727*b4c3e9b5SBjoern A. Zeeb {
1728*b4c3e9b5SBjoern A. Zeeb 	ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_addr),
1729*b4c3e9b5SBjoern A. Zeeb 		  ~0, 0);
1730*b4c3e9b5SBjoern A. Zeeb 	udelay(1);
1731*b4c3e9b5SBjoern A. Zeeb 	ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data),
1732*b4c3e9b5SBjoern A. Zeeb 		  0x4, 0);
1733*b4c3e9b5SBjoern A. Zeeb 	udelay(1);
1734*b4c3e9b5SBjoern A. Zeeb 	ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data),
1735*b4c3e9b5SBjoern A. Zeeb 		  0x4, 4);
1736*b4c3e9b5SBjoern A. Zeeb 	udelay(1);
1737*b4c3e9b5SBjoern A. Zeeb 	ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data),
1738*b4c3e9b5SBjoern A. Zeeb 		  0x4, 0);
1739*b4c3e9b5SBjoern A. Zeeb 	udelay(1);
1740*b4c3e9b5SBjoern A. Zeeb }
1741*b4c3e9b5SBjoern A. Zeeb 
1742*b4c3e9b5SBjoern A. Zeeb /* light way to turn on phy clock without reset for NPHY only
1743*b4c3e9b5SBjoern A. Zeeb  *  refer to brcms_b_core_phy_clk for full version
1744*b4c3e9b5SBjoern A. Zeeb  */
brcms_b_phyclk_fgc(struct brcms_hardware * wlc_hw,bool clk)1745*b4c3e9b5SBjoern A. Zeeb void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk)
1746*b4c3e9b5SBjoern A. Zeeb {
1747*b4c3e9b5SBjoern A. Zeeb 	/* support(necessary for NPHY and HYPHY) only */
1748*b4c3e9b5SBjoern A. Zeeb 	if (!BRCMS_ISNPHY(wlc_hw->band))
1749*b4c3e9b5SBjoern A. Zeeb 		return;
1750*b4c3e9b5SBjoern A. Zeeb 
1751*b4c3e9b5SBjoern A. Zeeb 	if (ON == clk)
1752*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw, SICF_FGC, SICF_FGC);
1753*b4c3e9b5SBjoern A. Zeeb 	else
1754*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw, SICF_FGC, 0);
1755*b4c3e9b5SBjoern A. Zeeb 
1756*b4c3e9b5SBjoern A. Zeeb }
1757*b4c3e9b5SBjoern A. Zeeb 
brcms_b_macphyclk_set(struct brcms_hardware * wlc_hw,bool clk)1758*b4c3e9b5SBjoern A. Zeeb void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk)
1759*b4c3e9b5SBjoern A. Zeeb {
1760*b4c3e9b5SBjoern A. Zeeb 	if (ON == clk)
1761*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw, SICF_MPCLKE, SICF_MPCLKE);
1762*b4c3e9b5SBjoern A. Zeeb 	else
1763*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw, SICF_MPCLKE, 0);
1764*b4c3e9b5SBjoern A. Zeeb }
1765*b4c3e9b5SBjoern A. Zeeb 
brcms_b_phy_reset(struct brcms_hardware * wlc_hw)1766*b4c3e9b5SBjoern A. Zeeb void brcms_b_phy_reset(struct brcms_hardware *wlc_hw)
1767*b4c3e9b5SBjoern A. Zeeb {
1768*b4c3e9b5SBjoern A. Zeeb 	struct brcms_phy_pub *pih = wlc_hw->band->pi;
1769*b4c3e9b5SBjoern A. Zeeb 	u32 phy_bw_clkbits;
1770*b4c3e9b5SBjoern A. Zeeb 
1771*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc_hw->d11core, "wl%d: reset phy\n", wlc_hw->unit);
1772*b4c3e9b5SBjoern A. Zeeb 
1773*b4c3e9b5SBjoern A. Zeeb 	if (pih == NULL)
1774*b4c3e9b5SBjoern A. Zeeb 		return;
1775*b4c3e9b5SBjoern A. Zeeb 
1776*b4c3e9b5SBjoern A. Zeeb 	phy_bw_clkbits = wlc_phy_clk_bwbits(wlc_hw->band->pi);
1777*b4c3e9b5SBjoern A. Zeeb 
1778*b4c3e9b5SBjoern A. Zeeb 	/* Specific reset sequence required for NPHY rev 3 and 4 */
1779*b4c3e9b5SBjoern A. Zeeb 	if (BRCMS_ISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) &&
1780*b4c3e9b5SBjoern A. Zeeb 	    NREV_LE(wlc_hw->band->phyrev, 4)) {
1781*b4c3e9b5SBjoern A. Zeeb 		/* Set the PHY bandwidth */
1782*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw, SICF_BWMASK, phy_bw_clkbits);
1783*b4c3e9b5SBjoern A. Zeeb 
1784*b4c3e9b5SBjoern A. Zeeb 		udelay(1);
1785*b4c3e9b5SBjoern A. Zeeb 
1786*b4c3e9b5SBjoern A. Zeeb 		/* Perform a soft reset of the PHY PLL */
1787*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_phypll_reset(wlc_hw);
1788*b4c3e9b5SBjoern A. Zeeb 
1789*b4c3e9b5SBjoern A. Zeeb 		/* reset the PHY */
1790*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_PCLKE),
1791*b4c3e9b5SBjoern A. Zeeb 				   (SICF_PRST | SICF_PCLKE));
1792*b4c3e9b5SBjoern A. Zeeb 	} else {
1793*b4c3e9b5SBjoern A. Zeeb 		brcms_b_core_ioctl(wlc_hw,
1794*b4c3e9b5SBjoern A. Zeeb 				   (SICF_PRST | SICF_PCLKE | SICF_BWMASK),
1795*b4c3e9b5SBjoern A. Zeeb 				   (SICF_PRST | SICF_PCLKE | phy_bw_clkbits));
1796*b4c3e9b5SBjoern A. Zeeb 	}
1797*b4c3e9b5SBjoern A. Zeeb 
1798*b4c3e9b5SBjoern A. Zeeb 	udelay(2);
1799*b4c3e9b5SBjoern A. Zeeb 	brcms_b_core_phy_clk(wlc_hw, ON);
1800*b4c3e9b5SBjoern A. Zeeb 
1801*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_anacore(pih, ON);
1802*b4c3e9b5SBjoern A. Zeeb }
1803*b4c3e9b5SBjoern A. Zeeb 
1804*b4c3e9b5SBjoern A. Zeeb /* switch to and initialize new band */
brcms_b_setband(struct brcms_hardware * wlc_hw,uint bandunit,u16 chanspec)1805*b4c3e9b5SBjoern A. Zeeb static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit,
1806*b4c3e9b5SBjoern A. Zeeb 			    u16 chanspec) {
1807*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_info *wlc = wlc_hw->wlc;
1808*b4c3e9b5SBjoern A. Zeeb 	u32 macintmask;
1809*b4c3e9b5SBjoern A. Zeeb 
1810*b4c3e9b5SBjoern A. Zeeb 	/* Enable the d11 core before accessing it */
1811*b4c3e9b5SBjoern A. Zeeb 	if (!bcma_core_is_enabled(wlc_hw->d11core)) {
1812*b4c3e9b5SBjoern A. Zeeb 		bcma_core_enable(wlc_hw->d11core, 0);
1813*b4c3e9b5SBjoern A. Zeeb 		brcms_c_mctrl_reset(wlc_hw);
1814*b4c3e9b5SBjoern A. Zeeb 	}
1815*b4c3e9b5SBjoern A. Zeeb 
1816*b4c3e9b5SBjoern A. Zeeb 	macintmask = brcms_c_setband_inact(wlc, bandunit);
1817*b4c3e9b5SBjoern A. Zeeb 
1818*b4c3e9b5SBjoern A. Zeeb 	if (!wlc_hw->up)
1819*b4c3e9b5SBjoern A. Zeeb 		return;
1820*b4c3e9b5SBjoern A. Zeeb 
1821*b4c3e9b5SBjoern A. Zeeb 	brcms_b_core_phy_clk(wlc_hw, ON);
1822*b4c3e9b5SBjoern A. Zeeb 
1823*b4c3e9b5SBjoern A. Zeeb 	/* band-specific initializations */
1824*b4c3e9b5SBjoern A. Zeeb 	brcms_b_bsinit(wlc, chanspec);
1825*b4c3e9b5SBjoern A. Zeeb 
1826*b4c3e9b5SBjoern A. Zeeb 	/*
1827*b4c3e9b5SBjoern A. Zeeb 	 * If there are any pending software interrupt bits,
1828*b4c3e9b5SBjoern A. Zeeb 	 * then replace these with a harmless nonzero value
1829*b4c3e9b5SBjoern A. Zeeb 	 * so brcms_c_dpc() will re-enable interrupts when done.
1830*b4c3e9b5SBjoern A. Zeeb 	 */
1831*b4c3e9b5SBjoern A. Zeeb 	if (wlc->macintstatus)
1832*b4c3e9b5SBjoern A. Zeeb 		wlc->macintstatus = MI_DMAINT;
1833*b4c3e9b5SBjoern A. Zeeb 
1834*b4c3e9b5SBjoern A. Zeeb 	/* restore macintmask */
1835*b4c3e9b5SBjoern A. Zeeb 	brcms_intrsrestore(wlc->wl, macintmask);
1836*b4c3e9b5SBjoern A. Zeeb 
1837*b4c3e9b5SBjoern A. Zeeb 	/* ucode should still be suspended.. */
1838*b4c3e9b5SBjoern A. Zeeb 	WARN_ON((bcma_read32(wlc_hw->d11core, D11REGOFFS(maccontrol)) &
1839*b4c3e9b5SBjoern A. Zeeb 		 MCTL_EN_MAC) != 0);
1840*b4c3e9b5SBjoern A. Zeeb }
1841*b4c3e9b5SBjoern A. Zeeb 
brcms_c_isgoodchip(struct brcms_hardware * wlc_hw)1842*b4c3e9b5SBjoern A. Zeeb static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw)
1843*b4c3e9b5SBjoern A. Zeeb {
1844*b4c3e9b5SBjoern A. Zeeb 
1845*b4c3e9b5SBjoern A. Zeeb 	/* reject unsupported corerev */
1846*b4c3e9b5SBjoern A. Zeeb 	if (!CONF_HAS(D11CONF, wlc_hw->corerev)) {
1847*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wlc_hw->wlc->wiphy, "unsupported core rev %d\n",
1848*b4c3e9b5SBjoern A. Zeeb 			  wlc_hw->corerev);
1849*b4c3e9b5SBjoern A. Zeeb 		return false;
1850*b4c3e9b5SBjoern A. Zeeb 	}
1851*b4c3e9b5SBjoern A. Zeeb 
1852*b4c3e9b5SBjoern A. Zeeb 	return true;
1853*b4c3e9b5SBjoern A. Zeeb }
1854*b4c3e9b5SBjoern A. Zeeb 
1855*b4c3e9b5SBjoern A. Zeeb /* Validate some board info parameters */
brcms_c_validboardtype(struct brcms_hardware * wlc_hw)1856*b4c3e9b5SBjoern A. Zeeb static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw)
1857*b4c3e9b5SBjoern A. Zeeb {
1858*b4c3e9b5SBjoern A. Zeeb 	uint boardrev = wlc_hw->boardrev;
1859*b4c3e9b5SBjoern A. Zeeb 
1860*b4c3e9b5SBjoern A. Zeeb 	/* 4 bits each for board type, major, minor, and tiny version */
1861*b4c3e9b5SBjoern A. Zeeb 	uint brt = (boardrev & 0xf000) >> 12;
1862*b4c3e9b5SBjoern A. Zeeb 	uint b0 = (boardrev & 0xf00) >> 8;
1863*b4c3e9b5SBjoern A. Zeeb 	uint b1 = (boardrev & 0xf0) >> 4;
1864*b4c3e9b5SBjoern A. Zeeb 	uint b2 = boardrev & 0xf;
1865*b4c3e9b5SBjoern A. Zeeb 
1866*b4c3e9b5SBjoern A. Zeeb 	/* voards from other vendors are always considered valid */
1867*b4c3e9b5SBjoern A. Zeeb 	if (ai_get_boardvendor(wlc_hw->sih) != PCI_VENDOR_ID_BROADCOM)
1868*b4c3e9b5SBjoern A. Zeeb 		return true;
1869*b4c3e9b5SBjoern A. Zeeb 
1870*b4c3e9b5SBjoern A. Zeeb 	/* do some boardrev sanity checks when boardvendor is Broadcom */
1871*b4c3e9b5SBjoern A. Zeeb 	if (boardrev == 0)
1872*b4c3e9b5SBjoern A. Zeeb 		return false;
1873*b4c3e9b5SBjoern A. Zeeb 
1874*b4c3e9b5SBjoern A. Zeeb 	if (boardrev <= 0xff)
1875*b4c3e9b5SBjoern A. Zeeb 		return true;
1876*b4c3e9b5SBjoern A. Zeeb 
1877*b4c3e9b5SBjoern A. Zeeb 	if ((brt > 2) || (brt == 0) || (b0 > 9) || (b0 == 0) || (b1 > 9)
1878*b4c3e9b5SBjoern A. Zeeb 		|| (b2 > 9))
1879*b4c3e9b5SBjoern A. Zeeb 		return false;
1880*b4c3e9b5SBjoern A. Zeeb 
1881*b4c3e9b5SBjoern A. Zeeb 	return true;
1882*b4c3e9b5SBjoern A. Zeeb }
1883*b4c3e9b5SBjoern A. Zeeb 
brcms_c_get_macaddr(struct brcms_hardware * wlc_hw,u8 etheraddr[ETH_ALEN])1884*b4c3e9b5SBjoern A. Zeeb static void brcms_c_get_macaddr(struct brcms_hardware *wlc_hw, u8 etheraddr[ETH_ALEN])
1885*b4c3e9b5SBjoern A. Zeeb {
1886*b4c3e9b5SBjoern A. Zeeb 	struct ssb_sprom *sprom = &wlc_hw->d11core->bus->sprom;
1887*b4c3e9b5SBjoern A. Zeeb 
1888*b4c3e9b5SBjoern A. Zeeb 	/* If macaddr exists, use it (Sromrev4, CIS, ...). */
1889*b4c3e9b5SBjoern A. Zeeb 	if (!is_zero_ether_addr(sprom->il0mac)) {
1890*b4c3e9b5SBjoern A. Zeeb 		memcpy(etheraddr, sprom->il0mac, ETH_ALEN);
1891*b4c3e9b5SBjoern A. Zeeb 		return;
1892*b4c3e9b5SBjoern A. Zeeb 	}
1893*b4c3e9b5SBjoern A. Zeeb 
1894*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->_nbands > 1)
1895*b4c3e9b5SBjoern A. Zeeb 		memcpy(etheraddr, sprom->et1mac, ETH_ALEN);
1896*b4c3e9b5SBjoern A. Zeeb 	else
1897*b4c3e9b5SBjoern A. Zeeb 		memcpy(etheraddr, sprom->il0mac, ETH_ALEN);
1898*b4c3e9b5SBjoern A. Zeeb }
1899*b4c3e9b5SBjoern A. Zeeb 
1900*b4c3e9b5SBjoern A. Zeeb /* power both the pll and external oscillator on/off */
brcms_b_xtal(struct brcms_hardware * wlc_hw,bool want)1901*b4c3e9b5SBjoern A. Zeeb static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)
1902*b4c3e9b5SBjoern A. Zeeb {
1903*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc_hw->d11core, "wl%d: want %d\n", wlc_hw->unit, want);
1904*b4c3e9b5SBjoern A. Zeeb 
1905*b4c3e9b5SBjoern A. Zeeb 	/*
1906*b4c3e9b5SBjoern A. Zeeb 	 * dont power down if plldown is false or
1907*b4c3e9b5SBjoern A. Zeeb 	 * we must poll hw radio disable
1908*b4c3e9b5SBjoern A. Zeeb 	 */
1909*b4c3e9b5SBjoern A. Zeeb 	if (!want && wlc_hw->pllreq)
1910*b4c3e9b5SBjoern A. Zeeb 		return;
1911*b4c3e9b5SBjoern A. Zeeb 
1912*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->sbclk = want;
1913*b4c3e9b5SBjoern A. Zeeb 	if (!wlc_hw->sbclk) {
1914*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->clk = false;
1915*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->band && wlc_hw->band->pi)
1916*b4c3e9b5SBjoern A. Zeeb 			wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
1917*b4c3e9b5SBjoern A. Zeeb 	}
1918*b4c3e9b5SBjoern A. Zeeb }
1919*b4c3e9b5SBjoern A. Zeeb 
1920*b4c3e9b5SBjoern A. Zeeb /*
1921*b4c3e9b5SBjoern A. Zeeb  * Return true if radio is disabled, otherwise false.
1922*b4c3e9b5SBjoern A. Zeeb  * hw radio disable signal is an external pin, users activate it asynchronously
1923*b4c3e9b5SBjoern A. Zeeb  * this function could be called when driver is down and w/o clock
1924*b4c3e9b5SBjoern A. Zeeb  * it operates on different registers depending on corerev and boardflag.
1925*b4c3e9b5SBjoern A. Zeeb  */
brcms_b_radio_read_hwdisabled(struct brcms_hardware * wlc_hw)1926*b4c3e9b5SBjoern A. Zeeb static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw)
1927*b4c3e9b5SBjoern A. Zeeb {
1928*b4c3e9b5SBjoern A. Zeeb 	bool v, clk, xtal;
1929*b4c3e9b5SBjoern A. Zeeb 	u32 flags = 0;
1930*b4c3e9b5SBjoern A. Zeeb 
1931*b4c3e9b5SBjoern A. Zeeb 	xtal = wlc_hw->sbclk;
1932*b4c3e9b5SBjoern A. Zeeb 	if (!xtal)
1933*b4c3e9b5SBjoern A. Zeeb 		brcms_b_xtal(wlc_hw, ON);
1934*b4c3e9b5SBjoern A. Zeeb 
1935*b4c3e9b5SBjoern A. Zeeb 	/* may need to take core out of reset first */
1936*b4c3e9b5SBjoern A. Zeeb 	clk = wlc_hw->clk;
1937*b4c3e9b5SBjoern A. Zeeb 	if (!clk) {
1938*b4c3e9b5SBjoern A. Zeeb 		/*
1939*b4c3e9b5SBjoern A. Zeeb 		 * mac no longer enables phyclk automatically when driver
1940*b4c3e9b5SBjoern A. Zeeb 		 * accesses phyreg throughput mac. This can be skipped since
1941*b4c3e9b5SBjoern A. Zeeb 		 * only mac reg is accessed below
1942*b4c3e9b5SBjoern A. Zeeb 		 */
1943*b4c3e9b5SBjoern A. Zeeb 		if (D11REV_GE(wlc_hw->corerev, 18))
1944*b4c3e9b5SBjoern A. Zeeb 			flags |= SICF_PCLKE;
1945*b4c3e9b5SBjoern A. Zeeb 
1946*b4c3e9b5SBjoern A. Zeeb 		/*
1947*b4c3e9b5SBjoern A. Zeeb 		 * TODO: test suspend/resume
1948*b4c3e9b5SBjoern A. Zeeb 		 *
1949*b4c3e9b5SBjoern A. Zeeb 		 * AI chip doesn't restore bar0win2 on
1950*b4c3e9b5SBjoern A. Zeeb 		 * hibernation/resume, need sw fixup
1951*b4c3e9b5SBjoern A. Zeeb 		 */
1952*b4c3e9b5SBjoern A. Zeeb 
1953*b4c3e9b5SBjoern A. Zeeb 		bcma_core_enable(wlc_hw->d11core, flags);
1954*b4c3e9b5SBjoern A. Zeeb 		brcms_c_mctrl_reset(wlc_hw);
1955*b4c3e9b5SBjoern A. Zeeb 	}
1956*b4c3e9b5SBjoern A. Zeeb 
1957*b4c3e9b5SBjoern A. Zeeb 	v = ((bcma_read32(wlc_hw->d11core,
1958*b4c3e9b5SBjoern A. Zeeb 			  D11REGOFFS(phydebug)) & PDBG_RFD) != 0);
1959*b4c3e9b5SBjoern A. Zeeb 
1960*b4c3e9b5SBjoern A. Zeeb 	/* put core back into reset */
1961*b4c3e9b5SBjoern A. Zeeb 	if (!clk)
1962*b4c3e9b5SBjoern A. Zeeb 		bcma_core_disable(wlc_hw->d11core, 0);
1963*b4c3e9b5SBjoern A. Zeeb 
1964*b4c3e9b5SBjoern A. Zeeb 	if (!xtal)
1965*b4c3e9b5SBjoern A. Zeeb 		brcms_b_xtal(wlc_hw, OFF);
1966*b4c3e9b5SBjoern A. Zeeb 
1967*b4c3e9b5SBjoern A. Zeeb 	return v;
1968*b4c3e9b5SBjoern A. Zeeb }
1969*b4c3e9b5SBjoern A. Zeeb 
wlc_dma_rxreset(struct brcms_hardware * wlc_hw,uint fifo)1970*b4c3e9b5SBjoern A. Zeeb static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo)
1971*b4c3e9b5SBjoern A. Zeeb {
1972*b4c3e9b5SBjoern A. Zeeb 	struct dma_pub *di = wlc_hw->di[fifo];
1973*b4c3e9b5SBjoern A. Zeeb 	return dma_rxreset(di);
1974*b4c3e9b5SBjoern A. Zeeb }
1975*b4c3e9b5SBjoern A. Zeeb 
1976*b4c3e9b5SBjoern A. Zeeb /* d11 core reset
1977*b4c3e9b5SBjoern A. Zeeb  *   ensure fask clock during reset
1978*b4c3e9b5SBjoern A. Zeeb  *   reset dma
1979*b4c3e9b5SBjoern A. Zeeb  *   reset d11(out of reset)
1980*b4c3e9b5SBjoern A. Zeeb  *   reset phy(out of reset)
1981*b4c3e9b5SBjoern A. Zeeb  *   clear software macintstatus for fresh new start
1982*b4c3e9b5SBjoern A. Zeeb  * one testing hack wlc_hw->noreset will bypass the d11/phy reset
1983*b4c3e9b5SBjoern A. Zeeb  */
brcms_b_corereset(struct brcms_hardware * wlc_hw,u32 flags)1984*b4c3e9b5SBjoern A. Zeeb void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
1985*b4c3e9b5SBjoern A. Zeeb {
1986*b4c3e9b5SBjoern A. Zeeb 	uint i;
1987*b4c3e9b5SBjoern A. Zeeb 	bool fastclk;
1988*b4c3e9b5SBjoern A. Zeeb 
1989*b4c3e9b5SBjoern A. Zeeb 	if (flags == BRCMS_USE_COREFLAGS)
1990*b4c3e9b5SBjoern A. Zeeb 		flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0);
1991*b4c3e9b5SBjoern A. Zeeb 
1992*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc_hw->d11core, "wl%d: core reset\n", wlc_hw->unit);
1993*b4c3e9b5SBjoern A. Zeeb 
1994*b4c3e9b5SBjoern A. Zeeb 	/* request FAST clock if not on  */
1995*b4c3e9b5SBjoern A. Zeeb 	fastclk = wlc_hw->forcefastclk;
1996*b4c3e9b5SBjoern A. Zeeb 	if (!fastclk)
1997*b4c3e9b5SBjoern A. Zeeb 		brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
1998*b4c3e9b5SBjoern A. Zeeb 
1999*b4c3e9b5SBjoern A. Zeeb 	/* reset the dma engines except first time thru */
2000*b4c3e9b5SBjoern A. Zeeb 	if (bcma_core_is_enabled(wlc_hw->d11core)) {
2001*b4c3e9b5SBjoern A. Zeeb 		for (i = 0; i < NFIFO; i++)
2002*b4c3e9b5SBjoern A. Zeeb 			if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i])))
2003*b4c3e9b5SBjoern A. Zeeb 				brcms_err(wlc_hw->d11core, "wl%d: %s: "
2004*b4c3e9b5SBjoern A. Zeeb 					  "dma_txreset[%d]: cannot stop dma\n",
2005*b4c3e9b5SBjoern A. Zeeb 					   wlc_hw->unit, __func__, i);
2006*b4c3e9b5SBjoern A. Zeeb 
2007*b4c3e9b5SBjoern A. Zeeb 		if ((wlc_hw->di[RX_FIFO])
2008*b4c3e9b5SBjoern A. Zeeb 		    && (!wlc_dma_rxreset(wlc_hw, RX_FIFO)))
2009*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc_hw->d11core, "wl%d: %s: dma_rxreset"
2010*b4c3e9b5SBjoern A. Zeeb 				  "[%d]: cannot stop dma\n",
2011*b4c3e9b5SBjoern A. Zeeb 				  wlc_hw->unit, __func__, RX_FIFO);
2012*b4c3e9b5SBjoern A. Zeeb 	}
2013*b4c3e9b5SBjoern A. Zeeb 	/* if noreset, just stop the psm and return */
2014*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->noreset) {
2015*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->wlc->macintstatus = 0;	/* skip wl_dpc after down */
2016*b4c3e9b5SBjoern A. Zeeb 		brcms_b_mctrl(wlc_hw, MCTL_PSM_RUN | MCTL_EN_MAC, 0);
2017*b4c3e9b5SBjoern A. Zeeb 		return;
2018*b4c3e9b5SBjoern A. Zeeb 	}
2019*b4c3e9b5SBjoern A. Zeeb 
2020*b4c3e9b5SBjoern A. Zeeb 	/*
2021*b4c3e9b5SBjoern A. Zeeb 	 * mac no longer enables phyclk automatically when driver accesses
2022*b4c3e9b5SBjoern A. Zeeb 	 * phyreg throughput mac, AND phy_reset is skipped at early stage when
2023*b4c3e9b5SBjoern A. Zeeb 	 * band->pi is invalid. need to enable PHY CLK
2024*b4c3e9b5SBjoern A. Zeeb 	 */
2025*b4c3e9b5SBjoern A. Zeeb 	if (D11REV_GE(wlc_hw->corerev, 18))
2026*b4c3e9b5SBjoern A. Zeeb 		flags |= SICF_PCLKE;
2027*b4c3e9b5SBjoern A. Zeeb 
2028*b4c3e9b5SBjoern A. Zeeb 	/*
2029*b4c3e9b5SBjoern A. Zeeb 	 * reset the core
2030*b4c3e9b5SBjoern A. Zeeb 	 * In chips with PMU, the fastclk request goes through d11 core
2031*b4c3e9b5SBjoern A. Zeeb 	 * reg 0x1e0, which is cleared by the core_reset. have to re-request it.
2032*b4c3e9b5SBjoern A. Zeeb 	 *
2033*b4c3e9b5SBjoern A. Zeeb 	 * This adds some delay and we can optimize it by also requesting
2034*b4c3e9b5SBjoern A. Zeeb 	 * fastclk through chipcommon during this period if necessary. But
2035*b4c3e9b5SBjoern A. Zeeb 	 * that has to work coordinate with other driver like mips/arm since
2036*b4c3e9b5SBjoern A. Zeeb 	 * they may touch chipcommon as well.
2037*b4c3e9b5SBjoern A. Zeeb 	 */
2038*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->clk = false;
2039*b4c3e9b5SBjoern A. Zeeb 	bcma_core_enable(wlc_hw->d11core, flags);
2040*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->clk = true;
2041*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->band && wlc_hw->band->pi)
2042*b4c3e9b5SBjoern A. Zeeb 		wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, true);
2043*b4c3e9b5SBjoern A. Zeeb 
2044*b4c3e9b5SBjoern A. Zeeb 	brcms_c_mctrl_reset(wlc_hw);
2045*b4c3e9b5SBjoern A. Zeeb 
2046*b4c3e9b5SBjoern A. Zeeb 	if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU)
2047*b4c3e9b5SBjoern A. Zeeb 		brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
2048*b4c3e9b5SBjoern A. Zeeb 
2049*b4c3e9b5SBjoern A. Zeeb 	brcms_b_phy_reset(wlc_hw);
2050*b4c3e9b5SBjoern A. Zeeb 
2051*b4c3e9b5SBjoern A. Zeeb 	/* turn on PHY_PLL */
2052*b4c3e9b5SBjoern A. Zeeb 	brcms_b_core_phypll_ctl(wlc_hw, true);
2053*b4c3e9b5SBjoern A. Zeeb 
2054*b4c3e9b5SBjoern A. Zeeb 	/* clear sw intstatus */
2055*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->wlc->macintstatus = 0;
2056*b4c3e9b5SBjoern A. Zeeb 
2057*b4c3e9b5SBjoern A. Zeeb 	/* restore the clk setting */
2058*b4c3e9b5SBjoern A. Zeeb 	if (!fastclk)
2059*b4c3e9b5SBjoern A. Zeeb 		brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
2060*b4c3e9b5SBjoern A. Zeeb }
2061*b4c3e9b5SBjoern A. Zeeb 
2062*b4c3e9b5SBjoern A. Zeeb /* txfifo sizes needs to be modified(increased) since the newer cores
2063*b4c3e9b5SBjoern A. Zeeb  * have more memory.
2064*b4c3e9b5SBjoern A. Zeeb  */
brcms_b_corerev_fifofixup(struct brcms_hardware * wlc_hw)2065*b4c3e9b5SBjoern A. Zeeb static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw)
2066*b4c3e9b5SBjoern A. Zeeb {
2067*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
2068*b4c3e9b5SBjoern A. Zeeb 	u16 fifo_nu;
2069*b4c3e9b5SBjoern A. Zeeb 	u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk;
2070*b4c3e9b5SBjoern A. Zeeb 	u16 txfifo_def, txfifo_def1;
2071*b4c3e9b5SBjoern A. Zeeb 	u16 txfifo_cmd;
2072*b4c3e9b5SBjoern A. Zeeb 
2073*b4c3e9b5SBjoern A. Zeeb 	/* tx fifos start at TXFIFO_START_BLK from the Base address */
2074*b4c3e9b5SBjoern A. Zeeb 	txfifo_startblk = TXFIFO_START_BLK;
2075*b4c3e9b5SBjoern A. Zeeb 
2076*b4c3e9b5SBjoern A. Zeeb 	/* sequence of operations:  reset fifo, set fifo size, reset fifo */
2077*b4c3e9b5SBjoern A. Zeeb 	for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) {
2078*b4c3e9b5SBjoern A. Zeeb 
2079*b4c3e9b5SBjoern A. Zeeb 		txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu];
2080*b4c3e9b5SBjoern A. Zeeb 		txfifo_def = (txfifo_startblk & 0xff) |
2081*b4c3e9b5SBjoern A. Zeeb 		    (((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT);
2082*b4c3e9b5SBjoern A. Zeeb 		txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) |
2083*b4c3e9b5SBjoern A. Zeeb 		    ((((txfifo_endblk -
2084*b4c3e9b5SBjoern A. Zeeb 			1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT);
2085*b4c3e9b5SBjoern A. Zeeb 		txfifo_cmd =
2086*b4c3e9b5SBjoern A. Zeeb 		    TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT);
2087*b4c3e9b5SBjoern A. Zeeb 
2088*b4c3e9b5SBjoern A. Zeeb 		bcma_write16(core, D11REGOFFS(xmtfifocmd), txfifo_cmd);
2089*b4c3e9b5SBjoern A. Zeeb 		bcma_write16(core, D11REGOFFS(xmtfifodef), txfifo_def);
2090*b4c3e9b5SBjoern A. Zeeb 		bcma_write16(core, D11REGOFFS(xmtfifodef1), txfifo_def1);
2091*b4c3e9b5SBjoern A. Zeeb 
2092*b4c3e9b5SBjoern A. Zeeb 		bcma_write16(core, D11REGOFFS(xmtfifocmd), txfifo_cmd);
2093*b4c3e9b5SBjoern A. Zeeb 
2094*b4c3e9b5SBjoern A. Zeeb 		txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu];
2095*b4c3e9b5SBjoern A. Zeeb 	}
2096*b4c3e9b5SBjoern A. Zeeb 	/*
2097*b4c3e9b5SBjoern A. Zeeb 	 * need to propagate to shm location to be in sync since ucode/hw won't
2098*b4c3e9b5SBjoern A. Zeeb 	 * do this
2099*b4c3e9b5SBjoern A. Zeeb 	 */
2100*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_FIFOSIZE0,
2101*b4c3e9b5SBjoern A. Zeeb 			   wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]);
2102*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_FIFOSIZE1,
2103*b4c3e9b5SBjoern A. Zeeb 			   wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]);
2104*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_FIFOSIZE2,
2105*b4c3e9b5SBjoern A. Zeeb 			   ((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw->
2106*b4c3e9b5SBjoern A. Zeeb 			    xmtfifo_sz[TX_AC_BK_FIFO]));
2107*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_FIFOSIZE3,
2108*b4c3e9b5SBjoern A. Zeeb 			   ((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw->
2109*b4c3e9b5SBjoern A. Zeeb 			    xmtfifo_sz[TX_BCMC_FIFO]));
2110*b4c3e9b5SBjoern A. Zeeb }
2111*b4c3e9b5SBjoern A. Zeeb 
2112*b4c3e9b5SBjoern A. Zeeb /* This function is used for changing the tsf frac register
2113*b4c3e9b5SBjoern A. Zeeb  * If spur avoidance mode is off, the mac freq will be 80/120/160Mhz
2114*b4c3e9b5SBjoern A. Zeeb  * If spur avoidance mode is on1, the mac freq will be 82/123/164Mhz
2115*b4c3e9b5SBjoern A. Zeeb  * If spur avoidance mode is on2, the mac freq will be 84/126/168Mhz
2116*b4c3e9b5SBjoern A. Zeeb  * HTPHY Formula is 2^26/freq(MHz) e.g.
2117*b4c3e9b5SBjoern A. Zeeb  * For spuron2 - 126MHz -> 2^26/126 = 532610.0
2118*b4c3e9b5SBjoern A. Zeeb  *  - 532610 = 0x82082 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x2082
2119*b4c3e9b5SBjoern A. Zeeb  * For spuron: 123MHz -> 2^26/123    = 545600.5
2120*b4c3e9b5SBjoern A. Zeeb  *  - 545601 = 0x85341 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x5341
2121*b4c3e9b5SBjoern A. Zeeb  * For spur off: 120MHz -> 2^26/120    = 559240.5
2122*b4c3e9b5SBjoern A. Zeeb  *  - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889
2123*b4c3e9b5SBjoern A. Zeeb  */
2124*b4c3e9b5SBjoern A. Zeeb 
brcms_b_switch_macfreq(struct brcms_hardware * wlc_hw,u8 spurmode)2125*b4c3e9b5SBjoern A. Zeeb void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode)
2126*b4c3e9b5SBjoern A. Zeeb {
2127*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
2128*b4c3e9b5SBjoern A. Zeeb 
2129*b4c3e9b5SBjoern A. Zeeb 	if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43224) ||
2130*b4c3e9b5SBjoern A. Zeeb 	    (ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43225)) {
2131*b4c3e9b5SBjoern A. Zeeb 		if (spurmode == WL_SPURAVOID_ON2) {	/* 126Mhz */
2132*b4c3e9b5SBjoern A. Zeeb 			bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x2082);
2133*b4c3e9b5SBjoern A. Zeeb 			bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8);
2134*b4c3e9b5SBjoern A. Zeeb 		} else if (spurmode == WL_SPURAVOID_ON1) {	/* 123Mhz */
2135*b4c3e9b5SBjoern A. Zeeb 			bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x5341);
2136*b4c3e9b5SBjoern A. Zeeb 			bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8);
2137*b4c3e9b5SBjoern A. Zeeb 		} else {	/* 120Mhz */
2138*b4c3e9b5SBjoern A. Zeeb 			bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x8889);
2139*b4c3e9b5SBjoern A. Zeeb 			bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8);
2140*b4c3e9b5SBjoern A. Zeeb 		}
2141*b4c3e9b5SBjoern A. Zeeb 	} else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
2142*b4c3e9b5SBjoern A. Zeeb 		if (spurmode == WL_SPURAVOID_ON1) {	/* 82Mhz */
2143*b4c3e9b5SBjoern A. Zeeb 			bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x7CE0);
2144*b4c3e9b5SBjoern A. Zeeb 			bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0xC);
2145*b4c3e9b5SBjoern A. Zeeb 		} else {	/* 80Mhz */
2146*b4c3e9b5SBjoern A. Zeeb 			bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0xCCCD);
2147*b4c3e9b5SBjoern A. Zeeb 			bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0xC);
2148*b4c3e9b5SBjoern A. Zeeb 		}
2149*b4c3e9b5SBjoern A. Zeeb 	}
2150*b4c3e9b5SBjoern A. Zeeb }
2151*b4c3e9b5SBjoern A. Zeeb 
brcms_c_start_station(struct brcms_c_info * wlc,u8 * addr)2152*b4c3e9b5SBjoern A. Zeeb void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr)
2153*b4c3e9b5SBjoern A. Zeeb {
2154*b4c3e9b5SBjoern A. Zeeb 	memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));
2155*b4c3e9b5SBjoern A. Zeeb 	wlc->bsscfg->type = BRCMS_TYPE_STATION;
2156*b4c3e9b5SBjoern A. Zeeb }
2157*b4c3e9b5SBjoern A. Zeeb 
brcms_c_start_ap(struct brcms_c_info * wlc,u8 * addr,const u8 * bssid,u8 * ssid,size_t ssid_len)2158*b4c3e9b5SBjoern A. Zeeb void brcms_c_start_ap(struct brcms_c_info *wlc, u8 *addr, const u8 *bssid,
2159*b4c3e9b5SBjoern A. Zeeb 		      u8 *ssid, size_t ssid_len)
2160*b4c3e9b5SBjoern A. Zeeb {
2161*b4c3e9b5SBjoern A. Zeeb 	brcms_c_set_ssid(wlc, ssid, ssid_len);
2162*b4c3e9b5SBjoern A. Zeeb 
2163*b4c3e9b5SBjoern A. Zeeb 	memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));
2164*b4c3e9b5SBjoern A. Zeeb 	memcpy(wlc->bsscfg->BSSID, bssid, sizeof(wlc->bsscfg->BSSID));
2165*b4c3e9b5SBjoern A. Zeeb 	wlc->bsscfg->type = BRCMS_TYPE_AP;
2166*b4c3e9b5SBjoern A. Zeeb 
2167*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mctrl(wlc->hw, MCTL_AP | MCTL_INFRA, MCTL_AP | MCTL_INFRA);
2168*b4c3e9b5SBjoern A. Zeeb }
2169*b4c3e9b5SBjoern A. Zeeb 
brcms_c_start_adhoc(struct brcms_c_info * wlc,u8 * addr)2170*b4c3e9b5SBjoern A. Zeeb void brcms_c_start_adhoc(struct brcms_c_info *wlc, u8 *addr)
2171*b4c3e9b5SBjoern A. Zeeb {
2172*b4c3e9b5SBjoern A. Zeeb 	memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));
2173*b4c3e9b5SBjoern A. Zeeb 	wlc->bsscfg->type = BRCMS_TYPE_ADHOC;
2174*b4c3e9b5SBjoern A. Zeeb 
2175*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mctrl(wlc->hw, MCTL_AP | MCTL_INFRA, 0);
2176*b4c3e9b5SBjoern A. Zeeb }
2177*b4c3e9b5SBjoern A. Zeeb 
2178*b4c3e9b5SBjoern A. Zeeb /* Initialize GPIOs that are controlled by D11 core */
brcms_c_gpio_init(struct brcms_c_info * wlc)2179*b4c3e9b5SBjoern A. Zeeb static void brcms_c_gpio_init(struct brcms_c_info *wlc)
2180*b4c3e9b5SBjoern A. Zeeb {
2181*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
2182*b4c3e9b5SBjoern A. Zeeb 	u32 gc, gm;
2183*b4c3e9b5SBjoern A. Zeeb 
2184*b4c3e9b5SBjoern A. Zeeb 	/* use GPIO select 0 to get all gpio signals from the gpio out reg */
2185*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mctrl(wlc_hw, MCTL_GPOUT_SEL_MASK, 0);
2186*b4c3e9b5SBjoern A. Zeeb 
2187*b4c3e9b5SBjoern A. Zeeb 	/*
2188*b4c3e9b5SBjoern A. Zeeb 	 * Common GPIO setup:
2189*b4c3e9b5SBjoern A. Zeeb 	 *      G0 = LED 0 = WLAN Activity
2190*b4c3e9b5SBjoern A. Zeeb 	 *      G1 = LED 1 = WLAN 2.4 GHz Radio State
2191*b4c3e9b5SBjoern A. Zeeb 	 *      G2 = LED 2 = WLAN 5 GHz Radio State
2192*b4c3e9b5SBjoern A. Zeeb 	 *      G4 = radio disable input (HI enabled, LO disabled)
2193*b4c3e9b5SBjoern A. Zeeb 	 */
2194*b4c3e9b5SBjoern A. Zeeb 
2195*b4c3e9b5SBjoern A. Zeeb 	gc = gm = 0;
2196*b4c3e9b5SBjoern A. Zeeb 
2197*b4c3e9b5SBjoern A. Zeeb 	/* Allocate GPIOs for mimo antenna diversity feature */
2198*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->antsel_type == ANTSEL_2x3) {
2199*b4c3e9b5SBjoern A. Zeeb 		/* Enable antenna diversity, use 2x3 mode */
2200*b4c3e9b5SBjoern A. Zeeb 		brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
2201*b4c3e9b5SBjoern A. Zeeb 			     MHF3_ANTSEL_EN, BRCM_BAND_ALL);
2202*b4c3e9b5SBjoern A. Zeeb 		brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE,
2203*b4c3e9b5SBjoern A. Zeeb 			     MHF3_ANTSEL_MODE, BRCM_BAND_ALL);
2204*b4c3e9b5SBjoern A. Zeeb 
2205*b4c3e9b5SBjoern A. Zeeb 		/* init superswitch control */
2206*b4c3e9b5SBjoern A. Zeeb 		wlc_phy_antsel_init(wlc_hw->band->pi, false);
2207*b4c3e9b5SBjoern A. Zeeb 
2208*b4c3e9b5SBjoern A. Zeeb 	} else if (wlc_hw->antsel_type == ANTSEL_2x4) {
2209*b4c3e9b5SBjoern A. Zeeb 		gm |= gc |= (BOARD_GPIO_12 | BOARD_GPIO_13);
2210*b4c3e9b5SBjoern A. Zeeb 		/*
2211*b4c3e9b5SBjoern A. Zeeb 		 * The board itself is powered by these GPIOs
2212*b4c3e9b5SBjoern A. Zeeb 		 * (when not sending pattern) so set them high
2213*b4c3e9b5SBjoern A. Zeeb 		 */
2214*b4c3e9b5SBjoern A. Zeeb 		bcma_set16(wlc_hw->d11core, D11REGOFFS(psm_gpio_oe),
2215*b4c3e9b5SBjoern A. Zeeb 			   (BOARD_GPIO_12 | BOARD_GPIO_13));
2216*b4c3e9b5SBjoern A. Zeeb 		bcma_set16(wlc_hw->d11core, D11REGOFFS(psm_gpio_out),
2217*b4c3e9b5SBjoern A. Zeeb 			   (BOARD_GPIO_12 | BOARD_GPIO_13));
2218*b4c3e9b5SBjoern A. Zeeb 
2219*b4c3e9b5SBjoern A. Zeeb 		/* Enable antenna diversity, use 2x4 mode */
2220*b4c3e9b5SBjoern A. Zeeb 		brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
2221*b4c3e9b5SBjoern A. Zeeb 			     MHF3_ANTSEL_EN, BRCM_BAND_ALL);
2222*b4c3e9b5SBjoern A. Zeeb 		brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, 0,
2223*b4c3e9b5SBjoern A. Zeeb 			     BRCM_BAND_ALL);
2224*b4c3e9b5SBjoern A. Zeeb 
2225*b4c3e9b5SBjoern A. Zeeb 		/* Configure the desired clock to be 4Mhz */
2226*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc_hw, M_ANTSEL_CLKDIV,
2227*b4c3e9b5SBjoern A. Zeeb 				   ANTSEL_CLKDIV_4MHZ);
2228*b4c3e9b5SBjoern A. Zeeb 	}
2229*b4c3e9b5SBjoern A. Zeeb 
2230*b4c3e9b5SBjoern A. Zeeb 	/*
2231*b4c3e9b5SBjoern A. Zeeb 	 * gpio 9 controls the PA. ucode is responsible
2232*b4c3e9b5SBjoern A. Zeeb 	 * for wiggling out and oe
2233*b4c3e9b5SBjoern A. Zeeb 	 */
2234*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->boardflags & BFL_PACTRL)
2235*b4c3e9b5SBjoern A. Zeeb 		gm |= gc |= BOARD_GPIO_PACTRL;
2236*b4c3e9b5SBjoern A. Zeeb 
2237*b4c3e9b5SBjoern A. Zeeb 	/* apply to gpiocontrol register */
2238*b4c3e9b5SBjoern A. Zeeb 	bcma_chipco_gpio_control(&wlc_hw->d11core->bus->drv_cc, gm, gc);
2239*b4c3e9b5SBjoern A. Zeeb }
2240*b4c3e9b5SBjoern A. Zeeb 
brcms_ucode_write(struct brcms_hardware * wlc_hw,const __le32 ucode[],const size_t nbytes)2241*b4c3e9b5SBjoern A. Zeeb static void brcms_ucode_write(struct brcms_hardware *wlc_hw,
2242*b4c3e9b5SBjoern A. Zeeb 			      const __le32 ucode[], const size_t nbytes)
2243*b4c3e9b5SBjoern A. Zeeb {
2244*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
2245*b4c3e9b5SBjoern A. Zeeb 	uint i;
2246*b4c3e9b5SBjoern A. Zeeb 	uint count;
2247*b4c3e9b5SBjoern A. Zeeb 
2248*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);
2249*b4c3e9b5SBjoern A. Zeeb 
2250*b4c3e9b5SBjoern A. Zeeb 	count = (nbytes / sizeof(u32));
2251*b4c3e9b5SBjoern A. Zeeb 
2252*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objaddr),
2253*b4c3e9b5SBjoern A. Zeeb 		     OBJADDR_AUTO_INC | OBJADDR_UCM_SEL);
2254*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(objaddr));
2255*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < count; i++)
2256*b4c3e9b5SBjoern A. Zeeb 		bcma_write32(core, D11REGOFFS(objdata), le32_to_cpu(ucode[i]));
2257*b4c3e9b5SBjoern A. Zeeb 
2258*b4c3e9b5SBjoern A. Zeeb }
2259*b4c3e9b5SBjoern A. Zeeb 
brcms_ucode_download(struct brcms_hardware * wlc_hw)2260*b4c3e9b5SBjoern A. Zeeb static void brcms_ucode_download(struct brcms_hardware *wlc_hw)
2261*b4c3e9b5SBjoern A. Zeeb {
2262*b4c3e9b5SBjoern A. Zeeb 	struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
2263*b4c3e9b5SBjoern A. Zeeb 
2264*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->ucode_loaded)
2265*b4c3e9b5SBjoern A. Zeeb 		return;
2266*b4c3e9b5SBjoern A. Zeeb 
2267*b4c3e9b5SBjoern A. Zeeb 	if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
2268*b4c3e9b5SBjoern A. Zeeb 		if (BRCMS_ISNPHY(wlc_hw->band)) {
2269*b4c3e9b5SBjoern A. Zeeb 			brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo,
2270*b4c3e9b5SBjoern A. Zeeb 					  ucode->bcm43xx_16_mimosz);
2271*b4c3e9b5SBjoern A. Zeeb 			wlc_hw->ucode_loaded = true;
2272*b4c3e9b5SBjoern A. Zeeb 		} else
2273*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc_hw->d11core,
2274*b4c3e9b5SBjoern A. Zeeb 				  "%s: wl%d: unsupported phy in corerev %d\n",
2275*b4c3e9b5SBjoern A. Zeeb 				  __func__, wlc_hw->unit, wlc_hw->corerev);
2276*b4c3e9b5SBjoern A. Zeeb 	} else if (D11REV_IS(wlc_hw->corerev, 24)) {
2277*b4c3e9b5SBjoern A. Zeeb 		if (BRCMS_ISLCNPHY(wlc_hw->band)) {
2278*b4c3e9b5SBjoern A. Zeeb 			brcms_ucode_write(wlc_hw, ucode->bcm43xx_24_lcn,
2279*b4c3e9b5SBjoern A. Zeeb 					  ucode->bcm43xx_24_lcnsz);
2280*b4c3e9b5SBjoern A. Zeeb 			wlc_hw->ucode_loaded = true;
2281*b4c3e9b5SBjoern A. Zeeb 		} else {
2282*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc_hw->d11core,
2283*b4c3e9b5SBjoern A. Zeeb 				  "%s: wl%d: unsupported phy in corerev %d\n",
2284*b4c3e9b5SBjoern A. Zeeb 				  __func__, wlc_hw->unit, wlc_hw->corerev);
2285*b4c3e9b5SBjoern A. Zeeb 		}
2286*b4c3e9b5SBjoern A. Zeeb 	}
2287*b4c3e9b5SBjoern A. Zeeb }
2288*b4c3e9b5SBjoern A. Zeeb 
brcms_b_txant_set(struct brcms_hardware * wlc_hw,u16 phytxant)2289*b4c3e9b5SBjoern A. Zeeb void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant)
2290*b4c3e9b5SBjoern A. Zeeb {
2291*b4c3e9b5SBjoern A. Zeeb 	/* update sw state */
2292*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->bmac_phytxant = phytxant;
2293*b4c3e9b5SBjoern A. Zeeb 
2294*b4c3e9b5SBjoern A. Zeeb 	/* push to ucode if up */
2295*b4c3e9b5SBjoern A. Zeeb 	if (!wlc_hw->up)
2296*b4c3e9b5SBjoern A. Zeeb 		return;
2297*b4c3e9b5SBjoern A. Zeeb 	brcms_c_ucode_txant_set(wlc_hw);
2298*b4c3e9b5SBjoern A. Zeeb 
2299*b4c3e9b5SBjoern A. Zeeb }
2300*b4c3e9b5SBjoern A. Zeeb 
brcms_b_get_txant(struct brcms_hardware * wlc_hw)2301*b4c3e9b5SBjoern A. Zeeb u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw)
2302*b4c3e9b5SBjoern A. Zeeb {
2303*b4c3e9b5SBjoern A. Zeeb 	return (u16) wlc_hw->wlc->stf->txant;
2304*b4c3e9b5SBjoern A. Zeeb }
2305*b4c3e9b5SBjoern A. Zeeb 
brcms_b_antsel_type_set(struct brcms_hardware * wlc_hw,u8 antsel_type)2306*b4c3e9b5SBjoern A. Zeeb void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type)
2307*b4c3e9b5SBjoern A. Zeeb {
2308*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->antsel_type = antsel_type;
2309*b4c3e9b5SBjoern A. Zeeb 
2310*b4c3e9b5SBjoern A. Zeeb 	/* Update the antsel type for phy module to use */
2311*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);
2312*b4c3e9b5SBjoern A. Zeeb }
2313*b4c3e9b5SBjoern A. Zeeb 
brcms_b_fifoerrors(struct brcms_hardware * wlc_hw)2314*b4c3e9b5SBjoern A. Zeeb static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
2315*b4c3e9b5SBjoern A. Zeeb {
2316*b4c3e9b5SBjoern A. Zeeb 	bool fatal = false;
2317*b4c3e9b5SBjoern A. Zeeb 	uint unit;
2318*b4c3e9b5SBjoern A. Zeeb 	uint intstatus, idx;
2319*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
2320*b4c3e9b5SBjoern A. Zeeb 
2321*b4c3e9b5SBjoern A. Zeeb 	unit = wlc_hw->unit;
2322*b4c3e9b5SBjoern A. Zeeb 
2323*b4c3e9b5SBjoern A. Zeeb 	for (idx = 0; idx < NFIFO; idx++) {
2324*b4c3e9b5SBjoern A. Zeeb 		/* read intstatus register and ignore any non-error bits */
2325*b4c3e9b5SBjoern A. Zeeb 		intstatus =
2326*b4c3e9b5SBjoern A. Zeeb 			bcma_read32(core,
2327*b4c3e9b5SBjoern A. Zeeb 				    D11REGOFFS(intctrlregs[idx].intstatus)) &
2328*b4c3e9b5SBjoern A. Zeeb 			I_ERRORS;
2329*b4c3e9b5SBjoern A. Zeeb 		if (!intstatus)
2330*b4c3e9b5SBjoern A. Zeeb 			continue;
2331*b4c3e9b5SBjoern A. Zeeb 
2332*b4c3e9b5SBjoern A. Zeeb 		brcms_dbg_int(core, "wl%d: intstatus%d 0x%x\n",
2333*b4c3e9b5SBjoern A. Zeeb 			      unit, idx, intstatus);
2334*b4c3e9b5SBjoern A. Zeeb 
2335*b4c3e9b5SBjoern A. Zeeb 		if (intstatus & I_RO) {
2336*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "wl%d: fifo %d: receive fifo "
2337*b4c3e9b5SBjoern A. Zeeb 				  "overflow\n", unit, idx);
2338*b4c3e9b5SBjoern A. Zeeb 			fatal = true;
2339*b4c3e9b5SBjoern A. Zeeb 		}
2340*b4c3e9b5SBjoern A. Zeeb 
2341*b4c3e9b5SBjoern A. Zeeb 		if (intstatus & I_PC) {
2342*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "wl%d: fifo %d: descriptor error\n",
2343*b4c3e9b5SBjoern A. Zeeb 				  unit, idx);
2344*b4c3e9b5SBjoern A. Zeeb 			fatal = true;
2345*b4c3e9b5SBjoern A. Zeeb 		}
2346*b4c3e9b5SBjoern A. Zeeb 
2347*b4c3e9b5SBjoern A. Zeeb 		if (intstatus & I_PD) {
2348*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "wl%d: fifo %d: data error\n", unit,
2349*b4c3e9b5SBjoern A. Zeeb 				  idx);
2350*b4c3e9b5SBjoern A. Zeeb 			fatal = true;
2351*b4c3e9b5SBjoern A. Zeeb 		}
2352*b4c3e9b5SBjoern A. Zeeb 
2353*b4c3e9b5SBjoern A. Zeeb 		if (intstatus & I_DE) {
2354*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "wl%d: fifo %d: descriptor protocol "
2355*b4c3e9b5SBjoern A. Zeeb 				  "error\n", unit, idx);
2356*b4c3e9b5SBjoern A. Zeeb 			fatal = true;
2357*b4c3e9b5SBjoern A. Zeeb 		}
2358*b4c3e9b5SBjoern A. Zeeb 
2359*b4c3e9b5SBjoern A. Zeeb 		if (intstatus & I_RU)
2360*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "wl%d: fifo %d: receive descriptor "
2361*b4c3e9b5SBjoern A. Zeeb 				  "underflow\n", idx, unit);
2362*b4c3e9b5SBjoern A. Zeeb 
2363*b4c3e9b5SBjoern A. Zeeb 		if (intstatus & I_XU) {
2364*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "wl%d: fifo %d: transmit fifo "
2365*b4c3e9b5SBjoern A. Zeeb 				  "underflow\n", idx, unit);
2366*b4c3e9b5SBjoern A. Zeeb 			fatal = true;
2367*b4c3e9b5SBjoern A. Zeeb 		}
2368*b4c3e9b5SBjoern A. Zeeb 
2369*b4c3e9b5SBjoern A. Zeeb 		if (fatal) {
2370*b4c3e9b5SBjoern A. Zeeb 			brcms_fatal_error(wlc_hw->wlc->wl); /* big hammer */
2371*b4c3e9b5SBjoern A. Zeeb 			break;
2372*b4c3e9b5SBjoern A. Zeeb 		} else
2373*b4c3e9b5SBjoern A. Zeeb 			bcma_write32(core,
2374*b4c3e9b5SBjoern A. Zeeb 				     D11REGOFFS(intctrlregs[idx].intstatus),
2375*b4c3e9b5SBjoern A. Zeeb 				     intstatus);
2376*b4c3e9b5SBjoern A. Zeeb 	}
2377*b4c3e9b5SBjoern A. Zeeb }
2378*b4c3e9b5SBjoern A. Zeeb 
brcms_c_intrson(struct brcms_c_info * wlc)2379*b4c3e9b5SBjoern A. Zeeb void brcms_c_intrson(struct brcms_c_info *wlc)
2380*b4c3e9b5SBjoern A. Zeeb {
2381*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
2382*b4c3e9b5SBjoern A. Zeeb 	wlc->macintmask = wlc->defmacintmask;
2383*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), wlc->macintmask);
2384*b4c3e9b5SBjoern A. Zeeb }
2385*b4c3e9b5SBjoern A. Zeeb 
brcms_c_intrsoff(struct brcms_c_info * wlc)2386*b4c3e9b5SBjoern A. Zeeb u32 brcms_c_intrsoff(struct brcms_c_info *wlc)
2387*b4c3e9b5SBjoern A. Zeeb {
2388*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
2389*b4c3e9b5SBjoern A. Zeeb 	u32 macintmask;
2390*b4c3e9b5SBjoern A. Zeeb 
2391*b4c3e9b5SBjoern A. Zeeb 	if (!wlc_hw->clk)
2392*b4c3e9b5SBjoern A. Zeeb 		return 0;
2393*b4c3e9b5SBjoern A. Zeeb 
2394*b4c3e9b5SBjoern A. Zeeb 	macintmask = wlc->macintmask;	/* isr can still happen */
2395*b4c3e9b5SBjoern A. Zeeb 
2396*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), 0);
2397*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(wlc_hw->d11core, D11REGOFFS(macintmask));
2398*b4c3e9b5SBjoern A. Zeeb 	udelay(1);		/* ensure int line is no longer driven */
2399*b4c3e9b5SBjoern A. Zeeb 	wlc->macintmask = 0;
2400*b4c3e9b5SBjoern A. Zeeb 
2401*b4c3e9b5SBjoern A. Zeeb 	/* return previous macintmask; resolve race between us and our isr */
2402*b4c3e9b5SBjoern A. Zeeb 	return wlc->macintstatus ? 0 : macintmask;
2403*b4c3e9b5SBjoern A. Zeeb }
2404*b4c3e9b5SBjoern A. Zeeb 
brcms_c_intrsrestore(struct brcms_c_info * wlc,u32 macintmask)2405*b4c3e9b5SBjoern A. Zeeb void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask)
2406*b4c3e9b5SBjoern A. Zeeb {
2407*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
2408*b4c3e9b5SBjoern A. Zeeb 	if (!wlc_hw->clk)
2409*b4c3e9b5SBjoern A. Zeeb 		return;
2410*b4c3e9b5SBjoern A. Zeeb 
2411*b4c3e9b5SBjoern A. Zeeb 	wlc->macintmask = macintmask;
2412*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), wlc->macintmask);
2413*b4c3e9b5SBjoern A. Zeeb }
2414*b4c3e9b5SBjoern A. Zeeb 
2415*b4c3e9b5SBjoern A. Zeeb /* assumes that the d11 MAC is enabled */
brcms_b_tx_fifo_suspend(struct brcms_hardware * wlc_hw,uint tx_fifo)2416*b4c3e9b5SBjoern A. Zeeb static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
2417*b4c3e9b5SBjoern A. Zeeb 				    uint tx_fifo)
2418*b4c3e9b5SBjoern A. Zeeb {
2419*b4c3e9b5SBjoern A. Zeeb 	u8 fifo = 1 << tx_fifo;
2420*b4c3e9b5SBjoern A. Zeeb 
2421*b4c3e9b5SBjoern A. Zeeb 	/* Two clients of this code, 11h Quiet period and scanning. */
2422*b4c3e9b5SBjoern A. Zeeb 
2423*b4c3e9b5SBjoern A. Zeeb 	/* only suspend if not already suspended */
2424*b4c3e9b5SBjoern A. Zeeb 	if ((wlc_hw->suspended_fifos & fifo) == fifo)
2425*b4c3e9b5SBjoern A. Zeeb 		return;
2426*b4c3e9b5SBjoern A. Zeeb 
2427*b4c3e9b5SBjoern A. Zeeb 	/* force the core awake only if not already */
2428*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->suspended_fifos == 0)
2429*b4c3e9b5SBjoern A. Zeeb 		brcms_c_ucode_wake_override_set(wlc_hw,
2430*b4c3e9b5SBjoern A. Zeeb 						BRCMS_WAKE_OVERRIDE_TXFIFO);
2431*b4c3e9b5SBjoern A. Zeeb 
2432*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->suspended_fifos |= fifo;
2433*b4c3e9b5SBjoern A. Zeeb 
2434*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->di[tx_fifo]) {
2435*b4c3e9b5SBjoern A. Zeeb 		/*
2436*b4c3e9b5SBjoern A. Zeeb 		 * Suspending AMPDU transmissions in the middle can cause
2437*b4c3e9b5SBjoern A. Zeeb 		 * underflow which may result in mismatch between ucode and
2438*b4c3e9b5SBjoern A. Zeeb 		 * driver so suspend the mac before suspending the FIFO
2439*b4c3e9b5SBjoern A. Zeeb 		 */
2440*b4c3e9b5SBjoern A. Zeeb 		if (BRCMS_PHY_11N_CAP(wlc_hw->band))
2441*b4c3e9b5SBjoern A. Zeeb 			brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
2442*b4c3e9b5SBjoern A. Zeeb 
2443*b4c3e9b5SBjoern A. Zeeb 		dma_txsuspend(wlc_hw->di[tx_fifo]);
2444*b4c3e9b5SBjoern A. Zeeb 
2445*b4c3e9b5SBjoern A. Zeeb 		if (BRCMS_PHY_11N_CAP(wlc_hw->band))
2446*b4c3e9b5SBjoern A. Zeeb 			brcms_c_enable_mac(wlc_hw->wlc);
2447*b4c3e9b5SBjoern A. Zeeb 	}
2448*b4c3e9b5SBjoern A. Zeeb }
2449*b4c3e9b5SBjoern A. Zeeb 
brcms_b_tx_fifo_resume(struct brcms_hardware * wlc_hw,uint tx_fifo)2450*b4c3e9b5SBjoern A. Zeeb static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
2451*b4c3e9b5SBjoern A. Zeeb 				   uint tx_fifo)
2452*b4c3e9b5SBjoern A. Zeeb {
2453*b4c3e9b5SBjoern A. Zeeb 	/* BMAC_NOTE: BRCMS_TX_FIFO_ENAB is done in brcms_c_dpc() for DMA case
2454*b4c3e9b5SBjoern A. Zeeb 	 * but need to be done here for PIO otherwise the watchdog will catch
2455*b4c3e9b5SBjoern A. Zeeb 	 * the inconsistency and fire
2456*b4c3e9b5SBjoern A. Zeeb 	 */
2457*b4c3e9b5SBjoern A. Zeeb 	/* Two clients of this code, 11h Quiet period and scanning. */
2458*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->di[tx_fifo])
2459*b4c3e9b5SBjoern A. Zeeb 		dma_txresume(wlc_hw->di[tx_fifo]);
2460*b4c3e9b5SBjoern A. Zeeb 
2461*b4c3e9b5SBjoern A. Zeeb 	/* allow core to sleep again */
2462*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->suspended_fifos == 0)
2463*b4c3e9b5SBjoern A. Zeeb 		return;
2464*b4c3e9b5SBjoern A. Zeeb 	else {
2465*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->suspended_fifos &= ~(1 << tx_fifo);
2466*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->suspended_fifos == 0)
2467*b4c3e9b5SBjoern A. Zeeb 			brcms_c_ucode_wake_override_clear(wlc_hw,
2468*b4c3e9b5SBjoern A. Zeeb 						BRCMS_WAKE_OVERRIDE_TXFIFO);
2469*b4c3e9b5SBjoern A. Zeeb 	}
2470*b4c3e9b5SBjoern A. Zeeb }
2471*b4c3e9b5SBjoern A. Zeeb 
2472*b4c3e9b5SBjoern A. Zeeb /* precondition: requires the mac core to be enabled */
brcms_b_mute(struct brcms_hardware * wlc_hw,bool mute_tx)2473*b4c3e9b5SBjoern A. Zeeb static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
2474*b4c3e9b5SBjoern A. Zeeb {
2475*b4c3e9b5SBjoern A. Zeeb 	static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
2476*b4c3e9b5SBjoern A. Zeeb 	u8 *ethaddr = wlc_hw->wlc->pub->cur_etheraddr;
2477*b4c3e9b5SBjoern A. Zeeb 
2478*b4c3e9b5SBjoern A. Zeeb 	if (mute_tx) {
2479*b4c3e9b5SBjoern A. Zeeb 		/* suspend tx fifos */
2480*b4c3e9b5SBjoern A. Zeeb 		brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO);
2481*b4c3e9b5SBjoern A. Zeeb 		brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO);
2482*b4c3e9b5SBjoern A. Zeeb 		brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_BK_FIFO);
2483*b4c3e9b5SBjoern A. Zeeb 		brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO);
2484*b4c3e9b5SBjoern A. Zeeb 
2485*b4c3e9b5SBjoern A. Zeeb 		/* zero the address match register so we do not send ACKs */
2486*b4c3e9b5SBjoern A. Zeeb 		brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, null_ether_addr);
2487*b4c3e9b5SBjoern A. Zeeb 	} else {
2488*b4c3e9b5SBjoern A. Zeeb 		/* resume tx fifos */
2489*b4c3e9b5SBjoern A. Zeeb 		brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO);
2490*b4c3e9b5SBjoern A. Zeeb 		brcms_b_tx_fifo_resume(wlc_hw, TX_CTL_FIFO);
2491*b4c3e9b5SBjoern A. Zeeb 		brcms_b_tx_fifo_resume(wlc_hw, TX_AC_BK_FIFO);
2492*b4c3e9b5SBjoern A. Zeeb 		brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO);
2493*b4c3e9b5SBjoern A. Zeeb 
2494*b4c3e9b5SBjoern A. Zeeb 		/* Restore address */
2495*b4c3e9b5SBjoern A. Zeeb 		brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, ethaddr);
2496*b4c3e9b5SBjoern A. Zeeb 	}
2497*b4c3e9b5SBjoern A. Zeeb 
2498*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0);
2499*b4c3e9b5SBjoern A. Zeeb 
2500*b4c3e9b5SBjoern A. Zeeb 	if (mute_tx)
2501*b4c3e9b5SBjoern A. Zeeb 		brcms_c_ucode_mute_override_set(wlc_hw);
2502*b4c3e9b5SBjoern A. Zeeb 	else
2503*b4c3e9b5SBjoern A. Zeeb 		brcms_c_ucode_mute_override_clear(wlc_hw);
2504*b4c3e9b5SBjoern A. Zeeb }
2505*b4c3e9b5SBjoern A. Zeeb 
2506*b4c3e9b5SBjoern A. Zeeb void
brcms_c_mute(struct brcms_c_info * wlc,bool mute_tx)2507*b4c3e9b5SBjoern A. Zeeb brcms_c_mute(struct brcms_c_info *wlc, bool mute_tx)
2508*b4c3e9b5SBjoern A. Zeeb {
2509*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mute(wlc->hw, mute_tx);
2510*b4c3e9b5SBjoern A. Zeeb }
2511*b4c3e9b5SBjoern A. Zeeb 
2512*b4c3e9b5SBjoern A. Zeeb /*
2513*b4c3e9b5SBjoern A. Zeeb  * Read and clear macintmask and macintstatus and intstatus registers.
2514*b4c3e9b5SBjoern A. Zeeb  * This routine should be called with interrupts off
2515*b4c3e9b5SBjoern A. Zeeb  * Return:
2516*b4c3e9b5SBjoern A. Zeeb  *   -1 if brcms_deviceremoved(wlc) evaluates to true;
2517*b4c3e9b5SBjoern A. Zeeb  *   0 if the interrupt is not for us, or we are in some special cases;
2518*b4c3e9b5SBjoern A. Zeeb  *   device interrupt status bits otherwise.
2519*b4c3e9b5SBjoern A. Zeeb  */
wlc_intstatus(struct brcms_c_info * wlc,bool in_isr)2520*b4c3e9b5SBjoern A. Zeeb static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr)
2521*b4c3e9b5SBjoern A. Zeeb {
2522*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
2523*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
2524*b4c3e9b5SBjoern A. Zeeb 	u32 macintstatus, mask;
2525*b4c3e9b5SBjoern A. Zeeb 
2526*b4c3e9b5SBjoern A. Zeeb 	/* macintstatus includes a DMA interrupt summary bit */
2527*b4c3e9b5SBjoern A. Zeeb 	macintstatus = bcma_read32(core, D11REGOFFS(macintstatus));
2528*b4c3e9b5SBjoern A. Zeeb 	mask = in_isr ? wlc->macintmask : wlc->defmacintmask;
2529*b4c3e9b5SBjoern A. Zeeb 
2530*b4c3e9b5SBjoern A. Zeeb 	trace_brcms_macintstatus(&core->dev, in_isr, macintstatus, mask);
2531*b4c3e9b5SBjoern A. Zeeb 
2532*b4c3e9b5SBjoern A. Zeeb 	/* detect cardbus removed, in power down(suspend) and in reset */
2533*b4c3e9b5SBjoern A. Zeeb 	if (brcms_deviceremoved(wlc))
2534*b4c3e9b5SBjoern A. Zeeb 		return -1;
2535*b4c3e9b5SBjoern A. Zeeb 
2536*b4c3e9b5SBjoern A. Zeeb 	/* brcms_deviceremoved() succeeds even when the core is still resetting,
2537*b4c3e9b5SBjoern A. Zeeb 	 * handle that case here.
2538*b4c3e9b5SBjoern A. Zeeb 	 */
2539*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus == 0xffffffff)
2540*b4c3e9b5SBjoern A. Zeeb 		return 0;
2541*b4c3e9b5SBjoern A. Zeeb 
2542*b4c3e9b5SBjoern A. Zeeb 	/* defer unsolicited interrupts */
2543*b4c3e9b5SBjoern A. Zeeb 	macintstatus &= mask;
2544*b4c3e9b5SBjoern A. Zeeb 
2545*b4c3e9b5SBjoern A. Zeeb 	/* if not for us */
2546*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus == 0)
2547*b4c3e9b5SBjoern A. Zeeb 		return 0;
2548*b4c3e9b5SBjoern A. Zeeb 
2549*b4c3e9b5SBjoern A. Zeeb 	/* turn off the interrupts */
2550*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(macintmask), 0);
2551*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(macintmask));
2552*b4c3e9b5SBjoern A. Zeeb 	wlc->macintmask = 0;
2553*b4c3e9b5SBjoern A. Zeeb 
2554*b4c3e9b5SBjoern A. Zeeb 	/* clear device interrupts */
2555*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(macintstatus), macintstatus);
2556*b4c3e9b5SBjoern A. Zeeb 
2557*b4c3e9b5SBjoern A. Zeeb 	/* MI_DMAINT is indication of non-zero intstatus */
2558*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus & MI_DMAINT)
2559*b4c3e9b5SBjoern A. Zeeb 		/*
2560*b4c3e9b5SBjoern A. Zeeb 		 * only fifo interrupt enabled is I_RI in
2561*b4c3e9b5SBjoern A. Zeeb 		 * RX_FIFO. If MI_DMAINT is set, assume it
2562*b4c3e9b5SBjoern A. Zeeb 		 * is set and clear the interrupt.
2563*b4c3e9b5SBjoern A. Zeeb 		 */
2564*b4c3e9b5SBjoern A. Zeeb 		bcma_write32(core, D11REGOFFS(intctrlregs[RX_FIFO].intstatus),
2565*b4c3e9b5SBjoern A. Zeeb 			     DEF_RXINTMASK);
2566*b4c3e9b5SBjoern A. Zeeb 
2567*b4c3e9b5SBjoern A. Zeeb 	return macintstatus;
2568*b4c3e9b5SBjoern A. Zeeb }
2569*b4c3e9b5SBjoern A. Zeeb 
2570*b4c3e9b5SBjoern A. Zeeb /* Update wlc->macintstatus and wlc->intstatus[]. */
2571*b4c3e9b5SBjoern A. Zeeb /* Return true if they are updated successfully. false otherwise */
brcms_c_intrsupd(struct brcms_c_info * wlc)2572*b4c3e9b5SBjoern A. Zeeb bool brcms_c_intrsupd(struct brcms_c_info *wlc)
2573*b4c3e9b5SBjoern A. Zeeb {
2574*b4c3e9b5SBjoern A. Zeeb 	u32 macintstatus;
2575*b4c3e9b5SBjoern A. Zeeb 
2576*b4c3e9b5SBjoern A. Zeeb 	/* read and clear macintstatus and intstatus registers */
2577*b4c3e9b5SBjoern A. Zeeb 	macintstatus = wlc_intstatus(wlc, false);
2578*b4c3e9b5SBjoern A. Zeeb 
2579*b4c3e9b5SBjoern A. Zeeb 	/* device is removed */
2580*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus == 0xffffffff)
2581*b4c3e9b5SBjoern A. Zeeb 		return false;
2582*b4c3e9b5SBjoern A. Zeeb 
2583*b4c3e9b5SBjoern A. Zeeb 	/* update interrupt status in software */
2584*b4c3e9b5SBjoern A. Zeeb 	wlc->macintstatus |= macintstatus;
2585*b4c3e9b5SBjoern A. Zeeb 
2586*b4c3e9b5SBjoern A. Zeeb 	return true;
2587*b4c3e9b5SBjoern A. Zeeb }
2588*b4c3e9b5SBjoern A. Zeeb 
2589*b4c3e9b5SBjoern A. Zeeb /*
2590*b4c3e9b5SBjoern A. Zeeb  * First-level interrupt processing.
2591*b4c3e9b5SBjoern A. Zeeb  * Return true if this was our interrupt
2592*b4c3e9b5SBjoern A. Zeeb  * and if further brcms_c_dpc() processing is required,
2593*b4c3e9b5SBjoern A. Zeeb  * false otherwise.
2594*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_isr(struct brcms_c_info * wlc)2595*b4c3e9b5SBjoern A. Zeeb bool brcms_c_isr(struct brcms_c_info *wlc)
2596*b4c3e9b5SBjoern A. Zeeb {
2597*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
2598*b4c3e9b5SBjoern A. Zeeb 	u32 macintstatus;
2599*b4c3e9b5SBjoern A. Zeeb 
2600*b4c3e9b5SBjoern A. Zeeb 	if (!wlc_hw->up || !wlc->macintmask)
2601*b4c3e9b5SBjoern A. Zeeb 		return false;
2602*b4c3e9b5SBjoern A. Zeeb 
2603*b4c3e9b5SBjoern A. Zeeb 	/* read and clear macintstatus and intstatus registers */
2604*b4c3e9b5SBjoern A. Zeeb 	macintstatus = wlc_intstatus(wlc, true);
2605*b4c3e9b5SBjoern A. Zeeb 
2606*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus == 0xffffffff) {
2607*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc_hw->d11core,
2608*b4c3e9b5SBjoern A. Zeeb 			  "DEVICEREMOVED detected in the ISR code path\n");
2609*b4c3e9b5SBjoern A. Zeeb 		return false;
2610*b4c3e9b5SBjoern A. Zeeb 	}
2611*b4c3e9b5SBjoern A. Zeeb 
2612*b4c3e9b5SBjoern A. Zeeb 	/* it is not for us */
2613*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus == 0)
2614*b4c3e9b5SBjoern A. Zeeb 		return false;
2615*b4c3e9b5SBjoern A. Zeeb 
2616*b4c3e9b5SBjoern A. Zeeb 	/* save interrupt status bits */
2617*b4c3e9b5SBjoern A. Zeeb 	wlc->macintstatus = macintstatus;
2618*b4c3e9b5SBjoern A. Zeeb 
2619*b4c3e9b5SBjoern A. Zeeb 	return true;
2620*b4c3e9b5SBjoern A. Zeeb 
2621*b4c3e9b5SBjoern A. Zeeb }
2622*b4c3e9b5SBjoern A. Zeeb 
brcms_c_suspend_mac_and_wait(struct brcms_c_info * wlc)2623*b4c3e9b5SBjoern A. Zeeb void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)
2624*b4c3e9b5SBjoern A. Zeeb {
2625*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
2626*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
2627*b4c3e9b5SBjoern A. Zeeb 	u32 mc, mi;
2628*b4c3e9b5SBjoern A. Zeeb 
2629*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_mac80211(core, "wl%d: bandunit %d\n", wlc_hw->unit,
2630*b4c3e9b5SBjoern A. Zeeb 			   wlc_hw->band->bandunit);
2631*b4c3e9b5SBjoern A. Zeeb 
2632*b4c3e9b5SBjoern A. Zeeb 	/*
2633*b4c3e9b5SBjoern A. Zeeb 	 * Track overlapping suspend requests
2634*b4c3e9b5SBjoern A. Zeeb 	 */
2635*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->mac_suspend_depth++;
2636*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->mac_suspend_depth > 1)
2637*b4c3e9b5SBjoern A. Zeeb 		return;
2638*b4c3e9b5SBjoern A. Zeeb 
2639*b4c3e9b5SBjoern A. Zeeb 	/* force the core awake */
2640*b4c3e9b5SBjoern A. Zeeb 	brcms_c_ucode_wake_override_set(wlc_hw, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
2641*b4c3e9b5SBjoern A. Zeeb 
2642*b4c3e9b5SBjoern A. Zeeb 	mc = bcma_read32(core, D11REGOFFS(maccontrol));
2643*b4c3e9b5SBjoern A. Zeeb 
2644*b4c3e9b5SBjoern A. Zeeb 	if (mc == 0xffffffff) {
2645*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
2646*b4c3e9b5SBjoern A. Zeeb 			  __func__);
2647*b4c3e9b5SBjoern A. Zeeb 		brcms_down(wlc->wl);
2648*b4c3e9b5SBjoern A. Zeeb 		return;
2649*b4c3e9b5SBjoern A. Zeeb 	}
2650*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(mc & MCTL_PSM_JMP_0);
2651*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(!(mc & MCTL_PSM_RUN));
2652*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(!(mc & MCTL_EN_MAC));
2653*b4c3e9b5SBjoern A. Zeeb 
2654*b4c3e9b5SBjoern A. Zeeb 	mi = bcma_read32(core, D11REGOFFS(macintstatus));
2655*b4c3e9b5SBjoern A. Zeeb 	if (mi == 0xffffffff) {
2656*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
2657*b4c3e9b5SBjoern A. Zeeb 			  __func__);
2658*b4c3e9b5SBjoern A. Zeeb 		brcms_down(wlc->wl);
2659*b4c3e9b5SBjoern A. Zeeb 		return;
2660*b4c3e9b5SBjoern A. Zeeb 	}
2661*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(mi & MI_MACSSPNDD);
2662*b4c3e9b5SBjoern A. Zeeb 
2663*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, 0);
2664*b4c3e9b5SBjoern A. Zeeb 
2665*b4c3e9b5SBjoern A. Zeeb 	SPINWAIT(!(bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD),
2666*b4c3e9b5SBjoern A. Zeeb 		 BRCMS_MAX_MAC_SUSPEND);
2667*b4c3e9b5SBjoern A. Zeeb 
2668*b4c3e9b5SBjoern A. Zeeb 	if (!(bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD)) {
2669*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "wl%d: wlc_suspend_mac_and_wait: waited %d uS"
2670*b4c3e9b5SBjoern A. Zeeb 			  " and MI_MACSSPNDD is still not on.\n",
2671*b4c3e9b5SBjoern A. Zeeb 			  wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND);
2672*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, "
2673*b4c3e9b5SBjoern A. Zeeb 			  "psm_brc 0x%04x\n", wlc_hw->unit,
2674*b4c3e9b5SBjoern A. Zeeb 			  bcma_read32(core, D11REGOFFS(psmdebug)),
2675*b4c3e9b5SBjoern A. Zeeb 			  bcma_read32(core, D11REGOFFS(phydebug)),
2676*b4c3e9b5SBjoern A. Zeeb 			  bcma_read16(core, D11REGOFFS(psm_brc)));
2677*b4c3e9b5SBjoern A. Zeeb 	}
2678*b4c3e9b5SBjoern A. Zeeb 
2679*b4c3e9b5SBjoern A. Zeeb 	mc = bcma_read32(core, D11REGOFFS(maccontrol));
2680*b4c3e9b5SBjoern A. Zeeb 	if (mc == 0xffffffff) {
2681*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
2682*b4c3e9b5SBjoern A. Zeeb 			  __func__);
2683*b4c3e9b5SBjoern A. Zeeb 		brcms_down(wlc->wl);
2684*b4c3e9b5SBjoern A. Zeeb 		return;
2685*b4c3e9b5SBjoern A. Zeeb 	}
2686*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(mc & MCTL_PSM_JMP_0);
2687*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(!(mc & MCTL_PSM_RUN));
2688*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(mc & MCTL_EN_MAC);
2689*b4c3e9b5SBjoern A. Zeeb }
2690*b4c3e9b5SBjoern A. Zeeb 
brcms_c_enable_mac(struct brcms_c_info * wlc)2691*b4c3e9b5SBjoern A. Zeeb void brcms_c_enable_mac(struct brcms_c_info *wlc)
2692*b4c3e9b5SBjoern A. Zeeb {
2693*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
2694*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
2695*b4c3e9b5SBjoern A. Zeeb 	u32 mc, mi;
2696*b4c3e9b5SBjoern A. Zeeb 
2697*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_mac80211(core, "wl%d: bandunit %d\n", wlc_hw->unit,
2698*b4c3e9b5SBjoern A. Zeeb 			   wlc->band->bandunit);
2699*b4c3e9b5SBjoern A. Zeeb 
2700*b4c3e9b5SBjoern A. Zeeb 	/*
2701*b4c3e9b5SBjoern A. Zeeb 	 * Track overlapping suspend requests
2702*b4c3e9b5SBjoern A. Zeeb 	 */
2703*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->mac_suspend_depth--;
2704*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->mac_suspend_depth > 0)
2705*b4c3e9b5SBjoern A. Zeeb 		return;
2706*b4c3e9b5SBjoern A. Zeeb 
2707*b4c3e9b5SBjoern A. Zeeb 	mc = bcma_read32(core, D11REGOFFS(maccontrol));
2708*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(mc & MCTL_PSM_JMP_0);
2709*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(mc & MCTL_EN_MAC);
2710*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(!(mc & MCTL_PSM_RUN));
2711*b4c3e9b5SBjoern A. Zeeb 
2712*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, MCTL_EN_MAC);
2713*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(macintstatus), MI_MACSSPNDD);
2714*b4c3e9b5SBjoern A. Zeeb 
2715*b4c3e9b5SBjoern A. Zeeb 	mc = bcma_read32(core, D11REGOFFS(maccontrol));
2716*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(mc & MCTL_PSM_JMP_0);
2717*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(!(mc & MCTL_EN_MAC));
2718*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(!(mc & MCTL_PSM_RUN));
2719*b4c3e9b5SBjoern A. Zeeb 
2720*b4c3e9b5SBjoern A. Zeeb 	mi = bcma_read32(core, D11REGOFFS(macintstatus));
2721*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(mi & MI_MACSSPNDD);
2722*b4c3e9b5SBjoern A. Zeeb 
2723*b4c3e9b5SBjoern A. Zeeb 	brcms_c_ucode_wake_override_clear(wlc_hw,
2724*b4c3e9b5SBjoern A. Zeeb 					  BRCMS_WAKE_OVERRIDE_MACSUSPEND);
2725*b4c3e9b5SBjoern A. Zeeb }
2726*b4c3e9b5SBjoern A. Zeeb 
brcms_b_band_stf_ss_set(struct brcms_hardware * wlc_hw,u8 stf_mode)2727*b4c3e9b5SBjoern A. Zeeb void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode)
2728*b4c3e9b5SBjoern A. Zeeb {
2729*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->hw_stf_ss_opmode = stf_mode;
2730*b4c3e9b5SBjoern A. Zeeb 
2731*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->clk)
2732*b4c3e9b5SBjoern A. Zeeb 		brcms_upd_ofdm_pctl1_table(wlc_hw);
2733*b4c3e9b5SBjoern A. Zeeb }
2734*b4c3e9b5SBjoern A. Zeeb 
brcms_b_validate_chip_access(struct brcms_hardware * wlc_hw)2735*b4c3e9b5SBjoern A. Zeeb static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw)
2736*b4c3e9b5SBjoern A. Zeeb {
2737*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
2738*b4c3e9b5SBjoern A. Zeeb 	u32 w, val;
2739*b4c3e9b5SBjoern A. Zeeb 	struct wiphy *wiphy = wlc_hw->wlc->wiphy;
2740*b4c3e9b5SBjoern A. Zeeb 
2741*b4c3e9b5SBjoern A. Zeeb 	/* Validate dchip register access */
2742*b4c3e9b5SBjoern A. Zeeb 
2743*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2744*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(objaddr));
2745*b4c3e9b5SBjoern A. Zeeb 	w = bcma_read32(core, D11REGOFFS(objdata));
2746*b4c3e9b5SBjoern A. Zeeb 
2747*b4c3e9b5SBjoern A. Zeeb 	/* Can we write and read back a 32bit register? */
2748*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2749*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(objaddr));
2750*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objdata), (u32) 0xaa5555aa);
2751*b4c3e9b5SBjoern A. Zeeb 
2752*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2753*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(objaddr));
2754*b4c3e9b5SBjoern A. Zeeb 	val = bcma_read32(core, D11REGOFFS(objdata));
2755*b4c3e9b5SBjoern A. Zeeb 	if (val != (u32) 0xaa5555aa) {
2756*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "
2757*b4c3e9b5SBjoern A. Zeeb 			  "expected 0xaa5555aa\n", wlc_hw->unit, val);
2758*b4c3e9b5SBjoern A. Zeeb 		return false;
2759*b4c3e9b5SBjoern A. Zeeb 	}
2760*b4c3e9b5SBjoern A. Zeeb 
2761*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2762*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(objaddr));
2763*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objdata), (u32) 0x55aaaa55);
2764*b4c3e9b5SBjoern A. Zeeb 
2765*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2766*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(objaddr));
2767*b4c3e9b5SBjoern A. Zeeb 	val = bcma_read32(core, D11REGOFFS(objdata));
2768*b4c3e9b5SBjoern A. Zeeb 	if (val != (u32) 0x55aaaa55) {
2769*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "
2770*b4c3e9b5SBjoern A. Zeeb 			  "expected 0x55aaaa55\n", wlc_hw->unit, val);
2771*b4c3e9b5SBjoern A. Zeeb 		return false;
2772*b4c3e9b5SBjoern A. Zeeb 	}
2773*b4c3e9b5SBjoern A. Zeeb 
2774*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
2775*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(objaddr));
2776*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objdata), w);
2777*b4c3e9b5SBjoern A. Zeeb 
2778*b4c3e9b5SBjoern A. Zeeb 	/* clear CFPStart */
2779*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(tsf_cfpstart), 0);
2780*b4c3e9b5SBjoern A. Zeeb 
2781*b4c3e9b5SBjoern A. Zeeb 	w = bcma_read32(core, D11REGOFFS(maccontrol));
2782*b4c3e9b5SBjoern A. Zeeb 	if ((w != (MCTL_IHR_EN | MCTL_WAKE)) &&
2783*b4c3e9b5SBjoern A. Zeeb 	    (w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) {
2784*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wiphy, "wl%d: validate_chip_access: maccontrol = "
2785*b4c3e9b5SBjoern A. Zeeb 			  "0x%x, expected 0x%x or 0x%x\n", wlc_hw->unit, w,
2786*b4c3e9b5SBjoern A. Zeeb 			  (MCTL_IHR_EN | MCTL_WAKE),
2787*b4c3e9b5SBjoern A. Zeeb 			  (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE));
2788*b4c3e9b5SBjoern A. Zeeb 		return false;
2789*b4c3e9b5SBjoern A. Zeeb 	}
2790*b4c3e9b5SBjoern A. Zeeb 
2791*b4c3e9b5SBjoern A. Zeeb 	return true;
2792*b4c3e9b5SBjoern A. Zeeb }
2793*b4c3e9b5SBjoern A. Zeeb 
2794*b4c3e9b5SBjoern A. Zeeb #define PHYPLL_WAIT_US	100000
2795*b4c3e9b5SBjoern A. Zeeb 
brcms_b_core_phypll_ctl(struct brcms_hardware * wlc_hw,bool on)2796*b4c3e9b5SBjoern A. Zeeb void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on)
2797*b4c3e9b5SBjoern A. Zeeb {
2798*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
2799*b4c3e9b5SBjoern A. Zeeb 	u32 tmp;
2800*b4c3e9b5SBjoern A. Zeeb 
2801*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(core, "wl%d\n", wlc_hw->unit);
2802*b4c3e9b5SBjoern A. Zeeb 
2803*b4c3e9b5SBjoern A. Zeeb 	tmp = 0;
2804*b4c3e9b5SBjoern A. Zeeb 
2805*b4c3e9b5SBjoern A. Zeeb 	if (on) {
2806*b4c3e9b5SBjoern A. Zeeb 		if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM4313)) {
2807*b4c3e9b5SBjoern A. Zeeb 			bcma_set32(core, D11REGOFFS(clk_ctl_st),
2808*b4c3e9b5SBjoern A. Zeeb 				   CCS_ERSRC_REQ_HT |
2809*b4c3e9b5SBjoern A. Zeeb 				   CCS_ERSRC_REQ_D11PLL |
2810*b4c3e9b5SBjoern A. Zeeb 				   CCS_ERSRC_REQ_PHYPLL);
2811*b4c3e9b5SBjoern A. Zeeb 			SPINWAIT((bcma_read32(core, D11REGOFFS(clk_ctl_st)) &
2812*b4c3e9b5SBjoern A. Zeeb 				  CCS_ERSRC_AVAIL_HT) != CCS_ERSRC_AVAIL_HT,
2813*b4c3e9b5SBjoern A. Zeeb 				 PHYPLL_WAIT_US);
2814*b4c3e9b5SBjoern A. Zeeb 
2815*b4c3e9b5SBjoern A. Zeeb 			tmp = bcma_read32(core, D11REGOFFS(clk_ctl_st));
2816*b4c3e9b5SBjoern A. Zeeb 			if ((tmp & CCS_ERSRC_AVAIL_HT) != CCS_ERSRC_AVAIL_HT)
2817*b4c3e9b5SBjoern A. Zeeb 				brcms_err(core, "%s: turn on PHY PLL failed\n",
2818*b4c3e9b5SBjoern A. Zeeb 					  __func__);
2819*b4c3e9b5SBjoern A. Zeeb 		} else {
2820*b4c3e9b5SBjoern A. Zeeb 			bcma_set32(core, D11REGOFFS(clk_ctl_st),
2821*b4c3e9b5SBjoern A. Zeeb 				   tmp | CCS_ERSRC_REQ_D11PLL |
2822*b4c3e9b5SBjoern A. Zeeb 				   CCS_ERSRC_REQ_PHYPLL);
2823*b4c3e9b5SBjoern A. Zeeb 			SPINWAIT((bcma_read32(core, D11REGOFFS(clk_ctl_st)) &
2824*b4c3e9b5SBjoern A. Zeeb 				  (CCS_ERSRC_AVAIL_D11PLL |
2825*b4c3e9b5SBjoern A. Zeeb 				   CCS_ERSRC_AVAIL_PHYPLL)) !=
2826*b4c3e9b5SBjoern A. Zeeb 				 (CCS_ERSRC_AVAIL_D11PLL |
2827*b4c3e9b5SBjoern A. Zeeb 				  CCS_ERSRC_AVAIL_PHYPLL), PHYPLL_WAIT_US);
2828*b4c3e9b5SBjoern A. Zeeb 
2829*b4c3e9b5SBjoern A. Zeeb 			tmp = bcma_read32(core, D11REGOFFS(clk_ctl_st));
2830*b4c3e9b5SBjoern A. Zeeb 			if ((tmp &
2831*b4c3e9b5SBjoern A. Zeeb 			     (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
2832*b4c3e9b5SBjoern A. Zeeb 			    !=
2833*b4c3e9b5SBjoern A. Zeeb 			    (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
2834*b4c3e9b5SBjoern A. Zeeb 				brcms_err(core, "%s: turn on PHY PLL failed\n",
2835*b4c3e9b5SBjoern A. Zeeb 					  __func__);
2836*b4c3e9b5SBjoern A. Zeeb 		}
2837*b4c3e9b5SBjoern A. Zeeb 	} else {
2838*b4c3e9b5SBjoern A. Zeeb 		/*
2839*b4c3e9b5SBjoern A. Zeeb 		 * Since the PLL may be shared, other cores can still
2840*b4c3e9b5SBjoern A. Zeeb 		 * be requesting it; so we'll deassert the request but
2841*b4c3e9b5SBjoern A. Zeeb 		 * not wait for status to comply.
2842*b4c3e9b5SBjoern A. Zeeb 		 */
2843*b4c3e9b5SBjoern A. Zeeb 		bcma_mask32(core, D11REGOFFS(clk_ctl_st),
2844*b4c3e9b5SBjoern A. Zeeb 			    ~CCS_ERSRC_REQ_PHYPLL);
2845*b4c3e9b5SBjoern A. Zeeb 		(void)bcma_read32(core, D11REGOFFS(clk_ctl_st));
2846*b4c3e9b5SBjoern A. Zeeb 	}
2847*b4c3e9b5SBjoern A. Zeeb }
2848*b4c3e9b5SBjoern A. Zeeb 
brcms_c_coredisable(struct brcms_hardware * wlc_hw)2849*b4c3e9b5SBjoern A. Zeeb static void brcms_c_coredisable(struct brcms_hardware *wlc_hw)
2850*b4c3e9b5SBjoern A. Zeeb {
2851*b4c3e9b5SBjoern A. Zeeb 	bool dev_gone;
2852*b4c3e9b5SBjoern A. Zeeb 
2853*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc_hw->d11core, "wl%d: disable core\n", wlc_hw->unit);
2854*b4c3e9b5SBjoern A. Zeeb 
2855*b4c3e9b5SBjoern A. Zeeb 	dev_gone = brcms_deviceremoved(wlc_hw->wlc);
2856*b4c3e9b5SBjoern A. Zeeb 
2857*b4c3e9b5SBjoern A. Zeeb 	if (dev_gone)
2858*b4c3e9b5SBjoern A. Zeeb 		return;
2859*b4c3e9b5SBjoern A. Zeeb 
2860*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->noreset)
2861*b4c3e9b5SBjoern A. Zeeb 		return;
2862*b4c3e9b5SBjoern A. Zeeb 
2863*b4c3e9b5SBjoern A. Zeeb 	/* radio off */
2864*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
2865*b4c3e9b5SBjoern A. Zeeb 
2866*b4c3e9b5SBjoern A. Zeeb 	/* turn off analog core */
2867*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_anacore(wlc_hw->band->pi, OFF);
2868*b4c3e9b5SBjoern A. Zeeb 
2869*b4c3e9b5SBjoern A. Zeeb 	/* turn off PHYPLL to save power */
2870*b4c3e9b5SBjoern A. Zeeb 	brcms_b_core_phypll_ctl(wlc_hw, false);
2871*b4c3e9b5SBjoern A. Zeeb 
2872*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->clk = false;
2873*b4c3e9b5SBjoern A. Zeeb 	bcma_core_disable(wlc_hw->d11core, 0);
2874*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
2875*b4c3e9b5SBjoern A. Zeeb }
2876*b4c3e9b5SBjoern A. Zeeb 
brcms_c_flushqueues(struct brcms_c_info * wlc)2877*b4c3e9b5SBjoern A. Zeeb static void brcms_c_flushqueues(struct brcms_c_info *wlc)
2878*b4c3e9b5SBjoern A. Zeeb {
2879*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
2880*b4c3e9b5SBjoern A. Zeeb 	uint i;
2881*b4c3e9b5SBjoern A. Zeeb 
2882*b4c3e9b5SBjoern A. Zeeb 	/* free any posted tx packets */
2883*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < NFIFO; i++) {
2884*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->di[i]) {
2885*b4c3e9b5SBjoern A. Zeeb 			dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL);
2886*b4c3e9b5SBjoern A. Zeeb 			if (i < TX_BCMC_FIFO)
2887*b4c3e9b5SBjoern A. Zeeb 				ieee80211_wake_queue(wlc->pub->ieee_hw,
2888*b4c3e9b5SBjoern A. Zeeb 						     brcms_fifo_to_ac(i));
2889*b4c3e9b5SBjoern A. Zeeb 		}
2890*b4c3e9b5SBjoern A. Zeeb 	}
2891*b4c3e9b5SBjoern A. Zeeb 
2892*b4c3e9b5SBjoern A. Zeeb 	/* free any posted rx packets */
2893*b4c3e9b5SBjoern A. Zeeb 	dma_rxreclaim(wlc_hw->di[RX_FIFO]);
2894*b4c3e9b5SBjoern A. Zeeb }
2895*b4c3e9b5SBjoern A. Zeeb 
2896*b4c3e9b5SBjoern A. Zeeb static u16
brcms_b_read_objmem(struct brcms_hardware * wlc_hw,uint offset,u32 sel)2897*b4c3e9b5SBjoern A. Zeeb brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel)
2898*b4c3e9b5SBjoern A. Zeeb {
2899*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
2900*b4c3e9b5SBjoern A. Zeeb 	u16 objoff = D11REGOFFS(objdata);
2901*b4c3e9b5SBjoern A. Zeeb 
2902*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objaddr), sel | (offset >> 2));
2903*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(objaddr));
2904*b4c3e9b5SBjoern A. Zeeb 	if (offset & 2)
2905*b4c3e9b5SBjoern A. Zeeb 		objoff += 2;
2906*b4c3e9b5SBjoern A. Zeeb 
2907*b4c3e9b5SBjoern A. Zeeb 	return bcma_read16(core, objoff);
2908*b4c3e9b5SBjoern A. Zeeb }
2909*b4c3e9b5SBjoern A. Zeeb 
2910*b4c3e9b5SBjoern A. Zeeb static void
brcms_b_write_objmem(struct brcms_hardware * wlc_hw,uint offset,u16 v,u32 sel)2911*b4c3e9b5SBjoern A. Zeeb brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset, u16 v,
2912*b4c3e9b5SBjoern A. Zeeb 		     u32 sel)
2913*b4c3e9b5SBjoern A. Zeeb {
2914*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
2915*b4c3e9b5SBjoern A. Zeeb 	u16 objoff = D11REGOFFS(objdata);
2916*b4c3e9b5SBjoern A. Zeeb 
2917*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objaddr), sel | (offset >> 2));
2918*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(objaddr));
2919*b4c3e9b5SBjoern A. Zeeb 	if (offset & 2)
2920*b4c3e9b5SBjoern A. Zeeb 		objoff += 2;
2921*b4c3e9b5SBjoern A. Zeeb 
2922*b4c3e9b5SBjoern A. Zeeb 	bcma_wflush16(core, objoff, v);
2923*b4c3e9b5SBjoern A. Zeeb }
2924*b4c3e9b5SBjoern A. Zeeb 
2925*b4c3e9b5SBjoern A. Zeeb /*
2926*b4c3e9b5SBjoern A. Zeeb  * Read a single u16 from shared memory.
2927*b4c3e9b5SBjoern A. Zeeb  * SHM 'offset' needs to be an even address
2928*b4c3e9b5SBjoern A. Zeeb  */
brcms_b_read_shm(struct brcms_hardware * wlc_hw,uint offset)2929*b4c3e9b5SBjoern A. Zeeb u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset)
2930*b4c3e9b5SBjoern A. Zeeb {
2931*b4c3e9b5SBjoern A. Zeeb 	return brcms_b_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL);
2932*b4c3e9b5SBjoern A. Zeeb }
2933*b4c3e9b5SBjoern A. Zeeb 
2934*b4c3e9b5SBjoern A. Zeeb /*
2935*b4c3e9b5SBjoern A. Zeeb  * Write a single u16 to shared memory.
2936*b4c3e9b5SBjoern A. Zeeb  * SHM 'offset' needs to be an even address
2937*b4c3e9b5SBjoern A. Zeeb  */
brcms_b_write_shm(struct brcms_hardware * wlc_hw,uint offset,u16 v)2938*b4c3e9b5SBjoern A. Zeeb void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v)
2939*b4c3e9b5SBjoern A. Zeeb {
2940*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL);
2941*b4c3e9b5SBjoern A. Zeeb }
2942*b4c3e9b5SBjoern A. Zeeb 
2943*b4c3e9b5SBjoern A. Zeeb /*
2944*b4c3e9b5SBjoern A. Zeeb  * Copy a buffer to shared memory of specified type .
2945*b4c3e9b5SBjoern A. Zeeb  * SHM 'offset' needs to be an even address and
2946*b4c3e9b5SBjoern A. Zeeb  * Buffer length 'len' must be an even number of bytes
2947*b4c3e9b5SBjoern A. Zeeb  * 'sel' selects the type of memory
2948*b4c3e9b5SBjoern A. Zeeb  */
2949*b4c3e9b5SBjoern A. Zeeb void
brcms_b_copyto_objmem(struct brcms_hardware * wlc_hw,uint offset,const void * buf,int len,u32 sel)2950*b4c3e9b5SBjoern A. Zeeb brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, uint offset,
2951*b4c3e9b5SBjoern A. Zeeb 		      const void *buf, int len, u32 sel)
2952*b4c3e9b5SBjoern A. Zeeb {
2953*b4c3e9b5SBjoern A. Zeeb 	u16 v;
2954*b4c3e9b5SBjoern A. Zeeb 	const u8 *p = (const u8 *)buf;
2955*b4c3e9b5SBjoern A. Zeeb 	int i;
2956*b4c3e9b5SBjoern A. Zeeb 
2957*b4c3e9b5SBjoern A. Zeeb 	if (len <= 0 || (offset & 1) || (len & 1))
2958*b4c3e9b5SBjoern A. Zeeb 		return;
2959*b4c3e9b5SBjoern A. Zeeb 
2960*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < len; i += 2) {
2961*b4c3e9b5SBjoern A. Zeeb 		v = p[i] | (p[i + 1] << 8);
2962*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_objmem(wlc_hw, offset + i, v, sel);
2963*b4c3e9b5SBjoern A. Zeeb 	}
2964*b4c3e9b5SBjoern A. Zeeb }
2965*b4c3e9b5SBjoern A. Zeeb 
2966*b4c3e9b5SBjoern A. Zeeb /*
2967*b4c3e9b5SBjoern A. Zeeb  * Copy a piece of shared memory of specified type to a buffer .
2968*b4c3e9b5SBjoern A. Zeeb  * SHM 'offset' needs to be an even address and
2969*b4c3e9b5SBjoern A. Zeeb  * Buffer length 'len' must be an even number of bytes
2970*b4c3e9b5SBjoern A. Zeeb  * 'sel' selects the type of memory
2971*b4c3e9b5SBjoern A. Zeeb  */
2972*b4c3e9b5SBjoern A. Zeeb void
brcms_b_copyfrom_objmem(struct brcms_hardware * wlc_hw,uint offset,void * buf,int len,u32 sel)2973*b4c3e9b5SBjoern A. Zeeb brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, void *buf,
2974*b4c3e9b5SBjoern A. Zeeb 			 int len, u32 sel)
2975*b4c3e9b5SBjoern A. Zeeb {
2976*b4c3e9b5SBjoern A. Zeeb 	u16 v;
2977*b4c3e9b5SBjoern A. Zeeb 	u8 *p = (u8 *) buf;
2978*b4c3e9b5SBjoern A. Zeeb 	int i;
2979*b4c3e9b5SBjoern A. Zeeb 
2980*b4c3e9b5SBjoern A. Zeeb 	if (len <= 0 || (offset & 1) || (len & 1))
2981*b4c3e9b5SBjoern A. Zeeb 		return;
2982*b4c3e9b5SBjoern A. Zeeb 
2983*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < len; i += 2) {
2984*b4c3e9b5SBjoern A. Zeeb 		v = brcms_b_read_objmem(wlc_hw, offset + i, sel);
2985*b4c3e9b5SBjoern A. Zeeb 		p[i] = v & 0xFF;
2986*b4c3e9b5SBjoern A. Zeeb 		p[i + 1] = (v >> 8) & 0xFF;
2987*b4c3e9b5SBjoern A. Zeeb 	}
2988*b4c3e9b5SBjoern A. Zeeb }
2989*b4c3e9b5SBjoern A. Zeeb 
2990*b4c3e9b5SBjoern A. Zeeb /* Copy a buffer to shared memory.
2991*b4c3e9b5SBjoern A. Zeeb  * SHM 'offset' needs to be an even address and
2992*b4c3e9b5SBjoern A. Zeeb  * Buffer length 'len' must be an even number of bytes
2993*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_copyto_shm(struct brcms_c_info * wlc,uint offset,const void * buf,int len)2994*b4c3e9b5SBjoern A. Zeeb static void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset,
2995*b4c3e9b5SBjoern A. Zeeb 			const void *buf, int len)
2996*b4c3e9b5SBjoern A. Zeeb {
2997*b4c3e9b5SBjoern A. Zeeb 	brcms_b_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL);
2998*b4c3e9b5SBjoern A. Zeeb }
2999*b4c3e9b5SBjoern A. Zeeb 
brcms_b_retrylimit_upd(struct brcms_hardware * wlc_hw,u16 SRL,u16 LRL)3000*b4c3e9b5SBjoern A. Zeeb static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw,
3001*b4c3e9b5SBjoern A. Zeeb 				   u16 SRL, u16 LRL)
3002*b4c3e9b5SBjoern A. Zeeb {
3003*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->SRL = SRL;
3004*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->LRL = LRL;
3005*b4c3e9b5SBjoern A. Zeeb 
3006*b4c3e9b5SBjoern A. Zeeb 	/* write retry limit to SCR, shouldn't need to suspend */
3007*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->up) {
3008*b4c3e9b5SBjoern A. Zeeb 		bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),
3009*b4c3e9b5SBjoern A. Zeeb 			     OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
3010*b4c3e9b5SBjoern A. Zeeb 		(void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));
3011*b4c3e9b5SBjoern A. Zeeb 		bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), wlc_hw->SRL);
3012*b4c3e9b5SBjoern A. Zeeb 		bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),
3013*b4c3e9b5SBjoern A. Zeeb 			     OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
3014*b4c3e9b5SBjoern A. Zeeb 		(void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));
3015*b4c3e9b5SBjoern A. Zeeb 		bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), wlc_hw->LRL);
3016*b4c3e9b5SBjoern A. Zeeb 	}
3017*b4c3e9b5SBjoern A. Zeeb }
3018*b4c3e9b5SBjoern A. Zeeb 
brcms_b_pllreq(struct brcms_hardware * wlc_hw,bool set,u32 req_bit)3019*b4c3e9b5SBjoern A. Zeeb static void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, u32 req_bit)
3020*b4c3e9b5SBjoern A. Zeeb {
3021*b4c3e9b5SBjoern A. Zeeb 	if (set) {
3022*b4c3e9b5SBjoern A. Zeeb 		if (mboolisset(wlc_hw->pllreq, req_bit))
3023*b4c3e9b5SBjoern A. Zeeb 			return;
3024*b4c3e9b5SBjoern A. Zeeb 
3025*b4c3e9b5SBjoern A. Zeeb 		mboolset(wlc_hw->pllreq, req_bit);
3026*b4c3e9b5SBjoern A. Zeeb 
3027*b4c3e9b5SBjoern A. Zeeb 		if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {
3028*b4c3e9b5SBjoern A. Zeeb 			if (!wlc_hw->sbclk)
3029*b4c3e9b5SBjoern A. Zeeb 				brcms_b_xtal(wlc_hw, ON);
3030*b4c3e9b5SBjoern A. Zeeb 		}
3031*b4c3e9b5SBjoern A. Zeeb 	} else {
3032*b4c3e9b5SBjoern A. Zeeb 		if (!mboolisset(wlc_hw->pllreq, req_bit))
3033*b4c3e9b5SBjoern A. Zeeb 			return;
3034*b4c3e9b5SBjoern A. Zeeb 
3035*b4c3e9b5SBjoern A. Zeeb 		mboolclr(wlc_hw->pllreq, req_bit);
3036*b4c3e9b5SBjoern A. Zeeb 
3037*b4c3e9b5SBjoern A. Zeeb 		if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {
3038*b4c3e9b5SBjoern A. Zeeb 			if (wlc_hw->sbclk)
3039*b4c3e9b5SBjoern A. Zeeb 				brcms_b_xtal(wlc_hw, OFF);
3040*b4c3e9b5SBjoern A. Zeeb 		}
3041*b4c3e9b5SBjoern A. Zeeb 	}
3042*b4c3e9b5SBjoern A. Zeeb }
3043*b4c3e9b5SBjoern A. Zeeb 
brcms_b_antsel_set(struct brcms_hardware * wlc_hw,u32 antsel_avail)3044*b4c3e9b5SBjoern A. Zeeb static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
3045*b4c3e9b5SBjoern A. Zeeb {
3046*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->antsel_avail = antsel_avail;
3047*b4c3e9b5SBjoern A. Zeeb }
3048*b4c3e9b5SBjoern A. Zeeb 
3049*b4c3e9b5SBjoern A. Zeeb /*
3050*b4c3e9b5SBjoern A. Zeeb  * conditions under which the PM bit should be set in outgoing frames
3051*b4c3e9b5SBjoern A. Zeeb  * and STAY_AWAKE is meaningful
3052*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_ps_allowed(struct brcms_c_info * wlc)3053*b4c3e9b5SBjoern A. Zeeb static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
3054*b4c3e9b5SBjoern A. Zeeb {
3055*b4c3e9b5SBjoern A. Zeeb 	/* not supporting PS so always return false for now */
3056*b4c3e9b5SBjoern A. Zeeb 	return false;
3057*b4c3e9b5SBjoern A. Zeeb }
3058*b4c3e9b5SBjoern A. Zeeb 
brcms_c_statsupd(struct brcms_c_info * wlc)3059*b4c3e9b5SBjoern A. Zeeb static void brcms_c_statsupd(struct brcms_c_info *wlc)
3060*b4c3e9b5SBjoern A. Zeeb {
3061*b4c3e9b5SBjoern A. Zeeb 	int i;
3062*b4c3e9b5SBjoern A. Zeeb 	struct macstat *macstats;
3063*b4c3e9b5SBjoern A. Zeeb #ifdef DEBUG
3064*b4c3e9b5SBjoern A. Zeeb 	u16 delta;
3065*b4c3e9b5SBjoern A. Zeeb 	u16 rxf0ovfl;
3066*b4c3e9b5SBjoern A. Zeeb 	u16 txfunfl[NFIFO];
3067*b4c3e9b5SBjoern A. Zeeb #endif				/* DEBUG */
3068*b4c3e9b5SBjoern A. Zeeb 
3069*b4c3e9b5SBjoern A. Zeeb 	/* if driver down, make no sense to update stats */
3070*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->pub->up)
3071*b4c3e9b5SBjoern A. Zeeb 		return;
3072*b4c3e9b5SBjoern A. Zeeb 
3073*b4c3e9b5SBjoern A. Zeeb 	macstats = wlc->core->macstat_snapshot;
3074*b4c3e9b5SBjoern A. Zeeb 
3075*b4c3e9b5SBjoern A. Zeeb #ifdef DEBUG
3076*b4c3e9b5SBjoern A. Zeeb 	/* save last rx fifo 0 overflow count */
3077*b4c3e9b5SBjoern A. Zeeb 	rxf0ovfl = macstats->rxf0ovfl;
3078*b4c3e9b5SBjoern A. Zeeb 
3079*b4c3e9b5SBjoern A. Zeeb 	/* save last tx fifo  underflow count */
3080*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < NFIFO; i++)
3081*b4c3e9b5SBjoern A. Zeeb 		txfunfl[i] = macstats->txfunfl[i];
3082*b4c3e9b5SBjoern A. Zeeb #endif				/* DEBUG */
3083*b4c3e9b5SBjoern A. Zeeb 
3084*b4c3e9b5SBjoern A. Zeeb 	/* Read mac stats from contiguous shared memory */
3085*b4c3e9b5SBjoern A. Zeeb 	brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, macstats,
3086*b4c3e9b5SBjoern A. Zeeb 				sizeof(*macstats), OBJADDR_SHM_SEL);
3087*b4c3e9b5SBjoern A. Zeeb 
3088*b4c3e9b5SBjoern A. Zeeb #ifdef DEBUG
3089*b4c3e9b5SBjoern A. Zeeb 	/* check for rx fifo 0 overflow */
3090*b4c3e9b5SBjoern A. Zeeb 	delta = (u16)(macstats->rxf0ovfl - rxf0ovfl);
3091*b4c3e9b5SBjoern A. Zeeb 	if (delta)
3092*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "wl%d: %u rx fifo 0 overflows!\n",
3093*b4c3e9b5SBjoern A. Zeeb 			  wlc->pub->unit, delta);
3094*b4c3e9b5SBjoern A. Zeeb 
3095*b4c3e9b5SBjoern A. Zeeb 	/* check for tx fifo underflows */
3096*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < NFIFO; i++) {
3097*b4c3e9b5SBjoern A. Zeeb 		delta = macstats->txfunfl[i] - txfunfl[i];
3098*b4c3e9b5SBjoern A. Zeeb 		if (delta)
3099*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc->hw->d11core,
3100*b4c3e9b5SBjoern A. Zeeb 				  "wl%d: %u tx fifo %d underflows!\n",
3101*b4c3e9b5SBjoern A. Zeeb 				  wlc->pub->unit, delta, i);
3102*b4c3e9b5SBjoern A. Zeeb 	}
3103*b4c3e9b5SBjoern A. Zeeb #endif				/* DEBUG */
3104*b4c3e9b5SBjoern A. Zeeb 
3105*b4c3e9b5SBjoern A. Zeeb 	/* merge counters from dma module */
3106*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < NFIFO; i++) {
3107*b4c3e9b5SBjoern A. Zeeb 		if (wlc->hw->di[i])
3108*b4c3e9b5SBjoern A. Zeeb 			dma_counterreset(wlc->hw->di[i]);
3109*b4c3e9b5SBjoern A. Zeeb 	}
3110*b4c3e9b5SBjoern A. Zeeb }
3111*b4c3e9b5SBjoern A. Zeeb 
brcms_b_reset(struct brcms_hardware * wlc_hw)3112*b4c3e9b5SBjoern A. Zeeb static void brcms_b_reset(struct brcms_hardware *wlc_hw)
3113*b4c3e9b5SBjoern A. Zeeb {
3114*b4c3e9b5SBjoern A. Zeeb 	/* reset the core */
3115*b4c3e9b5SBjoern A. Zeeb 	if (!brcms_deviceremoved(wlc_hw->wlc))
3116*b4c3e9b5SBjoern A. Zeeb 		brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
3117*b4c3e9b5SBjoern A. Zeeb 
3118*b4c3e9b5SBjoern A. Zeeb 	/* purge the dma rings */
3119*b4c3e9b5SBjoern A. Zeeb 	brcms_c_flushqueues(wlc_hw->wlc);
3120*b4c3e9b5SBjoern A. Zeeb }
3121*b4c3e9b5SBjoern A. Zeeb 
brcms_c_reset(struct brcms_c_info * wlc)3122*b4c3e9b5SBjoern A. Zeeb void brcms_c_reset(struct brcms_c_info *wlc)
3123*b4c3e9b5SBjoern A. Zeeb {
3124*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);
3125*b4c3e9b5SBjoern A. Zeeb 
3126*b4c3e9b5SBjoern A. Zeeb 	/* slurp up hw mac counters before core reset */
3127*b4c3e9b5SBjoern A. Zeeb 	brcms_c_statsupd(wlc);
3128*b4c3e9b5SBjoern A. Zeeb 
3129*b4c3e9b5SBjoern A. Zeeb 	/* reset our snapshot of macstat counters */
3130*b4c3e9b5SBjoern A. Zeeb 	memset(wlc->core->macstat_snapshot, 0, sizeof(struct macstat));
3131*b4c3e9b5SBjoern A. Zeeb 
3132*b4c3e9b5SBjoern A. Zeeb 	brcms_b_reset(wlc->hw);
3133*b4c3e9b5SBjoern A. Zeeb }
3134*b4c3e9b5SBjoern A. Zeeb 
brcms_c_init_scb(struct scb * scb)3135*b4c3e9b5SBjoern A. Zeeb void brcms_c_init_scb(struct scb *scb)
3136*b4c3e9b5SBjoern A. Zeeb {
3137*b4c3e9b5SBjoern A. Zeeb 	int i;
3138*b4c3e9b5SBjoern A. Zeeb 
3139*b4c3e9b5SBjoern A. Zeeb 	memset(scb, 0, sizeof(struct scb));
3140*b4c3e9b5SBjoern A. Zeeb 	scb->flags = SCB_WMECAP | SCB_HTCAP;
3141*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < NUMPRIO; i++) {
3142*b4c3e9b5SBjoern A. Zeeb 		scb->seqnum[i] = 0;
3143*b4c3e9b5SBjoern A. Zeeb 	}
3144*b4c3e9b5SBjoern A. Zeeb 
3145*b4c3e9b5SBjoern A. Zeeb 	scb->magic = SCB_MAGIC;
3146*b4c3e9b5SBjoern A. Zeeb }
3147*b4c3e9b5SBjoern A. Zeeb 
3148*b4c3e9b5SBjoern A. Zeeb /* d11 core init
3149*b4c3e9b5SBjoern A. Zeeb  *   reset PSM
3150*b4c3e9b5SBjoern A. Zeeb  *   download ucode/PCM
3151*b4c3e9b5SBjoern A. Zeeb  *   let ucode run to suspended
3152*b4c3e9b5SBjoern A. Zeeb  *   download ucode inits
3153*b4c3e9b5SBjoern A. Zeeb  *   config other core registers
3154*b4c3e9b5SBjoern A. Zeeb  *   init dma
3155*b4c3e9b5SBjoern A. Zeeb  */
brcms_b_coreinit(struct brcms_c_info * wlc)3156*b4c3e9b5SBjoern A. Zeeb static void brcms_b_coreinit(struct brcms_c_info *wlc)
3157*b4c3e9b5SBjoern A. Zeeb {
3158*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
3159*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
3160*b4c3e9b5SBjoern A. Zeeb 	u32 bcnint_us;
3161*b4c3e9b5SBjoern A. Zeeb 	uint i = 0;
3162*b4c3e9b5SBjoern A. Zeeb 	bool fifosz_fixup = false;
3163*b4c3e9b5SBjoern A. Zeeb 	int err = 0;
3164*b4c3e9b5SBjoern A. Zeeb 	u16 buf[NFIFO];
3165*b4c3e9b5SBjoern A. Zeeb 	struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
3166*b4c3e9b5SBjoern A. Zeeb 
3167*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(core, "wl%d: core init\n", wlc_hw->unit);
3168*b4c3e9b5SBjoern A. Zeeb 
3169*b4c3e9b5SBjoern A. Zeeb 	/* reset PSM */
3170*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE));
3171*b4c3e9b5SBjoern A. Zeeb 
3172*b4c3e9b5SBjoern A. Zeeb 	brcms_ucode_download(wlc_hw);
3173*b4c3e9b5SBjoern A. Zeeb 	/*
3174*b4c3e9b5SBjoern A. Zeeb 	 * FIFOSZ fixup. driver wants to controls the fifo allocation.
3175*b4c3e9b5SBjoern A. Zeeb 	 */
3176*b4c3e9b5SBjoern A. Zeeb 	fifosz_fixup = true;
3177*b4c3e9b5SBjoern A. Zeeb 
3178*b4c3e9b5SBjoern A. Zeeb 	/* let the PSM run to the suspended state, set mode to BSS STA */
3179*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(macintstatus), -1);
3180*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mctrl(wlc_hw, ~0,
3181*b4c3e9b5SBjoern A. Zeeb 		       (MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE));
3182*b4c3e9b5SBjoern A. Zeeb 
3183*b4c3e9b5SBjoern A. Zeeb 	/* wait for ucode to self-suspend after auto-init */
3184*b4c3e9b5SBjoern A. Zeeb 	SPINWAIT(((bcma_read32(core, D11REGOFFS(macintstatus)) &
3185*b4c3e9b5SBjoern A. Zeeb 		   MI_MACSSPNDD) == 0), 1000 * 1000);
3186*b4c3e9b5SBjoern A. Zeeb 	if ((bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD) == 0)
3187*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "wl%d: wlc_coreinit: ucode did not self-"
3188*b4c3e9b5SBjoern A. Zeeb 			  "suspend!\n", wlc_hw->unit);
3189*b4c3e9b5SBjoern A. Zeeb 
3190*b4c3e9b5SBjoern A. Zeeb 	brcms_c_gpio_init(wlc);
3191*b4c3e9b5SBjoern A. Zeeb 
3192*b4c3e9b5SBjoern A. Zeeb 	bcma_aread32(core, BCMA_IOST);
3193*b4c3e9b5SBjoern A. Zeeb 
3194*b4c3e9b5SBjoern A. Zeeb 	if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
3195*b4c3e9b5SBjoern A. Zeeb 		if (BRCMS_ISNPHY(wlc_hw->band))
3196*b4c3e9b5SBjoern A. Zeeb 			brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);
3197*b4c3e9b5SBjoern A. Zeeb 		else
3198*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "%s: wl%d: unsupported phy in corerev"
3199*b4c3e9b5SBjoern A. Zeeb 				  " %d\n", __func__, wlc_hw->unit,
3200*b4c3e9b5SBjoern A. Zeeb 				  wlc_hw->corerev);
3201*b4c3e9b5SBjoern A. Zeeb 	} else if (D11REV_IS(wlc_hw->corerev, 24)) {
3202*b4c3e9b5SBjoern A. Zeeb 		if (BRCMS_ISLCNPHY(wlc_hw->band))
3203*b4c3e9b5SBjoern A. Zeeb 			brcms_c_write_inits(wlc_hw, ucode->d11lcn0initvals24);
3204*b4c3e9b5SBjoern A. Zeeb 		else
3205*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "%s: wl%d: unsupported phy in corerev"
3206*b4c3e9b5SBjoern A. Zeeb 				  " %d\n", __func__, wlc_hw->unit,
3207*b4c3e9b5SBjoern A. Zeeb 				  wlc_hw->corerev);
3208*b4c3e9b5SBjoern A. Zeeb 	} else {
3209*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "%s: wl%d: unsupported corerev %d\n",
3210*b4c3e9b5SBjoern A. Zeeb 			  __func__, wlc_hw->unit, wlc_hw->corerev);
3211*b4c3e9b5SBjoern A. Zeeb 	}
3212*b4c3e9b5SBjoern A. Zeeb 
3213*b4c3e9b5SBjoern A. Zeeb 	/* For old ucode, txfifo sizes needs to be modified(increased) */
3214*b4c3e9b5SBjoern A. Zeeb 	if (fifosz_fixup)
3215*b4c3e9b5SBjoern A. Zeeb 		brcms_b_corerev_fifofixup(wlc_hw);
3216*b4c3e9b5SBjoern A. Zeeb 
3217*b4c3e9b5SBjoern A. Zeeb 	/* check txfifo allocations match between ucode and driver */
3218*b4c3e9b5SBjoern A. Zeeb 	buf[TX_AC_BE_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE0);
3219*b4c3e9b5SBjoern A. Zeeb 	if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) {
3220*b4c3e9b5SBjoern A. Zeeb 		i = TX_AC_BE_FIFO;
3221*b4c3e9b5SBjoern A. Zeeb 		err = -1;
3222*b4c3e9b5SBjoern A. Zeeb 	}
3223*b4c3e9b5SBjoern A. Zeeb 	buf[TX_AC_VI_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE1);
3224*b4c3e9b5SBjoern A. Zeeb 	if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) {
3225*b4c3e9b5SBjoern A. Zeeb 		i = TX_AC_VI_FIFO;
3226*b4c3e9b5SBjoern A. Zeeb 		err = -1;
3227*b4c3e9b5SBjoern A. Zeeb 	}
3228*b4c3e9b5SBjoern A. Zeeb 	buf[TX_AC_BK_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE2);
3229*b4c3e9b5SBjoern A. Zeeb 	buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff;
3230*b4c3e9b5SBjoern A. Zeeb 	buf[TX_AC_BK_FIFO] &= 0xff;
3231*b4c3e9b5SBjoern A. Zeeb 	if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) {
3232*b4c3e9b5SBjoern A. Zeeb 		i = TX_AC_BK_FIFO;
3233*b4c3e9b5SBjoern A. Zeeb 		err = -1;
3234*b4c3e9b5SBjoern A. Zeeb 	}
3235*b4c3e9b5SBjoern A. Zeeb 	if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) {
3236*b4c3e9b5SBjoern A. Zeeb 		i = TX_AC_VO_FIFO;
3237*b4c3e9b5SBjoern A. Zeeb 		err = -1;
3238*b4c3e9b5SBjoern A. Zeeb 	}
3239*b4c3e9b5SBjoern A. Zeeb 	buf[TX_BCMC_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE3);
3240*b4c3e9b5SBjoern A. Zeeb 	buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff;
3241*b4c3e9b5SBjoern A. Zeeb 	buf[TX_BCMC_FIFO] &= 0xff;
3242*b4c3e9b5SBjoern A. Zeeb 	if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) {
3243*b4c3e9b5SBjoern A. Zeeb 		i = TX_BCMC_FIFO;
3244*b4c3e9b5SBjoern A. Zeeb 		err = -1;
3245*b4c3e9b5SBjoern A. Zeeb 	}
3246*b4c3e9b5SBjoern A. Zeeb 	if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) {
3247*b4c3e9b5SBjoern A. Zeeb 		i = TX_ATIM_FIFO;
3248*b4c3e9b5SBjoern A. Zeeb 		err = -1;
3249*b4c3e9b5SBjoern A. Zeeb 	}
3250*b4c3e9b5SBjoern A. Zeeb 	if (err != 0)
3251*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "wlc_coreinit: txfifo mismatch: ucode size %d"
3252*b4c3e9b5SBjoern A. Zeeb 			  " driver size %d index %d\n", buf[i],
3253*b4c3e9b5SBjoern A. Zeeb 			  wlc_hw->xmtfifo_sz[i], i);
3254*b4c3e9b5SBjoern A. Zeeb 
3255*b4c3e9b5SBjoern A. Zeeb 	/* make sure we can still talk to the mac */
3256*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(bcma_read32(core, D11REGOFFS(maccontrol)) == 0xffffffff);
3257*b4c3e9b5SBjoern A. Zeeb 
3258*b4c3e9b5SBjoern A. Zeeb 	/* band-specific inits done by wlc_bsinit() */
3259*b4c3e9b5SBjoern A. Zeeb 
3260*b4c3e9b5SBjoern A. Zeeb 	/* Set up frame burst size and antenna swap threshold init values */
3261*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST);
3262*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT);
3263*b4c3e9b5SBjoern A. Zeeb 
3264*b4c3e9b5SBjoern A. Zeeb 	/* enable one rx interrupt per received frame */
3265*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(intrcvlazy[0]), (1 << IRL_FC_SHIFT));
3266*b4c3e9b5SBjoern A. Zeeb 
3267*b4c3e9b5SBjoern A. Zeeb 	/* set the station mode (BSS STA) */
3268*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mctrl(wlc_hw,
3269*b4c3e9b5SBjoern A. Zeeb 		       (MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP),
3270*b4c3e9b5SBjoern A. Zeeb 		       (MCTL_INFRA | MCTL_DISCARD_PMQ));
3271*b4c3e9b5SBjoern A. Zeeb 
3272*b4c3e9b5SBjoern A. Zeeb 	/* set up Beacon interval */
3273*b4c3e9b5SBjoern A. Zeeb 	bcnint_us = 0x8000 << 10;
3274*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(tsf_cfprep),
3275*b4c3e9b5SBjoern A. Zeeb 		     (bcnint_us << CFPREP_CBI_SHIFT));
3276*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(tsf_cfpstart), bcnint_us);
3277*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(macintstatus), MI_GP1);
3278*b4c3e9b5SBjoern A. Zeeb 
3279*b4c3e9b5SBjoern A. Zeeb 	/* write interrupt mask */
3280*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(intctrlregs[RX_FIFO].intmask),
3281*b4c3e9b5SBjoern A. Zeeb 		     DEF_RXINTMASK);
3282*b4c3e9b5SBjoern A. Zeeb 
3283*b4c3e9b5SBjoern A. Zeeb 	/* allow the MAC to control the PHY clock (dynamic on/off) */
3284*b4c3e9b5SBjoern A. Zeeb 	brcms_b_macphyclk_set(wlc_hw, ON);
3285*b4c3e9b5SBjoern A. Zeeb 
3286*b4c3e9b5SBjoern A. Zeeb 	/* program dynamic clock control fast powerup delay register */
3287*b4c3e9b5SBjoern A. Zeeb 	wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih);
3288*b4c3e9b5SBjoern A. Zeeb 	bcma_write16(core, D11REGOFFS(scc_fastpwrup_dly), wlc->fastpwrup_dly);
3289*b4c3e9b5SBjoern A. Zeeb 
3290*b4c3e9b5SBjoern A. Zeeb 	/* tell the ucode the corerev */
3291*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev);
3292*b4c3e9b5SBjoern A. Zeeb 
3293*b4c3e9b5SBjoern A. Zeeb 	/* tell the ucode MAC capabilities */
3294*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_MACHW_CAP_L,
3295*b4c3e9b5SBjoern A. Zeeb 			   (u16) (wlc_hw->machwcap & 0xffff));
3296*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_MACHW_CAP_H,
3297*b4c3e9b5SBjoern A. Zeeb 			   (u16) ((wlc_hw->
3298*b4c3e9b5SBjoern A. Zeeb 				      machwcap >> 16) & 0xffff));
3299*b4c3e9b5SBjoern A. Zeeb 
3300*b4c3e9b5SBjoern A. Zeeb 	/* write retry limits to SCR, this done after PSM init */
3301*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objaddr),
3302*b4c3e9b5SBjoern A. Zeeb 		     OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
3303*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(objaddr));
3304*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objdata), wlc_hw->SRL);
3305*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objaddr),
3306*b4c3e9b5SBjoern A. Zeeb 		     OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
3307*b4c3e9b5SBjoern A. Zeeb 	(void)bcma_read32(core, D11REGOFFS(objaddr));
3308*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(objdata), wlc_hw->LRL);
3309*b4c3e9b5SBjoern A. Zeeb 
3310*b4c3e9b5SBjoern A. Zeeb 	/* write rate fallback retry limits */
3311*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL);
3312*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL);
3313*b4c3e9b5SBjoern A. Zeeb 
3314*b4c3e9b5SBjoern A. Zeeb 	bcma_mask16(core, D11REGOFFS(ifs_ctl), 0x0FFF);
3315*b4c3e9b5SBjoern A. Zeeb 	bcma_write16(core, D11REGOFFS(ifs_aifsn), EDCF_AIFSN_MIN);
3316*b4c3e9b5SBjoern A. Zeeb 
3317*b4c3e9b5SBjoern A. Zeeb 	/* init the tx dma engines */
3318*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < NFIFO; i++) {
3319*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->di[i])
3320*b4c3e9b5SBjoern A. Zeeb 			dma_txinit(wlc_hw->di[i]);
3321*b4c3e9b5SBjoern A. Zeeb 	}
3322*b4c3e9b5SBjoern A. Zeeb 
3323*b4c3e9b5SBjoern A. Zeeb 	/* init the rx dma engine(s) and post receive buffers */
3324*b4c3e9b5SBjoern A. Zeeb 	dma_rxinit(wlc_hw->di[RX_FIFO]);
3325*b4c3e9b5SBjoern A. Zeeb 	dma_rxfill(wlc_hw->di[RX_FIFO]);
3326*b4c3e9b5SBjoern A. Zeeb }
3327*b4c3e9b5SBjoern A. Zeeb 
brcms_b_init(struct brcms_hardware * wlc_hw,u16 chanspec)3328*b4c3e9b5SBjoern A. Zeeb static void brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec)
3329*b4c3e9b5SBjoern A. Zeeb {
3330*b4c3e9b5SBjoern A. Zeeb 	u32 macintmask;
3331*b4c3e9b5SBjoern A. Zeeb 	bool fastclk;
3332*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_info *wlc = wlc_hw->wlc;
3333*b4c3e9b5SBjoern A. Zeeb 
3334*b4c3e9b5SBjoern A. Zeeb 	/* request FAST clock if not on */
3335*b4c3e9b5SBjoern A. Zeeb 	fastclk = wlc_hw->forcefastclk;
3336*b4c3e9b5SBjoern A. Zeeb 	if (!fastclk)
3337*b4c3e9b5SBjoern A. Zeeb 		brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
3338*b4c3e9b5SBjoern A. Zeeb 
3339*b4c3e9b5SBjoern A. Zeeb 	/* disable interrupts */
3340*b4c3e9b5SBjoern A. Zeeb 	macintmask = brcms_intrsoff(wlc->wl);
3341*b4c3e9b5SBjoern A. Zeeb 
3342*b4c3e9b5SBjoern A. Zeeb 	/* set up the specified band and chanspec */
3343*b4c3e9b5SBjoern A. Zeeb 	brcms_c_setxband(wlc_hw, chspec_bandunit(chanspec));
3344*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
3345*b4c3e9b5SBjoern A. Zeeb 
3346*b4c3e9b5SBjoern A. Zeeb 	/* do one-time phy inits and calibration */
3347*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_cal_init(wlc_hw->band->pi);
3348*b4c3e9b5SBjoern A. Zeeb 
3349*b4c3e9b5SBjoern A. Zeeb 	/* core-specific initialization */
3350*b4c3e9b5SBjoern A. Zeeb 	brcms_b_coreinit(wlc);
3351*b4c3e9b5SBjoern A. Zeeb 
3352*b4c3e9b5SBjoern A. Zeeb 	/* band-specific inits */
3353*b4c3e9b5SBjoern A. Zeeb 	brcms_b_bsinit(wlc, chanspec);
3354*b4c3e9b5SBjoern A. Zeeb 
3355*b4c3e9b5SBjoern A. Zeeb 	/* restore macintmask */
3356*b4c3e9b5SBjoern A. Zeeb 	brcms_intrsrestore(wlc->wl, macintmask);
3357*b4c3e9b5SBjoern A. Zeeb 
3358*b4c3e9b5SBjoern A. Zeeb 	/* seed wake_override with BRCMS_WAKE_OVERRIDE_MACSUSPEND since the mac
3359*b4c3e9b5SBjoern A. Zeeb 	 * is suspended and brcms_c_enable_mac() will clear this override bit.
3360*b4c3e9b5SBjoern A. Zeeb 	 */
3361*b4c3e9b5SBjoern A. Zeeb 	mboolset(wlc_hw->wake_override, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
3362*b4c3e9b5SBjoern A. Zeeb 
3363*b4c3e9b5SBjoern A. Zeeb 	/*
3364*b4c3e9b5SBjoern A. Zeeb 	 * initialize mac_suspend_depth to 1 to match ucode
3365*b4c3e9b5SBjoern A. Zeeb 	 * initial suspended state
3366*b4c3e9b5SBjoern A. Zeeb 	 */
3367*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->mac_suspend_depth = 1;
3368*b4c3e9b5SBjoern A. Zeeb 
3369*b4c3e9b5SBjoern A. Zeeb 	/* restore the clk */
3370*b4c3e9b5SBjoern A. Zeeb 	if (!fastclk)
3371*b4c3e9b5SBjoern A. Zeeb 		brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
3372*b4c3e9b5SBjoern A. Zeeb }
3373*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_phy_chanspec(struct brcms_c_info * wlc,u16 chanspec)3374*b4c3e9b5SBjoern A. Zeeb static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
3375*b4c3e9b5SBjoern A. Zeeb 				     u16 chanspec)
3376*b4c3e9b5SBjoern A. Zeeb {
3377*b4c3e9b5SBjoern A. Zeeb 	/* Save our copy of the chanspec */
3378*b4c3e9b5SBjoern A. Zeeb 	wlc->chanspec = chanspec;
3379*b4c3e9b5SBjoern A. Zeeb 
3380*b4c3e9b5SBjoern A. Zeeb 	/* Set the chanspec and power limits for this locale */
3381*b4c3e9b5SBjoern A. Zeeb 	brcms_c_channel_set_chanspec(wlc->cmi, chanspec, BRCMS_TXPWR_MAX);
3382*b4c3e9b5SBjoern A. Zeeb 
3383*b4c3e9b5SBjoern A. Zeeb 	if (wlc->stf->ss_algosel_auto)
3384*b4c3e9b5SBjoern A. Zeeb 		brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel,
3385*b4c3e9b5SBjoern A. Zeeb 					    chanspec);
3386*b4c3e9b5SBjoern A. Zeeb 
3387*b4c3e9b5SBjoern A. Zeeb 	brcms_c_stf_ss_update(wlc, wlc->band);
3388*b4c3e9b5SBjoern A. Zeeb }
3389*b4c3e9b5SBjoern A. Zeeb 
3390*b4c3e9b5SBjoern A. Zeeb static void
brcms_default_rateset(struct brcms_c_info * wlc,struct brcms_c_rateset * rs)3391*b4c3e9b5SBjoern A. Zeeb brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs)
3392*b4c3e9b5SBjoern A. Zeeb {
3393*b4c3e9b5SBjoern A. Zeeb 	brcms_c_rateset_default(rs, NULL, wlc->band->phytype,
3394*b4c3e9b5SBjoern A. Zeeb 		wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL,
3395*b4c3e9b5SBjoern A. Zeeb 		(bool) (wlc->pub->_n_enab & SUPPORT_11N),
3396*b4c3e9b5SBjoern A. Zeeb 		brcms_chspec_bw(wlc->default_bss->chanspec),
3397*b4c3e9b5SBjoern A. Zeeb 		wlc->stf->txstreams);
3398*b4c3e9b5SBjoern A. Zeeb }
3399*b4c3e9b5SBjoern A. Zeeb 
3400*b4c3e9b5SBjoern A. Zeeb /* derive wlc->band->basic_rate[] table from 'rateset' */
brcms_c_rate_lookup_init(struct brcms_c_info * wlc,struct brcms_c_rateset * rateset)3401*b4c3e9b5SBjoern A. Zeeb static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
3402*b4c3e9b5SBjoern A. Zeeb 			      struct brcms_c_rateset *rateset)
3403*b4c3e9b5SBjoern A. Zeeb {
3404*b4c3e9b5SBjoern A. Zeeb 	u8 rate;
3405*b4c3e9b5SBjoern A. Zeeb 	u8 mandatory;
3406*b4c3e9b5SBjoern A. Zeeb 	u8 cck_basic = 0;
3407*b4c3e9b5SBjoern A. Zeeb 	u8 ofdm_basic = 0;
3408*b4c3e9b5SBjoern A. Zeeb 	u8 *br = wlc->band->basic_rate;
3409*b4c3e9b5SBjoern A. Zeeb 	uint i;
3410*b4c3e9b5SBjoern A. Zeeb 
3411*b4c3e9b5SBjoern A. Zeeb 	/* incoming rates are in 500kbps units as in 802.11 Supported Rates */
3412*b4c3e9b5SBjoern A. Zeeb 	memset(br, 0, BRCM_MAXRATE + 1);
3413*b4c3e9b5SBjoern A. Zeeb 
3414*b4c3e9b5SBjoern A. Zeeb 	/* For each basic rate in the rates list, make an entry in the
3415*b4c3e9b5SBjoern A. Zeeb 	 * best basic lookup.
3416*b4c3e9b5SBjoern A. Zeeb 	 */
3417*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < rateset->count; i++) {
3418*b4c3e9b5SBjoern A. Zeeb 		/* only make an entry for a basic rate */
3419*b4c3e9b5SBjoern A. Zeeb 		if (!(rateset->rates[i] & BRCMS_RATE_FLAG))
3420*b4c3e9b5SBjoern A. Zeeb 			continue;
3421*b4c3e9b5SBjoern A. Zeeb 
3422*b4c3e9b5SBjoern A. Zeeb 		/* mask off basic bit */
3423*b4c3e9b5SBjoern A. Zeeb 		rate = (rateset->rates[i] & BRCMS_RATE_MASK);
3424*b4c3e9b5SBjoern A. Zeeb 
3425*b4c3e9b5SBjoern A. Zeeb 		if (rate > BRCM_MAXRATE) {
3426*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc->hw->d11core, "brcms_c_rate_lookup_init: "
3427*b4c3e9b5SBjoern A. Zeeb 				  "invalid rate 0x%X in rate set\n",
3428*b4c3e9b5SBjoern A. Zeeb 				  rateset->rates[i]);
3429*b4c3e9b5SBjoern A. Zeeb 			continue;
3430*b4c3e9b5SBjoern A. Zeeb 		}
3431*b4c3e9b5SBjoern A. Zeeb 
3432*b4c3e9b5SBjoern A. Zeeb 		br[rate] = rate;
3433*b4c3e9b5SBjoern A. Zeeb 	}
3434*b4c3e9b5SBjoern A. Zeeb 
3435*b4c3e9b5SBjoern A. Zeeb 	/* The rate lookup table now has non-zero entries for each
3436*b4c3e9b5SBjoern A. Zeeb 	 * basic rate, equal to the basic rate: br[basicN] = basicN
3437*b4c3e9b5SBjoern A. Zeeb 	 *
3438*b4c3e9b5SBjoern A. Zeeb 	 * To look up the best basic rate corresponding to any
3439*b4c3e9b5SBjoern A. Zeeb 	 * particular rate, code can use the basic_rate table
3440*b4c3e9b5SBjoern A. Zeeb 	 * like this
3441*b4c3e9b5SBjoern A. Zeeb 	 *
3442*b4c3e9b5SBjoern A. Zeeb 	 * basic_rate = wlc->band->basic_rate[tx_rate]
3443*b4c3e9b5SBjoern A. Zeeb 	 *
3444*b4c3e9b5SBjoern A. Zeeb 	 * Make sure there is a best basic rate entry for
3445*b4c3e9b5SBjoern A. Zeeb 	 * every rate by walking up the table from low rates
3446*b4c3e9b5SBjoern A. Zeeb 	 * to high, filling in holes in the lookup table
3447*b4c3e9b5SBjoern A. Zeeb 	 */
3448*b4c3e9b5SBjoern A. Zeeb 
3449*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < wlc->band->hw_rateset.count; i++) {
3450*b4c3e9b5SBjoern A. Zeeb 		rate = wlc->band->hw_rateset.rates[i];
3451*b4c3e9b5SBjoern A. Zeeb 
3452*b4c3e9b5SBjoern A. Zeeb 		if (br[rate] != 0) {
3453*b4c3e9b5SBjoern A. Zeeb 			/* This rate is a basic rate.
3454*b4c3e9b5SBjoern A. Zeeb 			 * Keep track of the best basic rate so far by
3455*b4c3e9b5SBjoern A. Zeeb 			 * modulation type.
3456*b4c3e9b5SBjoern A. Zeeb 			 */
3457*b4c3e9b5SBjoern A. Zeeb 			if (is_ofdm_rate(rate))
3458*b4c3e9b5SBjoern A. Zeeb 				ofdm_basic = rate;
3459*b4c3e9b5SBjoern A. Zeeb 			else
3460*b4c3e9b5SBjoern A. Zeeb 				cck_basic = rate;
3461*b4c3e9b5SBjoern A. Zeeb 
3462*b4c3e9b5SBjoern A. Zeeb 			continue;
3463*b4c3e9b5SBjoern A. Zeeb 		}
3464*b4c3e9b5SBjoern A. Zeeb 
3465*b4c3e9b5SBjoern A. Zeeb 		/* This rate is not a basic rate so figure out the
3466*b4c3e9b5SBjoern A. Zeeb 		 * best basic rate less than this rate and fill in
3467*b4c3e9b5SBjoern A. Zeeb 		 * the hole in the table
3468*b4c3e9b5SBjoern A. Zeeb 		 */
3469*b4c3e9b5SBjoern A. Zeeb 
3470*b4c3e9b5SBjoern A. Zeeb 		br[rate] = is_ofdm_rate(rate) ? ofdm_basic : cck_basic;
3471*b4c3e9b5SBjoern A. Zeeb 
3472*b4c3e9b5SBjoern A. Zeeb 		if (br[rate] != 0)
3473*b4c3e9b5SBjoern A. Zeeb 			continue;
3474*b4c3e9b5SBjoern A. Zeeb 
3475*b4c3e9b5SBjoern A. Zeeb 		if (is_ofdm_rate(rate)) {
3476*b4c3e9b5SBjoern A. Zeeb 			/*
3477*b4c3e9b5SBjoern A. Zeeb 			 * In 11g and 11a, the OFDM mandatory rates
3478*b4c3e9b5SBjoern A. Zeeb 			 * are 6, 12, and 24 Mbps
3479*b4c3e9b5SBjoern A. Zeeb 			 */
3480*b4c3e9b5SBjoern A. Zeeb 			if (rate >= BRCM_RATE_24M)
3481*b4c3e9b5SBjoern A. Zeeb 				mandatory = BRCM_RATE_24M;
3482*b4c3e9b5SBjoern A. Zeeb 			else if (rate >= BRCM_RATE_12M)
3483*b4c3e9b5SBjoern A. Zeeb 				mandatory = BRCM_RATE_12M;
3484*b4c3e9b5SBjoern A. Zeeb 			else
3485*b4c3e9b5SBjoern A. Zeeb 				mandatory = BRCM_RATE_6M;
3486*b4c3e9b5SBjoern A. Zeeb 		} else {
3487*b4c3e9b5SBjoern A. Zeeb 			/* In 11b, all CCK rates are mandatory 1 - 11 Mbps */
3488*b4c3e9b5SBjoern A. Zeeb 			mandatory = rate;
3489*b4c3e9b5SBjoern A. Zeeb 		}
3490*b4c3e9b5SBjoern A. Zeeb 
3491*b4c3e9b5SBjoern A. Zeeb 		br[rate] = mandatory;
3492*b4c3e9b5SBjoern A. Zeeb 	}
3493*b4c3e9b5SBjoern A. Zeeb }
3494*b4c3e9b5SBjoern A. Zeeb 
brcms_c_bandinit_ordered(struct brcms_c_info * wlc,u16 chanspec)3495*b4c3e9b5SBjoern A. Zeeb static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
3496*b4c3e9b5SBjoern A. Zeeb 				     u16 chanspec)
3497*b4c3e9b5SBjoern A. Zeeb {
3498*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_rateset default_rateset;
3499*b4c3e9b5SBjoern A. Zeeb 	uint parkband;
3500*b4c3e9b5SBjoern A. Zeeb 	uint i, band_order[2];
3501*b4c3e9b5SBjoern A. Zeeb 
3502*b4c3e9b5SBjoern A. Zeeb 	/*
3503*b4c3e9b5SBjoern A. Zeeb 	 * We might have been bandlocked during down and the chip
3504*b4c3e9b5SBjoern A. Zeeb 	 * power-cycled (hibernate). Figure out the right band to park on
3505*b4c3e9b5SBjoern A. Zeeb 	 */
3506*b4c3e9b5SBjoern A. Zeeb 	if (wlc->bandlocked || wlc->pub->_nbands == 1) {
3507*b4c3e9b5SBjoern A. Zeeb 		/* updated in brcms_c_bandlock() */
3508*b4c3e9b5SBjoern A. Zeeb 		parkband = wlc->band->bandunit;
3509*b4c3e9b5SBjoern A. Zeeb 		band_order[0] = band_order[1] = parkband;
3510*b4c3e9b5SBjoern A. Zeeb 	} else {
3511*b4c3e9b5SBjoern A. Zeeb 		/* park on the band of the specified chanspec */
3512*b4c3e9b5SBjoern A. Zeeb 		parkband = chspec_bandunit(chanspec);
3513*b4c3e9b5SBjoern A. Zeeb 
3514*b4c3e9b5SBjoern A. Zeeb 		/* order so that parkband initialize last */
3515*b4c3e9b5SBjoern A. Zeeb 		band_order[0] = parkband ^ 1;
3516*b4c3e9b5SBjoern A. Zeeb 		band_order[1] = parkband;
3517*b4c3e9b5SBjoern A. Zeeb 	}
3518*b4c3e9b5SBjoern A. Zeeb 
3519*b4c3e9b5SBjoern A. Zeeb 	/* make each band operational, software state init */
3520*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < wlc->pub->_nbands; i++) {
3521*b4c3e9b5SBjoern A. Zeeb 		uint j = band_order[i];
3522*b4c3e9b5SBjoern A. Zeeb 
3523*b4c3e9b5SBjoern A. Zeeb 		wlc->band = wlc->bandstate[j];
3524*b4c3e9b5SBjoern A. Zeeb 
3525*b4c3e9b5SBjoern A. Zeeb 		brcms_default_rateset(wlc, &default_rateset);
3526*b4c3e9b5SBjoern A. Zeeb 
3527*b4c3e9b5SBjoern A. Zeeb 		/* fill in hw_rate */
3528*b4c3e9b5SBjoern A. Zeeb 		brcms_c_rateset_filter(&default_rateset, &wlc->band->hw_rateset,
3529*b4c3e9b5SBjoern A. Zeeb 				   false, BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
3530*b4c3e9b5SBjoern A. Zeeb 				   (bool) (wlc->pub->_n_enab & SUPPORT_11N));
3531*b4c3e9b5SBjoern A. Zeeb 
3532*b4c3e9b5SBjoern A. Zeeb 		/* init basic rate lookup */
3533*b4c3e9b5SBjoern A. Zeeb 		brcms_c_rate_lookup_init(wlc, &default_rateset);
3534*b4c3e9b5SBjoern A. Zeeb 	}
3535*b4c3e9b5SBjoern A. Zeeb 
3536*b4c3e9b5SBjoern A. Zeeb 	/* sync up phy/radio chanspec */
3537*b4c3e9b5SBjoern A. Zeeb 	brcms_c_set_phy_chanspec(wlc, chanspec);
3538*b4c3e9b5SBjoern A. Zeeb }
3539*b4c3e9b5SBjoern A. Zeeb 
3540*b4c3e9b5SBjoern A. Zeeb /*
3541*b4c3e9b5SBjoern A. Zeeb  * Set or clear filtering related maccontrol bits based on
3542*b4c3e9b5SBjoern A. Zeeb  * specified filter flags
3543*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_mac_promisc(struct brcms_c_info * wlc,uint filter_flags)3544*b4c3e9b5SBjoern A. Zeeb void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags)
3545*b4c3e9b5SBjoern A. Zeeb {
3546*b4c3e9b5SBjoern A. Zeeb 	u32 promisc_bits = 0;
3547*b4c3e9b5SBjoern A. Zeeb 
3548*b4c3e9b5SBjoern A. Zeeb 	wlc->filter_flags = filter_flags;
3549*b4c3e9b5SBjoern A. Zeeb 
3550*b4c3e9b5SBjoern A. Zeeb 	if (filter_flags & FIF_OTHER_BSS)
3551*b4c3e9b5SBjoern A. Zeeb 		promisc_bits |= MCTL_PROMISC;
3552*b4c3e9b5SBjoern A. Zeeb 
3553*b4c3e9b5SBjoern A. Zeeb 	if (filter_flags & FIF_BCN_PRBRESP_PROMISC)
3554*b4c3e9b5SBjoern A. Zeeb 		promisc_bits |= MCTL_BCNS_PROMISC;
3555*b4c3e9b5SBjoern A. Zeeb 
3556*b4c3e9b5SBjoern A. Zeeb 	if (filter_flags & FIF_FCSFAIL)
3557*b4c3e9b5SBjoern A. Zeeb 		promisc_bits |= MCTL_KEEPBADFCS;
3558*b4c3e9b5SBjoern A. Zeeb 
3559*b4c3e9b5SBjoern A. Zeeb 	if (filter_flags & (FIF_CONTROL | FIF_PSPOLL))
3560*b4c3e9b5SBjoern A. Zeeb 		promisc_bits |= MCTL_KEEPCONTROL;
3561*b4c3e9b5SBjoern A. Zeeb 
3562*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mctrl(wlc->hw,
3563*b4c3e9b5SBjoern A. Zeeb 		MCTL_PROMISC | MCTL_BCNS_PROMISC |
3564*b4c3e9b5SBjoern A. Zeeb 		MCTL_KEEPCONTROL | MCTL_KEEPBADFCS,
3565*b4c3e9b5SBjoern A. Zeeb 		promisc_bits);
3566*b4c3e9b5SBjoern A. Zeeb }
3567*b4c3e9b5SBjoern A. Zeeb 
3568*b4c3e9b5SBjoern A. Zeeb /*
3569*b4c3e9b5SBjoern A. Zeeb  * ucode, hwmac update
3570*b4c3e9b5SBjoern A. Zeeb  *    Channel dependent updates for ucode and hw
3571*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_ucode_mac_upd(struct brcms_c_info * wlc)3572*b4c3e9b5SBjoern A. Zeeb static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
3573*b4c3e9b5SBjoern A. Zeeb {
3574*b4c3e9b5SBjoern A. Zeeb 	/* enable or disable any active IBSSs depending on whether or not
3575*b4c3e9b5SBjoern A. Zeeb 	 * we are on the home channel
3576*b4c3e9b5SBjoern A. Zeeb 	 */
3577*b4c3e9b5SBjoern A. Zeeb 	if (wlc->home_chanspec == wlc_phy_chanspec_get(wlc->band->pi)) {
3578*b4c3e9b5SBjoern A. Zeeb 		if (wlc->pub->associated) {
3579*b4c3e9b5SBjoern A. Zeeb 			/*
3580*b4c3e9b5SBjoern A. Zeeb 			 * BMAC_NOTE: This is something that should be fixed
3581*b4c3e9b5SBjoern A. Zeeb 			 * in ucode inits. I think that the ucode inits set
3582*b4c3e9b5SBjoern A. Zeeb 			 * up the bcn templates and shm values with a bogus
3583*b4c3e9b5SBjoern A. Zeeb 			 * beacon. This should not be done in the inits. If
3584*b4c3e9b5SBjoern A. Zeeb 			 * ucode needs to set up a beacon for testing, the
3585*b4c3e9b5SBjoern A. Zeeb 			 * test routines should write it down, not expect the
3586*b4c3e9b5SBjoern A. Zeeb 			 * inits to populate a bogus beacon.
3587*b4c3e9b5SBjoern A. Zeeb 			 */
3588*b4c3e9b5SBjoern A. Zeeb 			if (BRCMS_PHY_11N_CAP(wlc->band))
3589*b4c3e9b5SBjoern A. Zeeb 				brcms_b_write_shm(wlc->hw,
3590*b4c3e9b5SBjoern A. Zeeb 						M_BCN_TXTSF_OFFSET, 0);
3591*b4c3e9b5SBjoern A. Zeeb 		}
3592*b4c3e9b5SBjoern A. Zeeb 	} else {
3593*b4c3e9b5SBjoern A. Zeeb 		/* disable an active IBSS if we are not on the home channel */
3594*b4c3e9b5SBjoern A. Zeeb 	}
3595*b4c3e9b5SBjoern A. Zeeb }
3596*b4c3e9b5SBjoern A. Zeeb 
brcms_c_write_rate_shm(struct brcms_c_info * wlc,u8 rate,u8 basic_rate)3597*b4c3e9b5SBjoern A. Zeeb static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate,
3598*b4c3e9b5SBjoern A. Zeeb 				   u8 basic_rate)
3599*b4c3e9b5SBjoern A. Zeeb {
3600*b4c3e9b5SBjoern A. Zeeb 	u8 phy_rate, index;
3601*b4c3e9b5SBjoern A. Zeeb 	u8 basic_phy_rate, basic_index;
3602*b4c3e9b5SBjoern A. Zeeb 	u16 dir_table, basic_table;
3603*b4c3e9b5SBjoern A. Zeeb 	u16 basic_ptr;
3604*b4c3e9b5SBjoern A. Zeeb 
3605*b4c3e9b5SBjoern A. Zeeb 	/* Shared memory address for the table we are reading */
3606*b4c3e9b5SBjoern A. Zeeb 	dir_table = is_ofdm_rate(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B;
3607*b4c3e9b5SBjoern A. Zeeb 
3608*b4c3e9b5SBjoern A. Zeeb 	/* Shared memory address for the table we are writing */
3609*b4c3e9b5SBjoern A. Zeeb 	basic_table = is_ofdm_rate(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B;
3610*b4c3e9b5SBjoern A. Zeeb 
3611*b4c3e9b5SBjoern A. Zeeb 	/*
3612*b4c3e9b5SBjoern A. Zeeb 	 * for a given rate, the LS-nibble of the PLCP SIGNAL field is
3613*b4c3e9b5SBjoern A. Zeeb 	 * the index into the rate table.
3614*b4c3e9b5SBjoern A. Zeeb 	 */
3615*b4c3e9b5SBjoern A. Zeeb 	phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
3616*b4c3e9b5SBjoern A. Zeeb 	basic_phy_rate = rate_info[basic_rate] & BRCMS_RATE_MASK;
3617*b4c3e9b5SBjoern A. Zeeb 	index = phy_rate & 0xf;
3618*b4c3e9b5SBjoern A. Zeeb 	basic_index = basic_phy_rate & 0xf;
3619*b4c3e9b5SBjoern A. Zeeb 
3620*b4c3e9b5SBjoern A. Zeeb 	/* Find the SHM pointer to the ACK rate entry by looking in the
3621*b4c3e9b5SBjoern A. Zeeb 	 * Direct-map Table
3622*b4c3e9b5SBjoern A. Zeeb 	 */
3623*b4c3e9b5SBjoern A. Zeeb 	basic_ptr = brcms_b_read_shm(wlc->hw, (dir_table + basic_index * 2));
3624*b4c3e9b5SBjoern A. Zeeb 
3625*b4c3e9b5SBjoern A. Zeeb 	/* Update the SHM BSS-basic-rate-set mapping table with the pointer
3626*b4c3e9b5SBjoern A. Zeeb 	 * to the correct basic rate for the given incoming rate
3627*b4c3e9b5SBjoern A. Zeeb 	 */
3628*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc->hw, (basic_table + index * 2), basic_ptr);
3629*b4c3e9b5SBjoern A. Zeeb }
3630*b4c3e9b5SBjoern A. Zeeb 
3631*b4c3e9b5SBjoern A. Zeeb static const struct brcms_c_rateset *
brcms_c_rateset_get_hwrs(struct brcms_c_info * wlc)3632*b4c3e9b5SBjoern A. Zeeb brcms_c_rateset_get_hwrs(struct brcms_c_info *wlc)
3633*b4c3e9b5SBjoern A. Zeeb {
3634*b4c3e9b5SBjoern A. Zeeb 	const struct brcms_c_rateset *rs_dflt;
3635*b4c3e9b5SBjoern A. Zeeb 
3636*b4c3e9b5SBjoern A. Zeeb 	if (BRCMS_PHY_11N_CAP(wlc->band)) {
3637*b4c3e9b5SBjoern A. Zeeb 		if (wlc->band->bandtype == BRCM_BAND_5G)
3638*b4c3e9b5SBjoern A. Zeeb 			rs_dflt = &ofdm_mimo_rates;
3639*b4c3e9b5SBjoern A. Zeeb 		else
3640*b4c3e9b5SBjoern A. Zeeb 			rs_dflt = &cck_ofdm_mimo_rates;
3641*b4c3e9b5SBjoern A. Zeeb 	} else if (wlc->band->gmode)
3642*b4c3e9b5SBjoern A. Zeeb 		rs_dflt = &cck_ofdm_rates;
3643*b4c3e9b5SBjoern A. Zeeb 	else
3644*b4c3e9b5SBjoern A. Zeeb 		rs_dflt = &cck_rates;
3645*b4c3e9b5SBjoern A. Zeeb 
3646*b4c3e9b5SBjoern A. Zeeb 	return rs_dflt;
3647*b4c3e9b5SBjoern A. Zeeb }
3648*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_ratetable(struct brcms_c_info * wlc)3649*b4c3e9b5SBjoern A. Zeeb static void brcms_c_set_ratetable(struct brcms_c_info *wlc)
3650*b4c3e9b5SBjoern A. Zeeb {
3651*b4c3e9b5SBjoern A. Zeeb 	const struct brcms_c_rateset *rs_dflt;
3652*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_rateset rs;
3653*b4c3e9b5SBjoern A. Zeeb 	u8 rate, basic_rate;
3654*b4c3e9b5SBjoern A. Zeeb 	uint i;
3655*b4c3e9b5SBjoern A. Zeeb 
3656*b4c3e9b5SBjoern A. Zeeb 	rs_dflt = brcms_c_rateset_get_hwrs(wlc);
3657*b4c3e9b5SBjoern A. Zeeb 
3658*b4c3e9b5SBjoern A. Zeeb 	brcms_c_rateset_copy(rs_dflt, &rs);
3659*b4c3e9b5SBjoern A. Zeeb 	brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
3660*b4c3e9b5SBjoern A. Zeeb 
3661*b4c3e9b5SBjoern A. Zeeb 	/* walk the phy rate table and update SHM basic rate lookup table */
3662*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < rs.count; i++) {
3663*b4c3e9b5SBjoern A. Zeeb 		rate = rs.rates[i] & BRCMS_RATE_MASK;
3664*b4c3e9b5SBjoern A. Zeeb 
3665*b4c3e9b5SBjoern A. Zeeb 		/* for a given rate brcms_basic_rate returns the rate at
3666*b4c3e9b5SBjoern A. Zeeb 		 * which a response ACK/CTS should be sent.
3667*b4c3e9b5SBjoern A. Zeeb 		 */
3668*b4c3e9b5SBjoern A. Zeeb 		basic_rate = brcms_basic_rate(wlc, rate);
3669*b4c3e9b5SBjoern A. Zeeb 		if (basic_rate == 0)
3670*b4c3e9b5SBjoern A. Zeeb 			/* This should only happen if we are using a
3671*b4c3e9b5SBjoern A. Zeeb 			 * restricted rateset.
3672*b4c3e9b5SBjoern A. Zeeb 			 */
3673*b4c3e9b5SBjoern A. Zeeb 			basic_rate = rs.rates[0] & BRCMS_RATE_MASK;
3674*b4c3e9b5SBjoern A. Zeeb 
3675*b4c3e9b5SBjoern A. Zeeb 		brcms_c_write_rate_shm(wlc, rate, basic_rate);
3676*b4c3e9b5SBjoern A. Zeeb 	}
3677*b4c3e9b5SBjoern A. Zeeb }
3678*b4c3e9b5SBjoern A. Zeeb 
3679*b4c3e9b5SBjoern A. Zeeb /* band-specific init */
brcms_c_bsinit(struct brcms_c_info * wlc)3680*b4c3e9b5SBjoern A. Zeeb static void brcms_c_bsinit(struct brcms_c_info *wlc)
3681*b4c3e9b5SBjoern A. Zeeb {
3682*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc->hw->d11core, "wl%d: bandunit %d\n",
3683*b4c3e9b5SBjoern A. Zeeb 		       wlc->pub->unit, wlc->band->bandunit);
3684*b4c3e9b5SBjoern A. Zeeb 
3685*b4c3e9b5SBjoern A. Zeeb 	/* write ucode ACK/CTS rate table */
3686*b4c3e9b5SBjoern A. Zeeb 	brcms_c_set_ratetable(wlc);
3687*b4c3e9b5SBjoern A. Zeeb 
3688*b4c3e9b5SBjoern A. Zeeb 	/* update some band specific mac configuration */
3689*b4c3e9b5SBjoern A. Zeeb 	brcms_c_ucode_mac_upd(wlc);
3690*b4c3e9b5SBjoern A. Zeeb 
3691*b4c3e9b5SBjoern A. Zeeb 	/* init antenna selection */
3692*b4c3e9b5SBjoern A. Zeeb 	brcms_c_antsel_init(wlc->asi);
3693*b4c3e9b5SBjoern A. Zeeb 
3694*b4c3e9b5SBjoern A. Zeeb }
3695*b4c3e9b5SBjoern A. Zeeb 
3696*b4c3e9b5SBjoern A. Zeeb /* formula:  IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */
3697*b4c3e9b5SBjoern A. Zeeb static int
brcms_c_duty_cycle_set(struct brcms_c_info * wlc,int duty_cycle,bool isOFDM,bool writeToShm)3698*b4c3e9b5SBjoern A. Zeeb brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
3699*b4c3e9b5SBjoern A. Zeeb 		   bool writeToShm)
3700*b4c3e9b5SBjoern A. Zeeb {
3701*b4c3e9b5SBjoern A. Zeeb 	int idle_busy_ratio_x_16 = 0;
3702*b4c3e9b5SBjoern A. Zeeb 	uint offset =
3703*b4c3e9b5SBjoern A. Zeeb 	    isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM :
3704*b4c3e9b5SBjoern A. Zeeb 	    M_TX_IDLE_BUSY_RATIO_X_16_CCK;
3705*b4c3e9b5SBjoern A. Zeeb 	if (duty_cycle > 100 || duty_cycle < 0) {
3706*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core,
3707*b4c3e9b5SBjoern A. Zeeb 			  "wl%d:  duty cycle value off limit\n",
3708*b4c3e9b5SBjoern A. Zeeb 			  wlc->pub->unit);
3709*b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
3710*b4c3e9b5SBjoern A. Zeeb 	}
3711*b4c3e9b5SBjoern A. Zeeb 	if (duty_cycle)
3712*b4c3e9b5SBjoern A. Zeeb 		idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle;
3713*b4c3e9b5SBjoern A. Zeeb 	/* Only write to shared memory  when wl is up */
3714*b4c3e9b5SBjoern A. Zeeb 	if (writeToShm)
3715*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc->hw, offset, (u16) idle_busy_ratio_x_16);
3716*b4c3e9b5SBjoern A. Zeeb 
3717*b4c3e9b5SBjoern A. Zeeb 	if (isOFDM)
3718*b4c3e9b5SBjoern A. Zeeb 		wlc->tx_duty_cycle_ofdm = (u16) duty_cycle;
3719*b4c3e9b5SBjoern A. Zeeb 	else
3720*b4c3e9b5SBjoern A. Zeeb 		wlc->tx_duty_cycle_cck = (u16) duty_cycle;
3721*b4c3e9b5SBjoern A. Zeeb 
3722*b4c3e9b5SBjoern A. Zeeb 	return 0;
3723*b4c3e9b5SBjoern A. Zeeb }
3724*b4c3e9b5SBjoern A. Zeeb 
3725*b4c3e9b5SBjoern A. Zeeb /* push sw hps and wake state through hardware */
brcms_c_set_ps_ctrl(struct brcms_c_info * wlc)3726*b4c3e9b5SBjoern A. Zeeb static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
3727*b4c3e9b5SBjoern A. Zeeb {
3728*b4c3e9b5SBjoern A. Zeeb 	u32 v1, v2;
3729*b4c3e9b5SBjoern A. Zeeb 	bool hps;
3730*b4c3e9b5SBjoern A. Zeeb 	bool awake_before;
3731*b4c3e9b5SBjoern A. Zeeb 
3732*b4c3e9b5SBjoern A. Zeeb 	hps = brcms_c_ps_allowed(wlc);
3733*b4c3e9b5SBjoern A. Zeeb 
3734*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_mac80211(wlc->hw->d11core, "wl%d: hps %d\n", wlc->pub->unit,
3735*b4c3e9b5SBjoern A. Zeeb 			   hps);
3736*b4c3e9b5SBjoern A. Zeeb 
3737*b4c3e9b5SBjoern A. Zeeb 	v1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
3738*b4c3e9b5SBjoern A. Zeeb 	v2 = MCTL_WAKE;
3739*b4c3e9b5SBjoern A. Zeeb 	if (hps)
3740*b4c3e9b5SBjoern A. Zeeb 		v2 |= MCTL_HPS;
3741*b4c3e9b5SBjoern A. Zeeb 
3742*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2);
3743*b4c3e9b5SBjoern A. Zeeb 
3744*b4c3e9b5SBjoern A. Zeeb 	awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));
3745*b4c3e9b5SBjoern A. Zeeb 
3746*b4c3e9b5SBjoern A. Zeeb 	if (!awake_before)
3747*b4c3e9b5SBjoern A. Zeeb 		brcms_b_wait_for_wake(wlc->hw);
3748*b4c3e9b5SBjoern A. Zeeb }
3749*b4c3e9b5SBjoern A. Zeeb 
3750*b4c3e9b5SBjoern A. Zeeb /*
3751*b4c3e9b5SBjoern A. Zeeb  * Write this BSS config's MAC address to core.
3752*b4c3e9b5SBjoern A. Zeeb  * Updates RXE match engine.
3753*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_set_mac(struct brcms_bss_cfg * bsscfg)3754*b4c3e9b5SBjoern A. Zeeb static void brcms_c_set_mac(struct brcms_bss_cfg *bsscfg)
3755*b4c3e9b5SBjoern A. Zeeb {
3756*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_info *wlc = bsscfg->wlc;
3757*b4c3e9b5SBjoern A. Zeeb 
3758*b4c3e9b5SBjoern A. Zeeb 	/* enter the MAC addr into the RXE match registers */
3759*b4c3e9b5SBjoern A. Zeeb 	brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, wlc->pub->cur_etheraddr);
3760*b4c3e9b5SBjoern A. Zeeb 
3761*b4c3e9b5SBjoern A. Zeeb 	brcms_c_ampdu_macaddr_upd(wlc);
3762*b4c3e9b5SBjoern A. Zeeb }
3763*b4c3e9b5SBjoern A. Zeeb 
3764*b4c3e9b5SBjoern A. Zeeb /* Write the BSS config's BSSID address to core (set_bssid in d11procs.tcl).
3765*b4c3e9b5SBjoern A. Zeeb  * Updates RXE match engine.
3766*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_set_bssid(struct brcms_bss_cfg * bsscfg)3767*b4c3e9b5SBjoern A. Zeeb static void brcms_c_set_bssid(struct brcms_bss_cfg *bsscfg)
3768*b4c3e9b5SBjoern A. Zeeb {
3769*b4c3e9b5SBjoern A. Zeeb 	/* we need to update BSSID in RXE match registers */
3770*b4c3e9b5SBjoern A. Zeeb 	brcms_c_set_addrmatch(bsscfg->wlc, RCM_BSSID_OFFSET, bsscfg->BSSID);
3771*b4c3e9b5SBjoern A. Zeeb }
3772*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_ssid(struct brcms_c_info * wlc,u8 * ssid,size_t ssid_len)3773*b4c3e9b5SBjoern A. Zeeb void brcms_c_set_ssid(struct brcms_c_info *wlc, u8 *ssid, size_t ssid_len)
3774*b4c3e9b5SBjoern A. Zeeb {
3775*b4c3e9b5SBjoern A. Zeeb 	u8 len = min_t(u8, sizeof(wlc->bsscfg->SSID), ssid_len);
3776*b4c3e9b5SBjoern A. Zeeb 	memset(wlc->bsscfg->SSID, 0, sizeof(wlc->bsscfg->SSID));
3777*b4c3e9b5SBjoern A. Zeeb 
3778*b4c3e9b5SBjoern A. Zeeb 	memcpy(wlc->bsscfg->SSID, ssid, len);
3779*b4c3e9b5SBjoern A. Zeeb 	wlc->bsscfg->SSID_len = len;
3780*b4c3e9b5SBjoern A. Zeeb }
3781*b4c3e9b5SBjoern A. Zeeb 
brcms_b_set_shortslot(struct brcms_hardware * wlc_hw,bool shortslot)3782*b4c3e9b5SBjoern A. Zeeb static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)
3783*b4c3e9b5SBjoern A. Zeeb {
3784*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->shortslot = shortslot;
3785*b4c3e9b5SBjoern A. Zeeb 
3786*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->band->bandtype == BRCM_BAND_2G && wlc_hw->up) {
3787*b4c3e9b5SBjoern A. Zeeb 		brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
3788*b4c3e9b5SBjoern A. Zeeb 		brcms_b_update_slot_timing(wlc_hw, shortslot);
3789*b4c3e9b5SBjoern A. Zeeb 		brcms_c_enable_mac(wlc_hw->wlc);
3790*b4c3e9b5SBjoern A. Zeeb 	}
3791*b4c3e9b5SBjoern A. Zeeb }
3792*b4c3e9b5SBjoern A. Zeeb 
3793*b4c3e9b5SBjoern A. Zeeb /*
3794*b4c3e9b5SBjoern A. Zeeb  * Suspend the MAC and update the slot timing
3795*b4c3e9b5SBjoern A. Zeeb  * for standard 11b/g (20us slots) or shortslot 11g (9us slots).
3796*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_switch_shortslot(struct brcms_c_info * wlc,bool shortslot)3797*b4c3e9b5SBjoern A. Zeeb static void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot)
3798*b4c3e9b5SBjoern A. Zeeb {
3799*b4c3e9b5SBjoern A. Zeeb 	/* use the override if it is set */
3800*b4c3e9b5SBjoern A. Zeeb 	if (wlc->shortslot_override != BRCMS_SHORTSLOT_AUTO)
3801*b4c3e9b5SBjoern A. Zeeb 		shortslot = (wlc->shortslot_override == BRCMS_SHORTSLOT_ON);
3802*b4c3e9b5SBjoern A. Zeeb 
3803*b4c3e9b5SBjoern A. Zeeb 	if (wlc->shortslot == shortslot)
3804*b4c3e9b5SBjoern A. Zeeb 		return;
3805*b4c3e9b5SBjoern A. Zeeb 
3806*b4c3e9b5SBjoern A. Zeeb 	wlc->shortslot = shortslot;
3807*b4c3e9b5SBjoern A. Zeeb 
3808*b4c3e9b5SBjoern A. Zeeb 	brcms_b_set_shortslot(wlc->hw, shortslot);
3809*b4c3e9b5SBjoern A. Zeeb }
3810*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_home_chanspec(struct brcms_c_info * wlc,u16 chanspec)3811*b4c3e9b5SBjoern A. Zeeb static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
3812*b4c3e9b5SBjoern A. Zeeb {
3813*b4c3e9b5SBjoern A. Zeeb 	if (wlc->home_chanspec != chanspec) {
3814*b4c3e9b5SBjoern A. Zeeb 		wlc->home_chanspec = chanspec;
3815*b4c3e9b5SBjoern A. Zeeb 
3816*b4c3e9b5SBjoern A. Zeeb 		if (wlc->pub->associated)
3817*b4c3e9b5SBjoern A. Zeeb 			wlc->bsscfg->current_bss->chanspec = chanspec;
3818*b4c3e9b5SBjoern A. Zeeb 	}
3819*b4c3e9b5SBjoern A. Zeeb }
3820*b4c3e9b5SBjoern A. Zeeb 
3821*b4c3e9b5SBjoern A. Zeeb void
brcms_b_set_chanspec(struct brcms_hardware * wlc_hw,u16 chanspec,bool mute_tx,struct txpwr_limits * txpwr)3822*b4c3e9b5SBjoern A. Zeeb brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
3823*b4c3e9b5SBjoern A. Zeeb 		      bool mute_tx, struct txpwr_limits *txpwr)
3824*b4c3e9b5SBjoern A. Zeeb {
3825*b4c3e9b5SBjoern A. Zeeb 	uint bandunit;
3826*b4c3e9b5SBjoern A. Zeeb 
3827*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: 0x%x\n", wlc_hw->unit,
3828*b4c3e9b5SBjoern A. Zeeb 			   chanspec);
3829*b4c3e9b5SBjoern A. Zeeb 
3830*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->chanspec = chanspec;
3831*b4c3e9b5SBjoern A. Zeeb 
3832*b4c3e9b5SBjoern A. Zeeb 	/* Switch bands if necessary */
3833*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->_nbands > 1) {
3834*b4c3e9b5SBjoern A. Zeeb 		bandunit = chspec_bandunit(chanspec);
3835*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->band->bandunit != bandunit) {
3836*b4c3e9b5SBjoern A. Zeeb 			/* brcms_b_setband disables other bandunit,
3837*b4c3e9b5SBjoern A. Zeeb 			 *  use light band switch if not up yet
3838*b4c3e9b5SBjoern A. Zeeb 			 */
3839*b4c3e9b5SBjoern A. Zeeb 			if (wlc_hw->up) {
3840*b4c3e9b5SBjoern A. Zeeb 				wlc_phy_chanspec_radio_set(wlc_hw->
3841*b4c3e9b5SBjoern A. Zeeb 							   bandstate[bandunit]->
3842*b4c3e9b5SBjoern A. Zeeb 							   pi, chanspec);
3843*b4c3e9b5SBjoern A. Zeeb 				brcms_b_setband(wlc_hw, bandunit, chanspec);
3844*b4c3e9b5SBjoern A. Zeeb 			} else {
3845*b4c3e9b5SBjoern A. Zeeb 				brcms_c_setxband(wlc_hw, bandunit);
3846*b4c3e9b5SBjoern A. Zeeb 			}
3847*b4c3e9b5SBjoern A. Zeeb 		}
3848*b4c3e9b5SBjoern A. Zeeb 	}
3849*b4c3e9b5SBjoern A. Zeeb 
3850*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_initcal_enable(wlc_hw->band->pi, !mute_tx);
3851*b4c3e9b5SBjoern A. Zeeb 
3852*b4c3e9b5SBjoern A. Zeeb 	if (!wlc_hw->up) {
3853*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->clk)
3854*b4c3e9b5SBjoern A. Zeeb 			wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr,
3855*b4c3e9b5SBjoern A. Zeeb 						  chanspec);
3856*b4c3e9b5SBjoern A. Zeeb 		wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
3857*b4c3e9b5SBjoern A. Zeeb 	} else {
3858*b4c3e9b5SBjoern A. Zeeb 		wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec);
3859*b4c3e9b5SBjoern A. Zeeb 		wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);
3860*b4c3e9b5SBjoern A. Zeeb 
3861*b4c3e9b5SBjoern A. Zeeb 		/* Update muting of the channel */
3862*b4c3e9b5SBjoern A. Zeeb 		brcms_b_mute(wlc_hw, mute_tx);
3863*b4c3e9b5SBjoern A. Zeeb 	}
3864*b4c3e9b5SBjoern A. Zeeb }
3865*b4c3e9b5SBjoern A. Zeeb 
3866*b4c3e9b5SBjoern A. Zeeb /* switch to and initialize new band */
brcms_c_setband(struct brcms_c_info * wlc,uint bandunit)3867*b4c3e9b5SBjoern A. Zeeb static void brcms_c_setband(struct brcms_c_info *wlc,
3868*b4c3e9b5SBjoern A. Zeeb 					   uint bandunit)
3869*b4c3e9b5SBjoern A. Zeeb {
3870*b4c3e9b5SBjoern A. Zeeb 	wlc->band = wlc->bandstate[bandunit];
3871*b4c3e9b5SBjoern A. Zeeb 
3872*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->pub->up)
3873*b4c3e9b5SBjoern A. Zeeb 		return;
3874*b4c3e9b5SBjoern A. Zeeb 
3875*b4c3e9b5SBjoern A. Zeeb 	/* wait for at least one beacon before entering sleeping state */
3876*b4c3e9b5SBjoern A. Zeeb 	brcms_c_set_ps_ctrl(wlc);
3877*b4c3e9b5SBjoern A. Zeeb 
3878*b4c3e9b5SBjoern A. Zeeb 	/* band-specific initializations */
3879*b4c3e9b5SBjoern A. Zeeb 	brcms_c_bsinit(wlc);
3880*b4c3e9b5SBjoern A. Zeeb }
3881*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_chanspec(struct brcms_c_info * wlc,u16 chanspec)3882*b4c3e9b5SBjoern A. Zeeb static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
3883*b4c3e9b5SBjoern A. Zeeb {
3884*b4c3e9b5SBjoern A. Zeeb 	uint bandunit;
3885*b4c3e9b5SBjoern A. Zeeb 	u16 old_chanspec = wlc->chanspec;
3886*b4c3e9b5SBjoern A. Zeeb 
3887*b4c3e9b5SBjoern A. Zeeb 	if (!brcms_c_valid_chanspec_db(wlc->cmi, chanspec)) {
3888*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "wl%d: %s: Bad channel %d\n",
3889*b4c3e9b5SBjoern A. Zeeb 			  wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec));
3890*b4c3e9b5SBjoern A. Zeeb 		return;
3891*b4c3e9b5SBjoern A. Zeeb 	}
3892*b4c3e9b5SBjoern A. Zeeb 
3893*b4c3e9b5SBjoern A. Zeeb 	/* Switch bands if necessary */
3894*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->_nbands > 1) {
3895*b4c3e9b5SBjoern A. Zeeb 		bandunit = chspec_bandunit(chanspec);
3896*b4c3e9b5SBjoern A. Zeeb 		if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) {
3897*b4c3e9b5SBjoern A. Zeeb 			if (wlc->bandlocked) {
3898*b4c3e9b5SBjoern A. Zeeb 				brcms_err(wlc->hw->d11core,
3899*b4c3e9b5SBjoern A. Zeeb 					  "wl%d: %s: chspec %d band is locked!\n",
3900*b4c3e9b5SBjoern A. Zeeb 					  wlc->pub->unit, __func__,
3901*b4c3e9b5SBjoern A. Zeeb 					  CHSPEC_CHANNEL(chanspec));
3902*b4c3e9b5SBjoern A. Zeeb 				return;
3903*b4c3e9b5SBjoern A. Zeeb 			}
3904*b4c3e9b5SBjoern A. Zeeb 			/*
3905*b4c3e9b5SBjoern A. Zeeb 			 * should the setband call come after the
3906*b4c3e9b5SBjoern A. Zeeb 			 * brcms_b_chanspec() ? if the setband updates
3907*b4c3e9b5SBjoern A. Zeeb 			 * (brcms_c_bsinit) use low level calls to inspect and
3908*b4c3e9b5SBjoern A. Zeeb 			 * set state, the state inspected may be from the wrong
3909*b4c3e9b5SBjoern A. Zeeb 			 * band, or the following brcms_b_set_chanspec() may
3910*b4c3e9b5SBjoern A. Zeeb 			 * undo the work.
3911*b4c3e9b5SBjoern A. Zeeb 			 */
3912*b4c3e9b5SBjoern A. Zeeb 			brcms_c_setband(wlc, bandunit);
3913*b4c3e9b5SBjoern A. Zeeb 		}
3914*b4c3e9b5SBjoern A. Zeeb 	}
3915*b4c3e9b5SBjoern A. Zeeb 
3916*b4c3e9b5SBjoern A. Zeeb 	/* sync up phy/radio chanspec */
3917*b4c3e9b5SBjoern A. Zeeb 	brcms_c_set_phy_chanspec(wlc, chanspec);
3918*b4c3e9b5SBjoern A. Zeeb 
3919*b4c3e9b5SBjoern A. Zeeb 	/* init antenna selection */
3920*b4c3e9b5SBjoern A. Zeeb 	if (brcms_chspec_bw(old_chanspec) != brcms_chspec_bw(chanspec)) {
3921*b4c3e9b5SBjoern A. Zeeb 		brcms_c_antsel_init(wlc->asi);
3922*b4c3e9b5SBjoern A. Zeeb 
3923*b4c3e9b5SBjoern A. Zeeb 		/* Fix the hardware rateset based on bw.
3924*b4c3e9b5SBjoern A. Zeeb 		 * Mainly add MCS32 for 40Mhz, remove MCS 32 for 20Mhz
3925*b4c3e9b5SBjoern A. Zeeb 		 */
3926*b4c3e9b5SBjoern A. Zeeb 		brcms_c_rateset_bw_mcs_filter(&wlc->band->hw_rateset,
3927*b4c3e9b5SBjoern A. Zeeb 			wlc->band->mimo_cap_40 ? brcms_chspec_bw(chanspec) : 0);
3928*b4c3e9b5SBjoern A. Zeeb 	}
3929*b4c3e9b5SBjoern A. Zeeb 
3930*b4c3e9b5SBjoern A. Zeeb 	/* update some mac configuration since chanspec changed */
3931*b4c3e9b5SBjoern A. Zeeb 	brcms_c_ucode_mac_upd(wlc);
3932*b4c3e9b5SBjoern A. Zeeb }
3933*b4c3e9b5SBjoern A. Zeeb 
3934*b4c3e9b5SBjoern A. Zeeb /*
3935*b4c3e9b5SBjoern A. Zeeb  * This function changes the phytxctl for beacon based on current
3936*b4c3e9b5SBjoern A. Zeeb  * beacon ratespec AND txant setting as per this table:
3937*b4c3e9b5SBjoern A. Zeeb  *  ratespec     CCK		ant = wlc->stf->txant
3938*b4c3e9b5SBjoern A. Zeeb  *		OFDM		ant = 3
3939*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info * wlc,u32 bcn_rspec)3940*b4c3e9b5SBjoern A. Zeeb void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
3941*b4c3e9b5SBjoern A. Zeeb 				       u32 bcn_rspec)
3942*b4c3e9b5SBjoern A. Zeeb {
3943*b4c3e9b5SBjoern A. Zeeb 	u16 phyctl;
3944*b4c3e9b5SBjoern A. Zeeb 	u16 phytxant = wlc->stf->phytxant;
3945*b4c3e9b5SBjoern A. Zeeb 	u16 mask = PHY_TXC_ANT_MASK;
3946*b4c3e9b5SBjoern A. Zeeb 
3947*b4c3e9b5SBjoern A. Zeeb 	/* for non-siso rates or default setting, use the available chains */
3948*b4c3e9b5SBjoern A. Zeeb 	if (BRCMS_PHY_11N_CAP(wlc->band))
3949*b4c3e9b5SBjoern A. Zeeb 		phytxant = brcms_c_stf_phytxchain_sel(wlc, bcn_rspec);
3950*b4c3e9b5SBjoern A. Zeeb 
3951*b4c3e9b5SBjoern A. Zeeb 	phyctl = brcms_b_read_shm(wlc->hw, M_BCN_PCTLWD);
3952*b4c3e9b5SBjoern A. Zeeb 	phyctl = (phyctl & ~mask) | phytxant;
3953*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc->hw, M_BCN_PCTLWD, phyctl);
3954*b4c3e9b5SBjoern A. Zeeb }
3955*b4c3e9b5SBjoern A. Zeeb 
3956*b4c3e9b5SBjoern A. Zeeb /*
3957*b4c3e9b5SBjoern A. Zeeb  * centralized protection config change function to simplify debugging, no
3958*b4c3e9b5SBjoern A. Zeeb  * consistency checking this should be called only on changes to avoid overhead
3959*b4c3e9b5SBjoern A. Zeeb  * in periodic function
3960*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_protection_upd(struct brcms_c_info * wlc,uint idx,int val)3961*b4c3e9b5SBjoern A. Zeeb void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val)
3962*b4c3e9b5SBjoern A. Zeeb {
3963*b4c3e9b5SBjoern A. Zeeb 	/*
3964*b4c3e9b5SBjoern A. Zeeb 	 * Cannot use brcms_dbg_* here because this function is called
3965*b4c3e9b5SBjoern A. Zeeb 	 * before wlc is sufficiently initialized.
3966*b4c3e9b5SBjoern A. Zeeb 	 */
3967*b4c3e9b5SBjoern A. Zeeb 	BCMMSG(wlc->wiphy, "idx %d, val %d\n", idx, val);
3968*b4c3e9b5SBjoern A. Zeeb 
3969*b4c3e9b5SBjoern A. Zeeb 	switch (idx) {
3970*b4c3e9b5SBjoern A. Zeeb 	case BRCMS_PROT_G_SPEC:
3971*b4c3e9b5SBjoern A. Zeeb 		wlc->protection->_g = (bool) val;
3972*b4c3e9b5SBjoern A. Zeeb 		break;
3973*b4c3e9b5SBjoern A. Zeeb 	case BRCMS_PROT_G_OVR:
3974*b4c3e9b5SBjoern A. Zeeb 		wlc->protection->g_override = (s8) val;
3975*b4c3e9b5SBjoern A. Zeeb 		break;
3976*b4c3e9b5SBjoern A. Zeeb 	case BRCMS_PROT_G_USER:
3977*b4c3e9b5SBjoern A. Zeeb 		wlc->protection->gmode_user = (u8) val;
3978*b4c3e9b5SBjoern A. Zeeb 		break;
3979*b4c3e9b5SBjoern A. Zeeb 	case BRCMS_PROT_OVERLAP:
3980*b4c3e9b5SBjoern A. Zeeb 		wlc->protection->overlap = (s8) val;
3981*b4c3e9b5SBjoern A. Zeeb 		break;
3982*b4c3e9b5SBjoern A. Zeeb 	case BRCMS_PROT_N_USER:
3983*b4c3e9b5SBjoern A. Zeeb 		wlc->protection->nmode_user = (s8) val;
3984*b4c3e9b5SBjoern A. Zeeb 		break;
3985*b4c3e9b5SBjoern A. Zeeb 	case BRCMS_PROT_N_CFG:
3986*b4c3e9b5SBjoern A. Zeeb 		wlc->protection->n_cfg = (s8) val;
3987*b4c3e9b5SBjoern A. Zeeb 		break;
3988*b4c3e9b5SBjoern A. Zeeb 	case BRCMS_PROT_N_CFG_OVR:
3989*b4c3e9b5SBjoern A. Zeeb 		wlc->protection->n_cfg_override = (s8) val;
3990*b4c3e9b5SBjoern A. Zeeb 		break;
3991*b4c3e9b5SBjoern A. Zeeb 	case BRCMS_PROT_N_NONGF:
3992*b4c3e9b5SBjoern A. Zeeb 		wlc->protection->nongf = (bool) val;
3993*b4c3e9b5SBjoern A. Zeeb 		break;
3994*b4c3e9b5SBjoern A. Zeeb 	case BRCMS_PROT_N_NONGF_OVR:
3995*b4c3e9b5SBjoern A. Zeeb 		wlc->protection->nongf_override = (s8) val;
3996*b4c3e9b5SBjoern A. Zeeb 		break;
3997*b4c3e9b5SBjoern A. Zeeb 	case BRCMS_PROT_N_PAM_OVR:
3998*b4c3e9b5SBjoern A. Zeeb 		wlc->protection->n_pam_override = (s8) val;
3999*b4c3e9b5SBjoern A. Zeeb 		break;
4000*b4c3e9b5SBjoern A. Zeeb 	case BRCMS_PROT_N_OBSS:
4001*b4c3e9b5SBjoern A. Zeeb 		wlc->protection->n_obss = (bool) val;
4002*b4c3e9b5SBjoern A. Zeeb 		break;
4003*b4c3e9b5SBjoern A. Zeeb 
4004*b4c3e9b5SBjoern A. Zeeb 	default:
4005*b4c3e9b5SBjoern A. Zeeb 		break;
4006*b4c3e9b5SBjoern A. Zeeb 	}
4007*b4c3e9b5SBjoern A. Zeeb 
4008*b4c3e9b5SBjoern A. Zeeb }
4009*b4c3e9b5SBjoern A. Zeeb 
brcms_c_ht_update_sgi_rx(struct brcms_c_info * wlc,int val)4010*b4c3e9b5SBjoern A. Zeeb static void brcms_c_ht_update_sgi_rx(struct brcms_c_info *wlc, int val)
4011*b4c3e9b5SBjoern A. Zeeb {
4012*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->up) {
4013*b4c3e9b5SBjoern A. Zeeb 		brcms_c_update_beacon(wlc);
4014*b4c3e9b5SBjoern A. Zeeb 		brcms_c_update_probe_resp(wlc, true);
4015*b4c3e9b5SBjoern A. Zeeb 	}
4016*b4c3e9b5SBjoern A. Zeeb }
4017*b4c3e9b5SBjoern A. Zeeb 
brcms_c_ht_update_ldpc(struct brcms_c_info * wlc,s8 val)4018*b4c3e9b5SBjoern A. Zeeb static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val)
4019*b4c3e9b5SBjoern A. Zeeb {
4020*b4c3e9b5SBjoern A. Zeeb 	wlc->stf->ldpc = val;
4021*b4c3e9b5SBjoern A. Zeeb 
4022*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->up) {
4023*b4c3e9b5SBjoern A. Zeeb 		brcms_c_update_beacon(wlc);
4024*b4c3e9b5SBjoern A. Zeeb 		brcms_c_update_probe_resp(wlc, true);
4025*b4c3e9b5SBjoern A. Zeeb 		wlc_phy_ldpc_override_set(wlc->band->pi, (val ? true : false));
4026*b4c3e9b5SBjoern A. Zeeb 	}
4027*b4c3e9b5SBjoern A. Zeeb }
4028*b4c3e9b5SBjoern A. Zeeb 
brcms_c_wme_setparams(struct brcms_c_info * wlc,u16 aci,const struct ieee80211_tx_queue_params * params,bool suspend)4029*b4c3e9b5SBjoern A. Zeeb void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
4030*b4c3e9b5SBjoern A. Zeeb 		       const struct ieee80211_tx_queue_params *params,
4031*b4c3e9b5SBjoern A. Zeeb 		       bool suspend)
4032*b4c3e9b5SBjoern A. Zeeb {
4033*b4c3e9b5SBjoern A. Zeeb 	int i;
4034*b4c3e9b5SBjoern A. Zeeb 	struct shm_acparams acp_shm;
4035*b4c3e9b5SBjoern A. Zeeb 	u16 *shm_entry;
4036*b4c3e9b5SBjoern A. Zeeb 
4037*b4c3e9b5SBjoern A. Zeeb 	/* Only apply params if the core is out of reset and has clocks */
4038*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->clk) {
4039*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "wl%d: %s : no-clock\n",
4040*b4c3e9b5SBjoern A. Zeeb 			  wlc->pub->unit, __func__);
4041*b4c3e9b5SBjoern A. Zeeb 		return;
4042*b4c3e9b5SBjoern A. Zeeb 	}
4043*b4c3e9b5SBjoern A. Zeeb 
4044*b4c3e9b5SBjoern A. Zeeb 	memset(&acp_shm, 0, sizeof(struct shm_acparams));
4045*b4c3e9b5SBjoern A. Zeeb 	/* fill in shm ac params struct */
4046*b4c3e9b5SBjoern A. Zeeb 	acp_shm.txop = params->txop;
4047*b4c3e9b5SBjoern A. Zeeb 	/* convert from units of 32us to us for ucode */
4048*b4c3e9b5SBjoern A. Zeeb 	wlc->edcf_txop[aci & 0x3] = acp_shm.txop =
4049*b4c3e9b5SBjoern A. Zeeb 	    EDCF_TXOP2USEC(acp_shm.txop);
4050*b4c3e9b5SBjoern A. Zeeb 	acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK);
4051*b4c3e9b5SBjoern A. Zeeb 
4052*b4c3e9b5SBjoern A. Zeeb 	if (aci == IEEE80211_AC_VI && acp_shm.txop == 0
4053*b4c3e9b5SBjoern A. Zeeb 	    && acp_shm.aifs < EDCF_AIFSN_MAX)
4054*b4c3e9b5SBjoern A. Zeeb 		acp_shm.aifs++;
4055*b4c3e9b5SBjoern A. Zeeb 
4056*b4c3e9b5SBjoern A. Zeeb 	if (acp_shm.aifs < EDCF_AIFSN_MIN
4057*b4c3e9b5SBjoern A. Zeeb 	    || acp_shm.aifs > EDCF_AIFSN_MAX) {
4058*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "wl%d: edcf_setparams: bad "
4059*b4c3e9b5SBjoern A. Zeeb 			  "aifs %d\n", wlc->pub->unit, acp_shm.aifs);
4060*b4c3e9b5SBjoern A. Zeeb 	} else {
4061*b4c3e9b5SBjoern A. Zeeb 		acp_shm.cwmin = params->cw_min;
4062*b4c3e9b5SBjoern A. Zeeb 		acp_shm.cwmax = params->cw_max;
4063*b4c3e9b5SBjoern A. Zeeb 		acp_shm.cwcur = acp_shm.cwmin;
4064*b4c3e9b5SBjoern A. Zeeb 		acp_shm.bslots =
4065*b4c3e9b5SBjoern A. Zeeb 			bcma_read16(wlc->hw->d11core, D11REGOFFS(tsf_random)) &
4066*b4c3e9b5SBjoern A. Zeeb 			acp_shm.cwcur;
4067*b4c3e9b5SBjoern A. Zeeb 		acp_shm.reggap = acp_shm.bslots + acp_shm.aifs;
4068*b4c3e9b5SBjoern A. Zeeb 		/* Indicate the new params to the ucode */
4069*b4c3e9b5SBjoern A. Zeeb 		acp_shm.status = brcms_b_read_shm(wlc->hw, (M_EDCF_QINFO +
4070*b4c3e9b5SBjoern A. Zeeb 						  wme_ac2fifo[aci] *
4071*b4c3e9b5SBjoern A. Zeeb 						  M_EDCF_QLEN +
4072*b4c3e9b5SBjoern A. Zeeb 						  M_EDCF_STATUS_OFF));
4073*b4c3e9b5SBjoern A. Zeeb 		acp_shm.status |= WME_STATUS_NEWAC;
4074*b4c3e9b5SBjoern A. Zeeb 
4075*b4c3e9b5SBjoern A. Zeeb 		/* Fill in shm acparam table */
4076*b4c3e9b5SBjoern A. Zeeb 		shm_entry = (u16 *) &acp_shm;
4077*b4c3e9b5SBjoern A. Zeeb 		for (i = 0; i < (int)sizeof(struct shm_acparams); i += 2)
4078*b4c3e9b5SBjoern A. Zeeb 			brcms_b_write_shm(wlc->hw,
4079*b4c3e9b5SBjoern A. Zeeb 					  M_EDCF_QINFO +
4080*b4c3e9b5SBjoern A. Zeeb 					  wme_ac2fifo[aci] * M_EDCF_QLEN + i,
4081*b4c3e9b5SBjoern A. Zeeb 					  *shm_entry++);
4082*b4c3e9b5SBjoern A. Zeeb 	}
4083*b4c3e9b5SBjoern A. Zeeb 
4084*b4c3e9b5SBjoern A. Zeeb 	if (suspend)
4085*b4c3e9b5SBjoern A. Zeeb 		brcms_c_suspend_mac_and_wait(wlc);
4086*b4c3e9b5SBjoern A. Zeeb 
4087*b4c3e9b5SBjoern A. Zeeb 	brcms_c_update_beacon(wlc);
4088*b4c3e9b5SBjoern A. Zeeb 	brcms_c_update_probe_resp(wlc, false);
4089*b4c3e9b5SBjoern A. Zeeb 
4090*b4c3e9b5SBjoern A. Zeeb 	if (suspend)
4091*b4c3e9b5SBjoern A. Zeeb 		brcms_c_enable_mac(wlc);
4092*b4c3e9b5SBjoern A. Zeeb }
4093*b4c3e9b5SBjoern A. Zeeb 
brcms_c_edcf_setparams(struct brcms_c_info * wlc,bool suspend)4094*b4c3e9b5SBjoern A. Zeeb static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
4095*b4c3e9b5SBjoern A. Zeeb {
4096*b4c3e9b5SBjoern A. Zeeb 	u16 aci;
4097*b4c3e9b5SBjoern A. Zeeb 	int i_ac;
4098*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_tx_queue_params txq_pars;
4099*b4c3e9b5SBjoern A. Zeeb 	static const struct edcf_acparam default_edcf_acparams[] = {
4100*b4c3e9b5SBjoern A. Zeeb 		 {EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA, EDCF_AC_BE_TXOP_STA},
4101*b4c3e9b5SBjoern A. Zeeb 		 {EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA, EDCF_AC_BK_TXOP_STA},
4102*b4c3e9b5SBjoern A. Zeeb 		 {EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA, EDCF_AC_VI_TXOP_STA},
4103*b4c3e9b5SBjoern A. Zeeb 		 {EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA, EDCF_AC_VO_TXOP_STA}
4104*b4c3e9b5SBjoern A. Zeeb 	}; /* ucode needs these parameters during its initialization */
4105*b4c3e9b5SBjoern A. Zeeb 	const struct edcf_acparam *edcf_acp = &default_edcf_acparams[0];
4106*b4c3e9b5SBjoern A. Zeeb 
4107*b4c3e9b5SBjoern A. Zeeb 	for (i_ac = 0; i_ac < IEEE80211_NUM_ACS; i_ac++, edcf_acp++) {
4108*b4c3e9b5SBjoern A. Zeeb 		/* find out which ac this set of params applies to */
4109*b4c3e9b5SBjoern A. Zeeb 		aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;
4110*b4c3e9b5SBjoern A. Zeeb 
4111*b4c3e9b5SBjoern A. Zeeb 		/* fill in shm ac params struct */
4112*b4c3e9b5SBjoern A. Zeeb 		txq_pars.txop = edcf_acp->TXOP;
4113*b4c3e9b5SBjoern A. Zeeb 		txq_pars.aifs = edcf_acp->ACI;
4114*b4c3e9b5SBjoern A. Zeeb 
4115*b4c3e9b5SBjoern A. Zeeb 		/* CWmin = 2^(ECWmin) - 1 */
4116*b4c3e9b5SBjoern A. Zeeb 		txq_pars.cw_min = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK);
4117*b4c3e9b5SBjoern A. Zeeb 		/* CWmax = 2^(ECWmax) - 1 */
4118*b4c3e9b5SBjoern A. Zeeb 		txq_pars.cw_max = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK)
4119*b4c3e9b5SBjoern A. Zeeb 					    >> EDCF_ECWMAX_SHIFT);
4120*b4c3e9b5SBjoern A. Zeeb 		brcms_c_wme_setparams(wlc, aci, &txq_pars, suspend);
4121*b4c3e9b5SBjoern A. Zeeb 	}
4122*b4c3e9b5SBjoern A. Zeeb 
4123*b4c3e9b5SBjoern A. Zeeb 	if (suspend) {
4124*b4c3e9b5SBjoern A. Zeeb 		brcms_c_suspend_mac_and_wait(wlc);
4125*b4c3e9b5SBjoern A. Zeeb 		brcms_c_enable_mac(wlc);
4126*b4c3e9b5SBjoern A. Zeeb 	}
4127*b4c3e9b5SBjoern A. Zeeb }
4128*b4c3e9b5SBjoern A. Zeeb 
brcms_c_radio_monitor_start(struct brcms_c_info * wlc)4129*b4c3e9b5SBjoern A. Zeeb static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
4130*b4c3e9b5SBjoern A. Zeeb {
4131*b4c3e9b5SBjoern A. Zeeb 	/* Don't start the timer if HWRADIO feature is disabled */
4132*b4c3e9b5SBjoern A. Zeeb 	if (wlc->radio_monitor)
4133*b4c3e9b5SBjoern A. Zeeb 		return;
4134*b4c3e9b5SBjoern A. Zeeb 
4135*b4c3e9b5SBjoern A. Zeeb 	wlc->radio_monitor = true;
4136*b4c3e9b5SBjoern A. Zeeb 	brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_RADIO_MON);
4137*b4c3e9b5SBjoern A. Zeeb 	brcms_add_timer(wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, true);
4138*b4c3e9b5SBjoern A. Zeeb }
4139*b4c3e9b5SBjoern A. Zeeb 
brcms_c_radio_monitor_stop(struct brcms_c_info * wlc)4140*b4c3e9b5SBjoern A. Zeeb static bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
4141*b4c3e9b5SBjoern A. Zeeb {
4142*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->radio_monitor)
4143*b4c3e9b5SBjoern A. Zeeb 		return true;
4144*b4c3e9b5SBjoern A. Zeeb 
4145*b4c3e9b5SBjoern A. Zeeb 	wlc->radio_monitor = false;
4146*b4c3e9b5SBjoern A. Zeeb 	brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_RADIO_MON);
4147*b4c3e9b5SBjoern A. Zeeb 	return brcms_del_timer(wlc->radio_timer);
4148*b4c3e9b5SBjoern A. Zeeb }
4149*b4c3e9b5SBjoern A. Zeeb 
4150*b4c3e9b5SBjoern A. Zeeb /* read hwdisable state and propagate to wlc flag */
brcms_c_radio_hwdisable_upd(struct brcms_c_info * wlc)4151*b4c3e9b5SBjoern A. Zeeb static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc)
4152*b4c3e9b5SBjoern A. Zeeb {
4153*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->hw_off)
4154*b4c3e9b5SBjoern A. Zeeb 		return;
4155*b4c3e9b5SBjoern A. Zeeb 
4156*b4c3e9b5SBjoern A. Zeeb 	if (brcms_b_radio_read_hwdisabled(wlc->hw))
4157*b4c3e9b5SBjoern A. Zeeb 		mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
4158*b4c3e9b5SBjoern A. Zeeb 	else
4159*b4c3e9b5SBjoern A. Zeeb 		mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
4160*b4c3e9b5SBjoern A. Zeeb }
4161*b4c3e9b5SBjoern A. Zeeb 
4162*b4c3e9b5SBjoern A. Zeeb /* update hwradio status and return it */
brcms_c_check_radio_disabled(struct brcms_c_info * wlc)4163*b4c3e9b5SBjoern A. Zeeb bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc)
4164*b4c3e9b5SBjoern A. Zeeb {
4165*b4c3e9b5SBjoern A. Zeeb 	brcms_c_radio_hwdisable_upd(wlc);
4166*b4c3e9b5SBjoern A. Zeeb 
4167*b4c3e9b5SBjoern A. Zeeb 	return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ?
4168*b4c3e9b5SBjoern A. Zeeb 			true : false;
4169*b4c3e9b5SBjoern A. Zeeb }
4170*b4c3e9b5SBjoern A. Zeeb 
4171*b4c3e9b5SBjoern A. Zeeb /* periodical query hw radio button while driver is "down" */
brcms_c_radio_timer(void * arg)4172*b4c3e9b5SBjoern A. Zeeb static void brcms_c_radio_timer(void *arg)
4173*b4c3e9b5SBjoern A. Zeeb {
4174*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
4175*b4c3e9b5SBjoern A. Zeeb 
4176*b4c3e9b5SBjoern A. Zeeb 	if (brcms_deviceremoved(wlc)) {
4177*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "wl%d: %s: dead chip\n",
4178*b4c3e9b5SBjoern A. Zeeb 			  wlc->pub->unit, __func__);
4179*b4c3e9b5SBjoern A. Zeeb 		brcms_down(wlc->wl);
4180*b4c3e9b5SBjoern A. Zeeb 		return;
4181*b4c3e9b5SBjoern A. Zeeb 	}
4182*b4c3e9b5SBjoern A. Zeeb 
4183*b4c3e9b5SBjoern A. Zeeb 	brcms_c_radio_hwdisable_upd(wlc);
4184*b4c3e9b5SBjoern A. Zeeb }
4185*b4c3e9b5SBjoern A. Zeeb 
4186*b4c3e9b5SBjoern A. Zeeb /* common low-level watchdog code */
brcms_b_watchdog(struct brcms_c_info * wlc)4187*b4c3e9b5SBjoern A. Zeeb static void brcms_b_watchdog(struct brcms_c_info *wlc)
4188*b4c3e9b5SBjoern A. Zeeb {
4189*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
4190*b4c3e9b5SBjoern A. Zeeb 
4191*b4c3e9b5SBjoern A. Zeeb 	if (!wlc_hw->up)
4192*b4c3e9b5SBjoern A. Zeeb 		return;
4193*b4c3e9b5SBjoern A. Zeeb 
4194*b4c3e9b5SBjoern A. Zeeb 	/* increment second count */
4195*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->now++;
4196*b4c3e9b5SBjoern A. Zeeb 
4197*b4c3e9b5SBjoern A. Zeeb 	/* Check for FIFO error interrupts */
4198*b4c3e9b5SBjoern A. Zeeb 	brcms_b_fifoerrors(wlc_hw);
4199*b4c3e9b5SBjoern A. Zeeb 
4200*b4c3e9b5SBjoern A. Zeeb 	/* make sure RX dma has buffers */
4201*b4c3e9b5SBjoern A. Zeeb 	dma_rxfill(wlc->hw->di[RX_FIFO]);
4202*b4c3e9b5SBjoern A. Zeeb 
4203*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_watchdog(wlc_hw->band->pi);
4204*b4c3e9b5SBjoern A. Zeeb }
4205*b4c3e9b5SBjoern A. Zeeb 
4206*b4c3e9b5SBjoern A. Zeeb /* common watchdog code */
brcms_c_watchdog(struct brcms_c_info * wlc)4207*b4c3e9b5SBjoern A. Zeeb static void brcms_c_watchdog(struct brcms_c_info *wlc)
4208*b4c3e9b5SBjoern A. Zeeb {
4209*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);
4210*b4c3e9b5SBjoern A. Zeeb 
4211*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->pub->up)
4212*b4c3e9b5SBjoern A. Zeeb 		return;
4213*b4c3e9b5SBjoern A. Zeeb 
4214*b4c3e9b5SBjoern A. Zeeb 	if (brcms_deviceremoved(wlc)) {
4215*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "wl%d: %s: dead chip\n",
4216*b4c3e9b5SBjoern A. Zeeb 			  wlc->pub->unit, __func__);
4217*b4c3e9b5SBjoern A. Zeeb 		brcms_down(wlc->wl);
4218*b4c3e9b5SBjoern A. Zeeb 		return;
4219*b4c3e9b5SBjoern A. Zeeb 	}
4220*b4c3e9b5SBjoern A. Zeeb 
4221*b4c3e9b5SBjoern A. Zeeb 	/* increment second count */
4222*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->now++;
4223*b4c3e9b5SBjoern A. Zeeb 
4224*b4c3e9b5SBjoern A. Zeeb 	brcms_c_radio_hwdisable_upd(wlc);
4225*b4c3e9b5SBjoern A. Zeeb 	/* if radio is disable, driver may be down, quit here */
4226*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->radio_disabled)
4227*b4c3e9b5SBjoern A. Zeeb 		return;
4228*b4c3e9b5SBjoern A. Zeeb 
4229*b4c3e9b5SBjoern A. Zeeb 	brcms_b_watchdog(wlc);
4230*b4c3e9b5SBjoern A. Zeeb 
4231*b4c3e9b5SBjoern A. Zeeb 	/*
4232*b4c3e9b5SBjoern A. Zeeb 	 * occasionally sample mac stat counters to
4233*b4c3e9b5SBjoern A. Zeeb 	 * detect 16-bit counter wrap
4234*b4c3e9b5SBjoern A. Zeeb 	 */
4235*b4c3e9b5SBjoern A. Zeeb 	if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0)
4236*b4c3e9b5SBjoern A. Zeeb 		brcms_c_statsupd(wlc);
4237*b4c3e9b5SBjoern A. Zeeb 
4238*b4c3e9b5SBjoern A. Zeeb 	if (BRCMS_ISNPHY(wlc->band) &&
4239*b4c3e9b5SBjoern A. Zeeb 	    ((wlc->pub->now - wlc->tempsense_lasttime) >=
4240*b4c3e9b5SBjoern A. Zeeb 	     BRCMS_TEMPSENSE_PERIOD)) {
4241*b4c3e9b5SBjoern A. Zeeb 		wlc->tempsense_lasttime = wlc->pub->now;
4242*b4c3e9b5SBjoern A. Zeeb 		brcms_c_tempsense_upd(wlc);
4243*b4c3e9b5SBjoern A. Zeeb 	}
4244*b4c3e9b5SBjoern A. Zeeb }
4245*b4c3e9b5SBjoern A. Zeeb 
brcms_c_watchdog_by_timer(void * arg)4246*b4c3e9b5SBjoern A. Zeeb static void brcms_c_watchdog_by_timer(void *arg)
4247*b4c3e9b5SBjoern A. Zeeb {
4248*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
4249*b4c3e9b5SBjoern A. Zeeb 
4250*b4c3e9b5SBjoern A. Zeeb 	brcms_c_watchdog(wlc);
4251*b4c3e9b5SBjoern A. Zeeb }
4252*b4c3e9b5SBjoern A. Zeeb 
brcms_c_timers_init(struct brcms_c_info * wlc,int unit)4253*b4c3e9b5SBjoern A. Zeeb static bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit)
4254*b4c3e9b5SBjoern A. Zeeb {
4255*b4c3e9b5SBjoern A. Zeeb 	wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer,
4256*b4c3e9b5SBjoern A. Zeeb 		wlc, "watchdog");
4257*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->wdtimer) {
4258*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wlc->wiphy, "wl%d:  wl_init_timer for wdtimer "
4259*b4c3e9b5SBjoern A. Zeeb 			  "failed\n", unit);
4260*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4261*b4c3e9b5SBjoern A. Zeeb 	}
4262*b4c3e9b5SBjoern A. Zeeb 
4263*b4c3e9b5SBjoern A. Zeeb 	wlc->radio_timer = brcms_init_timer(wlc->wl, brcms_c_radio_timer,
4264*b4c3e9b5SBjoern A. Zeeb 		wlc, "radio");
4265*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->radio_timer) {
4266*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wlc->wiphy, "wl%d:  wl_init_timer for radio_timer "
4267*b4c3e9b5SBjoern A. Zeeb 			  "failed\n", unit);
4268*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4269*b4c3e9b5SBjoern A. Zeeb 	}
4270*b4c3e9b5SBjoern A. Zeeb 
4271*b4c3e9b5SBjoern A. Zeeb 	return true;
4272*b4c3e9b5SBjoern A. Zeeb 
4273*b4c3e9b5SBjoern A. Zeeb  fail:
4274*b4c3e9b5SBjoern A. Zeeb 	return false;
4275*b4c3e9b5SBjoern A. Zeeb }
4276*b4c3e9b5SBjoern A. Zeeb 
4277*b4c3e9b5SBjoern A. Zeeb /*
4278*b4c3e9b5SBjoern A. Zeeb  * Initialize brcms_c_info default values ...
4279*b4c3e9b5SBjoern A. Zeeb  * may get overrides later in this function
4280*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_info_init(struct brcms_c_info * wlc,int unit)4281*b4c3e9b5SBjoern A. Zeeb static void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
4282*b4c3e9b5SBjoern A. Zeeb {
4283*b4c3e9b5SBjoern A. Zeeb 	int i;
4284*b4c3e9b5SBjoern A. Zeeb 
4285*b4c3e9b5SBjoern A. Zeeb 	/* Save our copy of the chanspec */
4286*b4c3e9b5SBjoern A. Zeeb 	wlc->chanspec = ch20mhz_chspec(1);
4287*b4c3e9b5SBjoern A. Zeeb 
4288*b4c3e9b5SBjoern A. Zeeb 	/* various 802.11g modes */
4289*b4c3e9b5SBjoern A. Zeeb 	wlc->shortslot = false;
4290*b4c3e9b5SBjoern A. Zeeb 	wlc->shortslot_override = BRCMS_SHORTSLOT_AUTO;
4291*b4c3e9b5SBjoern A. Zeeb 
4292*b4c3e9b5SBjoern A. Zeeb 	brcms_c_protection_upd(wlc, BRCMS_PROT_G_OVR, BRCMS_PROTECTION_AUTO);
4293*b4c3e9b5SBjoern A. Zeeb 	brcms_c_protection_upd(wlc, BRCMS_PROT_G_SPEC, false);
4294*b4c3e9b5SBjoern A. Zeeb 
4295*b4c3e9b5SBjoern A. Zeeb 	brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG_OVR,
4296*b4c3e9b5SBjoern A. Zeeb 			       BRCMS_PROTECTION_AUTO);
4297*b4c3e9b5SBjoern A. Zeeb 	brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG, BRCMS_N_PROTECTION_OFF);
4298*b4c3e9b5SBjoern A. Zeeb 	brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF_OVR,
4299*b4c3e9b5SBjoern A. Zeeb 			       BRCMS_PROTECTION_AUTO);
4300*b4c3e9b5SBjoern A. Zeeb 	brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF, false);
4301*b4c3e9b5SBjoern A. Zeeb 	brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, AUTO);
4302*b4c3e9b5SBjoern A. Zeeb 
4303*b4c3e9b5SBjoern A. Zeeb 	brcms_c_protection_upd(wlc, BRCMS_PROT_OVERLAP,
4304*b4c3e9b5SBjoern A. Zeeb 			       BRCMS_PROTECTION_CTL_OVERLAP);
4305*b4c3e9b5SBjoern A. Zeeb 
4306*b4c3e9b5SBjoern A. Zeeb 	/* 802.11g draft 4.0 NonERP elt advertisement */
4307*b4c3e9b5SBjoern A. Zeeb 	wlc->include_legacy_erp = true;
4308*b4c3e9b5SBjoern A. Zeeb 
4309*b4c3e9b5SBjoern A. Zeeb 	wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF;
4310*b4c3e9b5SBjoern A. Zeeb 	wlc->stf->txant = ANT_TX_DEF;
4311*b4c3e9b5SBjoern A. Zeeb 
4312*b4c3e9b5SBjoern A. Zeeb 	wlc->prb_resp_timeout = BRCMS_PRB_RESP_TIMEOUT;
4313*b4c3e9b5SBjoern A. Zeeb 
4314*b4c3e9b5SBjoern A. Zeeb 	wlc->usr_fragthresh = DOT11_DEFAULT_FRAG_LEN;
4315*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < NFIFO; i++)
4316*b4c3e9b5SBjoern A. Zeeb 		wlc->fragthresh[i] = DOT11_DEFAULT_FRAG_LEN;
4317*b4c3e9b5SBjoern A. Zeeb 	wlc->RTSThresh = DOT11_DEFAULT_RTS_LEN;
4318*b4c3e9b5SBjoern A. Zeeb 
4319*b4c3e9b5SBjoern A. Zeeb 	/* default rate fallback retry limits */
4320*b4c3e9b5SBjoern A. Zeeb 	wlc->SFBL = RETRY_SHORT_FB;
4321*b4c3e9b5SBjoern A. Zeeb 	wlc->LFBL = RETRY_LONG_FB;
4322*b4c3e9b5SBjoern A. Zeeb 
4323*b4c3e9b5SBjoern A. Zeeb 	/* default mac retry limits */
4324*b4c3e9b5SBjoern A. Zeeb 	wlc->SRL = RETRY_SHORT_DEF;
4325*b4c3e9b5SBjoern A. Zeeb 	wlc->LRL = RETRY_LONG_DEF;
4326*b4c3e9b5SBjoern A. Zeeb 
4327*b4c3e9b5SBjoern A. Zeeb 	/* WME QoS mode is Auto by default */
4328*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->_ampdu = AMPDU_AGG_HOST;
4329*b4c3e9b5SBjoern A. Zeeb }
4330*b4c3e9b5SBjoern A. Zeeb 
brcms_c_attach_module(struct brcms_c_info * wlc)4331*b4c3e9b5SBjoern A. Zeeb static uint brcms_c_attach_module(struct brcms_c_info *wlc)
4332*b4c3e9b5SBjoern A. Zeeb {
4333*b4c3e9b5SBjoern A. Zeeb 	uint err = 0;
4334*b4c3e9b5SBjoern A. Zeeb 	uint unit;
4335*b4c3e9b5SBjoern A. Zeeb 	unit = wlc->pub->unit;
4336*b4c3e9b5SBjoern A. Zeeb 
4337*b4c3e9b5SBjoern A. Zeeb 	wlc->asi = brcms_c_antsel_attach(wlc);
4338*b4c3e9b5SBjoern A. Zeeb 	if (wlc->asi == NULL) {
4339*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wlc->wiphy, "wl%d: attach: antsel_attach "
4340*b4c3e9b5SBjoern A. Zeeb 			  "failed\n", unit);
4341*b4c3e9b5SBjoern A. Zeeb 		err = 44;
4342*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4343*b4c3e9b5SBjoern A. Zeeb 	}
4344*b4c3e9b5SBjoern A. Zeeb 
4345*b4c3e9b5SBjoern A. Zeeb 	wlc->ampdu = brcms_c_ampdu_attach(wlc);
4346*b4c3e9b5SBjoern A. Zeeb 	if (wlc->ampdu == NULL) {
4347*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wlc->wiphy, "wl%d: attach: ampdu_attach "
4348*b4c3e9b5SBjoern A. Zeeb 			  "failed\n", unit);
4349*b4c3e9b5SBjoern A. Zeeb 		err = 50;
4350*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4351*b4c3e9b5SBjoern A. Zeeb 	}
4352*b4c3e9b5SBjoern A. Zeeb 
4353*b4c3e9b5SBjoern A. Zeeb 	if ((brcms_c_stf_attach(wlc) != 0)) {
4354*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wlc->wiphy, "wl%d: attach: stf_attach "
4355*b4c3e9b5SBjoern A. Zeeb 			  "failed\n", unit);
4356*b4c3e9b5SBjoern A. Zeeb 		err = 68;
4357*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4358*b4c3e9b5SBjoern A. Zeeb 	}
4359*b4c3e9b5SBjoern A. Zeeb  fail:
4360*b4c3e9b5SBjoern A. Zeeb 	return err;
4361*b4c3e9b5SBjoern A. Zeeb }
4362*b4c3e9b5SBjoern A. Zeeb 
brcms_c_pub(struct brcms_c_info * wlc)4363*b4c3e9b5SBjoern A. Zeeb struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc)
4364*b4c3e9b5SBjoern A. Zeeb {
4365*b4c3e9b5SBjoern A. Zeeb 	return wlc->pub;
4366*b4c3e9b5SBjoern A. Zeeb }
4367*b4c3e9b5SBjoern A. Zeeb 
4368*b4c3e9b5SBjoern A. Zeeb /* low level attach
4369*b4c3e9b5SBjoern A. Zeeb  *    run backplane attach, init nvram
4370*b4c3e9b5SBjoern A. Zeeb  *    run phy attach
4371*b4c3e9b5SBjoern A. Zeeb  *    initialize software state for each core and band
4372*b4c3e9b5SBjoern A. Zeeb  *    put the whole chip in reset(driver down state), no clock
4373*b4c3e9b5SBjoern A. Zeeb  */
brcms_b_attach(struct brcms_c_info * wlc,struct bcma_device * core,uint unit,bool piomode)4374*b4c3e9b5SBjoern A. Zeeb static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
4375*b4c3e9b5SBjoern A. Zeeb 			  uint unit, bool piomode)
4376*b4c3e9b5SBjoern A. Zeeb {
4377*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw;
4378*b4c3e9b5SBjoern A. Zeeb 	uint err = 0;
4379*b4c3e9b5SBjoern A. Zeeb 	uint j;
4380*b4c3e9b5SBjoern A. Zeeb 	bool wme = false;
4381*b4c3e9b5SBjoern A. Zeeb 	struct shared_phy_params sha_params;
4382*b4c3e9b5SBjoern A. Zeeb 	struct wiphy *wiphy = wlc->wiphy;
4383*b4c3e9b5SBjoern A. Zeeb 	struct pci_dev *pcidev = core->bus->host_pci;
4384*b4c3e9b5SBjoern A. Zeeb 	struct ssb_sprom *sprom = &core->bus->sprom;
4385*b4c3e9b5SBjoern A. Zeeb 
4386*b4c3e9b5SBjoern A. Zeeb 	if (core->bus->hosttype == BCMA_HOSTTYPE_PCI)
4387*b4c3e9b5SBjoern A. Zeeb 		brcms_dbg_info(core, "wl%d: vendor 0x%x device 0x%x\n", unit,
4388*b4c3e9b5SBjoern A. Zeeb 			       pcidev->vendor,
4389*b4c3e9b5SBjoern A. Zeeb 			       pcidev->device);
4390*b4c3e9b5SBjoern A. Zeeb 	else
4391*b4c3e9b5SBjoern A. Zeeb 		brcms_dbg_info(core, "wl%d: vendor 0x%x device 0x%x\n", unit,
4392*b4c3e9b5SBjoern A. Zeeb 			       core->bus->boardinfo.vendor,
4393*b4c3e9b5SBjoern A. Zeeb 			       core->bus->boardinfo.type);
4394*b4c3e9b5SBjoern A. Zeeb 
4395*b4c3e9b5SBjoern A. Zeeb 	wme = true;
4396*b4c3e9b5SBjoern A. Zeeb 
4397*b4c3e9b5SBjoern A. Zeeb 	wlc_hw = wlc->hw;
4398*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->wlc = wlc;
4399*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->unit = unit;
4400*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->band = wlc_hw->bandstate[0];
4401*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->_piomode = piomode;
4402*b4c3e9b5SBjoern A. Zeeb 
4403*b4c3e9b5SBjoern A. Zeeb 	/* populate struct brcms_hardware with default values  */
4404*b4c3e9b5SBjoern A. Zeeb 	brcms_b_info_init(wlc_hw);
4405*b4c3e9b5SBjoern A. Zeeb 
4406*b4c3e9b5SBjoern A. Zeeb 	/*
4407*b4c3e9b5SBjoern A. Zeeb 	 * Do the hardware portion of the attach. Also initialize software
4408*b4c3e9b5SBjoern A. Zeeb 	 * state that depends on the particular hardware we are running.
4409*b4c3e9b5SBjoern A. Zeeb 	 */
4410*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->sih = ai_attach(core->bus);
4411*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->sih == NULL) {
4412*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n",
4413*b4c3e9b5SBjoern A. Zeeb 			  unit);
4414*b4c3e9b5SBjoern A. Zeeb 		err = 11;
4415*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4416*b4c3e9b5SBjoern A. Zeeb 	}
4417*b4c3e9b5SBjoern A. Zeeb 
4418*b4c3e9b5SBjoern A. Zeeb 	/* verify again the device is supported */
4419*b4c3e9b5SBjoern A. Zeeb 	if (!brcms_c_chipmatch(core)) {
4420*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported device\n",
4421*b4c3e9b5SBjoern A. Zeeb 			 unit);
4422*b4c3e9b5SBjoern A. Zeeb 		err = 12;
4423*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4424*b4c3e9b5SBjoern A. Zeeb 	}
4425*b4c3e9b5SBjoern A. Zeeb 
4426*b4c3e9b5SBjoern A. Zeeb 	if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
4427*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->vendorid = pcidev->vendor;
4428*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->deviceid = pcidev->device;
4429*b4c3e9b5SBjoern A. Zeeb 	} else {
4430*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->vendorid = core->bus->boardinfo.vendor;
4431*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->deviceid = core->bus->boardinfo.type;
4432*b4c3e9b5SBjoern A. Zeeb 	}
4433*b4c3e9b5SBjoern A. Zeeb 
4434*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->d11core = core;
4435*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->corerev = core->id.rev;
4436*b4c3e9b5SBjoern A. Zeeb 
4437*b4c3e9b5SBjoern A. Zeeb 	/* validate chip, chiprev and corerev */
4438*b4c3e9b5SBjoern A. Zeeb 	if (!brcms_c_isgoodchip(wlc_hw)) {
4439*b4c3e9b5SBjoern A. Zeeb 		err = 13;
4440*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4441*b4c3e9b5SBjoern A. Zeeb 	}
4442*b4c3e9b5SBjoern A. Zeeb 
4443*b4c3e9b5SBjoern A. Zeeb 	/* initialize power control registers */
4444*b4c3e9b5SBjoern A. Zeeb 	ai_clkctl_init(wlc_hw->sih);
4445*b4c3e9b5SBjoern A. Zeeb 
4446*b4c3e9b5SBjoern A. Zeeb 	/* request fastclock and force fastclock for the rest of attach
4447*b4c3e9b5SBjoern A. Zeeb 	 * bring the d11 core out of reset.
4448*b4c3e9b5SBjoern A. Zeeb 	 *   For PMU chips, the first wlc_clkctl_clk is no-op since core-clk
4449*b4c3e9b5SBjoern A. Zeeb 	 *   is still false; But it will be called again inside wlc_corereset,
4450*b4c3e9b5SBjoern A. Zeeb 	 *   after d11 is out of reset.
4451*b4c3e9b5SBjoern A. Zeeb 	 */
4452*b4c3e9b5SBjoern A. Zeeb 	brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
4453*b4c3e9b5SBjoern A. Zeeb 	brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
4454*b4c3e9b5SBjoern A. Zeeb 
4455*b4c3e9b5SBjoern A. Zeeb 	if (!brcms_b_validate_chip_access(wlc_hw)) {
4456*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wiphy, "wl%d: brcms_b_attach: validate_chip_access "
4457*b4c3e9b5SBjoern A. Zeeb 			"failed\n", unit);
4458*b4c3e9b5SBjoern A. Zeeb 		err = 14;
4459*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4460*b4c3e9b5SBjoern A. Zeeb 	}
4461*b4c3e9b5SBjoern A. Zeeb 
4462*b4c3e9b5SBjoern A. Zeeb 	/* get the board rev, used just below */
4463*b4c3e9b5SBjoern A. Zeeb 	j = sprom->board_rev;
4464*b4c3e9b5SBjoern A. Zeeb 	/* promote srom boardrev of 0xFF to 1 */
4465*b4c3e9b5SBjoern A. Zeeb 	if (j == BOARDREV_PROMOTABLE)
4466*b4c3e9b5SBjoern A. Zeeb 		j = BOARDREV_PROMOTED;
4467*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->boardrev = (u16) j;
4468*b4c3e9b5SBjoern A. Zeeb 	if (!brcms_c_validboardtype(wlc_hw)) {
4469*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom "
4470*b4c3e9b5SBjoern A. Zeeb 			  "board type (0x%x)" " or revision level (0x%x)\n",
4471*b4c3e9b5SBjoern A. Zeeb 			  unit, ai_get_boardtype(wlc_hw->sih),
4472*b4c3e9b5SBjoern A. Zeeb 			  wlc_hw->boardrev);
4473*b4c3e9b5SBjoern A. Zeeb 		err = 15;
4474*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4475*b4c3e9b5SBjoern A. Zeeb 	}
4476*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->sromrev = sprom->revision;
4477*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->boardflags = sprom->boardflags_lo + (sprom->boardflags_hi << 16);
4478*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->boardflags2 = sprom->boardflags2_lo + (sprom->boardflags2_hi << 16);
4479*b4c3e9b5SBjoern A. Zeeb 
4480*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->boardflags & BFL_NOPLLDOWN)
4481*b4c3e9b5SBjoern A. Zeeb 		brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED);
4482*b4c3e9b5SBjoern A. Zeeb 
4483*b4c3e9b5SBjoern A. Zeeb 	/* check device id(srom, nvram etc.) to set bands */
4484*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->deviceid == BCM43224_D11N_ID ||
4485*b4c3e9b5SBjoern A. Zeeb 	    wlc_hw->deviceid == BCM43224_D11N_ID_VEN1 ||
4486*b4c3e9b5SBjoern A. Zeeb 	    wlc_hw->deviceid == BCM43224_CHIP_ID)
4487*b4c3e9b5SBjoern A. Zeeb 		/* Dualband boards */
4488*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->_nbands = 2;
4489*b4c3e9b5SBjoern A. Zeeb 	else
4490*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->_nbands = 1;
4491*b4c3e9b5SBjoern A. Zeeb 
4492*b4c3e9b5SBjoern A. Zeeb 	if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43225))
4493*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->_nbands = 1;
4494*b4c3e9b5SBjoern A. Zeeb 
4495*b4c3e9b5SBjoern A. Zeeb 	/* BMAC_NOTE: remove init of pub values when brcms_c_attach()
4496*b4c3e9b5SBjoern A. Zeeb 	 * unconditionally does the init of these values
4497*b4c3e9b5SBjoern A. Zeeb 	 */
4498*b4c3e9b5SBjoern A. Zeeb 	wlc->vendorid = wlc_hw->vendorid;
4499*b4c3e9b5SBjoern A. Zeeb 	wlc->deviceid = wlc_hw->deviceid;
4500*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->sih = wlc_hw->sih;
4501*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->corerev = wlc_hw->corerev;
4502*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->sromrev = wlc_hw->sromrev;
4503*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->boardrev = wlc_hw->boardrev;
4504*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->boardflags = wlc_hw->boardflags;
4505*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->boardflags2 = wlc_hw->boardflags2;
4506*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->_nbands = wlc_hw->_nbands;
4507*b4c3e9b5SBjoern A. Zeeb 
4508*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc);
4509*b4c3e9b5SBjoern A. Zeeb 
4510*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->physhim == NULL) {
4511*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_shim_attach "
4512*b4c3e9b5SBjoern A. Zeeb 			"failed\n", unit);
4513*b4c3e9b5SBjoern A. Zeeb 		err = 25;
4514*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4515*b4c3e9b5SBjoern A. Zeeb 	}
4516*b4c3e9b5SBjoern A. Zeeb 
4517*b4c3e9b5SBjoern A. Zeeb 	/* pass all the parameters to wlc_phy_shared_attach in one struct */
4518*b4c3e9b5SBjoern A. Zeeb 	sha_params.sih = wlc_hw->sih;
4519*b4c3e9b5SBjoern A. Zeeb 	sha_params.physhim = wlc_hw->physhim;
4520*b4c3e9b5SBjoern A. Zeeb 	sha_params.unit = unit;
4521*b4c3e9b5SBjoern A. Zeeb 	sha_params.corerev = wlc_hw->corerev;
4522*b4c3e9b5SBjoern A. Zeeb 	sha_params.vid = wlc_hw->vendorid;
4523*b4c3e9b5SBjoern A. Zeeb 	sha_params.did = wlc_hw->deviceid;
4524*b4c3e9b5SBjoern A. Zeeb 	sha_params.chip = ai_get_chip_id(wlc_hw->sih);
4525*b4c3e9b5SBjoern A. Zeeb 	sha_params.chiprev = ai_get_chiprev(wlc_hw->sih);
4526*b4c3e9b5SBjoern A. Zeeb 	sha_params.chippkg = ai_get_chippkg(wlc_hw->sih);
4527*b4c3e9b5SBjoern A. Zeeb 	sha_params.sromrev = wlc_hw->sromrev;
4528*b4c3e9b5SBjoern A. Zeeb 	sha_params.boardtype = ai_get_boardtype(wlc_hw->sih);
4529*b4c3e9b5SBjoern A. Zeeb 	sha_params.boardrev = wlc_hw->boardrev;
4530*b4c3e9b5SBjoern A. Zeeb 	sha_params.boardflags = wlc_hw->boardflags;
4531*b4c3e9b5SBjoern A. Zeeb 	sha_params.boardflags2 = wlc_hw->boardflags2;
4532*b4c3e9b5SBjoern A. Zeeb 
4533*b4c3e9b5SBjoern A. Zeeb 	/* alloc and save pointer to shared phy state area */
4534*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params);
4535*b4c3e9b5SBjoern A. Zeeb 	if (!wlc_hw->phy_sh) {
4536*b4c3e9b5SBjoern A. Zeeb 		err = 16;
4537*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4538*b4c3e9b5SBjoern A. Zeeb 	}
4539*b4c3e9b5SBjoern A. Zeeb 
4540*b4c3e9b5SBjoern A. Zeeb 	/* initialize software state for each core and band */
4541*b4c3e9b5SBjoern A. Zeeb 	for (j = 0; j < wlc_hw->_nbands; j++) {
4542*b4c3e9b5SBjoern A. Zeeb 		/*
4543*b4c3e9b5SBjoern A. Zeeb 		 * band0 is always 2.4Ghz
4544*b4c3e9b5SBjoern A. Zeeb 		 * band1, if present, is 5Ghz
4545*b4c3e9b5SBjoern A. Zeeb 		 */
4546*b4c3e9b5SBjoern A. Zeeb 
4547*b4c3e9b5SBjoern A. Zeeb 		brcms_c_setxband(wlc_hw, j);
4548*b4c3e9b5SBjoern A. Zeeb 
4549*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->band->bandunit = j;
4550*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
4551*b4c3e9b5SBjoern A. Zeeb 		wlc->band->bandunit = j;
4552*b4c3e9b5SBjoern A. Zeeb 		wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
4553*b4c3e9b5SBjoern A. Zeeb 		wlc->core->coreidx = core->core_index;
4554*b4c3e9b5SBjoern A. Zeeb 
4555*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->machwcap = bcma_read32(core, D11REGOFFS(machwcap));
4556*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->machwcap_backup = wlc_hw->machwcap;
4557*b4c3e9b5SBjoern A. Zeeb 
4558*b4c3e9b5SBjoern A. Zeeb 		/* init tx fifo size */
4559*b4c3e9b5SBjoern A. Zeeb 		WARN_ON(wlc_hw->corerev < XMTFIFOTBL_STARTREV ||
4560*b4c3e9b5SBjoern A. Zeeb 			(wlc_hw->corerev - XMTFIFOTBL_STARTREV) >
4561*b4c3e9b5SBjoern A. Zeeb 				ARRAY_SIZE(xmtfifo_sz));
4562*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->xmtfifo_sz =
4563*b4c3e9b5SBjoern A. Zeeb 		    xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)];
4564*b4c3e9b5SBjoern A. Zeeb 		WARN_ON(!wlc_hw->xmtfifo_sz[0]);
4565*b4c3e9b5SBjoern A. Zeeb 
4566*b4c3e9b5SBjoern A. Zeeb 		/* Get a phy for this band */
4567*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->band->pi =
4568*b4c3e9b5SBjoern A. Zeeb 			wlc_phy_attach(wlc_hw->phy_sh, core,
4569*b4c3e9b5SBjoern A. Zeeb 				       wlc_hw->band->bandtype,
4570*b4c3e9b5SBjoern A. Zeeb 				       wlc->wiphy);
4571*b4c3e9b5SBjoern A. Zeeb 		if (wlc_hw->band->pi == NULL) {
4572*b4c3e9b5SBjoern A. Zeeb 			wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_"
4573*b4c3e9b5SBjoern A. Zeeb 				  "attach failed\n", unit);
4574*b4c3e9b5SBjoern A. Zeeb 			err = 17;
4575*b4c3e9b5SBjoern A. Zeeb 			goto fail;
4576*b4c3e9b5SBjoern A. Zeeb 		}
4577*b4c3e9b5SBjoern A. Zeeb 
4578*b4c3e9b5SBjoern A. Zeeb 		wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap);
4579*b4c3e9b5SBjoern A. Zeeb 
4580*b4c3e9b5SBjoern A. Zeeb 		wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype,
4581*b4c3e9b5SBjoern A. Zeeb 				       &wlc_hw->band->phyrev,
4582*b4c3e9b5SBjoern A. Zeeb 				       &wlc_hw->band->radioid,
4583*b4c3e9b5SBjoern A. Zeeb 				       &wlc_hw->band->radiorev);
4584*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->band->abgphy_encore =
4585*b4c3e9b5SBjoern A. Zeeb 		    wlc_phy_get_encore(wlc_hw->band->pi);
4586*b4c3e9b5SBjoern A. Zeeb 		wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi);
4587*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->band->core_flags =
4588*b4c3e9b5SBjoern A. Zeeb 		    wlc_phy_get_coreflags(wlc_hw->band->pi);
4589*b4c3e9b5SBjoern A. Zeeb 
4590*b4c3e9b5SBjoern A. Zeeb 		/* verify good phy_type & supported phy revision */
4591*b4c3e9b5SBjoern A. Zeeb 		if (BRCMS_ISNPHY(wlc_hw->band)) {
4592*b4c3e9b5SBjoern A. Zeeb 			if (NCONF_HAS(wlc_hw->band->phyrev))
4593*b4c3e9b5SBjoern A. Zeeb 				goto good_phy;
4594*b4c3e9b5SBjoern A. Zeeb 			else
4595*b4c3e9b5SBjoern A. Zeeb 				goto bad_phy;
4596*b4c3e9b5SBjoern A. Zeeb 		} else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
4597*b4c3e9b5SBjoern A. Zeeb 			if (LCNCONF_HAS(wlc_hw->band->phyrev))
4598*b4c3e9b5SBjoern A. Zeeb 				goto good_phy;
4599*b4c3e9b5SBjoern A. Zeeb 			else
4600*b4c3e9b5SBjoern A. Zeeb 				goto bad_phy;
4601*b4c3e9b5SBjoern A. Zeeb 		} else {
4602*b4c3e9b5SBjoern A. Zeeb  bad_phy:
4603*b4c3e9b5SBjoern A. Zeeb 			wiphy_err(wiphy, "wl%d: brcms_b_attach: unsupported "
4604*b4c3e9b5SBjoern A. Zeeb 				  "phy type/rev (%d/%d)\n", unit,
4605*b4c3e9b5SBjoern A. Zeeb 				  wlc_hw->band->phytype, wlc_hw->band->phyrev);
4606*b4c3e9b5SBjoern A. Zeeb 			err = 18;
4607*b4c3e9b5SBjoern A. Zeeb 			goto fail;
4608*b4c3e9b5SBjoern A. Zeeb 		}
4609*b4c3e9b5SBjoern A. Zeeb 
4610*b4c3e9b5SBjoern A. Zeeb  good_phy:
4611*b4c3e9b5SBjoern A. Zeeb 		/*
4612*b4c3e9b5SBjoern A. Zeeb 		 * BMAC_NOTE: wlc->band->pi should not be set below and should
4613*b4c3e9b5SBjoern A. Zeeb 		 * be done in the high level attach. However we can not make
4614*b4c3e9b5SBjoern A. Zeeb 		 * that change until all low level access is changed to
4615*b4c3e9b5SBjoern A. Zeeb 		 * wlc_hw->band->pi. Instead do the wlc->band->pi init below,
4616*b4c3e9b5SBjoern A. Zeeb 		 * keeping wlc_hw->band->pi as well for incremental update of
4617*b4c3e9b5SBjoern A. Zeeb 		 * low level fns, and cut over low only init when all fns
4618*b4c3e9b5SBjoern A. Zeeb 		 * updated.
4619*b4c3e9b5SBjoern A. Zeeb 		 */
4620*b4c3e9b5SBjoern A. Zeeb 		wlc->band->pi = wlc_hw->band->pi;
4621*b4c3e9b5SBjoern A. Zeeb 		wlc->band->phytype = wlc_hw->band->phytype;
4622*b4c3e9b5SBjoern A. Zeeb 		wlc->band->phyrev = wlc_hw->band->phyrev;
4623*b4c3e9b5SBjoern A. Zeeb 		wlc->band->radioid = wlc_hw->band->radioid;
4624*b4c3e9b5SBjoern A. Zeeb 		wlc->band->radiorev = wlc_hw->band->radiorev;
4625*b4c3e9b5SBjoern A. Zeeb 		brcms_dbg_info(core, "wl%d: phy %u/%u radio %x/%u\n", unit,
4626*b4c3e9b5SBjoern A. Zeeb 			       wlc->band->phytype, wlc->band->phyrev,
4627*b4c3e9b5SBjoern A. Zeeb 			       wlc->band->radioid, wlc->band->radiorev);
4628*b4c3e9b5SBjoern A. Zeeb 		/* default contention windows size limits */
4629*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->band->CWmin = APHY_CWMIN;
4630*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->band->CWmax = PHY_CWMAX;
4631*b4c3e9b5SBjoern A. Zeeb 
4632*b4c3e9b5SBjoern A. Zeeb 		if (!brcms_b_attach_dmapio(wlc, j, wme)) {
4633*b4c3e9b5SBjoern A. Zeeb 			err = 19;
4634*b4c3e9b5SBjoern A. Zeeb 			goto fail;
4635*b4c3e9b5SBjoern A. Zeeb 		}
4636*b4c3e9b5SBjoern A. Zeeb 	}
4637*b4c3e9b5SBjoern A. Zeeb 
4638*b4c3e9b5SBjoern A. Zeeb 	/* disable core to match driver "down" state */
4639*b4c3e9b5SBjoern A. Zeeb 	brcms_c_coredisable(wlc_hw);
4640*b4c3e9b5SBjoern A. Zeeb 
4641*b4c3e9b5SBjoern A. Zeeb 	/* Match driver "down" state */
4642*b4c3e9b5SBjoern A. Zeeb 	bcma_host_pci_down(wlc_hw->d11core->bus);
4643*b4c3e9b5SBjoern A. Zeeb 
4644*b4c3e9b5SBjoern A. Zeeb 	/* turn off pll and xtal to match driver "down" state */
4645*b4c3e9b5SBjoern A. Zeeb 	brcms_b_xtal(wlc_hw, OFF);
4646*b4c3e9b5SBjoern A. Zeeb 
4647*b4c3e9b5SBjoern A. Zeeb 	/* *******************************************************************
4648*b4c3e9b5SBjoern A. Zeeb 	 * The hardware is in the DOWN state at this point. D11 core
4649*b4c3e9b5SBjoern A. Zeeb 	 * or cores are in reset with clocks off, and the board PLLs
4650*b4c3e9b5SBjoern A. Zeeb 	 * are off if possible.
4651*b4c3e9b5SBjoern A. Zeeb 	 *
4652*b4c3e9b5SBjoern A. Zeeb 	 * Beyond this point, wlc->sbclk == false and chip registers
4653*b4c3e9b5SBjoern A. Zeeb 	 * should not be touched.
4654*b4c3e9b5SBjoern A. Zeeb 	 *********************************************************************
4655*b4c3e9b5SBjoern A. Zeeb 	 */
4656*b4c3e9b5SBjoern A. Zeeb 
4657*b4c3e9b5SBjoern A. Zeeb 	/* init etheraddr state variables */
4658*b4c3e9b5SBjoern A. Zeeb 	brcms_c_get_macaddr(wlc_hw, wlc_hw->etheraddr);
4659*b4c3e9b5SBjoern A. Zeeb 
4660*b4c3e9b5SBjoern A. Zeeb 	if (is_broadcast_ether_addr(wlc_hw->etheraddr) ||
4661*b4c3e9b5SBjoern A. Zeeb 	    is_zero_ether_addr(wlc_hw->etheraddr)) {
4662*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr\n",
4663*b4c3e9b5SBjoern A. Zeeb 			  unit);
4664*b4c3e9b5SBjoern A. Zeeb 		err = 22;
4665*b4c3e9b5SBjoern A. Zeeb 		goto fail;
4666*b4c3e9b5SBjoern A. Zeeb 	}
4667*b4c3e9b5SBjoern A. Zeeb 
4668*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc_hw->d11core, "deviceid 0x%x nbands %d board 0x%x\n",
4669*b4c3e9b5SBjoern A. Zeeb 		       wlc_hw->deviceid, wlc_hw->_nbands,
4670*b4c3e9b5SBjoern A. Zeeb 		       ai_get_boardtype(wlc_hw->sih));
4671*b4c3e9b5SBjoern A. Zeeb 
4672*b4c3e9b5SBjoern A. Zeeb 	return err;
4673*b4c3e9b5SBjoern A. Zeeb 
4674*b4c3e9b5SBjoern A. Zeeb  fail:
4675*b4c3e9b5SBjoern A. Zeeb 	wiphy_err(wiphy, "wl%d: brcms_b_attach: failed with err %d\n", unit,
4676*b4c3e9b5SBjoern A. Zeeb 		  err);
4677*b4c3e9b5SBjoern A. Zeeb 	return err;
4678*b4c3e9b5SBjoern A. Zeeb }
4679*b4c3e9b5SBjoern A. Zeeb 
brcms_c_attach_stf_ant_init(struct brcms_c_info * wlc)4680*b4c3e9b5SBjoern A. Zeeb static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
4681*b4c3e9b5SBjoern A. Zeeb {
4682*b4c3e9b5SBjoern A. Zeeb 	int aa;
4683*b4c3e9b5SBjoern A. Zeeb 	uint unit;
4684*b4c3e9b5SBjoern A. Zeeb 	int bandtype;
4685*b4c3e9b5SBjoern A. Zeeb 	struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
4686*b4c3e9b5SBjoern A. Zeeb 
4687*b4c3e9b5SBjoern A. Zeeb 	unit = wlc->pub->unit;
4688*b4c3e9b5SBjoern A. Zeeb 	bandtype = wlc->band->bandtype;
4689*b4c3e9b5SBjoern A. Zeeb 
4690*b4c3e9b5SBjoern A. Zeeb 	/* get antennas available */
4691*b4c3e9b5SBjoern A. Zeeb 	if (bandtype == BRCM_BAND_5G)
4692*b4c3e9b5SBjoern A. Zeeb 		aa = sprom->ant_available_a;
4693*b4c3e9b5SBjoern A. Zeeb 	else
4694*b4c3e9b5SBjoern A. Zeeb 		aa = sprom->ant_available_bg;
4695*b4c3e9b5SBjoern A. Zeeb 
4696*b4c3e9b5SBjoern A. Zeeb 	if ((aa < 1) || (aa > 15)) {
4697*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
4698*b4c3e9b5SBjoern A. Zeeb 			  " srom (0x%x), using 3\n", unit, __func__, aa);
4699*b4c3e9b5SBjoern A. Zeeb 		aa = 3;
4700*b4c3e9b5SBjoern A. Zeeb 	}
4701*b4c3e9b5SBjoern A. Zeeb 
4702*b4c3e9b5SBjoern A. Zeeb 	/* reset the defaults if we have a single antenna */
4703*b4c3e9b5SBjoern A. Zeeb 	if (aa == 1) {
4704*b4c3e9b5SBjoern A. Zeeb 		wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_0;
4705*b4c3e9b5SBjoern A. Zeeb 		wlc->stf->txant = ANT_TX_FORCE_0;
4706*b4c3e9b5SBjoern A. Zeeb 	} else if (aa == 2) {
4707*b4c3e9b5SBjoern A. Zeeb 		wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_1;
4708*b4c3e9b5SBjoern A. Zeeb 		wlc->stf->txant = ANT_TX_FORCE_1;
4709*b4c3e9b5SBjoern A. Zeeb 	} else {
4710*b4c3e9b5SBjoern A. Zeeb 	}
4711*b4c3e9b5SBjoern A. Zeeb 
4712*b4c3e9b5SBjoern A. Zeeb 	/* Compute Antenna Gain */
4713*b4c3e9b5SBjoern A. Zeeb 	if (bandtype == BRCM_BAND_5G)
4714*b4c3e9b5SBjoern A. Zeeb 		wlc->band->antgain = sprom->antenna_gain.a1;
4715*b4c3e9b5SBjoern A. Zeeb 	else
4716*b4c3e9b5SBjoern A. Zeeb 		wlc->band->antgain = sprom->antenna_gain.a0;
4717*b4c3e9b5SBjoern A. Zeeb 
4718*b4c3e9b5SBjoern A. Zeeb 	return true;
4719*b4c3e9b5SBjoern A. Zeeb }
4720*b4c3e9b5SBjoern A. Zeeb 
brcms_c_bss_default_init(struct brcms_c_info * wlc)4721*b4c3e9b5SBjoern A. Zeeb static void brcms_c_bss_default_init(struct brcms_c_info *wlc)
4722*b4c3e9b5SBjoern A. Zeeb {
4723*b4c3e9b5SBjoern A. Zeeb 	u16 chanspec;
4724*b4c3e9b5SBjoern A. Zeeb 	struct brcms_band *band;
4725*b4c3e9b5SBjoern A. Zeeb 	struct brcms_bss_info *bi = wlc->default_bss;
4726*b4c3e9b5SBjoern A. Zeeb 
4727*b4c3e9b5SBjoern A. Zeeb 	/* init default and target BSS with some sane initial values */
4728*b4c3e9b5SBjoern A. Zeeb 	memset(bi, 0, sizeof(*bi));
4729*b4c3e9b5SBjoern A. Zeeb 	bi->beacon_period = BEACON_INTERVAL_DEFAULT;
4730*b4c3e9b5SBjoern A. Zeeb 
4731*b4c3e9b5SBjoern A. Zeeb 	/* fill the default channel as the first valid channel
4732*b4c3e9b5SBjoern A. Zeeb 	 * starting from the 2G channels
4733*b4c3e9b5SBjoern A. Zeeb 	 */
4734*b4c3e9b5SBjoern A. Zeeb 	chanspec = ch20mhz_chspec(1);
4735*b4c3e9b5SBjoern A. Zeeb 	wlc->home_chanspec = bi->chanspec = chanspec;
4736*b4c3e9b5SBjoern A. Zeeb 
4737*b4c3e9b5SBjoern A. Zeeb 	/* find the band of our default channel */
4738*b4c3e9b5SBjoern A. Zeeb 	band = wlc->band;
4739*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->_nbands > 1 &&
4740*b4c3e9b5SBjoern A. Zeeb 	    band->bandunit != chspec_bandunit(chanspec))
4741*b4c3e9b5SBjoern A. Zeeb 		band = wlc->bandstate[OTHERBANDUNIT(wlc)];
4742*b4c3e9b5SBjoern A. Zeeb 
4743*b4c3e9b5SBjoern A. Zeeb 	/* init bss rates to the band specific default rate set */
4744*b4c3e9b5SBjoern A. Zeeb 	brcms_c_rateset_default(&bi->rateset, NULL, band->phytype,
4745*b4c3e9b5SBjoern A. Zeeb 		band->bandtype, false, BRCMS_RATE_MASK_FULL,
4746*b4c3e9b5SBjoern A. Zeeb 		(bool) (wlc->pub->_n_enab & SUPPORT_11N),
4747*b4c3e9b5SBjoern A. Zeeb 		brcms_chspec_bw(chanspec), wlc->stf->txstreams);
4748*b4c3e9b5SBjoern A. Zeeb 
4749*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->_n_enab & SUPPORT_11N)
4750*b4c3e9b5SBjoern A. Zeeb 		bi->flags |= BRCMS_BSS_HT;
4751*b4c3e9b5SBjoern A. Zeeb }
4752*b4c3e9b5SBjoern A. Zeeb 
brcms_c_update_mimo_band_bwcap(struct brcms_c_info * wlc,u8 bwcap)4753*b4c3e9b5SBjoern A. Zeeb static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap)
4754*b4c3e9b5SBjoern A. Zeeb {
4755*b4c3e9b5SBjoern A. Zeeb 	uint i;
4756*b4c3e9b5SBjoern A. Zeeb 	struct brcms_band *band;
4757*b4c3e9b5SBjoern A. Zeeb 
4758*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < wlc->pub->_nbands; i++) {
4759*b4c3e9b5SBjoern A. Zeeb 		band = wlc->bandstate[i];
4760*b4c3e9b5SBjoern A. Zeeb 		if (band->bandtype == BRCM_BAND_5G) {
4761*b4c3e9b5SBjoern A. Zeeb 			if ((bwcap == BRCMS_N_BW_40ALL)
4762*b4c3e9b5SBjoern A. Zeeb 			    || (bwcap == BRCMS_N_BW_20IN2G_40IN5G))
4763*b4c3e9b5SBjoern A. Zeeb 				band->mimo_cap_40 = true;
4764*b4c3e9b5SBjoern A. Zeeb 			else
4765*b4c3e9b5SBjoern A. Zeeb 				band->mimo_cap_40 = false;
4766*b4c3e9b5SBjoern A. Zeeb 		} else {
4767*b4c3e9b5SBjoern A. Zeeb 			if (bwcap == BRCMS_N_BW_40ALL)
4768*b4c3e9b5SBjoern A. Zeeb 				band->mimo_cap_40 = true;
4769*b4c3e9b5SBjoern A. Zeeb 			else
4770*b4c3e9b5SBjoern A. Zeeb 				band->mimo_cap_40 = false;
4771*b4c3e9b5SBjoern A. Zeeb 		}
4772*b4c3e9b5SBjoern A. Zeeb 	}
4773*b4c3e9b5SBjoern A. Zeeb }
4774*b4c3e9b5SBjoern A. Zeeb 
brcms_c_timers_deinit(struct brcms_c_info * wlc)4775*b4c3e9b5SBjoern A. Zeeb static void brcms_c_timers_deinit(struct brcms_c_info *wlc)
4776*b4c3e9b5SBjoern A. Zeeb {
4777*b4c3e9b5SBjoern A. Zeeb 	/* free timer state */
4778*b4c3e9b5SBjoern A. Zeeb 	if (wlc->wdtimer) {
4779*b4c3e9b5SBjoern A. Zeeb 		brcms_free_timer(wlc->wdtimer);
4780*b4c3e9b5SBjoern A. Zeeb 		wlc->wdtimer = NULL;
4781*b4c3e9b5SBjoern A. Zeeb 	}
4782*b4c3e9b5SBjoern A. Zeeb 	if (wlc->radio_timer) {
4783*b4c3e9b5SBjoern A. Zeeb 		brcms_free_timer(wlc->radio_timer);
4784*b4c3e9b5SBjoern A. Zeeb 		wlc->radio_timer = NULL;
4785*b4c3e9b5SBjoern A. Zeeb 	}
4786*b4c3e9b5SBjoern A. Zeeb }
4787*b4c3e9b5SBjoern A. Zeeb 
brcms_c_detach_module(struct brcms_c_info * wlc)4788*b4c3e9b5SBjoern A. Zeeb static void brcms_c_detach_module(struct brcms_c_info *wlc)
4789*b4c3e9b5SBjoern A. Zeeb {
4790*b4c3e9b5SBjoern A. Zeeb 	if (wlc->asi) {
4791*b4c3e9b5SBjoern A. Zeeb 		brcms_c_antsel_detach(wlc->asi);
4792*b4c3e9b5SBjoern A. Zeeb 		wlc->asi = NULL;
4793*b4c3e9b5SBjoern A. Zeeb 	}
4794*b4c3e9b5SBjoern A. Zeeb 
4795*b4c3e9b5SBjoern A. Zeeb 	if (wlc->ampdu) {
4796*b4c3e9b5SBjoern A. Zeeb 		brcms_c_ampdu_detach(wlc->ampdu);
4797*b4c3e9b5SBjoern A. Zeeb 		wlc->ampdu = NULL;
4798*b4c3e9b5SBjoern A. Zeeb 	}
4799*b4c3e9b5SBjoern A. Zeeb 
4800*b4c3e9b5SBjoern A. Zeeb 	brcms_c_stf_detach(wlc);
4801*b4c3e9b5SBjoern A. Zeeb }
4802*b4c3e9b5SBjoern A. Zeeb 
4803*b4c3e9b5SBjoern A. Zeeb /*
4804*b4c3e9b5SBjoern A. Zeeb  * low level detach
4805*b4c3e9b5SBjoern A. Zeeb  */
brcms_b_detach(struct brcms_c_info * wlc)4806*b4c3e9b5SBjoern A. Zeeb static void brcms_b_detach(struct brcms_c_info *wlc)
4807*b4c3e9b5SBjoern A. Zeeb {
4808*b4c3e9b5SBjoern A. Zeeb 	uint i;
4809*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hw_band *band;
4810*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
4811*b4c3e9b5SBjoern A. Zeeb 
4812*b4c3e9b5SBjoern A. Zeeb 	brcms_b_detach_dmapio(wlc_hw);
4813*b4c3e9b5SBjoern A. Zeeb 
4814*b4c3e9b5SBjoern A. Zeeb 	band = wlc_hw->band;
4815*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < wlc_hw->_nbands; i++) {
4816*b4c3e9b5SBjoern A. Zeeb 		if (band->pi) {
4817*b4c3e9b5SBjoern A. Zeeb 			/* Detach this band's phy */
4818*b4c3e9b5SBjoern A. Zeeb 			wlc_phy_detach(band->pi);
4819*b4c3e9b5SBjoern A. Zeeb 			band->pi = NULL;
4820*b4c3e9b5SBjoern A. Zeeb 		}
4821*b4c3e9b5SBjoern A. Zeeb 		band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)];
4822*b4c3e9b5SBjoern A. Zeeb 	}
4823*b4c3e9b5SBjoern A. Zeeb 
4824*b4c3e9b5SBjoern A. Zeeb 	/* Free shared phy state */
4825*b4c3e9b5SBjoern A. Zeeb 	kfree(wlc_hw->phy_sh);
4826*b4c3e9b5SBjoern A. Zeeb 
4827*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_shim_detach(wlc_hw->physhim);
4828*b4c3e9b5SBjoern A. Zeeb 
4829*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->sih) {
4830*b4c3e9b5SBjoern A. Zeeb 		ai_detach(wlc_hw->sih);
4831*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->sih = NULL;
4832*b4c3e9b5SBjoern A. Zeeb 	}
4833*b4c3e9b5SBjoern A. Zeeb }
4834*b4c3e9b5SBjoern A. Zeeb 
4835*b4c3e9b5SBjoern A. Zeeb /*
4836*b4c3e9b5SBjoern A. Zeeb  * Return a count of the number of driver callbacks still pending.
4837*b4c3e9b5SBjoern A. Zeeb  *
4838*b4c3e9b5SBjoern A. Zeeb  * General policy is that brcms_c_detach can only dealloc/free software states.
4839*b4c3e9b5SBjoern A. Zeeb  * It can NOT touch hardware registers since the d11core may be in reset and
4840*b4c3e9b5SBjoern A. Zeeb  * clock may not be available.
4841*b4c3e9b5SBjoern A. Zeeb  * One exception is sb register access, which is possible if crystal is turned
4842*b4c3e9b5SBjoern A. Zeeb  * on after "down" state, driver should avoid software timer with the exception
4843*b4c3e9b5SBjoern A. Zeeb  * of radio_monitor.
4844*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_detach(struct brcms_c_info * wlc)4845*b4c3e9b5SBjoern A. Zeeb uint brcms_c_detach(struct brcms_c_info *wlc)
4846*b4c3e9b5SBjoern A. Zeeb {
4847*b4c3e9b5SBjoern A. Zeeb 	uint callbacks;
4848*b4c3e9b5SBjoern A. Zeeb 
4849*b4c3e9b5SBjoern A. Zeeb 	if (wlc == NULL)
4850*b4c3e9b5SBjoern A. Zeeb 		return 0;
4851*b4c3e9b5SBjoern A. Zeeb 
4852*b4c3e9b5SBjoern A. Zeeb 	brcms_b_detach(wlc);
4853*b4c3e9b5SBjoern A. Zeeb 
4854*b4c3e9b5SBjoern A. Zeeb 	/* delete software timers */
4855*b4c3e9b5SBjoern A. Zeeb 	callbacks = 0;
4856*b4c3e9b5SBjoern A. Zeeb 	if (!brcms_c_radio_monitor_stop(wlc))
4857*b4c3e9b5SBjoern A. Zeeb 		callbacks++;
4858*b4c3e9b5SBjoern A. Zeeb 
4859*b4c3e9b5SBjoern A. Zeeb 	brcms_c_channel_mgr_detach(wlc->cmi);
4860*b4c3e9b5SBjoern A. Zeeb 
4861*b4c3e9b5SBjoern A. Zeeb 	brcms_c_timers_deinit(wlc);
4862*b4c3e9b5SBjoern A. Zeeb 
4863*b4c3e9b5SBjoern A. Zeeb 	brcms_c_detach_module(wlc);
4864*b4c3e9b5SBjoern A. Zeeb 
4865*b4c3e9b5SBjoern A. Zeeb 	brcms_c_detach_mfree(wlc);
4866*b4c3e9b5SBjoern A. Zeeb 	return callbacks;
4867*b4c3e9b5SBjoern A. Zeeb }
4868*b4c3e9b5SBjoern A. Zeeb 
4869*b4c3e9b5SBjoern A. Zeeb /* update state that depends on the current value of "ap" */
brcms_c_ap_upd(struct brcms_c_info * wlc)4870*b4c3e9b5SBjoern A. Zeeb static void brcms_c_ap_upd(struct brcms_c_info *wlc)
4871*b4c3e9b5SBjoern A. Zeeb {
4872*b4c3e9b5SBjoern A. Zeeb 	/* STA-BSS; short capable */
4873*b4c3e9b5SBjoern A. Zeeb 	wlc->PLCPHdr_override = BRCMS_PLCP_SHORT;
4874*b4c3e9b5SBjoern A. Zeeb }
4875*b4c3e9b5SBjoern A. Zeeb 
4876*b4c3e9b5SBjoern A. Zeeb /* Initialize just the hardware when coming out of POR or S3/S5 system states */
brcms_b_hw_up(struct brcms_hardware * wlc_hw)4877*b4c3e9b5SBjoern A. Zeeb static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
4878*b4c3e9b5SBjoern A. Zeeb {
4879*b4c3e9b5SBjoern A. Zeeb 	if (wlc_hw->wlc->pub->hw_up)
4880*b4c3e9b5SBjoern A. Zeeb 		return;
4881*b4c3e9b5SBjoern A. Zeeb 
4882*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);
4883*b4c3e9b5SBjoern A. Zeeb 
4884*b4c3e9b5SBjoern A. Zeeb 	/*
4885*b4c3e9b5SBjoern A. Zeeb 	 * Enable pll and xtal, initialize the power control registers,
4886*b4c3e9b5SBjoern A. Zeeb 	 * and force fastclock for the remainder of brcms_c_up().
4887*b4c3e9b5SBjoern A. Zeeb 	 */
4888*b4c3e9b5SBjoern A. Zeeb 	brcms_b_xtal(wlc_hw, ON);
4889*b4c3e9b5SBjoern A. Zeeb 	ai_clkctl_init(wlc_hw->sih);
4890*b4c3e9b5SBjoern A. Zeeb 	brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
4891*b4c3e9b5SBjoern A. Zeeb 
4892*b4c3e9b5SBjoern A. Zeeb 	/*
4893*b4c3e9b5SBjoern A. Zeeb 	 * TODO: test suspend/resume
4894*b4c3e9b5SBjoern A. Zeeb 	 *
4895*b4c3e9b5SBjoern A. Zeeb 	 * AI chip doesn't restore bar0win2 on
4896*b4c3e9b5SBjoern A. Zeeb 	 * hibernation/resume, need sw fixup
4897*b4c3e9b5SBjoern A. Zeeb 	 */
4898*b4c3e9b5SBjoern A. Zeeb 
4899*b4c3e9b5SBjoern A. Zeeb 	/*
4900*b4c3e9b5SBjoern A. Zeeb 	 * Inform phy that a POR reset has occurred so
4901*b4c3e9b5SBjoern A. Zeeb 	 * it does a complete phy init
4902*b4c3e9b5SBjoern A. Zeeb 	 */
4903*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_por_inform(wlc_hw->band->pi);
4904*b4c3e9b5SBjoern A. Zeeb 
4905*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->ucode_loaded = false;
4906*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->wlc->pub->hw_up = true;
4907*b4c3e9b5SBjoern A. Zeeb 
4908*b4c3e9b5SBjoern A. Zeeb 	if ((wlc_hw->boardflags & BFL_FEM)
4909*b4c3e9b5SBjoern A. Zeeb 	    && (ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM4313)) {
4910*b4c3e9b5SBjoern A. Zeeb 		if (!
4911*b4c3e9b5SBjoern A. Zeeb 		    (wlc_hw->boardrev >= 0x1250
4912*b4c3e9b5SBjoern A. Zeeb 		     && (wlc_hw->boardflags & BFL_FEM_BT)))
4913*b4c3e9b5SBjoern A. Zeeb 			ai_epa_4313war(wlc_hw->sih);
4914*b4c3e9b5SBjoern A. Zeeb 	}
4915*b4c3e9b5SBjoern A. Zeeb }
4916*b4c3e9b5SBjoern A. Zeeb 
brcms_b_up_prep(struct brcms_hardware * wlc_hw)4917*b4c3e9b5SBjoern A. Zeeb static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
4918*b4c3e9b5SBjoern A. Zeeb {
4919*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);
4920*b4c3e9b5SBjoern A. Zeeb 
4921*b4c3e9b5SBjoern A. Zeeb 	/*
4922*b4c3e9b5SBjoern A. Zeeb 	 * Enable pll and xtal, initialize the power control registers,
4923*b4c3e9b5SBjoern A. Zeeb 	 * and force fastclock for the remainder of brcms_c_up().
4924*b4c3e9b5SBjoern A. Zeeb 	 */
4925*b4c3e9b5SBjoern A. Zeeb 	brcms_b_xtal(wlc_hw, ON);
4926*b4c3e9b5SBjoern A. Zeeb 	ai_clkctl_init(wlc_hw->sih);
4927*b4c3e9b5SBjoern A. Zeeb 	brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
4928*b4c3e9b5SBjoern A. Zeeb 
4929*b4c3e9b5SBjoern A. Zeeb 	/*
4930*b4c3e9b5SBjoern A. Zeeb 	 * Configure pci/pcmcia here instead of in brcms_c_attach()
4931*b4c3e9b5SBjoern A. Zeeb 	 * to allow mfg hotswap:  down, hotswap (chip power cycle), up.
4932*b4c3e9b5SBjoern A. Zeeb 	 */
4933*b4c3e9b5SBjoern A. Zeeb 	bcma_host_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core,
4934*b4c3e9b5SBjoern A. Zeeb 			      true);
4935*b4c3e9b5SBjoern A. Zeeb 
4936*b4c3e9b5SBjoern A. Zeeb 	/*
4937*b4c3e9b5SBjoern A. Zeeb 	 * Need to read the hwradio status here to cover the case where the
4938*b4c3e9b5SBjoern A. Zeeb 	 * system is loaded with the hw radio disabled. We do not want to
4939*b4c3e9b5SBjoern A. Zeeb 	 * bring the driver up in this case.
4940*b4c3e9b5SBjoern A. Zeeb 	 */
4941*b4c3e9b5SBjoern A. Zeeb 	if (brcms_b_radio_read_hwdisabled(wlc_hw)) {
4942*b4c3e9b5SBjoern A. Zeeb 		/* put SB PCI in down state again */
4943*b4c3e9b5SBjoern A. Zeeb 		bcma_host_pci_down(wlc_hw->d11core->bus);
4944*b4c3e9b5SBjoern A. Zeeb 		brcms_b_xtal(wlc_hw, OFF);
4945*b4c3e9b5SBjoern A. Zeeb 		return -ENOMEDIUM;
4946*b4c3e9b5SBjoern A. Zeeb 	}
4947*b4c3e9b5SBjoern A. Zeeb 
4948*b4c3e9b5SBjoern A. Zeeb 	bcma_host_pci_up(wlc_hw->d11core->bus);
4949*b4c3e9b5SBjoern A. Zeeb 
4950*b4c3e9b5SBjoern A. Zeeb 	/* reset the d11 core */
4951*b4c3e9b5SBjoern A. Zeeb 	brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
4952*b4c3e9b5SBjoern A. Zeeb 
4953*b4c3e9b5SBjoern A. Zeeb 	return 0;
4954*b4c3e9b5SBjoern A. Zeeb }
4955*b4c3e9b5SBjoern A. Zeeb 
brcms_b_up_finish(struct brcms_hardware * wlc_hw)4956*b4c3e9b5SBjoern A. Zeeb static int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
4957*b4c3e9b5SBjoern A. Zeeb {
4958*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->up = true;
4959*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
4960*b4c3e9b5SBjoern A. Zeeb 
4961*b4c3e9b5SBjoern A. Zeeb 	/* FULLY enable dynamic power control and d11 core interrupt */
4962*b4c3e9b5SBjoern A. Zeeb 	brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
4963*b4c3e9b5SBjoern A. Zeeb 	brcms_intrson(wlc_hw->wlc->wl);
4964*b4c3e9b5SBjoern A. Zeeb 	return 0;
4965*b4c3e9b5SBjoern A. Zeeb }
4966*b4c3e9b5SBjoern A. Zeeb 
4967*b4c3e9b5SBjoern A. Zeeb /*
4968*b4c3e9b5SBjoern A. Zeeb  * Write WME tunable parameters for retransmit/max rate
4969*b4c3e9b5SBjoern A. Zeeb  * from wlc struct to ucode
4970*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_wme_retries_write(struct brcms_c_info * wlc)4971*b4c3e9b5SBjoern A. Zeeb static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
4972*b4c3e9b5SBjoern A. Zeeb {
4973*b4c3e9b5SBjoern A. Zeeb 	int ac;
4974*b4c3e9b5SBjoern A. Zeeb 
4975*b4c3e9b5SBjoern A. Zeeb 	/* Need clock to do this */
4976*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->clk)
4977*b4c3e9b5SBjoern A. Zeeb 		return;
4978*b4c3e9b5SBjoern A. Zeeb 
4979*b4c3e9b5SBjoern A. Zeeb 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
4980*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc->hw, M_AC_TXLMT_ADDR(ac),
4981*b4c3e9b5SBjoern A. Zeeb 				  wlc->wme_retries[ac]);
4982*b4c3e9b5SBjoern A. Zeeb }
4983*b4c3e9b5SBjoern A. Zeeb 
4984*b4c3e9b5SBjoern A. Zeeb /* make interface operational */
brcms_c_up(struct brcms_c_info * wlc)4985*b4c3e9b5SBjoern A. Zeeb int brcms_c_up(struct brcms_c_info *wlc)
4986*b4c3e9b5SBjoern A. Zeeb {
4987*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_channel *ch;
4988*b4c3e9b5SBjoern A. Zeeb 
4989*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);
4990*b4c3e9b5SBjoern A. Zeeb 
4991*b4c3e9b5SBjoern A. Zeeb 	/* HW is turned off so don't try to access it */
4992*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->hw_off || brcms_deviceremoved(wlc))
4993*b4c3e9b5SBjoern A. Zeeb 		return -ENOMEDIUM;
4994*b4c3e9b5SBjoern A. Zeeb 
4995*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->pub->hw_up) {
4996*b4c3e9b5SBjoern A. Zeeb 		brcms_b_hw_up(wlc->hw);
4997*b4c3e9b5SBjoern A. Zeeb 		wlc->pub->hw_up = true;
4998*b4c3e9b5SBjoern A. Zeeb 	}
4999*b4c3e9b5SBjoern A. Zeeb 
5000*b4c3e9b5SBjoern A. Zeeb 	if ((wlc->pub->boardflags & BFL_FEM)
5001*b4c3e9b5SBjoern A. Zeeb 	    && (ai_get_chip_id(wlc->hw->sih) == BCMA_CHIP_ID_BCM4313)) {
5002*b4c3e9b5SBjoern A. Zeeb 		if (wlc->pub->boardrev >= 0x1250
5003*b4c3e9b5SBjoern A. Zeeb 		    && (wlc->pub->boardflags & BFL_FEM_BT))
5004*b4c3e9b5SBjoern A. Zeeb 			brcms_b_mhf(wlc->hw, MHF5, MHF5_4313_GPIOCTRL,
5005*b4c3e9b5SBjoern A. Zeeb 				MHF5_4313_GPIOCTRL, BRCM_BAND_ALL);
5006*b4c3e9b5SBjoern A. Zeeb 		else
5007*b4c3e9b5SBjoern A. Zeeb 			brcms_b_mhf(wlc->hw, MHF4, MHF4_EXTPA_ENABLE,
5008*b4c3e9b5SBjoern A. Zeeb 				    MHF4_EXTPA_ENABLE, BRCM_BAND_ALL);
5009*b4c3e9b5SBjoern A. Zeeb 	}
5010*b4c3e9b5SBjoern A. Zeeb 
5011*b4c3e9b5SBjoern A. Zeeb 	/*
5012*b4c3e9b5SBjoern A. Zeeb 	 * Need to read the hwradio status here to cover the case where the
5013*b4c3e9b5SBjoern A. Zeeb 	 * system is loaded with the hw radio disabled. We do not want to bring
5014*b4c3e9b5SBjoern A. Zeeb 	 * the driver up in this case. If radio is disabled, abort up, lower
5015*b4c3e9b5SBjoern A. Zeeb 	 * power, start radio timer and return 0(for NDIS) don't call
5016*b4c3e9b5SBjoern A. Zeeb 	 * radio_update to avoid looping brcms_c_up.
5017*b4c3e9b5SBjoern A. Zeeb 	 *
5018*b4c3e9b5SBjoern A. Zeeb 	 * brcms_b_up_prep() returns either 0 or -BCME_RADIOOFF only
5019*b4c3e9b5SBjoern A. Zeeb 	 */
5020*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->pub->radio_disabled) {
5021*b4c3e9b5SBjoern A. Zeeb 		int status = brcms_b_up_prep(wlc->hw);
5022*b4c3e9b5SBjoern A. Zeeb 		if (status == -ENOMEDIUM) {
5023*b4c3e9b5SBjoern A. Zeeb 			if (!mboolisset
5024*b4c3e9b5SBjoern A. Zeeb 			    (wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE)) {
5025*b4c3e9b5SBjoern A. Zeeb 				struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
5026*b4c3e9b5SBjoern A. Zeeb 				mboolset(wlc->pub->radio_disabled,
5027*b4c3e9b5SBjoern A. Zeeb 					 WL_RADIO_HW_DISABLE);
5028*b4c3e9b5SBjoern A. Zeeb 				if (bsscfg->type == BRCMS_TYPE_STATION ||
5029*b4c3e9b5SBjoern A. Zeeb 				    bsscfg->type == BRCMS_TYPE_ADHOC)
5030*b4c3e9b5SBjoern A. Zeeb 					brcms_err(wlc->hw->d11core,
5031*b4c3e9b5SBjoern A. Zeeb 						  "wl%d: up: rfdisable -> "
5032*b4c3e9b5SBjoern A. Zeeb 						  "bsscfg_disable()\n",
5033*b4c3e9b5SBjoern A. Zeeb 						   wlc->pub->unit);
5034*b4c3e9b5SBjoern A. Zeeb 			}
5035*b4c3e9b5SBjoern A. Zeeb 		}
5036*b4c3e9b5SBjoern A. Zeeb 	}
5037*b4c3e9b5SBjoern A. Zeeb 
5038*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->radio_disabled) {
5039*b4c3e9b5SBjoern A. Zeeb 		brcms_c_radio_monitor_start(wlc);
5040*b4c3e9b5SBjoern A. Zeeb 		return 0;
5041*b4c3e9b5SBjoern A. Zeeb 	}
5042*b4c3e9b5SBjoern A. Zeeb 
5043*b4c3e9b5SBjoern A. Zeeb 	/* brcms_b_up_prep has done brcms_c_corereset(). so clk is on, set it */
5044*b4c3e9b5SBjoern A. Zeeb 	wlc->clk = true;
5045*b4c3e9b5SBjoern A. Zeeb 
5046*b4c3e9b5SBjoern A. Zeeb 	brcms_c_radio_monitor_stop(wlc);
5047*b4c3e9b5SBjoern A. Zeeb 
5048*b4c3e9b5SBjoern A. Zeeb 	/* Set EDCF hostflags */
5049*b4c3e9b5SBjoern A. Zeeb 	brcms_b_mhf(wlc->hw, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL);
5050*b4c3e9b5SBjoern A. Zeeb 
5051*b4c3e9b5SBjoern A. Zeeb 	brcms_init(wlc->wl);
5052*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->up = true;
5053*b4c3e9b5SBjoern A. Zeeb 
5054*b4c3e9b5SBjoern A. Zeeb 	if (wlc->bandinit_pending) {
5055*b4c3e9b5SBjoern A. Zeeb 		ch = wlc->pub->ieee_hw->conf.chandef.chan;
5056*b4c3e9b5SBjoern A. Zeeb 		brcms_c_suspend_mac_and_wait(wlc);
5057*b4c3e9b5SBjoern A. Zeeb 		brcms_c_set_chanspec(wlc, ch20mhz_chspec(ch->hw_value));
5058*b4c3e9b5SBjoern A. Zeeb 		wlc->bandinit_pending = false;
5059*b4c3e9b5SBjoern A. Zeeb 		brcms_c_enable_mac(wlc);
5060*b4c3e9b5SBjoern A. Zeeb 	}
5061*b4c3e9b5SBjoern A. Zeeb 
5062*b4c3e9b5SBjoern A. Zeeb 	brcms_b_up_finish(wlc->hw);
5063*b4c3e9b5SBjoern A. Zeeb 
5064*b4c3e9b5SBjoern A. Zeeb 	/* Program the TX wme params with the current settings */
5065*b4c3e9b5SBjoern A. Zeeb 	brcms_c_wme_retries_write(wlc);
5066*b4c3e9b5SBjoern A. Zeeb 
5067*b4c3e9b5SBjoern A. Zeeb 	/* start one second watchdog timer */
5068*b4c3e9b5SBjoern A. Zeeb 	brcms_add_timer(wlc->wdtimer, TIMER_INTERVAL_WATCHDOG, true);
5069*b4c3e9b5SBjoern A. Zeeb 	wlc->WDarmed = true;
5070*b4c3e9b5SBjoern A. Zeeb 
5071*b4c3e9b5SBjoern A. Zeeb 	/* ensure antenna config is up to date */
5072*b4c3e9b5SBjoern A. Zeeb 	brcms_c_stf_phy_txant_upd(wlc);
5073*b4c3e9b5SBjoern A. Zeeb 	/* ensure LDPC config is in sync */
5074*b4c3e9b5SBjoern A. Zeeb 	brcms_c_ht_update_ldpc(wlc, wlc->stf->ldpc);
5075*b4c3e9b5SBjoern A. Zeeb 
5076*b4c3e9b5SBjoern A. Zeeb 	return 0;
5077*b4c3e9b5SBjoern A. Zeeb }
5078*b4c3e9b5SBjoern A. Zeeb 
brcms_b_bmac_down_prep(struct brcms_hardware * wlc_hw)5079*b4c3e9b5SBjoern A. Zeeb static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
5080*b4c3e9b5SBjoern A. Zeeb {
5081*b4c3e9b5SBjoern A. Zeeb 	bool dev_gone;
5082*b4c3e9b5SBjoern A. Zeeb 	uint callbacks = 0;
5083*b4c3e9b5SBjoern A. Zeeb 
5084*b4c3e9b5SBjoern A. Zeeb 	if (!wlc_hw->up)
5085*b4c3e9b5SBjoern A. Zeeb 		return callbacks;
5086*b4c3e9b5SBjoern A. Zeeb 
5087*b4c3e9b5SBjoern A. Zeeb 	dev_gone = brcms_deviceremoved(wlc_hw->wlc);
5088*b4c3e9b5SBjoern A. Zeeb 
5089*b4c3e9b5SBjoern A. Zeeb 	/* disable interrupts */
5090*b4c3e9b5SBjoern A. Zeeb 	if (dev_gone)
5091*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->wlc->macintmask = 0;
5092*b4c3e9b5SBjoern A. Zeeb 	else {
5093*b4c3e9b5SBjoern A. Zeeb 		/* now disable interrupts */
5094*b4c3e9b5SBjoern A. Zeeb 		brcms_intrsoff(wlc_hw->wlc->wl);
5095*b4c3e9b5SBjoern A. Zeeb 
5096*b4c3e9b5SBjoern A. Zeeb 		/* ensure we're running on the pll clock again */
5097*b4c3e9b5SBjoern A. Zeeb 		brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
5098*b4c3e9b5SBjoern A. Zeeb 	}
5099*b4c3e9b5SBjoern A. Zeeb 	/* down phy at the last of this stage */
5100*b4c3e9b5SBjoern A. Zeeb 	callbacks += wlc_phy_down(wlc_hw->band->pi);
5101*b4c3e9b5SBjoern A. Zeeb 
5102*b4c3e9b5SBjoern A. Zeeb 	return callbacks;
5103*b4c3e9b5SBjoern A. Zeeb }
5104*b4c3e9b5SBjoern A. Zeeb 
brcms_b_down_finish(struct brcms_hardware * wlc_hw)5105*b4c3e9b5SBjoern A. Zeeb static int brcms_b_down_finish(struct brcms_hardware *wlc_hw)
5106*b4c3e9b5SBjoern A. Zeeb {
5107*b4c3e9b5SBjoern A. Zeeb 	uint callbacks = 0;
5108*b4c3e9b5SBjoern A. Zeeb 	bool dev_gone;
5109*b4c3e9b5SBjoern A. Zeeb 
5110*b4c3e9b5SBjoern A. Zeeb 	if (!wlc_hw->up)
5111*b4c3e9b5SBjoern A. Zeeb 		return callbacks;
5112*b4c3e9b5SBjoern A. Zeeb 
5113*b4c3e9b5SBjoern A. Zeeb 	wlc_hw->up = false;
5114*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_hw_state_upd(wlc_hw->band->pi, false);
5115*b4c3e9b5SBjoern A. Zeeb 
5116*b4c3e9b5SBjoern A. Zeeb 	dev_gone = brcms_deviceremoved(wlc_hw->wlc);
5117*b4c3e9b5SBjoern A. Zeeb 
5118*b4c3e9b5SBjoern A. Zeeb 	if (dev_gone) {
5119*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->sbclk = false;
5120*b4c3e9b5SBjoern A. Zeeb 		wlc_hw->clk = false;
5121*b4c3e9b5SBjoern A. Zeeb 		wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
5122*b4c3e9b5SBjoern A. Zeeb 
5123*b4c3e9b5SBjoern A. Zeeb 		/* reclaim any posted packets */
5124*b4c3e9b5SBjoern A. Zeeb 		brcms_c_flushqueues(wlc_hw->wlc);
5125*b4c3e9b5SBjoern A. Zeeb 	} else {
5126*b4c3e9b5SBjoern A. Zeeb 
5127*b4c3e9b5SBjoern A. Zeeb 		/* Reset and disable the core */
5128*b4c3e9b5SBjoern A. Zeeb 		if (bcma_core_is_enabled(wlc_hw->d11core)) {
5129*b4c3e9b5SBjoern A. Zeeb 			if (bcma_read32(wlc_hw->d11core,
5130*b4c3e9b5SBjoern A. Zeeb 					D11REGOFFS(maccontrol)) & MCTL_EN_MAC)
5131*b4c3e9b5SBjoern A. Zeeb 				brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
5132*b4c3e9b5SBjoern A. Zeeb 			callbacks += brcms_reset(wlc_hw->wlc->wl);
5133*b4c3e9b5SBjoern A. Zeeb 			brcms_c_coredisable(wlc_hw);
5134*b4c3e9b5SBjoern A. Zeeb 		}
5135*b4c3e9b5SBjoern A. Zeeb 
5136*b4c3e9b5SBjoern A. Zeeb 		/* turn off primary xtal and pll */
5137*b4c3e9b5SBjoern A. Zeeb 		if (!wlc_hw->noreset) {
5138*b4c3e9b5SBjoern A. Zeeb 			bcma_host_pci_down(wlc_hw->d11core->bus);
5139*b4c3e9b5SBjoern A. Zeeb 			brcms_b_xtal(wlc_hw, OFF);
5140*b4c3e9b5SBjoern A. Zeeb 		}
5141*b4c3e9b5SBjoern A. Zeeb 	}
5142*b4c3e9b5SBjoern A. Zeeb 
5143*b4c3e9b5SBjoern A. Zeeb 	return callbacks;
5144*b4c3e9b5SBjoern A. Zeeb }
5145*b4c3e9b5SBjoern A. Zeeb 
5146*b4c3e9b5SBjoern A. Zeeb /*
5147*b4c3e9b5SBjoern A. Zeeb  * Mark the interface nonoperational, stop the software mechanisms,
5148*b4c3e9b5SBjoern A. Zeeb  * disable the hardware, free any transient buffer state.
5149*b4c3e9b5SBjoern A. Zeeb  * Return a count of the number of driver callbacks still pending.
5150*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_down(struct brcms_c_info * wlc)5151*b4c3e9b5SBjoern A. Zeeb uint brcms_c_down(struct brcms_c_info *wlc)
5152*b4c3e9b5SBjoern A. Zeeb {
5153*b4c3e9b5SBjoern A. Zeeb 
5154*b4c3e9b5SBjoern A. Zeeb 	uint callbacks = 0;
5155*b4c3e9b5SBjoern A. Zeeb 	int i;
5156*b4c3e9b5SBjoern A. Zeeb 
5157*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);
5158*b4c3e9b5SBjoern A. Zeeb 
5159*b4c3e9b5SBjoern A. Zeeb 	/* check if we are already in the going down path */
5160*b4c3e9b5SBjoern A. Zeeb 	if (wlc->going_down) {
5161*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core,
5162*b4c3e9b5SBjoern A. Zeeb 			  "wl%d: %s: Driver going down so return\n",
5163*b4c3e9b5SBjoern A. Zeeb 			  wlc->pub->unit, __func__);
5164*b4c3e9b5SBjoern A. Zeeb 		return 0;
5165*b4c3e9b5SBjoern A. Zeeb 	}
5166*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->pub->up)
5167*b4c3e9b5SBjoern A. Zeeb 		return callbacks;
5168*b4c3e9b5SBjoern A. Zeeb 
5169*b4c3e9b5SBjoern A. Zeeb 	wlc->going_down = true;
5170*b4c3e9b5SBjoern A. Zeeb 
5171*b4c3e9b5SBjoern A. Zeeb 	callbacks += brcms_b_bmac_down_prep(wlc->hw);
5172*b4c3e9b5SBjoern A. Zeeb 
5173*b4c3e9b5SBjoern A. Zeeb 	brcms_deviceremoved(wlc);
5174*b4c3e9b5SBjoern A. Zeeb 
5175*b4c3e9b5SBjoern A. Zeeb 	/* Call any registered down handlers */
5176*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < BRCMS_MAXMODULES; i++) {
5177*b4c3e9b5SBjoern A. Zeeb 		if (wlc->modulecb[i].down_fn)
5178*b4c3e9b5SBjoern A. Zeeb 			callbacks +=
5179*b4c3e9b5SBjoern A. Zeeb 			    wlc->modulecb[i].down_fn(wlc->modulecb[i].hdl);
5180*b4c3e9b5SBjoern A. Zeeb 	}
5181*b4c3e9b5SBjoern A. Zeeb 
5182*b4c3e9b5SBjoern A. Zeeb 	/* cancel the watchdog timer */
5183*b4c3e9b5SBjoern A. Zeeb 	if (wlc->WDarmed) {
5184*b4c3e9b5SBjoern A. Zeeb 		if (!brcms_del_timer(wlc->wdtimer))
5185*b4c3e9b5SBjoern A. Zeeb 			callbacks++;
5186*b4c3e9b5SBjoern A. Zeeb 		wlc->WDarmed = false;
5187*b4c3e9b5SBjoern A. Zeeb 	}
5188*b4c3e9b5SBjoern A. Zeeb 
5189*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->up = false;
5190*b4c3e9b5SBjoern A. Zeeb 
5191*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_mute_upd(wlc->band->pi, false, PHY_MUTE_ALL);
5192*b4c3e9b5SBjoern A. Zeeb 
5193*b4c3e9b5SBjoern A. Zeeb 	callbacks += brcms_b_down_finish(wlc->hw);
5194*b4c3e9b5SBjoern A. Zeeb 
5195*b4c3e9b5SBjoern A. Zeeb 	/* brcms_b_down_finish has done brcms_c_coredisable(). so clk is off */
5196*b4c3e9b5SBjoern A. Zeeb 	wlc->clk = false;
5197*b4c3e9b5SBjoern A. Zeeb 
5198*b4c3e9b5SBjoern A. Zeeb 	wlc->going_down = false;
5199*b4c3e9b5SBjoern A. Zeeb 	return callbacks;
5200*b4c3e9b5SBjoern A. Zeeb }
5201*b4c3e9b5SBjoern A. Zeeb 
5202*b4c3e9b5SBjoern A. Zeeb /* Set the current gmode configuration */
brcms_c_set_gmode(struct brcms_c_info * wlc,u8 gmode,bool config)5203*b4c3e9b5SBjoern A. Zeeb int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
5204*b4c3e9b5SBjoern A. Zeeb {
5205*b4c3e9b5SBjoern A. Zeeb 	int ret = 0;
5206*b4c3e9b5SBjoern A. Zeeb 	uint i;
5207*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_rateset rs;
5208*b4c3e9b5SBjoern A. Zeeb 	/* Default to 54g Auto */
5209*b4c3e9b5SBjoern A. Zeeb 	/* Advertise and use shortslot (-1/0/1 Auto/Off/On) */
5210*b4c3e9b5SBjoern A. Zeeb 	s8 shortslot = BRCMS_SHORTSLOT_AUTO;
5211*b4c3e9b5SBjoern A. Zeeb 	bool ofdm_basic = false;	/* Make 6, 12, and 24 basic rates */
5212*b4c3e9b5SBjoern A. Zeeb 	struct brcms_band *band;
5213*b4c3e9b5SBjoern A. Zeeb 
5214*b4c3e9b5SBjoern A. Zeeb 	/* if N-support is enabled, allow Gmode set as long as requested
5215*b4c3e9b5SBjoern A. Zeeb 	 * Gmode is not GMODE_LEGACY_B
5216*b4c3e9b5SBjoern A. Zeeb 	 */
5217*b4c3e9b5SBjoern A. Zeeb 	if ((wlc->pub->_n_enab & SUPPORT_11N) && gmode == GMODE_LEGACY_B)
5218*b4c3e9b5SBjoern A. Zeeb 		return -ENOTSUPP;
5219*b4c3e9b5SBjoern A. Zeeb 
5220*b4c3e9b5SBjoern A. Zeeb 	/* verify that we are dealing with 2G band and grab the band pointer */
5221*b4c3e9b5SBjoern A. Zeeb 	if (wlc->band->bandtype == BRCM_BAND_2G)
5222*b4c3e9b5SBjoern A. Zeeb 		band = wlc->band;
5223*b4c3e9b5SBjoern A. Zeeb 	else if ((wlc->pub->_nbands > 1) &&
5224*b4c3e9b5SBjoern A. Zeeb 		 (wlc->bandstate[OTHERBANDUNIT(wlc)]->bandtype == BRCM_BAND_2G))
5225*b4c3e9b5SBjoern A. Zeeb 		band = wlc->bandstate[OTHERBANDUNIT(wlc)];
5226*b4c3e9b5SBjoern A. Zeeb 	else
5227*b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
5228*b4c3e9b5SBjoern A. Zeeb 
5229*b4c3e9b5SBjoern A. Zeeb 	/* update configuration value */
5230*b4c3e9b5SBjoern A. Zeeb 	if (config)
5231*b4c3e9b5SBjoern A. Zeeb 		brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode);
5232*b4c3e9b5SBjoern A. Zeeb 
5233*b4c3e9b5SBjoern A. Zeeb 	/* Clear rateset override */
5234*b4c3e9b5SBjoern A. Zeeb 	memset(&rs, 0, sizeof(rs));
5235*b4c3e9b5SBjoern A. Zeeb 
5236*b4c3e9b5SBjoern A. Zeeb 	switch (gmode) {
5237*b4c3e9b5SBjoern A. Zeeb 	case GMODE_LEGACY_B:
5238*b4c3e9b5SBjoern A. Zeeb 		shortslot = BRCMS_SHORTSLOT_OFF;
5239*b4c3e9b5SBjoern A. Zeeb 		brcms_c_rateset_copy(&gphy_legacy_rates, &rs);
5240*b4c3e9b5SBjoern A. Zeeb 
5241*b4c3e9b5SBjoern A. Zeeb 		break;
5242*b4c3e9b5SBjoern A. Zeeb 
5243*b4c3e9b5SBjoern A. Zeeb 	case GMODE_LRS:
5244*b4c3e9b5SBjoern A. Zeeb 		break;
5245*b4c3e9b5SBjoern A. Zeeb 
5246*b4c3e9b5SBjoern A. Zeeb 	case GMODE_AUTO:
5247*b4c3e9b5SBjoern A. Zeeb 		/* Accept defaults */
5248*b4c3e9b5SBjoern A. Zeeb 		break;
5249*b4c3e9b5SBjoern A. Zeeb 
5250*b4c3e9b5SBjoern A. Zeeb 	case GMODE_ONLY:
5251*b4c3e9b5SBjoern A. Zeeb 		ofdm_basic = true;
5252*b4c3e9b5SBjoern A. Zeeb 		break;
5253*b4c3e9b5SBjoern A. Zeeb 
5254*b4c3e9b5SBjoern A. Zeeb 	case GMODE_PERFORMANCE:
5255*b4c3e9b5SBjoern A. Zeeb 		shortslot = BRCMS_SHORTSLOT_ON;
5256*b4c3e9b5SBjoern A. Zeeb 		ofdm_basic = true;
5257*b4c3e9b5SBjoern A. Zeeb 		break;
5258*b4c3e9b5SBjoern A. Zeeb 
5259*b4c3e9b5SBjoern A. Zeeb 	default:
5260*b4c3e9b5SBjoern A. Zeeb 		/* Error */
5261*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "wl%d: %s: invalid gmode %d\n",
5262*b4c3e9b5SBjoern A. Zeeb 			  wlc->pub->unit, __func__, gmode);
5263*b4c3e9b5SBjoern A. Zeeb 		return -ENOTSUPP;
5264*b4c3e9b5SBjoern A. Zeeb 	}
5265*b4c3e9b5SBjoern A. Zeeb 
5266*b4c3e9b5SBjoern A. Zeeb 	band->gmode = gmode;
5267*b4c3e9b5SBjoern A. Zeeb 
5268*b4c3e9b5SBjoern A. Zeeb 	wlc->shortslot_override = shortslot;
5269*b4c3e9b5SBjoern A. Zeeb 
5270*b4c3e9b5SBjoern A. Zeeb 	/* Use the default 11g rateset */
5271*b4c3e9b5SBjoern A. Zeeb 	if (!rs.count)
5272*b4c3e9b5SBjoern A. Zeeb 		brcms_c_rateset_copy(&cck_ofdm_rates, &rs);
5273*b4c3e9b5SBjoern A. Zeeb 
5274*b4c3e9b5SBjoern A. Zeeb 	if (ofdm_basic) {
5275*b4c3e9b5SBjoern A. Zeeb 		for (i = 0; i < rs.count; i++) {
5276*b4c3e9b5SBjoern A. Zeeb 			if (rs.rates[i] == BRCM_RATE_6M
5277*b4c3e9b5SBjoern A. Zeeb 			    || rs.rates[i] == BRCM_RATE_12M
5278*b4c3e9b5SBjoern A. Zeeb 			    || rs.rates[i] == BRCM_RATE_24M)
5279*b4c3e9b5SBjoern A. Zeeb 				rs.rates[i] |= BRCMS_RATE_FLAG;
5280*b4c3e9b5SBjoern A. Zeeb 		}
5281*b4c3e9b5SBjoern A. Zeeb 	}
5282*b4c3e9b5SBjoern A. Zeeb 
5283*b4c3e9b5SBjoern A. Zeeb 	/* Set default bss rateset */
5284*b4c3e9b5SBjoern A. Zeeb 	wlc->default_bss->rateset.count = rs.count;
5285*b4c3e9b5SBjoern A. Zeeb 	memcpy(wlc->default_bss->rateset.rates, rs.rates,
5286*b4c3e9b5SBjoern A. Zeeb 	       sizeof(wlc->default_bss->rateset.rates));
5287*b4c3e9b5SBjoern A. Zeeb 
5288*b4c3e9b5SBjoern A. Zeeb 	return ret;
5289*b4c3e9b5SBjoern A. Zeeb }
5290*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_nmode(struct brcms_c_info * wlc)5291*b4c3e9b5SBjoern A. Zeeb int brcms_c_set_nmode(struct brcms_c_info *wlc)
5292*b4c3e9b5SBjoern A. Zeeb {
5293*b4c3e9b5SBjoern A. Zeeb 	uint i;
5294*b4c3e9b5SBjoern A. Zeeb 	s32 nmode = AUTO;
5295*b4c3e9b5SBjoern A. Zeeb 
5296*b4c3e9b5SBjoern A. Zeeb 	if (wlc->stf->txstreams == WL_11N_3x3)
5297*b4c3e9b5SBjoern A. Zeeb 		nmode = WL_11N_3x3;
5298*b4c3e9b5SBjoern A. Zeeb 	else
5299*b4c3e9b5SBjoern A. Zeeb 		nmode = WL_11N_2x2;
5300*b4c3e9b5SBjoern A. Zeeb 
5301*b4c3e9b5SBjoern A. Zeeb 	/* force GMODE_AUTO if NMODE is ON */
5302*b4c3e9b5SBjoern A. Zeeb 	brcms_c_set_gmode(wlc, GMODE_AUTO, true);
5303*b4c3e9b5SBjoern A. Zeeb 	if (nmode == WL_11N_3x3)
5304*b4c3e9b5SBjoern A. Zeeb 		wlc->pub->_n_enab = SUPPORT_HT;
5305*b4c3e9b5SBjoern A. Zeeb 	else
5306*b4c3e9b5SBjoern A. Zeeb 		wlc->pub->_n_enab = SUPPORT_11N;
5307*b4c3e9b5SBjoern A. Zeeb 	wlc->default_bss->flags |= BRCMS_BSS_HT;
5308*b4c3e9b5SBjoern A. Zeeb 	/* add the mcs rates to the default and hw ratesets */
5309*b4c3e9b5SBjoern A. Zeeb 	brcms_c_rateset_mcs_build(&wlc->default_bss->rateset,
5310*b4c3e9b5SBjoern A. Zeeb 			      wlc->stf->txstreams);
5311*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < wlc->pub->_nbands; i++)
5312*b4c3e9b5SBjoern A. Zeeb 		memcpy(wlc->bandstate[i]->hw_rateset.mcs,
5313*b4c3e9b5SBjoern A. Zeeb 		       wlc->default_bss->rateset.mcs, MCSSET_LEN);
5314*b4c3e9b5SBjoern A. Zeeb 
5315*b4c3e9b5SBjoern A. Zeeb 	return 0;
5316*b4c3e9b5SBjoern A. Zeeb }
5317*b4c3e9b5SBjoern A. Zeeb 
5318*b4c3e9b5SBjoern A. Zeeb static int
brcms_c_set_internal_rateset(struct brcms_c_info * wlc,struct brcms_c_rateset * rs_arg)5319*b4c3e9b5SBjoern A. Zeeb brcms_c_set_internal_rateset(struct brcms_c_info *wlc,
5320*b4c3e9b5SBjoern A. Zeeb 			     struct brcms_c_rateset *rs_arg)
5321*b4c3e9b5SBjoern A. Zeeb {
5322*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_rateset rs, new;
5323*b4c3e9b5SBjoern A. Zeeb 	uint bandunit;
5324*b4c3e9b5SBjoern A. Zeeb 
5325*b4c3e9b5SBjoern A. Zeeb 	memcpy(&rs, rs_arg, sizeof(struct brcms_c_rateset));
5326*b4c3e9b5SBjoern A. Zeeb 
5327*b4c3e9b5SBjoern A. Zeeb 	/* check for bad count value */
5328*b4c3e9b5SBjoern A. Zeeb 	if ((rs.count == 0) || (rs.count > BRCMS_NUMRATES))
5329*b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
5330*b4c3e9b5SBjoern A. Zeeb 
5331*b4c3e9b5SBjoern A. Zeeb 	/* try the current band */
5332*b4c3e9b5SBjoern A. Zeeb 	bandunit = wlc->band->bandunit;
5333*b4c3e9b5SBjoern A. Zeeb 	memcpy(&new, &rs, sizeof(struct brcms_c_rateset));
5334*b4c3e9b5SBjoern A. Zeeb 	if (brcms_c_rate_hwrs_filter_sort_validate
5335*b4c3e9b5SBjoern A. Zeeb 	    (&new, &wlc->bandstate[bandunit]->hw_rateset, true,
5336*b4c3e9b5SBjoern A. Zeeb 	     wlc->stf->txstreams))
5337*b4c3e9b5SBjoern A. Zeeb 		goto good;
5338*b4c3e9b5SBjoern A. Zeeb 
5339*b4c3e9b5SBjoern A. Zeeb 	/* try the other band */
5340*b4c3e9b5SBjoern A. Zeeb 	if (brcms_is_mband_unlocked(wlc)) {
5341*b4c3e9b5SBjoern A. Zeeb 		bandunit = OTHERBANDUNIT(wlc);
5342*b4c3e9b5SBjoern A. Zeeb 		memcpy(&new, &rs, sizeof(struct brcms_c_rateset));
5343*b4c3e9b5SBjoern A. Zeeb 		if (brcms_c_rate_hwrs_filter_sort_validate(&new,
5344*b4c3e9b5SBjoern A. Zeeb 						       &wlc->
5345*b4c3e9b5SBjoern A. Zeeb 						       bandstate[bandunit]->
5346*b4c3e9b5SBjoern A. Zeeb 						       hw_rateset, true,
5347*b4c3e9b5SBjoern A. Zeeb 						       wlc->stf->txstreams))
5348*b4c3e9b5SBjoern A. Zeeb 			goto good;
5349*b4c3e9b5SBjoern A. Zeeb 	}
5350*b4c3e9b5SBjoern A. Zeeb 
5351*b4c3e9b5SBjoern A. Zeeb 	return -EBADE;
5352*b4c3e9b5SBjoern A. Zeeb 
5353*b4c3e9b5SBjoern A. Zeeb  good:
5354*b4c3e9b5SBjoern A. Zeeb 	/* apply new rateset */
5355*b4c3e9b5SBjoern A. Zeeb 	memcpy(&wlc->default_bss->rateset, &new,
5356*b4c3e9b5SBjoern A. Zeeb 	       sizeof(struct brcms_c_rateset));
5357*b4c3e9b5SBjoern A. Zeeb 	memcpy(&wlc->bandstate[bandunit]->defrateset, &new,
5358*b4c3e9b5SBjoern A. Zeeb 	       sizeof(struct brcms_c_rateset));
5359*b4c3e9b5SBjoern A. Zeeb 	return 0;
5360*b4c3e9b5SBjoern A. Zeeb }
5361*b4c3e9b5SBjoern A. Zeeb 
brcms_c_ofdm_rateset_war(struct brcms_c_info * wlc)5362*b4c3e9b5SBjoern A. Zeeb static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)
5363*b4c3e9b5SBjoern A. Zeeb {
5364*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_ofdm_rateset_war(wlc->band->pi, false);
5365*b4c3e9b5SBjoern A. Zeeb }
5366*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_channel(struct brcms_c_info * wlc,u16 channel)5367*b4c3e9b5SBjoern A. Zeeb int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)
5368*b4c3e9b5SBjoern A. Zeeb {
5369*b4c3e9b5SBjoern A. Zeeb 	u16 chspec = ch20mhz_chspec(channel);
5370*b4c3e9b5SBjoern A. Zeeb 
5371*b4c3e9b5SBjoern A. Zeeb 	if (channel > MAXCHANNEL)
5372*b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
5373*b4c3e9b5SBjoern A. Zeeb 
5374*b4c3e9b5SBjoern A. Zeeb 	if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec))
5375*b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
5376*b4c3e9b5SBjoern A. Zeeb 
5377*b4c3e9b5SBjoern A. Zeeb 
5378*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->pub->up && brcms_is_mband_unlocked(wlc)) {
5379*b4c3e9b5SBjoern A. Zeeb 		if (wlc->band->bandunit != chspec_bandunit(chspec))
5380*b4c3e9b5SBjoern A. Zeeb 			wlc->bandinit_pending = true;
5381*b4c3e9b5SBjoern A. Zeeb 		else
5382*b4c3e9b5SBjoern A. Zeeb 			wlc->bandinit_pending = false;
5383*b4c3e9b5SBjoern A. Zeeb 	}
5384*b4c3e9b5SBjoern A. Zeeb 
5385*b4c3e9b5SBjoern A. Zeeb 	wlc->default_bss->chanspec = chspec;
5386*b4c3e9b5SBjoern A. Zeeb 	/* brcms_c_BSSinit() will sanitize the rateset before
5387*b4c3e9b5SBjoern A. Zeeb 	 * using it.. */
5388*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->up && (wlc_phy_chanspec_get(wlc->band->pi) != chspec)) {
5389*b4c3e9b5SBjoern A. Zeeb 		brcms_c_set_home_chanspec(wlc, chspec);
5390*b4c3e9b5SBjoern A. Zeeb 		brcms_c_suspend_mac_and_wait(wlc);
5391*b4c3e9b5SBjoern A. Zeeb 		brcms_c_set_chanspec(wlc, chspec);
5392*b4c3e9b5SBjoern A. Zeeb 		brcms_c_enable_mac(wlc);
5393*b4c3e9b5SBjoern A. Zeeb 	}
5394*b4c3e9b5SBjoern A. Zeeb 	return 0;
5395*b4c3e9b5SBjoern A. Zeeb }
5396*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_rate_limit(struct brcms_c_info * wlc,u16 srl,u16 lrl)5397*b4c3e9b5SBjoern A. Zeeb int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl)
5398*b4c3e9b5SBjoern A. Zeeb {
5399*b4c3e9b5SBjoern A. Zeeb 	int ac;
5400*b4c3e9b5SBjoern A. Zeeb 
5401*b4c3e9b5SBjoern A. Zeeb 	if (srl < 1 || srl > RETRY_SHORT_MAX ||
5402*b4c3e9b5SBjoern A. Zeeb 	    lrl < 1 || lrl > RETRY_SHORT_MAX)
5403*b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
5404*b4c3e9b5SBjoern A. Zeeb 
5405*b4c3e9b5SBjoern A. Zeeb 	wlc->SRL = srl;
5406*b4c3e9b5SBjoern A. Zeeb 	wlc->LRL = lrl;
5407*b4c3e9b5SBjoern A. Zeeb 
5408*b4c3e9b5SBjoern A. Zeeb 	brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
5409*b4c3e9b5SBjoern A. Zeeb 
5410*b4c3e9b5SBjoern A. Zeeb 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
5411*b4c3e9b5SBjoern A. Zeeb 		wlc->wme_retries[ac] =	SFIELD(wlc->wme_retries[ac],
5412*b4c3e9b5SBjoern A. Zeeb 					       EDCF_SHORT,  wlc->SRL);
5413*b4c3e9b5SBjoern A. Zeeb 		wlc->wme_retries[ac] =	SFIELD(wlc->wme_retries[ac],
5414*b4c3e9b5SBjoern A. Zeeb 					       EDCF_LONG, wlc->LRL);
5415*b4c3e9b5SBjoern A. Zeeb 	}
5416*b4c3e9b5SBjoern A. Zeeb 	brcms_c_wme_retries_write(wlc);
5417*b4c3e9b5SBjoern A. Zeeb 
5418*b4c3e9b5SBjoern A. Zeeb 	return 0;
5419*b4c3e9b5SBjoern A. Zeeb }
5420*b4c3e9b5SBjoern A. Zeeb 
brcms_c_get_current_rateset(struct brcms_c_info * wlc,struct brcm_rateset * currs)5421*b4c3e9b5SBjoern A. Zeeb void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
5422*b4c3e9b5SBjoern A. Zeeb 				 struct brcm_rateset *currs)
5423*b4c3e9b5SBjoern A. Zeeb {
5424*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_rateset *rs;
5425*b4c3e9b5SBjoern A. Zeeb 
5426*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->associated)
5427*b4c3e9b5SBjoern A. Zeeb 		rs = &wlc->bsscfg->current_bss->rateset;
5428*b4c3e9b5SBjoern A. Zeeb 	else
5429*b4c3e9b5SBjoern A. Zeeb 		rs = &wlc->default_bss->rateset;
5430*b4c3e9b5SBjoern A. Zeeb 
5431*b4c3e9b5SBjoern A. Zeeb 	/* Copy only legacy rateset section */
5432*b4c3e9b5SBjoern A. Zeeb 	currs->count = rs->count;
5433*b4c3e9b5SBjoern A. Zeeb 	memcpy(&currs->rates, &rs->rates, rs->count);
5434*b4c3e9b5SBjoern A. Zeeb }
5435*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_rateset(struct brcms_c_info * wlc,struct brcm_rateset * rs)5436*b4c3e9b5SBjoern A. Zeeb int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
5437*b4c3e9b5SBjoern A. Zeeb {
5438*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_rateset internal_rs;
5439*b4c3e9b5SBjoern A. Zeeb 	int bcmerror;
5440*b4c3e9b5SBjoern A. Zeeb 
5441*b4c3e9b5SBjoern A. Zeeb 	if (rs->count > BRCMS_NUMRATES)
5442*b4c3e9b5SBjoern A. Zeeb 		return -ENOBUFS;
5443*b4c3e9b5SBjoern A. Zeeb 
5444*b4c3e9b5SBjoern A. Zeeb 	memset(&internal_rs, 0, sizeof(internal_rs));
5445*b4c3e9b5SBjoern A. Zeeb 
5446*b4c3e9b5SBjoern A. Zeeb 	/* Copy only legacy rateset section */
5447*b4c3e9b5SBjoern A. Zeeb 	internal_rs.count = rs->count;
5448*b4c3e9b5SBjoern A. Zeeb 	memcpy(&internal_rs.rates, &rs->rates, internal_rs.count);
5449*b4c3e9b5SBjoern A. Zeeb 
5450*b4c3e9b5SBjoern A. Zeeb 	/* merge rateset coming in with the current mcsset */
5451*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->_n_enab & SUPPORT_11N) {
5452*b4c3e9b5SBjoern A. Zeeb 		struct brcms_bss_info *mcsset_bss;
5453*b4c3e9b5SBjoern A. Zeeb 		if (wlc->pub->associated)
5454*b4c3e9b5SBjoern A. Zeeb 			mcsset_bss = wlc->bsscfg->current_bss;
5455*b4c3e9b5SBjoern A. Zeeb 		else
5456*b4c3e9b5SBjoern A. Zeeb 			mcsset_bss = wlc->default_bss;
5457*b4c3e9b5SBjoern A. Zeeb 		memcpy(internal_rs.mcs, &mcsset_bss->rateset.mcs[0],
5458*b4c3e9b5SBjoern A. Zeeb 		       MCSSET_LEN);
5459*b4c3e9b5SBjoern A. Zeeb 	}
5460*b4c3e9b5SBjoern A. Zeeb 
5461*b4c3e9b5SBjoern A. Zeeb 	bcmerror = brcms_c_set_internal_rateset(wlc, &internal_rs);
5462*b4c3e9b5SBjoern A. Zeeb 	if (!bcmerror)
5463*b4c3e9b5SBjoern A. Zeeb 		brcms_c_ofdm_rateset_war(wlc);
5464*b4c3e9b5SBjoern A. Zeeb 
5465*b4c3e9b5SBjoern A. Zeeb 	return bcmerror;
5466*b4c3e9b5SBjoern A. Zeeb }
5467*b4c3e9b5SBjoern A. Zeeb 
brcms_c_time_lock(struct brcms_c_info * wlc)5468*b4c3e9b5SBjoern A. Zeeb static void brcms_c_time_lock(struct brcms_c_info *wlc)
5469*b4c3e9b5SBjoern A. Zeeb {
5470*b4c3e9b5SBjoern A. Zeeb 	bcma_set32(wlc->hw->d11core, D11REGOFFS(maccontrol), MCTL_TBTTHOLD);
5471*b4c3e9b5SBjoern A. Zeeb 	/* Commit the write */
5472*b4c3e9b5SBjoern A. Zeeb 	bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
5473*b4c3e9b5SBjoern A. Zeeb }
5474*b4c3e9b5SBjoern A. Zeeb 
brcms_c_time_unlock(struct brcms_c_info * wlc)5475*b4c3e9b5SBjoern A. Zeeb static void brcms_c_time_unlock(struct brcms_c_info *wlc)
5476*b4c3e9b5SBjoern A. Zeeb {
5477*b4c3e9b5SBjoern A. Zeeb 	bcma_mask32(wlc->hw->d11core, D11REGOFFS(maccontrol), ~MCTL_TBTTHOLD);
5478*b4c3e9b5SBjoern A. Zeeb 	/* Commit the write */
5479*b4c3e9b5SBjoern A. Zeeb 	bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
5480*b4c3e9b5SBjoern A. Zeeb }
5481*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_beacon_period(struct brcms_c_info * wlc,u16 period)5482*b4c3e9b5SBjoern A. Zeeb int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
5483*b4c3e9b5SBjoern A. Zeeb {
5484*b4c3e9b5SBjoern A. Zeeb 	u32 bcnint_us;
5485*b4c3e9b5SBjoern A. Zeeb 
5486*b4c3e9b5SBjoern A. Zeeb 	if (period == 0)
5487*b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
5488*b4c3e9b5SBjoern A. Zeeb 
5489*b4c3e9b5SBjoern A. Zeeb 	wlc->default_bss->beacon_period = period;
5490*b4c3e9b5SBjoern A. Zeeb 
5491*b4c3e9b5SBjoern A. Zeeb 	bcnint_us = period << 10;
5492*b4c3e9b5SBjoern A. Zeeb 	brcms_c_time_lock(wlc);
5493*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_cfprep),
5494*b4c3e9b5SBjoern A. Zeeb 		     (bcnint_us << CFPREP_CBI_SHIFT));
5495*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_cfpstart), bcnint_us);
5496*b4c3e9b5SBjoern A. Zeeb 	brcms_c_time_unlock(wlc);
5497*b4c3e9b5SBjoern A. Zeeb 
5498*b4c3e9b5SBjoern A. Zeeb 	return 0;
5499*b4c3e9b5SBjoern A. Zeeb }
5500*b4c3e9b5SBjoern A. Zeeb 
brcms_c_get_phy_type(struct brcms_c_info * wlc,int phyidx)5501*b4c3e9b5SBjoern A. Zeeb u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx)
5502*b4c3e9b5SBjoern A. Zeeb {
5503*b4c3e9b5SBjoern A. Zeeb 	return wlc->band->phytype;
5504*b4c3e9b5SBjoern A. Zeeb }
5505*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_shortslot_override(struct brcms_c_info * wlc,s8 sslot_override)5506*b4c3e9b5SBjoern A. Zeeb void brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override)
5507*b4c3e9b5SBjoern A. Zeeb {
5508*b4c3e9b5SBjoern A. Zeeb 	wlc->shortslot_override = sslot_override;
5509*b4c3e9b5SBjoern A. Zeeb 
5510*b4c3e9b5SBjoern A. Zeeb 	/*
5511*b4c3e9b5SBjoern A. Zeeb 	 * shortslot is an 11g feature, so no more work if we are
5512*b4c3e9b5SBjoern A. Zeeb 	 * currently on the 5G band
5513*b4c3e9b5SBjoern A. Zeeb 	 */
5514*b4c3e9b5SBjoern A. Zeeb 	if (wlc->band->bandtype == BRCM_BAND_5G)
5515*b4c3e9b5SBjoern A. Zeeb 		return;
5516*b4c3e9b5SBjoern A. Zeeb 
5517*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->up && wlc->pub->associated) {
5518*b4c3e9b5SBjoern A. Zeeb 		/* let watchdog or beacon processing update shortslot */
5519*b4c3e9b5SBjoern A. Zeeb 	} else if (wlc->pub->up) {
5520*b4c3e9b5SBjoern A. Zeeb 		/* unassociated shortslot is off */
5521*b4c3e9b5SBjoern A. Zeeb 		brcms_c_switch_shortslot(wlc, false);
5522*b4c3e9b5SBjoern A. Zeeb 	} else {
5523*b4c3e9b5SBjoern A. Zeeb 		/* driver is down, so just update the brcms_c_info
5524*b4c3e9b5SBjoern A. Zeeb 		 * value */
5525*b4c3e9b5SBjoern A. Zeeb 		if (wlc->shortslot_override == BRCMS_SHORTSLOT_AUTO)
5526*b4c3e9b5SBjoern A. Zeeb 			wlc->shortslot = false;
5527*b4c3e9b5SBjoern A. Zeeb 		else
5528*b4c3e9b5SBjoern A. Zeeb 			wlc->shortslot =
5529*b4c3e9b5SBjoern A. Zeeb 			    (wlc->shortslot_override ==
5530*b4c3e9b5SBjoern A. Zeeb 			     BRCMS_SHORTSLOT_ON);
5531*b4c3e9b5SBjoern A. Zeeb 	}
5532*b4c3e9b5SBjoern A. Zeeb }
5533*b4c3e9b5SBjoern A. Zeeb 
5534*b4c3e9b5SBjoern A. Zeeb /*
5535*b4c3e9b5SBjoern A. Zeeb  * register watchdog and down handlers.
5536*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_module_register(struct brcms_pub * pub,const char * name,struct brcms_info * hdl,int (* d_fn)(void * handle))5537*b4c3e9b5SBjoern A. Zeeb int brcms_c_module_register(struct brcms_pub *pub,
5538*b4c3e9b5SBjoern A. Zeeb 			    const char *name, struct brcms_info *hdl,
5539*b4c3e9b5SBjoern A. Zeeb 			    int (*d_fn)(void *handle))
5540*b4c3e9b5SBjoern A. Zeeb {
5541*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc;
5542*b4c3e9b5SBjoern A. Zeeb 	int i;
5543*b4c3e9b5SBjoern A. Zeeb 
5544*b4c3e9b5SBjoern A. Zeeb 	/* find an empty entry and just add, no duplication check! */
5545*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < BRCMS_MAXMODULES; i++) {
5546*b4c3e9b5SBjoern A. Zeeb 		if (wlc->modulecb[i].name[0] == '\0') {
5547*b4c3e9b5SBjoern A. Zeeb 			strscpy(wlc->modulecb[i].name, name,
5548*b4c3e9b5SBjoern A. Zeeb 				sizeof(wlc->modulecb[i].name));
5549*b4c3e9b5SBjoern A. Zeeb 			wlc->modulecb[i].hdl = hdl;
5550*b4c3e9b5SBjoern A. Zeeb 			wlc->modulecb[i].down_fn = d_fn;
5551*b4c3e9b5SBjoern A. Zeeb 			return 0;
5552*b4c3e9b5SBjoern A. Zeeb 		}
5553*b4c3e9b5SBjoern A. Zeeb 	}
5554*b4c3e9b5SBjoern A. Zeeb 
5555*b4c3e9b5SBjoern A. Zeeb 	return -ENOSR;
5556*b4c3e9b5SBjoern A. Zeeb }
5557*b4c3e9b5SBjoern A. Zeeb 
5558*b4c3e9b5SBjoern A. Zeeb /* unregister module callbacks */
brcms_c_module_unregister(struct brcms_pub * pub,const char * name,struct brcms_info * hdl)5559*b4c3e9b5SBjoern A. Zeeb int brcms_c_module_unregister(struct brcms_pub *pub, const char *name,
5560*b4c3e9b5SBjoern A. Zeeb 			      struct brcms_info *hdl)
5561*b4c3e9b5SBjoern A. Zeeb {
5562*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc;
5563*b4c3e9b5SBjoern A. Zeeb 	int i;
5564*b4c3e9b5SBjoern A. Zeeb 
5565*b4c3e9b5SBjoern A. Zeeb 	if (wlc == NULL)
5566*b4c3e9b5SBjoern A. Zeeb 		return -ENODATA;
5567*b4c3e9b5SBjoern A. Zeeb 
5568*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < BRCMS_MAXMODULES; i++) {
5569*b4c3e9b5SBjoern A. Zeeb 		if (!strcmp(wlc->modulecb[i].name, name) &&
5570*b4c3e9b5SBjoern A. Zeeb 		    (wlc->modulecb[i].hdl == hdl)) {
5571*b4c3e9b5SBjoern A. Zeeb 			memset(&wlc->modulecb[i], 0, sizeof(wlc->modulecb[i]));
5572*b4c3e9b5SBjoern A. Zeeb 			return 0;
5573*b4c3e9b5SBjoern A. Zeeb 		}
5574*b4c3e9b5SBjoern A. Zeeb 	}
5575*b4c3e9b5SBjoern A. Zeeb 
5576*b4c3e9b5SBjoern A. Zeeb 	/* table not found! */
5577*b4c3e9b5SBjoern A. Zeeb 	return -ENODATA;
5578*b4c3e9b5SBjoern A. Zeeb }
5579*b4c3e9b5SBjoern A. Zeeb 
brcms_c_chipmatch_pci(struct bcma_device * core)5580*b4c3e9b5SBjoern A. Zeeb static bool brcms_c_chipmatch_pci(struct bcma_device *core)
5581*b4c3e9b5SBjoern A. Zeeb {
5582*b4c3e9b5SBjoern A. Zeeb 	struct pci_dev *pcidev = core->bus->host_pci;
5583*b4c3e9b5SBjoern A. Zeeb 	u16 vendor = pcidev->vendor;
5584*b4c3e9b5SBjoern A. Zeeb 	u16 device = pcidev->device;
5585*b4c3e9b5SBjoern A. Zeeb 
5586*b4c3e9b5SBjoern A. Zeeb 	if (vendor != PCI_VENDOR_ID_BROADCOM) {
5587*b4c3e9b5SBjoern A. Zeeb 		pr_err("unknown vendor id %04x\n", vendor);
5588*b4c3e9b5SBjoern A. Zeeb 		return false;
5589*b4c3e9b5SBjoern A. Zeeb 	}
5590*b4c3e9b5SBjoern A. Zeeb 
5591*b4c3e9b5SBjoern A. Zeeb 	if (device == BCM43224_D11N_ID_VEN1 || device == BCM43224_CHIP_ID)
5592*b4c3e9b5SBjoern A. Zeeb 		return true;
5593*b4c3e9b5SBjoern A. Zeeb 	if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID))
5594*b4c3e9b5SBjoern A. Zeeb 		return true;
5595*b4c3e9b5SBjoern A. Zeeb 	if (device == BCM4313_D11N2G_ID || device == BCM4313_CHIP_ID)
5596*b4c3e9b5SBjoern A. Zeeb 		return true;
5597*b4c3e9b5SBjoern A. Zeeb 	if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID))
5598*b4c3e9b5SBjoern A. Zeeb 		return true;
5599*b4c3e9b5SBjoern A. Zeeb 
5600*b4c3e9b5SBjoern A. Zeeb 	pr_err("unknown device id %04x\n", device);
5601*b4c3e9b5SBjoern A. Zeeb 	return false;
5602*b4c3e9b5SBjoern A. Zeeb }
5603*b4c3e9b5SBjoern A. Zeeb 
brcms_c_chipmatch_soc(struct bcma_device * core)5604*b4c3e9b5SBjoern A. Zeeb static bool brcms_c_chipmatch_soc(struct bcma_device *core)
5605*b4c3e9b5SBjoern A. Zeeb {
5606*b4c3e9b5SBjoern A. Zeeb 	struct bcma_chipinfo *chipinfo = &core->bus->chipinfo;
5607*b4c3e9b5SBjoern A. Zeeb 
5608*b4c3e9b5SBjoern A. Zeeb 	if (chipinfo->id == BCMA_CHIP_ID_BCM4716)
5609*b4c3e9b5SBjoern A. Zeeb 		return true;
5610*b4c3e9b5SBjoern A. Zeeb 
5611*b4c3e9b5SBjoern A. Zeeb 	pr_err("unknown chip id %04x\n", chipinfo->id);
5612*b4c3e9b5SBjoern A. Zeeb 	return false;
5613*b4c3e9b5SBjoern A. Zeeb }
5614*b4c3e9b5SBjoern A. Zeeb 
brcms_c_chipmatch(struct bcma_device * core)5615*b4c3e9b5SBjoern A. Zeeb bool brcms_c_chipmatch(struct bcma_device *core)
5616*b4c3e9b5SBjoern A. Zeeb {
5617*b4c3e9b5SBjoern A. Zeeb 	switch (core->bus->hosttype) {
5618*b4c3e9b5SBjoern A. Zeeb 	case BCMA_HOSTTYPE_PCI:
5619*b4c3e9b5SBjoern A. Zeeb 		return brcms_c_chipmatch_pci(core);
5620*b4c3e9b5SBjoern A. Zeeb 	case BCMA_HOSTTYPE_SOC:
5621*b4c3e9b5SBjoern A. Zeeb 		return brcms_c_chipmatch_soc(core);
5622*b4c3e9b5SBjoern A. Zeeb 	default:
5623*b4c3e9b5SBjoern A. Zeeb 		pr_err("unknown host type: %i\n", core->bus->hosttype);
5624*b4c3e9b5SBjoern A. Zeeb 		return false;
5625*b4c3e9b5SBjoern A. Zeeb 	}
5626*b4c3e9b5SBjoern A. Zeeb }
5627*b4c3e9b5SBjoern A. Zeeb 
brcms_b_rate_shm_offset(struct brcms_hardware * wlc_hw,u8 rate)5628*b4c3e9b5SBjoern A. Zeeb u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)
5629*b4c3e9b5SBjoern A. Zeeb {
5630*b4c3e9b5SBjoern A. Zeeb 	u16 table_ptr;
5631*b4c3e9b5SBjoern A. Zeeb 	u8 phy_rate, index;
5632*b4c3e9b5SBjoern A. Zeeb 
5633*b4c3e9b5SBjoern A. Zeeb 	/* get the phy specific rate encoding for the PLCP SIGNAL field */
5634*b4c3e9b5SBjoern A. Zeeb 	if (is_ofdm_rate(rate))
5635*b4c3e9b5SBjoern A. Zeeb 		table_ptr = M_RT_DIRMAP_A;
5636*b4c3e9b5SBjoern A. Zeeb 	else
5637*b4c3e9b5SBjoern A. Zeeb 		table_ptr = M_RT_DIRMAP_B;
5638*b4c3e9b5SBjoern A. Zeeb 
5639*b4c3e9b5SBjoern A. Zeeb 	/* for a given rate, the LS-nibble of the PLCP SIGNAL field is
5640*b4c3e9b5SBjoern A. Zeeb 	 * the index into the rate table.
5641*b4c3e9b5SBjoern A. Zeeb 	 */
5642*b4c3e9b5SBjoern A. Zeeb 	phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
5643*b4c3e9b5SBjoern A. Zeeb 	index = phy_rate & 0xf;
5644*b4c3e9b5SBjoern A. Zeeb 
5645*b4c3e9b5SBjoern A. Zeeb 	/* Find the SHM pointer to the rate table entry by looking in the
5646*b4c3e9b5SBjoern A. Zeeb 	 * Direct-map Table
5647*b4c3e9b5SBjoern A. Zeeb 	 */
5648*b4c3e9b5SBjoern A. Zeeb 	return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2));
5649*b4c3e9b5SBjoern A. Zeeb }
5650*b4c3e9b5SBjoern A. Zeeb 
5651*b4c3e9b5SBjoern A. Zeeb /*
5652*b4c3e9b5SBjoern A. Zeeb  * bcmc_fid_generate:
5653*b4c3e9b5SBjoern A. Zeeb  * Generate frame ID for a BCMC packet.  The frag field is not used
5654*b4c3e9b5SBjoern A. Zeeb  * for MC frames so is used as part of the sequence number.
5655*b4c3e9b5SBjoern A. Zeeb  */
5656*b4c3e9b5SBjoern A. Zeeb static inline u16
bcmc_fid_generate(struct brcms_c_info * wlc,struct brcms_bss_cfg * bsscfg,struct d11txh * txh)5657*b4c3e9b5SBjoern A. Zeeb bcmc_fid_generate(struct brcms_c_info *wlc, struct brcms_bss_cfg *bsscfg,
5658*b4c3e9b5SBjoern A. Zeeb 		  struct d11txh *txh)
5659*b4c3e9b5SBjoern A. Zeeb {
5660*b4c3e9b5SBjoern A. Zeeb 	u16 frameid;
5661*b4c3e9b5SBjoern A. Zeeb 
5662*b4c3e9b5SBjoern A. Zeeb 	frameid = le16_to_cpu(txh->TxFrameID) & ~(TXFID_SEQ_MASK |
5663*b4c3e9b5SBjoern A. Zeeb 						  TXFID_QUEUE_MASK);
5664*b4c3e9b5SBjoern A. Zeeb 	frameid |=
5665*b4c3e9b5SBjoern A. Zeeb 	    (((wlc->
5666*b4c3e9b5SBjoern A. Zeeb 	       mc_fid_counter++) << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
5667*b4c3e9b5SBjoern A. Zeeb 	    TX_BCMC_FIFO;
5668*b4c3e9b5SBjoern A. Zeeb 
5669*b4c3e9b5SBjoern A. Zeeb 	return frameid;
5670*b4c3e9b5SBjoern A. Zeeb }
5671*b4c3e9b5SBjoern A. Zeeb 
5672*b4c3e9b5SBjoern A. Zeeb static uint
brcms_c_calc_ack_time(struct brcms_c_info * wlc,u32 rspec,u8 preamble_type)5673*b4c3e9b5SBjoern A. Zeeb brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec,
5674*b4c3e9b5SBjoern A. Zeeb 		      u8 preamble_type)
5675*b4c3e9b5SBjoern A. Zeeb {
5676*b4c3e9b5SBjoern A. Zeeb 	uint dur = 0;
5677*b4c3e9b5SBjoern A. Zeeb 
5678*b4c3e9b5SBjoern A. Zeeb 	/*
5679*b4c3e9b5SBjoern A. Zeeb 	 * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
5680*b4c3e9b5SBjoern A. Zeeb 	 * is less than or equal to the rate of the immediately previous
5681*b4c3e9b5SBjoern A. Zeeb 	 * frame in the FES
5682*b4c3e9b5SBjoern A. Zeeb 	 */
5683*b4c3e9b5SBjoern A. Zeeb 	rspec = brcms_basic_rate(wlc, rspec);
5684*b4c3e9b5SBjoern A. Zeeb 	/* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */
5685*b4c3e9b5SBjoern A. Zeeb 	dur =
5686*b4c3e9b5SBjoern A. Zeeb 	    brcms_c_calc_frame_time(wlc, rspec, preamble_type,
5687*b4c3e9b5SBjoern A. Zeeb 				(DOT11_ACK_LEN + FCS_LEN));
5688*b4c3e9b5SBjoern A. Zeeb 	return dur;
5689*b4c3e9b5SBjoern A. Zeeb }
5690*b4c3e9b5SBjoern A. Zeeb 
5691*b4c3e9b5SBjoern A. Zeeb static uint
brcms_c_calc_cts_time(struct brcms_c_info * wlc,u32 rspec,u8 preamble_type)5692*b4c3e9b5SBjoern A. Zeeb brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec,
5693*b4c3e9b5SBjoern A. Zeeb 		      u8 preamble_type)
5694*b4c3e9b5SBjoern A. Zeeb {
5695*b4c3e9b5SBjoern A. Zeeb 	return brcms_c_calc_ack_time(wlc, rspec, preamble_type);
5696*b4c3e9b5SBjoern A. Zeeb }
5697*b4c3e9b5SBjoern A. Zeeb 
5698*b4c3e9b5SBjoern A. Zeeb static uint
brcms_c_calc_ba_time(struct brcms_c_info * wlc,u32 rspec,u8 preamble_type)5699*b4c3e9b5SBjoern A. Zeeb brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec,
5700*b4c3e9b5SBjoern A. Zeeb 		     u8 preamble_type)
5701*b4c3e9b5SBjoern A. Zeeb {
5702*b4c3e9b5SBjoern A. Zeeb 	/*
5703*b4c3e9b5SBjoern A. Zeeb 	 * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
5704*b4c3e9b5SBjoern A. Zeeb 	 * is less than or equal to the rate of the immediately previous
5705*b4c3e9b5SBjoern A. Zeeb 	 * frame in the FES
5706*b4c3e9b5SBjoern A. Zeeb 	 */
5707*b4c3e9b5SBjoern A. Zeeb 	rspec = brcms_basic_rate(wlc, rspec);
5708*b4c3e9b5SBjoern A. Zeeb 	/* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */
5709*b4c3e9b5SBjoern A. Zeeb 	return brcms_c_calc_frame_time(wlc, rspec, preamble_type,
5710*b4c3e9b5SBjoern A. Zeeb 				   (DOT11_BA_LEN + DOT11_BA_BITMAP_LEN +
5711*b4c3e9b5SBjoern A. Zeeb 				    FCS_LEN));
5712*b4c3e9b5SBjoern A. Zeeb }
5713*b4c3e9b5SBjoern A. Zeeb 
5714*b4c3e9b5SBjoern A. Zeeb /* brcms_c_compute_frame_dur()
5715*b4c3e9b5SBjoern A. Zeeb  *
5716*b4c3e9b5SBjoern A. Zeeb  * Calculate the 802.11 MAC header DUR field for MPDU
5717*b4c3e9b5SBjoern A. Zeeb  * DUR for a single frame = 1 SIFS + 1 ACK
5718*b4c3e9b5SBjoern A. Zeeb  * DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time
5719*b4c3e9b5SBjoern A. Zeeb  *
5720*b4c3e9b5SBjoern A. Zeeb  * rate			MPDU rate in unit of 500kbps
5721*b4c3e9b5SBjoern A. Zeeb  * next_frag_len	next MPDU length in bytes
5722*b4c3e9b5SBjoern A. Zeeb  * preamble_type	use short/GF or long/MM PLCP header
5723*b4c3e9b5SBjoern A. Zeeb  */
5724*b4c3e9b5SBjoern A. Zeeb static u16
brcms_c_compute_frame_dur(struct brcms_c_info * wlc,u32 rate,u8 preamble_type,uint next_frag_len)5725*b4c3e9b5SBjoern A. Zeeb brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate,
5726*b4c3e9b5SBjoern A. Zeeb 		      u8 preamble_type, uint next_frag_len)
5727*b4c3e9b5SBjoern A. Zeeb {
5728*b4c3e9b5SBjoern A. Zeeb 	u16 dur, sifs;
5729*b4c3e9b5SBjoern A. Zeeb 
5730*b4c3e9b5SBjoern A. Zeeb 	sifs = get_sifs(wlc->band);
5731*b4c3e9b5SBjoern A. Zeeb 
5732*b4c3e9b5SBjoern A. Zeeb 	dur = sifs;
5733*b4c3e9b5SBjoern A. Zeeb 	dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type);
5734*b4c3e9b5SBjoern A. Zeeb 
5735*b4c3e9b5SBjoern A. Zeeb 	if (next_frag_len) {
5736*b4c3e9b5SBjoern A. Zeeb 		/* Double the current DUR to get 2 SIFS + 2 ACKs */
5737*b4c3e9b5SBjoern A. Zeeb 		dur *= 2;
5738*b4c3e9b5SBjoern A. Zeeb 		/* add another SIFS and the frag time */
5739*b4c3e9b5SBjoern A. Zeeb 		dur += sifs;
5740*b4c3e9b5SBjoern A. Zeeb 		dur +=
5741*b4c3e9b5SBjoern A. Zeeb 		    (u16) brcms_c_calc_frame_time(wlc, rate, preamble_type,
5742*b4c3e9b5SBjoern A. Zeeb 						 next_frag_len);
5743*b4c3e9b5SBjoern A. Zeeb 	}
5744*b4c3e9b5SBjoern A. Zeeb 	return dur;
5745*b4c3e9b5SBjoern A. Zeeb }
5746*b4c3e9b5SBjoern A. Zeeb 
5747*b4c3e9b5SBjoern A. Zeeb /* The opposite of brcms_c_calc_frame_time */
5748*b4c3e9b5SBjoern A. Zeeb static uint
brcms_c_calc_frame_len(struct brcms_c_info * wlc,u32 ratespec,u8 preamble_type,uint dur)5749*b4c3e9b5SBjoern A. Zeeb brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec,
5750*b4c3e9b5SBjoern A. Zeeb 		   u8 preamble_type, uint dur)
5751*b4c3e9b5SBjoern A. Zeeb {
5752*b4c3e9b5SBjoern A. Zeeb 	uint nsyms, mac_len, Ndps, kNdps;
5753*b4c3e9b5SBjoern A. Zeeb 	uint rate = rspec2rate(ratespec);
5754*b4c3e9b5SBjoern A. Zeeb 
5755*b4c3e9b5SBjoern A. Zeeb 	if (is_mcs_rate(ratespec)) {
5756*b4c3e9b5SBjoern A. Zeeb 		uint mcs = ratespec & RSPEC_RATE_MASK;
5757*b4c3e9b5SBjoern A. Zeeb 		int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
5758*b4c3e9b5SBjoern A. Zeeb 		dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
5759*b4c3e9b5SBjoern A. Zeeb 		/* payload calculation matches that of regular ofdm */
5760*b4c3e9b5SBjoern A. Zeeb 		if (wlc->band->bandtype == BRCM_BAND_2G)
5761*b4c3e9b5SBjoern A. Zeeb 			dur -= DOT11_OFDM_SIGNAL_EXTENSION;
5762*b4c3e9b5SBjoern A. Zeeb 		/* kNdbps = kbps * 4 */
5763*b4c3e9b5SBjoern A. Zeeb 		kNdps =	mcs_2_rate(mcs, rspec_is40mhz(ratespec),
5764*b4c3e9b5SBjoern A. Zeeb 				   rspec_issgi(ratespec)) * 4;
5765*b4c3e9b5SBjoern A. Zeeb 		nsyms = dur / APHY_SYMBOL_TIME;
5766*b4c3e9b5SBjoern A. Zeeb 		mac_len =
5767*b4c3e9b5SBjoern A. Zeeb 		    ((nsyms * kNdps) -
5768*b4c3e9b5SBjoern A. Zeeb 		     ((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000;
5769*b4c3e9b5SBjoern A. Zeeb 	} else if (is_ofdm_rate(ratespec)) {
5770*b4c3e9b5SBjoern A. Zeeb 		dur -= APHY_PREAMBLE_TIME;
5771*b4c3e9b5SBjoern A. Zeeb 		dur -= APHY_SIGNAL_TIME;
5772*b4c3e9b5SBjoern A. Zeeb 		/* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
5773*b4c3e9b5SBjoern A. Zeeb 		Ndps = rate * 2;
5774*b4c3e9b5SBjoern A. Zeeb 		nsyms = dur / APHY_SYMBOL_TIME;
5775*b4c3e9b5SBjoern A. Zeeb 		mac_len =
5776*b4c3e9b5SBjoern A. Zeeb 		    ((nsyms * Ndps) -
5777*b4c3e9b5SBjoern A. Zeeb 		     (APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8;
5778*b4c3e9b5SBjoern A. Zeeb 	} else {
5779*b4c3e9b5SBjoern A. Zeeb 		if (preamble_type & BRCMS_SHORT_PREAMBLE)
5780*b4c3e9b5SBjoern A. Zeeb 			dur -= BPHY_PLCP_SHORT_TIME;
5781*b4c3e9b5SBjoern A. Zeeb 		else
5782*b4c3e9b5SBjoern A. Zeeb 			dur -= BPHY_PLCP_TIME;
5783*b4c3e9b5SBjoern A. Zeeb 		mac_len = dur * rate;
5784*b4c3e9b5SBjoern A. Zeeb 		/* divide out factor of 2 in rate (1/2 mbps) */
5785*b4c3e9b5SBjoern A. Zeeb 		mac_len = mac_len / 8 / 2;
5786*b4c3e9b5SBjoern A. Zeeb 	}
5787*b4c3e9b5SBjoern A. Zeeb 	return mac_len;
5788*b4c3e9b5SBjoern A. Zeeb }
5789*b4c3e9b5SBjoern A. Zeeb 
5790*b4c3e9b5SBjoern A. Zeeb /*
5791*b4c3e9b5SBjoern A. Zeeb  * Return true if the specified rate is supported by the specified band.
5792*b4c3e9b5SBjoern A. Zeeb  * BRCM_BAND_AUTO indicates the current band.
5793*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_valid_rate(struct brcms_c_info * wlc,u32 rspec,int band,bool verbose)5794*b4c3e9b5SBjoern A. Zeeb static bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band,
5795*b4c3e9b5SBjoern A. Zeeb 		    bool verbose)
5796*b4c3e9b5SBjoern A. Zeeb {
5797*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_rateset *hw_rateset;
5798*b4c3e9b5SBjoern A. Zeeb 	uint i;
5799*b4c3e9b5SBjoern A. Zeeb 
5800*b4c3e9b5SBjoern A. Zeeb 	if ((band == BRCM_BAND_AUTO) || (band == wlc->band->bandtype))
5801*b4c3e9b5SBjoern A. Zeeb 		hw_rateset = &wlc->band->hw_rateset;
5802*b4c3e9b5SBjoern A. Zeeb 	else if (wlc->pub->_nbands > 1)
5803*b4c3e9b5SBjoern A. Zeeb 		hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset;
5804*b4c3e9b5SBjoern A. Zeeb 	else
5805*b4c3e9b5SBjoern A. Zeeb 		/* other band specified and we are a single band device */
5806*b4c3e9b5SBjoern A. Zeeb 		return false;
5807*b4c3e9b5SBjoern A. Zeeb 
5808*b4c3e9b5SBjoern A. Zeeb 	/* check if this is a mimo rate */
5809*b4c3e9b5SBjoern A. Zeeb 	if (is_mcs_rate(rspec)) {
5810*b4c3e9b5SBjoern A. Zeeb 		if ((rspec & RSPEC_RATE_MASK) >= MCS_TABLE_SIZE)
5811*b4c3e9b5SBjoern A. Zeeb 			goto error;
5812*b4c3e9b5SBjoern A. Zeeb 
5813*b4c3e9b5SBjoern A. Zeeb 		return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK));
5814*b4c3e9b5SBjoern A. Zeeb 	}
5815*b4c3e9b5SBjoern A. Zeeb 
5816*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < hw_rateset->count; i++)
5817*b4c3e9b5SBjoern A. Zeeb 		if (hw_rateset->rates[i] == rspec2rate(rspec))
5818*b4c3e9b5SBjoern A. Zeeb 			return true;
5819*b4c3e9b5SBjoern A. Zeeb  error:
5820*b4c3e9b5SBjoern A. Zeeb 	if (verbose)
5821*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "wl%d: valid_rate: rate spec 0x%x "
5822*b4c3e9b5SBjoern A. Zeeb 			  "not in hw_rateset\n", wlc->pub->unit, rspec);
5823*b4c3e9b5SBjoern A. Zeeb 
5824*b4c3e9b5SBjoern A. Zeeb 	return false;
5825*b4c3e9b5SBjoern A. Zeeb }
5826*b4c3e9b5SBjoern A. Zeeb 
5827*b4c3e9b5SBjoern A. Zeeb static u32
mac80211_wlc_set_nrate(struct brcms_c_info * wlc,struct brcms_band * cur_band,u32 int_val)5828*b4c3e9b5SBjoern A. Zeeb mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
5829*b4c3e9b5SBjoern A. Zeeb 		       u32 int_val)
5830*b4c3e9b5SBjoern A. Zeeb {
5831*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc->hw->d11core;
5832*b4c3e9b5SBjoern A. Zeeb 	u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT;
5833*b4c3e9b5SBjoern A. Zeeb 	u8 rate = int_val & NRATE_RATE_MASK;
5834*b4c3e9b5SBjoern A. Zeeb 	u32 rspec;
5835*b4c3e9b5SBjoern A. Zeeb 	bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE);
5836*b4c3e9b5SBjoern A. Zeeb 	bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT);
5837*b4c3e9b5SBjoern A. Zeeb 	bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY)
5838*b4c3e9b5SBjoern A. Zeeb 				  == NRATE_OVERRIDE_MCS_ONLY);
5839*b4c3e9b5SBjoern A. Zeeb 
5840*b4c3e9b5SBjoern A. Zeeb 	if (!ismcs)
5841*b4c3e9b5SBjoern A. Zeeb 		return (u32) rate;
5842*b4c3e9b5SBjoern A. Zeeb 
5843*b4c3e9b5SBjoern A. Zeeb 	/* validate the combination of rate/mcs/stf is allowed */
5844*b4c3e9b5SBjoern A. Zeeb 	if ((wlc->pub->_n_enab & SUPPORT_11N) && ismcs) {
5845*b4c3e9b5SBjoern A. Zeeb 		/* mcs only allowed when nmode */
5846*b4c3e9b5SBjoern A. Zeeb 		if (stf > PHY_TXC1_MODE_SDM) {
5847*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "wl%d: %s: Invalid stf\n",
5848*b4c3e9b5SBjoern A. Zeeb 				  wlc->pub->unit, __func__);
5849*b4c3e9b5SBjoern A. Zeeb 			goto done;
5850*b4c3e9b5SBjoern A. Zeeb 		}
5851*b4c3e9b5SBjoern A. Zeeb 
5852*b4c3e9b5SBjoern A. Zeeb 		/* mcs 32 is a special case, DUP mode 40 only */
5853*b4c3e9b5SBjoern A. Zeeb 		if (rate == 32) {
5854*b4c3e9b5SBjoern A. Zeeb 			if (!CHSPEC_IS40(wlc->home_chanspec) ||
5855*b4c3e9b5SBjoern A. Zeeb 			    ((stf != PHY_TXC1_MODE_SISO)
5856*b4c3e9b5SBjoern A. Zeeb 			     && (stf != PHY_TXC1_MODE_CDD))) {
5857*b4c3e9b5SBjoern A. Zeeb 				brcms_err(core, "wl%d: %s: Invalid mcs 32\n",
5858*b4c3e9b5SBjoern A. Zeeb 					  wlc->pub->unit, __func__);
5859*b4c3e9b5SBjoern A. Zeeb 				goto done;
5860*b4c3e9b5SBjoern A. Zeeb 			}
5861*b4c3e9b5SBjoern A. Zeeb 			/* mcs > 7 must use stf SDM */
5862*b4c3e9b5SBjoern A. Zeeb 		} else if (rate > HIGHEST_SINGLE_STREAM_MCS) {
5863*b4c3e9b5SBjoern A. Zeeb 			/* mcs > 7 must use stf SDM */
5864*b4c3e9b5SBjoern A. Zeeb 			if (stf != PHY_TXC1_MODE_SDM) {
5865*b4c3e9b5SBjoern A. Zeeb 				brcms_dbg_mac80211(core, "wl%d: enabling "
5866*b4c3e9b5SBjoern A. Zeeb 						   "SDM mode for mcs %d\n",
5867*b4c3e9b5SBjoern A. Zeeb 						   wlc->pub->unit, rate);
5868*b4c3e9b5SBjoern A. Zeeb 				stf = PHY_TXC1_MODE_SDM;
5869*b4c3e9b5SBjoern A. Zeeb 			}
5870*b4c3e9b5SBjoern A. Zeeb 		} else {
5871*b4c3e9b5SBjoern A. Zeeb 			/*
5872*b4c3e9b5SBjoern A. Zeeb 			 * MCS 0-7 may use SISO, CDD, and for
5873*b4c3e9b5SBjoern A. Zeeb 			 * phy_rev >= 3 STBC
5874*b4c3e9b5SBjoern A. Zeeb 			 */
5875*b4c3e9b5SBjoern A. Zeeb 			if ((stf > PHY_TXC1_MODE_STBC) ||
5876*b4c3e9b5SBjoern A. Zeeb 			    (!BRCMS_STBC_CAP_PHY(wlc)
5877*b4c3e9b5SBjoern A. Zeeb 			     && (stf == PHY_TXC1_MODE_STBC))) {
5878*b4c3e9b5SBjoern A. Zeeb 				brcms_err(core, "wl%d: %s: Invalid STBC\n",
5879*b4c3e9b5SBjoern A. Zeeb 					  wlc->pub->unit, __func__);
5880*b4c3e9b5SBjoern A. Zeeb 				goto done;
5881*b4c3e9b5SBjoern A. Zeeb 			}
5882*b4c3e9b5SBjoern A. Zeeb 		}
5883*b4c3e9b5SBjoern A. Zeeb 	} else if (is_ofdm_rate(rate)) {
5884*b4c3e9b5SBjoern A. Zeeb 		if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {
5885*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "wl%d: %s: Invalid OFDM\n",
5886*b4c3e9b5SBjoern A. Zeeb 				  wlc->pub->unit, __func__);
5887*b4c3e9b5SBjoern A. Zeeb 			goto done;
5888*b4c3e9b5SBjoern A. Zeeb 		}
5889*b4c3e9b5SBjoern A. Zeeb 	} else if (is_cck_rate(rate)) {
5890*b4c3e9b5SBjoern A. Zeeb 		if ((cur_band->bandtype != BRCM_BAND_2G)
5891*b4c3e9b5SBjoern A. Zeeb 		    || (stf != PHY_TXC1_MODE_SISO)) {
5892*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "wl%d: %s: Invalid CCK\n",
5893*b4c3e9b5SBjoern A. Zeeb 				  wlc->pub->unit, __func__);
5894*b4c3e9b5SBjoern A. Zeeb 			goto done;
5895*b4c3e9b5SBjoern A. Zeeb 		}
5896*b4c3e9b5SBjoern A. Zeeb 	} else {
5897*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "wl%d: %s: Unknown rate type\n",
5898*b4c3e9b5SBjoern A. Zeeb 			  wlc->pub->unit, __func__);
5899*b4c3e9b5SBjoern A. Zeeb 		goto done;
5900*b4c3e9b5SBjoern A. Zeeb 	}
5901*b4c3e9b5SBjoern A. Zeeb 	/* make sure multiple antennae are available for non-siso rates */
5902*b4c3e9b5SBjoern A. Zeeb 	if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) {
5903*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "wl%d: %s: SISO antenna but !SISO "
5904*b4c3e9b5SBjoern A. Zeeb 			  "request\n", wlc->pub->unit, __func__);
5905*b4c3e9b5SBjoern A. Zeeb 		goto done;
5906*b4c3e9b5SBjoern A. Zeeb 	}
5907*b4c3e9b5SBjoern A. Zeeb 
5908*b4c3e9b5SBjoern A. Zeeb 	rspec = rate;
5909*b4c3e9b5SBjoern A. Zeeb 	if (ismcs) {
5910*b4c3e9b5SBjoern A. Zeeb 		rspec |= RSPEC_MIMORATE;
5911*b4c3e9b5SBjoern A. Zeeb 		/* For STBC populate the STC field of the ratespec */
5912*b4c3e9b5SBjoern A. Zeeb 		if (stf == PHY_TXC1_MODE_STBC) {
5913*b4c3e9b5SBjoern A. Zeeb 			u8 stc;
5914*b4c3e9b5SBjoern A. Zeeb 			stc = 1;	/* Nss for single stream is always 1 */
5915*b4c3e9b5SBjoern A. Zeeb 			rspec |= (stc << RSPEC_STC_SHIFT);
5916*b4c3e9b5SBjoern A. Zeeb 		}
5917*b4c3e9b5SBjoern A. Zeeb 	}
5918*b4c3e9b5SBjoern A. Zeeb 
5919*b4c3e9b5SBjoern A. Zeeb 	rspec |= (stf << RSPEC_STF_SHIFT);
5920*b4c3e9b5SBjoern A. Zeeb 
5921*b4c3e9b5SBjoern A. Zeeb 	if (override_mcs_only)
5922*b4c3e9b5SBjoern A. Zeeb 		rspec |= RSPEC_OVERRIDE_MCS_ONLY;
5923*b4c3e9b5SBjoern A. Zeeb 
5924*b4c3e9b5SBjoern A. Zeeb 	if (issgi)
5925*b4c3e9b5SBjoern A. Zeeb 		rspec |= RSPEC_SHORT_GI;
5926*b4c3e9b5SBjoern A. Zeeb 
5927*b4c3e9b5SBjoern A. Zeeb 	if ((rate != 0)
5928*b4c3e9b5SBjoern A. Zeeb 	    && !brcms_c_valid_rate(wlc, rspec, cur_band->bandtype, true))
5929*b4c3e9b5SBjoern A. Zeeb 		return rate;
5930*b4c3e9b5SBjoern A. Zeeb 
5931*b4c3e9b5SBjoern A. Zeeb 	return rspec;
5932*b4c3e9b5SBjoern A. Zeeb done:
5933*b4c3e9b5SBjoern A. Zeeb 	return rate;
5934*b4c3e9b5SBjoern A. Zeeb }
5935*b4c3e9b5SBjoern A. Zeeb 
5936*b4c3e9b5SBjoern A. Zeeb /*
5937*b4c3e9b5SBjoern A. Zeeb  * Compute PLCP, but only requires actual rate and length of pkt.
5938*b4c3e9b5SBjoern A. Zeeb  * Rate is given in the driver standard multiple of 500 kbps.
5939*b4c3e9b5SBjoern A. Zeeb  * le is set for 11 Mbps rate if necessary.
5940*b4c3e9b5SBjoern A. Zeeb  * Broken out for PRQ.
5941*b4c3e9b5SBjoern A. Zeeb  */
5942*b4c3e9b5SBjoern A. Zeeb 
brcms_c_cck_plcp_set(struct brcms_c_info * wlc,int rate_500,uint length,u8 * plcp)5943*b4c3e9b5SBjoern A. Zeeb static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500,
5944*b4c3e9b5SBjoern A. Zeeb 			     uint length, u8 *plcp)
5945*b4c3e9b5SBjoern A. Zeeb {
5946*b4c3e9b5SBjoern A. Zeeb 	u16 usec = 0;
5947*b4c3e9b5SBjoern A. Zeeb 	u8 le = 0;
5948*b4c3e9b5SBjoern A. Zeeb 
5949*b4c3e9b5SBjoern A. Zeeb 	switch (rate_500) {
5950*b4c3e9b5SBjoern A. Zeeb 	case BRCM_RATE_1M:
5951*b4c3e9b5SBjoern A. Zeeb 		usec = length << 3;
5952*b4c3e9b5SBjoern A. Zeeb 		break;
5953*b4c3e9b5SBjoern A. Zeeb 	case BRCM_RATE_2M:
5954*b4c3e9b5SBjoern A. Zeeb 		usec = length << 2;
5955*b4c3e9b5SBjoern A. Zeeb 		break;
5956*b4c3e9b5SBjoern A. Zeeb 	case BRCM_RATE_5M5:
5957*b4c3e9b5SBjoern A. Zeeb 		usec = (length << 4) / 11;
5958*b4c3e9b5SBjoern A. Zeeb 		if ((length << 4) - (usec * 11) > 0)
5959*b4c3e9b5SBjoern A. Zeeb 			usec++;
5960*b4c3e9b5SBjoern A. Zeeb 		break;
5961*b4c3e9b5SBjoern A. Zeeb 	case BRCM_RATE_11M:
5962*b4c3e9b5SBjoern A. Zeeb 		usec = (length << 3) / 11;
5963*b4c3e9b5SBjoern A. Zeeb 		if ((length << 3) - (usec * 11) > 0) {
5964*b4c3e9b5SBjoern A. Zeeb 			usec++;
5965*b4c3e9b5SBjoern A. Zeeb 			if ((usec * 11) - (length << 3) >= 8)
5966*b4c3e9b5SBjoern A. Zeeb 				le = D11B_PLCP_SIGNAL_LE;
5967*b4c3e9b5SBjoern A. Zeeb 		}
5968*b4c3e9b5SBjoern A. Zeeb 		break;
5969*b4c3e9b5SBjoern A. Zeeb 
5970*b4c3e9b5SBjoern A. Zeeb 	default:
5971*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core,
5972*b4c3e9b5SBjoern A. Zeeb 			  "brcms_c_cck_plcp_set: unsupported rate %d\n",
5973*b4c3e9b5SBjoern A. Zeeb 			  rate_500);
5974*b4c3e9b5SBjoern A. Zeeb 		rate_500 = BRCM_RATE_1M;
5975*b4c3e9b5SBjoern A. Zeeb 		usec = length << 3;
5976*b4c3e9b5SBjoern A. Zeeb 		break;
5977*b4c3e9b5SBjoern A. Zeeb 	}
5978*b4c3e9b5SBjoern A. Zeeb 	/* PLCP signal byte */
5979*b4c3e9b5SBjoern A. Zeeb 	plcp[0] = rate_500 * 5;	/* r (500kbps) * 5 == r (100kbps) */
5980*b4c3e9b5SBjoern A. Zeeb 	/* PLCP service byte */
5981*b4c3e9b5SBjoern A. Zeeb 	plcp[1] = (u8) (le | D11B_PLCP_SIGNAL_LOCKED);
5982*b4c3e9b5SBjoern A. Zeeb 	/* PLCP length u16, little endian */
5983*b4c3e9b5SBjoern A. Zeeb 	plcp[2] = usec & 0xff;
5984*b4c3e9b5SBjoern A. Zeeb 	plcp[3] = (usec >> 8) & 0xff;
5985*b4c3e9b5SBjoern A. Zeeb 	/* PLCP CRC16 */
5986*b4c3e9b5SBjoern A. Zeeb 	plcp[4] = 0;
5987*b4c3e9b5SBjoern A. Zeeb 	plcp[5] = 0;
5988*b4c3e9b5SBjoern A. Zeeb }
5989*b4c3e9b5SBjoern A. Zeeb 
5990*b4c3e9b5SBjoern A. Zeeb /* Rate: 802.11 rate code, length: PSDU length in octets */
brcms_c_compute_mimo_plcp(u32 rspec,uint length,u8 * plcp)5991*b4c3e9b5SBjoern A. Zeeb static void brcms_c_compute_mimo_plcp(u32 rspec, uint length, u8 *plcp)
5992*b4c3e9b5SBjoern A. Zeeb {
5993*b4c3e9b5SBjoern A. Zeeb 	u8 mcs = (u8) (rspec & RSPEC_RATE_MASK);
5994*b4c3e9b5SBjoern A. Zeeb 	plcp[0] = mcs;
5995*b4c3e9b5SBjoern A. Zeeb 	if (rspec_is40mhz(rspec) || (mcs == 32))
5996*b4c3e9b5SBjoern A. Zeeb 		plcp[0] |= MIMO_PLCP_40MHZ;
5997*b4c3e9b5SBjoern A. Zeeb 	BRCMS_SET_MIMO_PLCP_LEN(plcp, length);
5998*b4c3e9b5SBjoern A. Zeeb 	plcp[3] = rspec_mimoplcp3(rspec); /* rspec already holds this byte */
5999*b4c3e9b5SBjoern A. Zeeb 	plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */
6000*b4c3e9b5SBjoern A. Zeeb 	plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */
6001*b4c3e9b5SBjoern A. Zeeb 	plcp[5] = 0;
6002*b4c3e9b5SBjoern A. Zeeb }
6003*b4c3e9b5SBjoern A. Zeeb 
6004*b4c3e9b5SBjoern A. Zeeb /* Rate: 802.11 rate code, length: PSDU length in octets */
6005*b4c3e9b5SBjoern A. Zeeb static void
brcms_c_compute_ofdm_plcp(u32 rspec,u32 length,u8 * plcp)6006*b4c3e9b5SBjoern A. Zeeb brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp)
6007*b4c3e9b5SBjoern A. Zeeb {
6008*b4c3e9b5SBjoern A. Zeeb 	u8 rate_signal;
6009*b4c3e9b5SBjoern A. Zeeb 	u32 tmp = 0;
6010*b4c3e9b5SBjoern A. Zeeb 	int rate = rspec2rate(rspec);
6011*b4c3e9b5SBjoern A. Zeeb 
6012*b4c3e9b5SBjoern A. Zeeb 	/*
6013*b4c3e9b5SBjoern A. Zeeb 	 * encode rate per 802.11a-1999 sec 17.3.4.1, with lsb
6014*b4c3e9b5SBjoern A. Zeeb 	 * transmitted first
6015*b4c3e9b5SBjoern A. Zeeb 	 */
6016*b4c3e9b5SBjoern A. Zeeb 	rate_signal = rate_info[rate] & BRCMS_RATE_MASK;
6017*b4c3e9b5SBjoern A. Zeeb 	memset(plcp, 0, D11_PHY_HDR_LEN);
6018*b4c3e9b5SBjoern A. Zeeb 	D11A_PHY_HDR_SRATE((struct ofdm_phy_hdr *) plcp, rate_signal);
6019*b4c3e9b5SBjoern A. Zeeb 
6020*b4c3e9b5SBjoern A. Zeeb 	tmp = (length & 0xfff) << 5;
6021*b4c3e9b5SBjoern A. Zeeb 	plcp[2] |= (tmp >> 16) & 0xff;
6022*b4c3e9b5SBjoern A. Zeeb 	plcp[1] |= (tmp >> 8) & 0xff;
6023*b4c3e9b5SBjoern A. Zeeb 	plcp[0] |= tmp & 0xff;
6024*b4c3e9b5SBjoern A. Zeeb }
6025*b4c3e9b5SBjoern A. Zeeb 
6026*b4c3e9b5SBjoern A. Zeeb /* Rate: 802.11 rate code, length: PSDU length in octets */
brcms_c_compute_cck_plcp(struct brcms_c_info * wlc,u32 rspec,uint length,u8 * plcp)6027*b4c3e9b5SBjoern A. Zeeb static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rspec,
6028*b4c3e9b5SBjoern A. Zeeb 				 uint length, u8 *plcp)
6029*b4c3e9b5SBjoern A. Zeeb {
6030*b4c3e9b5SBjoern A. Zeeb 	int rate = rspec2rate(rspec);
6031*b4c3e9b5SBjoern A. Zeeb 
6032*b4c3e9b5SBjoern A. Zeeb 	brcms_c_cck_plcp_set(wlc, rate, length, plcp);
6033*b4c3e9b5SBjoern A. Zeeb }
6034*b4c3e9b5SBjoern A. Zeeb 
6035*b4c3e9b5SBjoern A. Zeeb static void
brcms_c_compute_plcp(struct brcms_c_info * wlc,u32 rspec,uint length,u8 * plcp)6036*b4c3e9b5SBjoern A. Zeeb brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec,
6037*b4c3e9b5SBjoern A. Zeeb 		     uint length, u8 *plcp)
6038*b4c3e9b5SBjoern A. Zeeb {
6039*b4c3e9b5SBjoern A. Zeeb 	if (is_mcs_rate(rspec))
6040*b4c3e9b5SBjoern A. Zeeb 		brcms_c_compute_mimo_plcp(rspec, length, plcp);
6041*b4c3e9b5SBjoern A. Zeeb 	else if (is_ofdm_rate(rspec))
6042*b4c3e9b5SBjoern A. Zeeb 		brcms_c_compute_ofdm_plcp(rspec, length, plcp);
6043*b4c3e9b5SBjoern A. Zeeb 	else
6044*b4c3e9b5SBjoern A. Zeeb 		brcms_c_compute_cck_plcp(wlc, rspec, length, plcp);
6045*b4c3e9b5SBjoern A. Zeeb }
6046*b4c3e9b5SBjoern A. Zeeb 
6047*b4c3e9b5SBjoern A. Zeeb /* brcms_c_compute_rtscts_dur()
6048*b4c3e9b5SBjoern A. Zeeb  *
6049*b4c3e9b5SBjoern A. Zeeb  * Calculate the 802.11 MAC header DUR field for an RTS or CTS frame
6050*b4c3e9b5SBjoern A. Zeeb  * DUR for normal RTS/CTS w/ frame = 3 SIFS + 1 CTS + next frame time + 1 ACK
6051*b4c3e9b5SBjoern A. Zeeb  * DUR for CTS-TO-SELF w/ frame    = 2 SIFS         + next frame time + 1 ACK
6052*b4c3e9b5SBjoern A. Zeeb  *
6053*b4c3e9b5SBjoern A. Zeeb  * cts			cts-to-self or rts/cts
6054*b4c3e9b5SBjoern A. Zeeb  * rts_rate		rts or cts rate in unit of 500kbps
6055*b4c3e9b5SBjoern A. Zeeb  * rate			next MPDU rate in unit of 500kbps
6056*b4c3e9b5SBjoern A. Zeeb  * frame_len		next MPDU frame length in bytes
6057*b4c3e9b5SBjoern A. Zeeb  */
6058*b4c3e9b5SBjoern A. Zeeb u16
brcms_c_compute_rtscts_dur(struct brcms_c_info * wlc,bool cts_only,u32 rts_rate,u32 frame_rate,u8 rts_preamble_type,u8 frame_preamble_type,uint frame_len,bool ba)6059*b4c3e9b5SBjoern A. Zeeb brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
6060*b4c3e9b5SBjoern A. Zeeb 			   u32 rts_rate,
6061*b4c3e9b5SBjoern A. Zeeb 			   u32 frame_rate, u8 rts_preamble_type,
6062*b4c3e9b5SBjoern A. Zeeb 			   u8 frame_preamble_type, uint frame_len, bool ba)
6063*b4c3e9b5SBjoern A. Zeeb {
6064*b4c3e9b5SBjoern A. Zeeb 	u16 dur, sifs;
6065*b4c3e9b5SBjoern A. Zeeb 
6066*b4c3e9b5SBjoern A. Zeeb 	sifs = get_sifs(wlc->band);
6067*b4c3e9b5SBjoern A. Zeeb 
6068*b4c3e9b5SBjoern A. Zeeb 	if (!cts_only) {
6069*b4c3e9b5SBjoern A. Zeeb 		/* RTS/CTS */
6070*b4c3e9b5SBjoern A. Zeeb 		dur = 3 * sifs;
6071*b4c3e9b5SBjoern A. Zeeb 		dur +=
6072*b4c3e9b5SBjoern A. Zeeb 		    (u16) brcms_c_calc_cts_time(wlc, rts_rate,
6073*b4c3e9b5SBjoern A. Zeeb 					       rts_preamble_type);
6074*b4c3e9b5SBjoern A. Zeeb 	} else {
6075*b4c3e9b5SBjoern A. Zeeb 		/* CTS-TO-SELF */
6076*b4c3e9b5SBjoern A. Zeeb 		dur = 2 * sifs;
6077*b4c3e9b5SBjoern A. Zeeb 	}
6078*b4c3e9b5SBjoern A. Zeeb 
6079*b4c3e9b5SBjoern A. Zeeb 	dur +=
6080*b4c3e9b5SBjoern A. Zeeb 	    (u16) brcms_c_calc_frame_time(wlc, frame_rate, frame_preamble_type,
6081*b4c3e9b5SBjoern A. Zeeb 					 frame_len);
6082*b4c3e9b5SBjoern A. Zeeb 	if (ba)
6083*b4c3e9b5SBjoern A. Zeeb 		dur +=
6084*b4c3e9b5SBjoern A. Zeeb 		    (u16) brcms_c_calc_ba_time(wlc, frame_rate,
6085*b4c3e9b5SBjoern A. Zeeb 					      BRCMS_SHORT_PREAMBLE);
6086*b4c3e9b5SBjoern A. Zeeb 	else
6087*b4c3e9b5SBjoern A. Zeeb 		dur +=
6088*b4c3e9b5SBjoern A. Zeeb 		    (u16) brcms_c_calc_ack_time(wlc, frame_rate,
6089*b4c3e9b5SBjoern A. Zeeb 					       frame_preamble_type);
6090*b4c3e9b5SBjoern A. Zeeb 	return dur;
6091*b4c3e9b5SBjoern A. Zeeb }
6092*b4c3e9b5SBjoern A. Zeeb 
brcms_c_phytxctl1_calc(struct brcms_c_info * wlc,u32 rspec)6093*b4c3e9b5SBjoern A. Zeeb static u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
6094*b4c3e9b5SBjoern A. Zeeb {
6095*b4c3e9b5SBjoern A. Zeeb 	u16 phyctl1 = 0;
6096*b4c3e9b5SBjoern A. Zeeb 	u16 bw;
6097*b4c3e9b5SBjoern A. Zeeb 
6098*b4c3e9b5SBjoern A. Zeeb 	if (BRCMS_ISLCNPHY(wlc->band)) {
6099*b4c3e9b5SBjoern A. Zeeb 		bw = PHY_TXC1_BW_20MHZ;
6100*b4c3e9b5SBjoern A. Zeeb 	} else {
6101*b4c3e9b5SBjoern A. Zeeb 		bw = rspec_get_bw(rspec);
6102*b4c3e9b5SBjoern A. Zeeb 		/* 10Mhz is not supported yet */
6103*b4c3e9b5SBjoern A. Zeeb 		if (bw < PHY_TXC1_BW_20MHZ) {
6104*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc->hw->d11core, "phytxctl1_calc: bw %d is "
6105*b4c3e9b5SBjoern A. Zeeb 				  "not supported yet, set to 20L\n", bw);
6106*b4c3e9b5SBjoern A. Zeeb 			bw = PHY_TXC1_BW_20MHZ;
6107*b4c3e9b5SBjoern A. Zeeb 		}
6108*b4c3e9b5SBjoern A. Zeeb 	}
6109*b4c3e9b5SBjoern A. Zeeb 
6110*b4c3e9b5SBjoern A. Zeeb 	if (is_mcs_rate(rspec)) {
6111*b4c3e9b5SBjoern A. Zeeb 		uint mcs = rspec & RSPEC_RATE_MASK;
6112*b4c3e9b5SBjoern A. Zeeb 
6113*b4c3e9b5SBjoern A. Zeeb 		/* bw, stf, coding-type is part of rspec_phytxbyte2 returns */
6114*b4c3e9b5SBjoern A. Zeeb 		phyctl1 = rspec_phytxbyte2(rspec);
6115*b4c3e9b5SBjoern A. Zeeb 		/* set the upper byte of phyctl1 */
6116*b4c3e9b5SBjoern A. Zeeb 		phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8);
6117*b4c3e9b5SBjoern A. Zeeb 	} else if (is_cck_rate(rspec) && !BRCMS_ISLCNPHY(wlc->band)
6118*b4c3e9b5SBjoern A. Zeeb 		   && !BRCMS_ISSSLPNPHY(wlc->band)) {
6119*b4c3e9b5SBjoern A. Zeeb 		/*
6120*b4c3e9b5SBjoern A. Zeeb 		 * In CCK mode LPPHY overloads OFDM Modulation bits with CCK
6121*b4c3e9b5SBjoern A. Zeeb 		 * Data Rate. Eventually MIMOPHY would also be converted to
6122*b4c3e9b5SBjoern A. Zeeb 		 * this format
6123*b4c3e9b5SBjoern A. Zeeb 		 */
6124*b4c3e9b5SBjoern A. Zeeb 		/* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */
6125*b4c3e9b5SBjoern A. Zeeb 		phyctl1 = (bw | (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));
6126*b4c3e9b5SBjoern A. Zeeb 	} else {		/* legacy OFDM/CCK */
6127*b4c3e9b5SBjoern A. Zeeb 		s16 phycfg;
6128*b4c3e9b5SBjoern A. Zeeb 		/* get the phyctl byte from rate phycfg table */
6129*b4c3e9b5SBjoern A. Zeeb 		phycfg = brcms_c_rate_legacy_phyctl(rspec2rate(rspec));
6130*b4c3e9b5SBjoern A. Zeeb 		if (phycfg == -1) {
6131*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc->hw->d11core, "phytxctl1_calc: wrong "
6132*b4c3e9b5SBjoern A. Zeeb 				  "legacy OFDM/CCK rate\n");
6133*b4c3e9b5SBjoern A. Zeeb 			phycfg = 0;
6134*b4c3e9b5SBjoern A. Zeeb 		}
6135*b4c3e9b5SBjoern A. Zeeb 		/* set the upper byte of phyctl1 */
6136*b4c3e9b5SBjoern A. Zeeb 		phyctl1 =
6137*b4c3e9b5SBjoern A. Zeeb 		    (bw | (phycfg << 8) |
6138*b4c3e9b5SBjoern A. Zeeb 		     (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));
6139*b4c3e9b5SBjoern A. Zeeb 	}
6140*b4c3e9b5SBjoern A. Zeeb 	return phyctl1;
6141*b4c3e9b5SBjoern A. Zeeb }
6142*b4c3e9b5SBjoern A. Zeeb 
6143*b4c3e9b5SBjoern A. Zeeb /*
6144*b4c3e9b5SBjoern A. Zeeb  * Add struct d11txh, struct cck_phy_hdr.
6145*b4c3e9b5SBjoern A. Zeeb  *
6146*b4c3e9b5SBjoern A. Zeeb  * 'p' data must start with 802.11 MAC header
6147*b4c3e9b5SBjoern A. Zeeb  * 'p' must allow enough bytes of local headers to be "pushed" onto the packet
6148*b4c3e9b5SBjoern A. Zeeb  *
6149*b4c3e9b5SBjoern A. Zeeb  * headroom == D11_PHY_HDR_LEN + D11_TXH_LEN (D11_TXH_LEN is now 104 bytes)
6150*b4c3e9b5SBjoern A. Zeeb  *
6151*b4c3e9b5SBjoern A. Zeeb  */
6152*b4c3e9b5SBjoern A. Zeeb static u16
brcms_c_d11hdrs_mac80211(struct brcms_c_info * wlc,struct ieee80211_hw * hw,struct sk_buff * p,struct scb * scb,uint frag,uint nfrags,uint queue,uint next_frag_len)6153*b4c3e9b5SBjoern A. Zeeb brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
6154*b4c3e9b5SBjoern A. Zeeb 		     struct sk_buff *p, struct scb *scb, uint frag,
6155*b4c3e9b5SBjoern A. Zeeb 		     uint nfrags, uint queue, uint next_frag_len)
6156*b4c3e9b5SBjoern A. Zeeb {
6157*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_hdr *h;
6158*b4c3e9b5SBjoern A. Zeeb 	struct d11txh *txh;
6159*b4c3e9b5SBjoern A. Zeeb 	u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN];
6160*b4c3e9b5SBjoern A. Zeeb 	int len, phylen, rts_phylen;
6161*b4c3e9b5SBjoern A. Zeeb 	u16 mch, phyctl, xfts, mainrates;
6162*b4c3e9b5SBjoern A. Zeeb 	u16 seq = 0, mcl = 0, status = 0, frameid = 0;
6163*b4c3e9b5SBjoern A. Zeeb 	u32 rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
6164*b4c3e9b5SBjoern A. Zeeb 	u32 rts_rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
6165*b4c3e9b5SBjoern A. Zeeb 	bool use_rts = false;
6166*b4c3e9b5SBjoern A. Zeeb 	bool use_cts = false;
6167*b4c3e9b5SBjoern A. Zeeb 	bool use_rifs = false;
6168*b4c3e9b5SBjoern A. Zeeb 	u8 preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };
6169*b4c3e9b5SBjoern A. Zeeb 	u8 rts_preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };
6170*b4c3e9b5SBjoern A. Zeeb 	u8 *rts_plcp, rts_plcp_fallback[D11_PHY_HDR_LEN];
6171*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_rts *rts = NULL;
6172*b4c3e9b5SBjoern A. Zeeb 	bool qos;
6173*b4c3e9b5SBjoern A. Zeeb 	uint ac;
6174*b4c3e9b5SBjoern A. Zeeb 	bool hwtkmic = false;
6175*b4c3e9b5SBjoern A. Zeeb 	u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
6176*b4c3e9b5SBjoern A. Zeeb #define ANTCFG_NONE 0xFF
6177*b4c3e9b5SBjoern A. Zeeb 	u8 antcfg = ANTCFG_NONE;
6178*b4c3e9b5SBjoern A. Zeeb 	u8 fbantcfg = ANTCFG_NONE;
6179*b4c3e9b5SBjoern A. Zeeb 	uint phyctl1_stf = 0;
6180*b4c3e9b5SBjoern A. Zeeb 	u16 durid = 0;
6181*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_tx_rate *txrate[2];
6182*b4c3e9b5SBjoern A. Zeeb 	int k;
6183*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_tx_info *tx_info;
6184*b4c3e9b5SBjoern A. Zeeb 	bool is_mcs;
6185*b4c3e9b5SBjoern A. Zeeb 	u16 mimo_txbw;
6186*b4c3e9b5SBjoern A. Zeeb 	u8 mimo_preamble_type;
6187*b4c3e9b5SBjoern A. Zeeb 
6188*b4c3e9b5SBjoern A. Zeeb 	/* locate 802.11 MAC header */
6189*b4c3e9b5SBjoern A. Zeeb 	h = (struct ieee80211_hdr *)(p->data);
6190*b4c3e9b5SBjoern A. Zeeb 	qos = ieee80211_is_data_qos(h->frame_control);
6191*b4c3e9b5SBjoern A. Zeeb 
6192*b4c3e9b5SBjoern A. Zeeb 	/* compute length of frame in bytes for use in PLCP computations */
6193*b4c3e9b5SBjoern A. Zeeb 	len = p->len;
6194*b4c3e9b5SBjoern A. Zeeb 	phylen = len + FCS_LEN;
6195*b4c3e9b5SBjoern A. Zeeb 
6196*b4c3e9b5SBjoern A. Zeeb 	/* Get tx_info */
6197*b4c3e9b5SBjoern A. Zeeb 	tx_info = IEEE80211_SKB_CB(p);
6198*b4c3e9b5SBjoern A. Zeeb 
6199*b4c3e9b5SBjoern A. Zeeb 	/* add PLCP */
6200*b4c3e9b5SBjoern A. Zeeb 	plcp = skb_push(p, D11_PHY_HDR_LEN);
6201*b4c3e9b5SBjoern A. Zeeb 
6202*b4c3e9b5SBjoern A. Zeeb 	/* add Broadcom tx descriptor header */
6203*b4c3e9b5SBjoern A. Zeeb 	txh = (struct d11txh *) skb_push(p, D11_TXH_LEN);
6204*b4c3e9b5SBjoern A. Zeeb 	memset(txh, 0, D11_TXH_LEN);
6205*b4c3e9b5SBjoern A. Zeeb 
6206*b4c3e9b5SBjoern A. Zeeb 	/* setup frameid */
6207*b4c3e9b5SBjoern A. Zeeb 	if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
6208*b4c3e9b5SBjoern A. Zeeb 		/* non-AP STA should never use BCMC queue */
6209*b4c3e9b5SBjoern A. Zeeb 		if (queue == TX_BCMC_FIFO) {
6210*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc->hw->d11core,
6211*b4c3e9b5SBjoern A. Zeeb 				  "wl%d: %s: ASSERT queue == TX_BCMC!\n",
6212*b4c3e9b5SBjoern A. Zeeb 				  wlc->pub->unit, __func__);
6213*b4c3e9b5SBjoern A. Zeeb 			frameid = bcmc_fid_generate(wlc, NULL, txh);
6214*b4c3e9b5SBjoern A. Zeeb 		} else {
6215*b4c3e9b5SBjoern A. Zeeb 			/* Increment the counter for first fragment */
6216*b4c3e9b5SBjoern A. Zeeb 			if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
6217*b4c3e9b5SBjoern A. Zeeb 				scb->seqnum[p->priority]++;
6218*b4c3e9b5SBjoern A. Zeeb 
6219*b4c3e9b5SBjoern A. Zeeb 			/* extract fragment number from frame first */
6220*b4c3e9b5SBjoern A. Zeeb 			seq = le16_to_cpu(h->seq_ctrl) & FRAGNUM_MASK;
6221*b4c3e9b5SBjoern A. Zeeb 			seq |= (scb->seqnum[p->priority] << SEQNUM_SHIFT);
6222*b4c3e9b5SBjoern A. Zeeb 			h->seq_ctrl = cpu_to_le16(seq);
6223*b4c3e9b5SBjoern A. Zeeb 
6224*b4c3e9b5SBjoern A. Zeeb 			frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
6225*b4c3e9b5SBjoern A. Zeeb 			    (queue & TXFID_QUEUE_MASK);
6226*b4c3e9b5SBjoern A. Zeeb 		}
6227*b4c3e9b5SBjoern A. Zeeb 	}
6228*b4c3e9b5SBjoern A. Zeeb 	frameid |= queue & TXFID_QUEUE_MASK;
6229*b4c3e9b5SBjoern A. Zeeb 
6230*b4c3e9b5SBjoern A. Zeeb 	/* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */
6231*b4c3e9b5SBjoern A. Zeeb 	if (ieee80211_is_beacon(h->frame_control))
6232*b4c3e9b5SBjoern A. Zeeb 		mcl |= TXC_IGNOREPMQ;
6233*b4c3e9b5SBjoern A. Zeeb 
6234*b4c3e9b5SBjoern A. Zeeb 	txrate[0] = tx_info->control.rates;
6235*b4c3e9b5SBjoern A. Zeeb 	txrate[1] = txrate[0] + 1;
6236*b4c3e9b5SBjoern A. Zeeb 
6237*b4c3e9b5SBjoern A. Zeeb 	/*
6238*b4c3e9b5SBjoern A. Zeeb 	 * if rate control algorithm didn't give us a fallback
6239*b4c3e9b5SBjoern A. Zeeb 	 * rate, use the primary rate
6240*b4c3e9b5SBjoern A. Zeeb 	 */
6241*b4c3e9b5SBjoern A. Zeeb 	if (txrate[1]->idx < 0)
6242*b4c3e9b5SBjoern A. Zeeb 		txrate[1] = txrate[0];
6243*b4c3e9b5SBjoern A. Zeeb 
6244*b4c3e9b5SBjoern A. Zeeb 	for (k = 0; k < hw->max_rates; k++) {
6245*b4c3e9b5SBjoern A. Zeeb 		is_mcs = txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false;
6246*b4c3e9b5SBjoern A. Zeeb 		if (!is_mcs) {
6247*b4c3e9b5SBjoern A. Zeeb 			if ((txrate[k]->idx >= 0)
6248*b4c3e9b5SBjoern A. Zeeb 			    && (txrate[k]->idx <
6249*b4c3e9b5SBjoern A. Zeeb 				hw->wiphy->bands[tx_info->band]->n_bitrates)) {
6250*b4c3e9b5SBjoern A. Zeeb 				rspec[k] =
6251*b4c3e9b5SBjoern A. Zeeb 				    hw->wiphy->bands[tx_info->band]->
6252*b4c3e9b5SBjoern A. Zeeb 				    bitrates[txrate[k]->idx].hw_value;
6253*b4c3e9b5SBjoern A. Zeeb 			} else {
6254*b4c3e9b5SBjoern A. Zeeb 				rspec[k] = BRCM_RATE_1M;
6255*b4c3e9b5SBjoern A. Zeeb 			}
6256*b4c3e9b5SBjoern A. Zeeb 		} else {
6257*b4c3e9b5SBjoern A. Zeeb 			rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band,
6258*b4c3e9b5SBjoern A. Zeeb 					NRATE_MCS_INUSE | txrate[k]->idx);
6259*b4c3e9b5SBjoern A. Zeeb 		}
6260*b4c3e9b5SBjoern A. Zeeb 
6261*b4c3e9b5SBjoern A. Zeeb 		/*
6262*b4c3e9b5SBjoern A. Zeeb 		 * Currently only support same setting for primary and
6263*b4c3e9b5SBjoern A. Zeeb 		 * fallback rates. Unify flags for each rate into a
6264*b4c3e9b5SBjoern A. Zeeb 		 * single value for the frame
6265*b4c3e9b5SBjoern A. Zeeb 		 */
6266*b4c3e9b5SBjoern A. Zeeb 		use_rts |=
6267*b4c3e9b5SBjoern A. Zeeb 		    txrate[k]->
6268*b4c3e9b5SBjoern A. Zeeb 		    flags & IEEE80211_TX_RC_USE_RTS_CTS ? true : false;
6269*b4c3e9b5SBjoern A. Zeeb 		use_cts |=
6270*b4c3e9b5SBjoern A. Zeeb 		    txrate[k]->
6271*b4c3e9b5SBjoern A. Zeeb 		    flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? true : false;
6272*b4c3e9b5SBjoern A. Zeeb 
6273*b4c3e9b5SBjoern A. Zeeb 
6274*b4c3e9b5SBjoern A. Zeeb 		/*
6275*b4c3e9b5SBjoern A. Zeeb 		 * (1) RATE:
6276*b4c3e9b5SBjoern A. Zeeb 		 *   determine and validate primary rate
6277*b4c3e9b5SBjoern A. Zeeb 		 *   and fallback rates
6278*b4c3e9b5SBjoern A. Zeeb 		 */
6279*b4c3e9b5SBjoern A. Zeeb 		if (!rspec_active(rspec[k])) {
6280*b4c3e9b5SBjoern A. Zeeb 			rspec[k] = BRCM_RATE_1M;
6281*b4c3e9b5SBjoern A. Zeeb 		} else {
6282*b4c3e9b5SBjoern A. Zeeb 			if (!is_multicast_ether_addr(h->addr1)) {
6283*b4c3e9b5SBjoern A. Zeeb 				/* set tx antenna config */
6284*b4c3e9b5SBjoern A. Zeeb 				brcms_c_antsel_antcfg_get(wlc->asi, false,
6285*b4c3e9b5SBjoern A. Zeeb 					false, 0, 0, &antcfg, &fbantcfg);
6286*b4c3e9b5SBjoern A. Zeeb 			}
6287*b4c3e9b5SBjoern A. Zeeb 		}
6288*b4c3e9b5SBjoern A. Zeeb 	}
6289*b4c3e9b5SBjoern A. Zeeb 
6290*b4c3e9b5SBjoern A. Zeeb 	phyctl1_stf = wlc->stf->ss_opmode;
6291*b4c3e9b5SBjoern A. Zeeb 
6292*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->_n_enab & SUPPORT_11N) {
6293*b4c3e9b5SBjoern A. Zeeb 		for (k = 0; k < hw->max_rates; k++) {
6294*b4c3e9b5SBjoern A. Zeeb 			/*
6295*b4c3e9b5SBjoern A. Zeeb 			 * apply siso/cdd to single stream mcs's or ofdm
6296*b4c3e9b5SBjoern A. Zeeb 			 * if rspec is auto selected
6297*b4c3e9b5SBjoern A. Zeeb 			 */
6298*b4c3e9b5SBjoern A. Zeeb 			if (((is_mcs_rate(rspec[k]) &&
6299*b4c3e9b5SBjoern A. Zeeb 			      is_single_stream(rspec[k] & RSPEC_RATE_MASK)) ||
6300*b4c3e9b5SBjoern A. Zeeb 			     is_ofdm_rate(rspec[k]))
6301*b4c3e9b5SBjoern A. Zeeb 			    && ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY)
6302*b4c3e9b5SBjoern A. Zeeb 				|| !(rspec[k] & RSPEC_OVERRIDE))) {
6303*b4c3e9b5SBjoern A. Zeeb 				rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK);
6304*b4c3e9b5SBjoern A. Zeeb 
6305*b4c3e9b5SBjoern A. Zeeb 				/* For SISO MCS use STBC if possible */
6306*b4c3e9b5SBjoern A. Zeeb 				if (is_mcs_rate(rspec[k])
6307*b4c3e9b5SBjoern A. Zeeb 				    && BRCMS_STF_SS_STBC_TX(wlc, scb)) {
6308*b4c3e9b5SBjoern A. Zeeb 					u8 stc;
6309*b4c3e9b5SBjoern A. Zeeb 
6310*b4c3e9b5SBjoern A. Zeeb 					/* Nss for single stream is always 1 */
6311*b4c3e9b5SBjoern A. Zeeb 					stc = 1;
6312*b4c3e9b5SBjoern A. Zeeb 					rspec[k] |= (PHY_TXC1_MODE_STBC <<
6313*b4c3e9b5SBjoern A. Zeeb 							RSPEC_STF_SHIFT) |
6314*b4c3e9b5SBjoern A. Zeeb 						    (stc << RSPEC_STC_SHIFT);
6315*b4c3e9b5SBjoern A. Zeeb 				} else
6316*b4c3e9b5SBjoern A. Zeeb 					rspec[k] |=
6317*b4c3e9b5SBjoern A. Zeeb 					    (phyctl1_stf << RSPEC_STF_SHIFT);
6318*b4c3e9b5SBjoern A. Zeeb 			}
6319*b4c3e9b5SBjoern A. Zeeb 
6320*b4c3e9b5SBjoern A. Zeeb 			/*
6321*b4c3e9b5SBjoern A. Zeeb 			 * Is the phy configured to use 40MHZ frames? If
6322*b4c3e9b5SBjoern A. Zeeb 			 * so then pick the desired txbw
6323*b4c3e9b5SBjoern A. Zeeb 			 */
6324*b4c3e9b5SBjoern A. Zeeb 			if (brcms_chspec_bw(wlc->chanspec) == BRCMS_40_MHZ) {
6325*b4c3e9b5SBjoern A. Zeeb 				/* default txbw is 20in40 SB */
6326*b4c3e9b5SBjoern A. Zeeb 				mimo_ctlchbw = mimo_txbw =
6327*b4c3e9b5SBjoern A. Zeeb 				   CHSPEC_SB_UPPER(wlc_phy_chanspec_get(
6328*b4c3e9b5SBjoern A. Zeeb 								 wlc->band->pi))
6329*b4c3e9b5SBjoern A. Zeeb 				   ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
6330*b4c3e9b5SBjoern A. Zeeb 
6331*b4c3e9b5SBjoern A. Zeeb 				if (is_mcs_rate(rspec[k])) {
6332*b4c3e9b5SBjoern A. Zeeb 					/* mcs 32 must be 40b/w DUP */
6333*b4c3e9b5SBjoern A. Zeeb 					if ((rspec[k] & RSPEC_RATE_MASK)
6334*b4c3e9b5SBjoern A. Zeeb 					    == 32) {
6335*b4c3e9b5SBjoern A. Zeeb 						mimo_txbw =
6336*b4c3e9b5SBjoern A. Zeeb 						    PHY_TXC1_BW_40MHZ_DUP;
6337*b4c3e9b5SBjoern A. Zeeb 						/* use override */
6338*b4c3e9b5SBjoern A. Zeeb 					} else if (wlc->mimo_40txbw != AUTO)
6339*b4c3e9b5SBjoern A. Zeeb 						mimo_txbw = wlc->mimo_40txbw;
6340*b4c3e9b5SBjoern A. Zeeb 					/* else check if dst is using 40 Mhz */
6341*b4c3e9b5SBjoern A. Zeeb 					else if (scb->flags & SCB_IS40)
6342*b4c3e9b5SBjoern A. Zeeb 						mimo_txbw = PHY_TXC1_BW_40MHZ;
6343*b4c3e9b5SBjoern A. Zeeb 				} else if (is_ofdm_rate(rspec[k])) {
6344*b4c3e9b5SBjoern A. Zeeb 					if (wlc->ofdm_40txbw != AUTO)
6345*b4c3e9b5SBjoern A. Zeeb 						mimo_txbw = wlc->ofdm_40txbw;
6346*b4c3e9b5SBjoern A. Zeeb 				} else if (wlc->cck_40txbw != AUTO) {
6347*b4c3e9b5SBjoern A. Zeeb 					mimo_txbw = wlc->cck_40txbw;
6348*b4c3e9b5SBjoern A. Zeeb 				}
6349*b4c3e9b5SBjoern A. Zeeb 			} else {
6350*b4c3e9b5SBjoern A. Zeeb 				/*
6351*b4c3e9b5SBjoern A. Zeeb 				 * mcs32 is 40 b/w only.
6352*b4c3e9b5SBjoern A. Zeeb 				 * This is possible for probe packets on
6353*b4c3e9b5SBjoern A. Zeeb 				 * a STA during SCAN
6354*b4c3e9b5SBjoern A. Zeeb 				 */
6355*b4c3e9b5SBjoern A. Zeeb 				if ((rspec[k] & RSPEC_RATE_MASK) == 32)
6356*b4c3e9b5SBjoern A. Zeeb 					/* mcs 0 */
6357*b4c3e9b5SBjoern A. Zeeb 					rspec[k] = RSPEC_MIMORATE;
6358*b4c3e9b5SBjoern A. Zeeb 
6359*b4c3e9b5SBjoern A. Zeeb 				mimo_txbw = PHY_TXC1_BW_20MHZ;
6360*b4c3e9b5SBjoern A. Zeeb 			}
6361*b4c3e9b5SBjoern A. Zeeb 
6362*b4c3e9b5SBjoern A. Zeeb 			/* Set channel width */
6363*b4c3e9b5SBjoern A. Zeeb 			rspec[k] &= ~RSPEC_BW_MASK;
6364*b4c3e9b5SBjoern A. Zeeb 			if ((k == 0) || ((k > 0) && is_mcs_rate(rspec[k])))
6365*b4c3e9b5SBjoern A. Zeeb 				rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT);
6366*b4c3e9b5SBjoern A. Zeeb 			else
6367*b4c3e9b5SBjoern A. Zeeb 				rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
6368*b4c3e9b5SBjoern A. Zeeb 
6369*b4c3e9b5SBjoern A. Zeeb 			/* Disable short GI, not supported yet */
6370*b4c3e9b5SBjoern A. Zeeb 			rspec[k] &= ~RSPEC_SHORT_GI;
6371*b4c3e9b5SBjoern A. Zeeb 
6372*b4c3e9b5SBjoern A. Zeeb 			mimo_preamble_type = BRCMS_MM_PREAMBLE;
6373*b4c3e9b5SBjoern A. Zeeb 			if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD)
6374*b4c3e9b5SBjoern A. Zeeb 				mimo_preamble_type = BRCMS_GF_PREAMBLE;
6375*b4c3e9b5SBjoern A. Zeeb 
6376*b4c3e9b5SBjoern A. Zeeb 			if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
6377*b4c3e9b5SBjoern A. Zeeb 			    && (!is_mcs_rate(rspec[k]))) {
6378*b4c3e9b5SBjoern A. Zeeb 				brcms_warn(wlc->hw->d11core,
6379*b4c3e9b5SBjoern A. Zeeb 					   "wl%d: %s: IEEE80211_TX_RC_MCS != is_mcs_rate(rspec)\n",
6380*b4c3e9b5SBjoern A. Zeeb 					   wlc->pub->unit, __func__);
6381*b4c3e9b5SBjoern A. Zeeb 			}
6382*b4c3e9b5SBjoern A. Zeeb 
6383*b4c3e9b5SBjoern A. Zeeb 			if (is_mcs_rate(rspec[k])) {
6384*b4c3e9b5SBjoern A. Zeeb 				preamble_type[k] = mimo_preamble_type;
6385*b4c3e9b5SBjoern A. Zeeb 
6386*b4c3e9b5SBjoern A. Zeeb 				/*
6387*b4c3e9b5SBjoern A. Zeeb 				 * if SGI is selected, then forced mm
6388*b4c3e9b5SBjoern A. Zeeb 				 * for single stream
6389*b4c3e9b5SBjoern A. Zeeb 				 */
6390*b4c3e9b5SBjoern A. Zeeb 				if ((rspec[k] & RSPEC_SHORT_GI)
6391*b4c3e9b5SBjoern A. Zeeb 				    && is_single_stream(rspec[k] &
6392*b4c3e9b5SBjoern A. Zeeb 							RSPEC_RATE_MASK))
6393*b4c3e9b5SBjoern A. Zeeb 					preamble_type[k] = BRCMS_MM_PREAMBLE;
6394*b4c3e9b5SBjoern A. Zeeb 			}
6395*b4c3e9b5SBjoern A. Zeeb 
6396*b4c3e9b5SBjoern A. Zeeb 			/* should be better conditionalized */
6397*b4c3e9b5SBjoern A. Zeeb 			if (!is_mcs_rate(rspec[0])
6398*b4c3e9b5SBjoern A. Zeeb 			    && (tx_info->control.rates[0].
6399*b4c3e9b5SBjoern A. Zeeb 				flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE))
6400*b4c3e9b5SBjoern A. Zeeb 				preamble_type[k] = BRCMS_SHORT_PREAMBLE;
6401*b4c3e9b5SBjoern A. Zeeb 		}
6402*b4c3e9b5SBjoern A. Zeeb 	} else {
6403*b4c3e9b5SBjoern A. Zeeb 		for (k = 0; k < hw->max_rates; k++) {
6404*b4c3e9b5SBjoern A. Zeeb 			/* Set ctrlchbw as 20Mhz */
6405*b4c3e9b5SBjoern A. Zeeb 			rspec[k] &= ~RSPEC_BW_MASK;
6406*b4c3e9b5SBjoern A. Zeeb 			rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT);
6407*b4c3e9b5SBjoern A. Zeeb 
6408*b4c3e9b5SBjoern A. Zeeb 			/* for nphy, stf of ofdm frames must follow policies */
6409*b4c3e9b5SBjoern A. Zeeb 			if (BRCMS_ISNPHY(wlc->band) && is_ofdm_rate(rspec[k])) {
6410*b4c3e9b5SBjoern A. Zeeb 				rspec[k] &= ~RSPEC_STF_MASK;
6411*b4c3e9b5SBjoern A. Zeeb 				rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT;
6412*b4c3e9b5SBjoern A. Zeeb 			}
6413*b4c3e9b5SBjoern A. Zeeb 		}
6414*b4c3e9b5SBjoern A. Zeeb 	}
6415*b4c3e9b5SBjoern A. Zeeb 
6416*b4c3e9b5SBjoern A. Zeeb 	/* Reset these for use with AMPDU's */
6417*b4c3e9b5SBjoern A. Zeeb 	txrate[0]->count = 0;
6418*b4c3e9b5SBjoern A. Zeeb 	txrate[1]->count = 0;
6419*b4c3e9b5SBjoern A. Zeeb 
6420*b4c3e9b5SBjoern A. Zeeb 	/* (2) PROTECTION, may change rspec */
6421*b4c3e9b5SBjoern A. Zeeb 	if ((ieee80211_is_data(h->frame_control) ||
6422*b4c3e9b5SBjoern A. Zeeb 	    ieee80211_is_mgmt(h->frame_control)) &&
6423*b4c3e9b5SBjoern A. Zeeb 	    (phylen > wlc->RTSThresh) && !is_multicast_ether_addr(h->addr1))
6424*b4c3e9b5SBjoern A. Zeeb 		use_rts = true;
6425*b4c3e9b5SBjoern A. Zeeb 
6426*b4c3e9b5SBjoern A. Zeeb 	/* (3) PLCP: determine PLCP header and MAC duration,
6427*b4c3e9b5SBjoern A. Zeeb 	 * fill struct d11txh */
6428*b4c3e9b5SBjoern A. Zeeb 	brcms_c_compute_plcp(wlc, rspec[0], phylen, plcp);
6429*b4c3e9b5SBjoern A. Zeeb 	brcms_c_compute_plcp(wlc, rspec[1], phylen, plcp_fallback);
6430*b4c3e9b5SBjoern A. Zeeb 	memcpy(&txh->FragPLCPFallback,
6431*b4c3e9b5SBjoern A. Zeeb 	       plcp_fallback, sizeof(txh->FragPLCPFallback));
6432*b4c3e9b5SBjoern A. Zeeb 
6433*b4c3e9b5SBjoern A. Zeeb 	/* Length field now put in CCK FBR CRC field */
6434*b4c3e9b5SBjoern A. Zeeb 	if (is_cck_rate(rspec[1])) {
6435*b4c3e9b5SBjoern A. Zeeb 		txh->FragPLCPFallback[4] = phylen & 0xff;
6436*b4c3e9b5SBjoern A. Zeeb 		txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8;
6437*b4c3e9b5SBjoern A. Zeeb 	}
6438*b4c3e9b5SBjoern A. Zeeb 
6439*b4c3e9b5SBjoern A. Zeeb 	/* MIMO-RATE: need validation ?? */
6440*b4c3e9b5SBjoern A. Zeeb 	mainrates = is_ofdm_rate(rspec[0]) ?
6441*b4c3e9b5SBjoern A. Zeeb 			D11A_PHY_HDR_GRATE((struct ofdm_phy_hdr *) plcp) :
6442*b4c3e9b5SBjoern A. Zeeb 			plcp[0];
6443*b4c3e9b5SBjoern A. Zeeb 
6444*b4c3e9b5SBjoern A. Zeeb 	/* DUR field for main rate */
6445*b4c3e9b5SBjoern A. Zeeb 	if (!ieee80211_is_pspoll(h->frame_control) &&
6446*b4c3e9b5SBjoern A. Zeeb 	    !is_multicast_ether_addr(h->addr1) && !use_rifs) {
6447*b4c3e9b5SBjoern A. Zeeb 		durid =
6448*b4c3e9b5SBjoern A. Zeeb 		    brcms_c_compute_frame_dur(wlc, rspec[0], preamble_type[0],
6449*b4c3e9b5SBjoern A. Zeeb 					  next_frag_len);
6450*b4c3e9b5SBjoern A. Zeeb 		h->duration_id = cpu_to_le16(durid);
6451*b4c3e9b5SBjoern A. Zeeb 	} else if (use_rifs) {
6452*b4c3e9b5SBjoern A. Zeeb 		/* NAV protect to end of next max packet size */
6453*b4c3e9b5SBjoern A. Zeeb 		durid =
6454*b4c3e9b5SBjoern A. Zeeb 		    (u16) brcms_c_calc_frame_time(wlc, rspec[0],
6455*b4c3e9b5SBjoern A. Zeeb 						 preamble_type[0],
6456*b4c3e9b5SBjoern A. Zeeb 						 DOT11_MAX_FRAG_LEN);
6457*b4c3e9b5SBjoern A. Zeeb 		durid += RIFS_11N_TIME;
6458*b4c3e9b5SBjoern A. Zeeb 		h->duration_id = cpu_to_le16(durid);
6459*b4c3e9b5SBjoern A. Zeeb 	}
6460*b4c3e9b5SBjoern A. Zeeb 
6461*b4c3e9b5SBjoern A. Zeeb 	/* DUR field for fallback rate */
6462*b4c3e9b5SBjoern A. Zeeb 	if (ieee80211_is_pspoll(h->frame_control))
6463*b4c3e9b5SBjoern A. Zeeb 		txh->FragDurFallback = h->duration_id;
6464*b4c3e9b5SBjoern A. Zeeb 	else if (is_multicast_ether_addr(h->addr1) || use_rifs)
6465*b4c3e9b5SBjoern A. Zeeb 		txh->FragDurFallback = 0;
6466*b4c3e9b5SBjoern A. Zeeb 	else {
6467*b4c3e9b5SBjoern A. Zeeb 		durid = brcms_c_compute_frame_dur(wlc, rspec[1],
6468*b4c3e9b5SBjoern A. Zeeb 					      preamble_type[1], next_frag_len);
6469*b4c3e9b5SBjoern A. Zeeb 		txh->FragDurFallback = cpu_to_le16(durid);
6470*b4c3e9b5SBjoern A. Zeeb 	}
6471*b4c3e9b5SBjoern A. Zeeb 
6472*b4c3e9b5SBjoern A. Zeeb 	/* (4) MAC-HDR: MacTxControlLow */
6473*b4c3e9b5SBjoern A. Zeeb 	if (frag == 0)
6474*b4c3e9b5SBjoern A. Zeeb 		mcl |= TXC_STARTMSDU;
6475*b4c3e9b5SBjoern A. Zeeb 
6476*b4c3e9b5SBjoern A. Zeeb 	if (!is_multicast_ether_addr(h->addr1))
6477*b4c3e9b5SBjoern A. Zeeb 		mcl |= TXC_IMMEDACK;
6478*b4c3e9b5SBjoern A. Zeeb 
6479*b4c3e9b5SBjoern A. Zeeb 	if (wlc->band->bandtype == BRCM_BAND_5G)
6480*b4c3e9b5SBjoern A. Zeeb 		mcl |= TXC_FREQBAND_5G;
6481*b4c3e9b5SBjoern A. Zeeb 
6482*b4c3e9b5SBjoern A. Zeeb 	if (CHSPEC_IS40(wlc_phy_chanspec_get(wlc->band->pi)))
6483*b4c3e9b5SBjoern A. Zeeb 		mcl |= TXC_BW_40;
6484*b4c3e9b5SBjoern A. Zeeb 
6485*b4c3e9b5SBjoern A. Zeeb 	/* set AMIC bit if using hardware TKIP MIC */
6486*b4c3e9b5SBjoern A. Zeeb 	if (hwtkmic)
6487*b4c3e9b5SBjoern A. Zeeb 		mcl |= TXC_AMIC;
6488*b4c3e9b5SBjoern A. Zeeb 
6489*b4c3e9b5SBjoern A. Zeeb 	txh->MacTxControlLow = cpu_to_le16(mcl);
6490*b4c3e9b5SBjoern A. Zeeb 
6491*b4c3e9b5SBjoern A. Zeeb 	/* MacTxControlHigh */
6492*b4c3e9b5SBjoern A. Zeeb 	mch = 0;
6493*b4c3e9b5SBjoern A. Zeeb 
6494*b4c3e9b5SBjoern A. Zeeb 	/* Set fallback rate preamble type */
6495*b4c3e9b5SBjoern A. Zeeb 	if ((preamble_type[1] == BRCMS_SHORT_PREAMBLE) ||
6496*b4c3e9b5SBjoern A. Zeeb 	    (preamble_type[1] == BRCMS_GF_PREAMBLE)) {
6497*b4c3e9b5SBjoern A. Zeeb 		if (rspec2rate(rspec[1]) != BRCM_RATE_1M)
6498*b4c3e9b5SBjoern A. Zeeb 			mch |= TXC_PREAMBLE_DATA_FB_SHORT;
6499*b4c3e9b5SBjoern A. Zeeb 	}
6500*b4c3e9b5SBjoern A. Zeeb 
6501*b4c3e9b5SBjoern A. Zeeb 	/* MacFrameControl */
6502*b4c3e9b5SBjoern A. Zeeb 	memcpy(&txh->MacFrameControl, &h->frame_control, sizeof(u16));
6503*b4c3e9b5SBjoern A. Zeeb 	txh->TxFesTimeNormal = cpu_to_le16(0);
6504*b4c3e9b5SBjoern A. Zeeb 
6505*b4c3e9b5SBjoern A. Zeeb 	txh->TxFesTimeFallback = cpu_to_le16(0);
6506*b4c3e9b5SBjoern A. Zeeb 
6507*b4c3e9b5SBjoern A. Zeeb 	/* TxFrameRA */
6508*b4c3e9b5SBjoern A. Zeeb 	memcpy(&txh->TxFrameRA, &h->addr1, ETH_ALEN);
6509*b4c3e9b5SBjoern A. Zeeb 
6510*b4c3e9b5SBjoern A. Zeeb 	/* TxFrameID */
6511*b4c3e9b5SBjoern A. Zeeb 	txh->TxFrameID = cpu_to_le16(frameid);
6512*b4c3e9b5SBjoern A. Zeeb 
6513*b4c3e9b5SBjoern A. Zeeb 	/*
6514*b4c3e9b5SBjoern A. Zeeb 	 * TxStatus, Note the case of recreating the first frag of a suppressed
6515*b4c3e9b5SBjoern A. Zeeb 	 * frame then we may need to reset the retry cnt's via the status reg
6516*b4c3e9b5SBjoern A. Zeeb 	 */
6517*b4c3e9b5SBjoern A. Zeeb 	txh->TxStatus = cpu_to_le16(status);
6518*b4c3e9b5SBjoern A. Zeeb 
6519*b4c3e9b5SBjoern A. Zeeb 	/*
6520*b4c3e9b5SBjoern A. Zeeb 	 * extra fields for ucode AMPDU aggregation, the new fields are added to
6521*b4c3e9b5SBjoern A. Zeeb 	 * the END of previous structure so that it's compatible in driver.
6522*b4c3e9b5SBjoern A. Zeeb 	 */
6523*b4c3e9b5SBjoern A. Zeeb 	txh->MaxNMpdus = cpu_to_le16(0);
6524*b4c3e9b5SBjoern A. Zeeb 	txh->MaxABytes_MRT = cpu_to_le16(0);
6525*b4c3e9b5SBjoern A. Zeeb 	txh->MaxABytes_FBR = cpu_to_le16(0);
6526*b4c3e9b5SBjoern A. Zeeb 	txh->MinMBytes = cpu_to_le16(0);
6527*b4c3e9b5SBjoern A. Zeeb 
6528*b4c3e9b5SBjoern A. Zeeb 	/* (5) RTS/CTS: determine RTS/CTS PLCP header and MAC duration,
6529*b4c3e9b5SBjoern A. Zeeb 	 * furnish struct d11txh */
6530*b4c3e9b5SBjoern A. Zeeb 	/* RTS PLCP header and RTS frame */
6531*b4c3e9b5SBjoern A. Zeeb 	if (use_rts || use_cts) {
6532*b4c3e9b5SBjoern A. Zeeb 		if (use_rts && use_cts)
6533*b4c3e9b5SBjoern A. Zeeb 			use_cts = false;
6534*b4c3e9b5SBjoern A. Zeeb 
6535*b4c3e9b5SBjoern A. Zeeb 		for (k = 0; k < 2; k++) {
6536*b4c3e9b5SBjoern A. Zeeb 			rts_rspec[k] = brcms_c_rspec_to_rts_rspec(wlc, rspec[k],
6537*b4c3e9b5SBjoern A. Zeeb 							      false,
6538*b4c3e9b5SBjoern A. Zeeb 							      mimo_ctlchbw);
6539*b4c3e9b5SBjoern A. Zeeb 		}
6540*b4c3e9b5SBjoern A. Zeeb 
6541*b4c3e9b5SBjoern A. Zeeb 		if (!is_ofdm_rate(rts_rspec[0]) &&
6542*b4c3e9b5SBjoern A. Zeeb 		    !((rspec2rate(rts_rspec[0]) == BRCM_RATE_1M) ||
6543*b4c3e9b5SBjoern A. Zeeb 		      (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
6544*b4c3e9b5SBjoern A. Zeeb 			rts_preamble_type[0] = BRCMS_SHORT_PREAMBLE;
6545*b4c3e9b5SBjoern A. Zeeb 			mch |= TXC_PREAMBLE_RTS_MAIN_SHORT;
6546*b4c3e9b5SBjoern A. Zeeb 		}
6547*b4c3e9b5SBjoern A. Zeeb 
6548*b4c3e9b5SBjoern A. Zeeb 		if (!is_ofdm_rate(rts_rspec[1]) &&
6549*b4c3e9b5SBjoern A. Zeeb 		    !((rspec2rate(rts_rspec[1]) == BRCM_RATE_1M) ||
6550*b4c3e9b5SBjoern A. Zeeb 		      (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
6551*b4c3e9b5SBjoern A. Zeeb 			rts_preamble_type[1] = BRCMS_SHORT_PREAMBLE;
6552*b4c3e9b5SBjoern A. Zeeb 			mch |= TXC_PREAMBLE_RTS_FB_SHORT;
6553*b4c3e9b5SBjoern A. Zeeb 		}
6554*b4c3e9b5SBjoern A. Zeeb 
6555*b4c3e9b5SBjoern A. Zeeb 		/* RTS/CTS additions to MacTxControlLow */
6556*b4c3e9b5SBjoern A. Zeeb 		if (use_cts) {
6557*b4c3e9b5SBjoern A. Zeeb 			txh->MacTxControlLow |= cpu_to_le16(TXC_SENDCTS);
6558*b4c3e9b5SBjoern A. Zeeb 		} else {
6559*b4c3e9b5SBjoern A. Zeeb 			txh->MacTxControlLow |= cpu_to_le16(TXC_SENDRTS);
6560*b4c3e9b5SBjoern A. Zeeb 			txh->MacTxControlLow |= cpu_to_le16(TXC_LONGFRAME);
6561*b4c3e9b5SBjoern A. Zeeb 		}
6562*b4c3e9b5SBjoern A. Zeeb 
6563*b4c3e9b5SBjoern A. Zeeb 		/* RTS PLCP header */
6564*b4c3e9b5SBjoern A. Zeeb 		rts_plcp = txh->RTSPhyHeader;
6565*b4c3e9b5SBjoern A. Zeeb 		if (use_cts)
6566*b4c3e9b5SBjoern A. Zeeb 			rts_phylen = DOT11_CTS_LEN + FCS_LEN;
6567*b4c3e9b5SBjoern A. Zeeb 		else
6568*b4c3e9b5SBjoern A. Zeeb 			rts_phylen = DOT11_RTS_LEN + FCS_LEN;
6569*b4c3e9b5SBjoern A. Zeeb 
6570*b4c3e9b5SBjoern A. Zeeb 		brcms_c_compute_plcp(wlc, rts_rspec[0], rts_phylen, rts_plcp);
6571*b4c3e9b5SBjoern A. Zeeb 
6572*b4c3e9b5SBjoern A. Zeeb 		/* fallback rate version of RTS PLCP header */
6573*b4c3e9b5SBjoern A. Zeeb 		brcms_c_compute_plcp(wlc, rts_rspec[1], rts_phylen,
6574*b4c3e9b5SBjoern A. Zeeb 				 rts_plcp_fallback);
6575*b4c3e9b5SBjoern A. Zeeb 		memcpy(&txh->RTSPLCPFallback, rts_plcp_fallback,
6576*b4c3e9b5SBjoern A. Zeeb 		       sizeof(txh->RTSPLCPFallback));
6577*b4c3e9b5SBjoern A. Zeeb 
6578*b4c3e9b5SBjoern A. Zeeb 		/* RTS frame fields... */
6579*b4c3e9b5SBjoern A. Zeeb 		rts = (struct ieee80211_rts *)&txh->rts_frame;
6580*b4c3e9b5SBjoern A. Zeeb 
6581*b4c3e9b5SBjoern A. Zeeb 		durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec[0],
6582*b4c3e9b5SBjoern A. Zeeb 					       rspec[0], rts_preamble_type[0],
6583*b4c3e9b5SBjoern A. Zeeb 					       preamble_type[0], phylen, false);
6584*b4c3e9b5SBjoern A. Zeeb 		rts->duration = cpu_to_le16(durid);
6585*b4c3e9b5SBjoern A. Zeeb 		/* fallback rate version of RTS DUR field */
6586*b4c3e9b5SBjoern A. Zeeb 		durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
6587*b4c3e9b5SBjoern A. Zeeb 					       rts_rspec[1], rspec[1],
6588*b4c3e9b5SBjoern A. Zeeb 					       rts_preamble_type[1],
6589*b4c3e9b5SBjoern A. Zeeb 					       preamble_type[1], phylen, false);
6590*b4c3e9b5SBjoern A. Zeeb 		txh->RTSDurFallback = cpu_to_le16(durid);
6591*b4c3e9b5SBjoern A. Zeeb 
6592*b4c3e9b5SBjoern A. Zeeb 		if (use_cts) {
6593*b4c3e9b5SBjoern A. Zeeb 			rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
6594*b4c3e9b5SBjoern A. Zeeb 							 IEEE80211_STYPE_CTS);
6595*b4c3e9b5SBjoern A. Zeeb 
6596*b4c3e9b5SBjoern A. Zeeb 			memcpy(&rts->ra, &h->addr2, ETH_ALEN);
6597*b4c3e9b5SBjoern A. Zeeb 		} else {
6598*b4c3e9b5SBjoern A. Zeeb 			rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
6599*b4c3e9b5SBjoern A. Zeeb 							 IEEE80211_STYPE_RTS);
6600*b4c3e9b5SBjoern A. Zeeb 
6601*b4c3e9b5SBjoern A. Zeeb 			memcpy(&rts->ra, &h->addr1, ETH_ALEN);
6602*b4c3e9b5SBjoern A. Zeeb 			memcpy(&rts->ta, &h->addr2, ETH_ALEN);
6603*b4c3e9b5SBjoern A. Zeeb 		}
6604*b4c3e9b5SBjoern A. Zeeb 
6605*b4c3e9b5SBjoern A. Zeeb 		/* mainrate
6606*b4c3e9b5SBjoern A. Zeeb 		 *    low 8 bits: main frag rate/mcs,
6607*b4c3e9b5SBjoern A. Zeeb 		 *    high 8 bits: rts/cts rate/mcs
6608*b4c3e9b5SBjoern A. Zeeb 		 */
6609*b4c3e9b5SBjoern A. Zeeb 		mainrates |= (is_ofdm_rate(rts_rspec[0]) ?
6610*b4c3e9b5SBjoern A. Zeeb 				D11A_PHY_HDR_GRATE(
6611*b4c3e9b5SBjoern A. Zeeb 					(struct ofdm_phy_hdr *) rts_plcp) :
6612*b4c3e9b5SBjoern A. Zeeb 				rts_plcp[0]) << 8;
6613*b4c3e9b5SBjoern A. Zeeb 	} else {
6614*b4c3e9b5SBjoern A. Zeeb 		memset(txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);
6615*b4c3e9b5SBjoern A. Zeeb 		memset(&txh->rts_frame, 0, sizeof(struct ieee80211_rts));
6616*b4c3e9b5SBjoern A. Zeeb 		memset(txh->RTSPLCPFallback, 0, sizeof(txh->RTSPLCPFallback));
6617*b4c3e9b5SBjoern A. Zeeb 		txh->RTSDurFallback = 0;
6618*b4c3e9b5SBjoern A. Zeeb 	}
6619*b4c3e9b5SBjoern A. Zeeb 
6620*b4c3e9b5SBjoern A. Zeeb #ifdef SUPPORT_40MHZ
6621*b4c3e9b5SBjoern A. Zeeb 	/* add null delimiter count */
6622*b4c3e9b5SBjoern A. Zeeb 	if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && is_mcs_rate(rspec))
6623*b4c3e9b5SBjoern A. Zeeb 		txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] =
6624*b4c3e9b5SBjoern A. Zeeb 		   brcm_c_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen);
6625*b4c3e9b5SBjoern A. Zeeb 
6626*b4c3e9b5SBjoern A. Zeeb #endif
6627*b4c3e9b5SBjoern A. Zeeb 
6628*b4c3e9b5SBjoern A. Zeeb 	/*
6629*b4c3e9b5SBjoern A. Zeeb 	 * Now that RTS/RTS FB preamble types are updated, write
6630*b4c3e9b5SBjoern A. Zeeb 	 * the final value
6631*b4c3e9b5SBjoern A. Zeeb 	 */
6632*b4c3e9b5SBjoern A. Zeeb 	txh->MacTxControlHigh = cpu_to_le16(mch);
6633*b4c3e9b5SBjoern A. Zeeb 
6634*b4c3e9b5SBjoern A. Zeeb 	/*
6635*b4c3e9b5SBjoern A. Zeeb 	 * MainRates (both the rts and frag plcp rates have
6636*b4c3e9b5SBjoern A. Zeeb 	 * been calculated now)
6637*b4c3e9b5SBjoern A. Zeeb 	 */
6638*b4c3e9b5SBjoern A. Zeeb 	txh->MainRates = cpu_to_le16(mainrates);
6639*b4c3e9b5SBjoern A. Zeeb 
6640*b4c3e9b5SBjoern A. Zeeb 	/* XtraFrameTypes */
6641*b4c3e9b5SBjoern A. Zeeb 	xfts = frametype(rspec[1], wlc->mimoft);
6642*b4c3e9b5SBjoern A. Zeeb 	xfts |= (frametype(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);
6643*b4c3e9b5SBjoern A. Zeeb 	xfts |= (frametype(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);
6644*b4c3e9b5SBjoern A. Zeeb 	xfts |= CHSPEC_CHANNEL(wlc_phy_chanspec_get(wlc->band->pi)) <<
6645*b4c3e9b5SBjoern A. Zeeb 							     XFTS_CHANNEL_SHIFT;
6646*b4c3e9b5SBjoern A. Zeeb 	txh->XtraFrameTypes = cpu_to_le16(xfts);
6647*b4c3e9b5SBjoern A. Zeeb 
6648*b4c3e9b5SBjoern A. Zeeb 	/* PhyTxControlWord */
6649*b4c3e9b5SBjoern A. Zeeb 	phyctl = frametype(rspec[0], wlc->mimoft);
6650*b4c3e9b5SBjoern A. Zeeb 	if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) ||
6651*b4c3e9b5SBjoern A. Zeeb 	    (preamble_type[0] == BRCMS_GF_PREAMBLE)) {
6652*b4c3e9b5SBjoern A. Zeeb 		if (rspec2rate(rspec[0]) != BRCM_RATE_1M)
6653*b4c3e9b5SBjoern A. Zeeb 			phyctl |= PHY_TXC_SHORT_HDR;
6654*b4c3e9b5SBjoern A. Zeeb 	}
6655*b4c3e9b5SBjoern A. Zeeb 
6656*b4c3e9b5SBjoern A. Zeeb 	/* phytxant is properly bit shifted */
6657*b4c3e9b5SBjoern A. Zeeb 	phyctl |= brcms_c_stf_d11hdrs_phyctl_txant(wlc, rspec[0]);
6658*b4c3e9b5SBjoern A. Zeeb 	txh->PhyTxControlWord = cpu_to_le16(phyctl);
6659*b4c3e9b5SBjoern A. Zeeb 
6660*b4c3e9b5SBjoern A. Zeeb 	/* PhyTxControlWord_1 */
6661*b4c3e9b5SBjoern A. Zeeb 	if (BRCMS_PHY_11N_CAP(wlc->band)) {
6662*b4c3e9b5SBjoern A. Zeeb 		u16 phyctl1 = 0;
6663*b4c3e9b5SBjoern A. Zeeb 
6664*b4c3e9b5SBjoern A. Zeeb 		phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[0]);
6665*b4c3e9b5SBjoern A. Zeeb 		txh->PhyTxControlWord_1 = cpu_to_le16(phyctl1);
6666*b4c3e9b5SBjoern A. Zeeb 		phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[1]);
6667*b4c3e9b5SBjoern A. Zeeb 		txh->PhyTxControlWord_1_Fbr = cpu_to_le16(phyctl1);
6668*b4c3e9b5SBjoern A. Zeeb 
6669*b4c3e9b5SBjoern A. Zeeb 		if (use_rts || use_cts) {
6670*b4c3e9b5SBjoern A. Zeeb 			phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[0]);
6671*b4c3e9b5SBjoern A. Zeeb 			txh->PhyTxControlWord_1_Rts = cpu_to_le16(phyctl1);
6672*b4c3e9b5SBjoern A. Zeeb 			phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[1]);
6673*b4c3e9b5SBjoern A. Zeeb 			txh->PhyTxControlWord_1_FbrRts = cpu_to_le16(phyctl1);
6674*b4c3e9b5SBjoern A. Zeeb 		}
6675*b4c3e9b5SBjoern A. Zeeb 
6676*b4c3e9b5SBjoern A. Zeeb 		/*
6677*b4c3e9b5SBjoern A. Zeeb 		 * For mcs frames, if mixedmode(overloaded with long preamble)
6678*b4c3e9b5SBjoern A. Zeeb 		 * is going to be set, fill in non-zero MModeLen and/or
6679*b4c3e9b5SBjoern A. Zeeb 		 * MModeFbrLen it will be unnecessary if they are separated
6680*b4c3e9b5SBjoern A. Zeeb 		 */
6681*b4c3e9b5SBjoern A. Zeeb 		if (is_mcs_rate(rspec[0]) &&
6682*b4c3e9b5SBjoern A. Zeeb 		    (preamble_type[0] == BRCMS_MM_PREAMBLE)) {
6683*b4c3e9b5SBjoern A. Zeeb 			u16 mmodelen =
6684*b4c3e9b5SBjoern A. Zeeb 			    brcms_c_calc_lsig_len(wlc, rspec[0], phylen);
6685*b4c3e9b5SBjoern A. Zeeb 			txh->MModeLen = cpu_to_le16(mmodelen);
6686*b4c3e9b5SBjoern A. Zeeb 		}
6687*b4c3e9b5SBjoern A. Zeeb 
6688*b4c3e9b5SBjoern A. Zeeb 		if (is_mcs_rate(rspec[1]) &&
6689*b4c3e9b5SBjoern A. Zeeb 		    (preamble_type[1] == BRCMS_MM_PREAMBLE)) {
6690*b4c3e9b5SBjoern A. Zeeb 			u16 mmodefbrlen =
6691*b4c3e9b5SBjoern A. Zeeb 			    brcms_c_calc_lsig_len(wlc, rspec[1], phylen);
6692*b4c3e9b5SBjoern A. Zeeb 			txh->MModeFbrLen = cpu_to_le16(mmodefbrlen);
6693*b4c3e9b5SBjoern A. Zeeb 		}
6694*b4c3e9b5SBjoern A. Zeeb 	}
6695*b4c3e9b5SBjoern A. Zeeb 
6696*b4c3e9b5SBjoern A. Zeeb 	ac = skb_get_queue_mapping(p);
6697*b4c3e9b5SBjoern A. Zeeb 	if ((scb->flags & SCB_WMECAP) && qos && wlc->edcf_txop[ac]) {
6698*b4c3e9b5SBjoern A. Zeeb 		uint frag_dur, dur, dur_fallback;
6699*b4c3e9b5SBjoern A. Zeeb 
6700*b4c3e9b5SBjoern A. Zeeb 		/* WME: Update TXOP threshold */
6701*b4c3e9b5SBjoern A. Zeeb 		if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) && frag == 0) {
6702*b4c3e9b5SBjoern A. Zeeb 			frag_dur =
6703*b4c3e9b5SBjoern A. Zeeb 			    brcms_c_calc_frame_time(wlc, rspec[0],
6704*b4c3e9b5SBjoern A. Zeeb 					preamble_type[0], phylen);
6705*b4c3e9b5SBjoern A. Zeeb 
6706*b4c3e9b5SBjoern A. Zeeb 			if (rts) {
6707*b4c3e9b5SBjoern A. Zeeb 				/* 1 RTS or CTS-to-self frame */
6708*b4c3e9b5SBjoern A. Zeeb 				dur =
6709*b4c3e9b5SBjoern A. Zeeb 				    brcms_c_calc_cts_time(wlc, rts_rspec[0],
6710*b4c3e9b5SBjoern A. Zeeb 						      rts_preamble_type[0]);
6711*b4c3e9b5SBjoern A. Zeeb 				dur_fallback =
6712*b4c3e9b5SBjoern A. Zeeb 				    brcms_c_calc_cts_time(wlc, rts_rspec[1],
6713*b4c3e9b5SBjoern A. Zeeb 						      rts_preamble_type[1]);
6714*b4c3e9b5SBjoern A. Zeeb 				/* (SIFS + CTS) + SIFS + frame + SIFS + ACK */
6715*b4c3e9b5SBjoern A. Zeeb 				dur += le16_to_cpu(rts->duration);
6716*b4c3e9b5SBjoern A. Zeeb 				dur_fallback +=
6717*b4c3e9b5SBjoern A. Zeeb 					le16_to_cpu(txh->RTSDurFallback);
6718*b4c3e9b5SBjoern A. Zeeb 			} else if (use_rifs) {
6719*b4c3e9b5SBjoern A. Zeeb 				dur = frag_dur;
6720*b4c3e9b5SBjoern A. Zeeb 				dur_fallback = 0;
6721*b4c3e9b5SBjoern A. Zeeb 			} else {
6722*b4c3e9b5SBjoern A. Zeeb 				/* frame + SIFS + ACK */
6723*b4c3e9b5SBjoern A. Zeeb 				dur = frag_dur;
6724*b4c3e9b5SBjoern A. Zeeb 				dur +=
6725*b4c3e9b5SBjoern A. Zeeb 				    brcms_c_compute_frame_dur(wlc, rspec[0],
6726*b4c3e9b5SBjoern A. Zeeb 							  preamble_type[0], 0);
6727*b4c3e9b5SBjoern A. Zeeb 
6728*b4c3e9b5SBjoern A. Zeeb 				dur_fallback =
6729*b4c3e9b5SBjoern A. Zeeb 				    brcms_c_calc_frame_time(wlc, rspec[1],
6730*b4c3e9b5SBjoern A. Zeeb 							preamble_type[1],
6731*b4c3e9b5SBjoern A. Zeeb 							phylen);
6732*b4c3e9b5SBjoern A. Zeeb 				dur_fallback +=
6733*b4c3e9b5SBjoern A. Zeeb 				    brcms_c_compute_frame_dur(wlc, rspec[1],
6734*b4c3e9b5SBjoern A. Zeeb 							  preamble_type[1], 0);
6735*b4c3e9b5SBjoern A. Zeeb 			}
6736*b4c3e9b5SBjoern A. Zeeb 			/* NEED to set TxFesTimeNormal (hard) */
6737*b4c3e9b5SBjoern A. Zeeb 			txh->TxFesTimeNormal = cpu_to_le16((u16) dur);
6738*b4c3e9b5SBjoern A. Zeeb 			/*
6739*b4c3e9b5SBjoern A. Zeeb 			 * NEED to set fallback rate version of
6740*b4c3e9b5SBjoern A. Zeeb 			 * TxFesTimeNormal (hard)
6741*b4c3e9b5SBjoern A. Zeeb 			 */
6742*b4c3e9b5SBjoern A. Zeeb 			txh->TxFesTimeFallback =
6743*b4c3e9b5SBjoern A. Zeeb 				cpu_to_le16((u16) dur_fallback);
6744*b4c3e9b5SBjoern A. Zeeb 
6745*b4c3e9b5SBjoern A. Zeeb 			/*
6746*b4c3e9b5SBjoern A. Zeeb 			 * update txop byte threshold (txop minus intraframe
6747*b4c3e9b5SBjoern A. Zeeb 			 * overhead)
6748*b4c3e9b5SBjoern A. Zeeb 			 */
6749*b4c3e9b5SBjoern A. Zeeb 			if (wlc->edcf_txop[ac] >= (dur - frag_dur)) {
6750*b4c3e9b5SBjoern A. Zeeb 				uint newfragthresh;
6751*b4c3e9b5SBjoern A. Zeeb 
6752*b4c3e9b5SBjoern A. Zeeb 				newfragthresh =
6753*b4c3e9b5SBjoern A. Zeeb 				    brcms_c_calc_frame_len(wlc,
6754*b4c3e9b5SBjoern A. Zeeb 					rspec[0], preamble_type[0],
6755*b4c3e9b5SBjoern A. Zeeb 					(wlc->edcf_txop[ac] -
6756*b4c3e9b5SBjoern A. Zeeb 						(dur - frag_dur)));
6757*b4c3e9b5SBjoern A. Zeeb 				/* range bound the fragthreshold */
6758*b4c3e9b5SBjoern A. Zeeb 				if (newfragthresh < DOT11_MIN_FRAG_LEN)
6759*b4c3e9b5SBjoern A. Zeeb 					newfragthresh =
6760*b4c3e9b5SBjoern A. Zeeb 					    DOT11_MIN_FRAG_LEN;
6761*b4c3e9b5SBjoern A. Zeeb 				else if (newfragthresh >
6762*b4c3e9b5SBjoern A. Zeeb 					 wlc->usr_fragthresh)
6763*b4c3e9b5SBjoern A. Zeeb 					newfragthresh =
6764*b4c3e9b5SBjoern A. Zeeb 					    wlc->usr_fragthresh;
6765*b4c3e9b5SBjoern A. Zeeb 				/* update the fragthresh and do txc update */
6766*b4c3e9b5SBjoern A. Zeeb 				if (wlc->fragthresh[queue] !=
6767*b4c3e9b5SBjoern A. Zeeb 				    (u16) newfragthresh)
6768*b4c3e9b5SBjoern A. Zeeb 					wlc->fragthresh[queue] =
6769*b4c3e9b5SBjoern A. Zeeb 					    (u16) newfragthresh;
6770*b4c3e9b5SBjoern A. Zeeb 			} else {
6771*b4c3e9b5SBjoern A. Zeeb 				brcms_warn(wlc->hw->d11core,
6772*b4c3e9b5SBjoern A. Zeeb 					   "wl%d: %s txop invalid for rate %d\n",
6773*b4c3e9b5SBjoern A. Zeeb 					   wlc->pub->unit, fifo_names[queue],
6774*b4c3e9b5SBjoern A. Zeeb 					   rspec2rate(rspec[0]));
6775*b4c3e9b5SBjoern A. Zeeb 			}
6776*b4c3e9b5SBjoern A. Zeeb 
6777*b4c3e9b5SBjoern A. Zeeb 			if (dur > wlc->edcf_txop[ac])
6778*b4c3e9b5SBjoern A. Zeeb 				brcms_warn(wlc->hw->d11core,
6779*b4c3e9b5SBjoern A. Zeeb 					   "wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n",
6780*b4c3e9b5SBjoern A. Zeeb 					   wlc->pub->unit, __func__,
6781*b4c3e9b5SBjoern A. Zeeb 					   fifo_names[queue],
6782*b4c3e9b5SBjoern A. Zeeb 					   phylen, wlc->fragthresh[queue],
6783*b4c3e9b5SBjoern A. Zeeb 					   dur, wlc->edcf_txop[ac]);
6784*b4c3e9b5SBjoern A. Zeeb 		}
6785*b4c3e9b5SBjoern A. Zeeb 	}
6786*b4c3e9b5SBjoern A. Zeeb 
6787*b4c3e9b5SBjoern A. Zeeb 	return 0;
6788*b4c3e9b5SBjoern A. Zeeb }
6789*b4c3e9b5SBjoern A. Zeeb 
brcms_c_tx(struct brcms_c_info * wlc,struct sk_buff * skb)6790*b4c3e9b5SBjoern A. Zeeb static int brcms_c_tx(struct brcms_c_info *wlc, struct sk_buff *skb)
6791*b4c3e9b5SBjoern A. Zeeb {
6792*b4c3e9b5SBjoern A. Zeeb 	struct dma_pub *dma;
6793*b4c3e9b5SBjoern A. Zeeb 	int fifo, ret = -ENOSPC;
6794*b4c3e9b5SBjoern A. Zeeb 	struct d11txh *txh;
6795*b4c3e9b5SBjoern A. Zeeb 	u16 frameid = INVALIDFID;
6796*b4c3e9b5SBjoern A. Zeeb 
6797*b4c3e9b5SBjoern A. Zeeb 	fifo = brcms_ac_to_fifo(skb_get_queue_mapping(skb));
6798*b4c3e9b5SBjoern A. Zeeb 	dma = wlc->hw->di[fifo];
6799*b4c3e9b5SBjoern A. Zeeb 	txh = (struct d11txh *)(skb->data);
6800*b4c3e9b5SBjoern A. Zeeb 
6801*b4c3e9b5SBjoern A. Zeeb 	if (dma->txavail == 0) {
6802*b4c3e9b5SBjoern A. Zeeb 		/*
6803*b4c3e9b5SBjoern A. Zeeb 		 * We sometimes get a frame from mac80211 after stopping
6804*b4c3e9b5SBjoern A. Zeeb 		 * the queues. This only ever seems to be a single frame
6805*b4c3e9b5SBjoern A. Zeeb 		 * and is seems likely to be a race. TX_HEADROOM should
6806*b4c3e9b5SBjoern A. Zeeb 		 * ensure that we have enough space to handle these stray
6807*b4c3e9b5SBjoern A. Zeeb 		 * packets, so warn if there isn't. If we're out of space
6808*b4c3e9b5SBjoern A. Zeeb 		 * in the tx ring and the tx queue isn't stopped then
6809*b4c3e9b5SBjoern A. Zeeb 		 * we've really got a bug; warn loudly if that happens.
6810*b4c3e9b5SBjoern A. Zeeb 		 */
6811*b4c3e9b5SBjoern A. Zeeb 		brcms_warn(wlc->hw->d11core,
6812*b4c3e9b5SBjoern A. Zeeb 			   "Received frame for tx with no space in DMA ring\n");
6813*b4c3e9b5SBjoern A. Zeeb 		WARN_ON(!ieee80211_queue_stopped(wlc->pub->ieee_hw,
6814*b4c3e9b5SBjoern A. Zeeb 						 skb_get_queue_mapping(skb)));
6815*b4c3e9b5SBjoern A. Zeeb 		return -ENOSPC;
6816*b4c3e9b5SBjoern A. Zeeb 	}
6817*b4c3e9b5SBjoern A. Zeeb 
6818*b4c3e9b5SBjoern A. Zeeb 	/* When a BC/MC frame is being committed to the BCMC fifo
6819*b4c3e9b5SBjoern A. Zeeb 	 * via DMA (NOT PIO), update ucode or BSS info as appropriate.
6820*b4c3e9b5SBjoern A. Zeeb 	 */
6821*b4c3e9b5SBjoern A. Zeeb 	if (fifo == TX_BCMC_FIFO)
6822*b4c3e9b5SBjoern A. Zeeb 		frameid = le16_to_cpu(txh->TxFrameID);
6823*b4c3e9b5SBjoern A. Zeeb 
6824*b4c3e9b5SBjoern A. Zeeb 	/* Commit BCMC sequence number in the SHM frame ID location */
6825*b4c3e9b5SBjoern A. Zeeb 	if (frameid != INVALIDFID) {
6826*b4c3e9b5SBjoern A. Zeeb 		/*
6827*b4c3e9b5SBjoern A. Zeeb 		 * To inform the ucode of the last mcast frame posted
6828*b4c3e9b5SBjoern A. Zeeb 		 * so that it can clear moredata bit
6829*b4c3e9b5SBjoern A. Zeeb 		 */
6830*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc->hw, M_BCMC_FID, frameid);
6831*b4c3e9b5SBjoern A. Zeeb 	}
6832*b4c3e9b5SBjoern A. Zeeb 
6833*b4c3e9b5SBjoern A. Zeeb 	ret = brcms_c_txfifo(wlc, fifo, skb);
6834*b4c3e9b5SBjoern A. Zeeb 	/*
6835*b4c3e9b5SBjoern A. Zeeb 	 * The only reason for brcms_c_txfifo to fail is because
6836*b4c3e9b5SBjoern A. Zeeb 	 * there weren't any DMA descriptors, but we've already
6837*b4c3e9b5SBjoern A. Zeeb 	 * checked for that. So if it does fail yell loudly.
6838*b4c3e9b5SBjoern A. Zeeb 	 */
6839*b4c3e9b5SBjoern A. Zeeb 	WARN_ON_ONCE(ret);
6840*b4c3e9b5SBjoern A. Zeeb 
6841*b4c3e9b5SBjoern A. Zeeb 	return ret;
6842*b4c3e9b5SBjoern A. Zeeb }
6843*b4c3e9b5SBjoern A. Zeeb 
brcms_c_sendpkt_mac80211(struct brcms_c_info * wlc,struct sk_buff * sdu,struct ieee80211_hw * hw)6844*b4c3e9b5SBjoern A. Zeeb bool brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu,
6845*b4c3e9b5SBjoern A. Zeeb 			      struct ieee80211_hw *hw)
6846*b4c3e9b5SBjoern A. Zeeb {
6847*b4c3e9b5SBjoern A. Zeeb 	uint fifo;
6848*b4c3e9b5SBjoern A. Zeeb 	struct scb *scb = &wlc->pri_scb;
6849*b4c3e9b5SBjoern A. Zeeb 
6850*b4c3e9b5SBjoern A. Zeeb 	fifo = brcms_ac_to_fifo(skb_get_queue_mapping(sdu));
6851*b4c3e9b5SBjoern A. Zeeb 	brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0);
6852*b4c3e9b5SBjoern A. Zeeb 	if (!brcms_c_tx(wlc, sdu))
6853*b4c3e9b5SBjoern A. Zeeb 		return true;
6854*b4c3e9b5SBjoern A. Zeeb 
6855*b4c3e9b5SBjoern A. Zeeb 	/* packet discarded */
6856*b4c3e9b5SBjoern A. Zeeb 	dev_kfree_skb_any(sdu);
6857*b4c3e9b5SBjoern A. Zeeb 	return false;
6858*b4c3e9b5SBjoern A. Zeeb }
6859*b4c3e9b5SBjoern A. Zeeb 
6860*b4c3e9b5SBjoern A. Zeeb int
brcms_c_txfifo(struct brcms_c_info * wlc,uint fifo,struct sk_buff * p)6861*b4c3e9b5SBjoern A. Zeeb brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p)
6862*b4c3e9b5SBjoern A. Zeeb {
6863*b4c3e9b5SBjoern A. Zeeb 	struct dma_pub *dma = wlc->hw->di[fifo];
6864*b4c3e9b5SBjoern A. Zeeb 	int ret;
6865*b4c3e9b5SBjoern A. Zeeb 	u16 queue;
6866*b4c3e9b5SBjoern A. Zeeb 
6867*b4c3e9b5SBjoern A. Zeeb 	ret = dma_txfast(wlc, dma, p);
6868*b4c3e9b5SBjoern A. Zeeb 	if (ret	< 0)
6869*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n");
6870*b4c3e9b5SBjoern A. Zeeb 
6871*b4c3e9b5SBjoern A. Zeeb 	/*
6872*b4c3e9b5SBjoern A. Zeeb 	 * Stop queue if DMA ring is full. Reserve some free descriptors,
6873*b4c3e9b5SBjoern A. Zeeb 	 * as we sometimes receive a frame from mac80211 after the queues
6874*b4c3e9b5SBjoern A. Zeeb 	 * are stopped.
6875*b4c3e9b5SBjoern A. Zeeb 	 */
6876*b4c3e9b5SBjoern A. Zeeb 	queue = skb_get_queue_mapping(p);
6877*b4c3e9b5SBjoern A. Zeeb 	if (dma->txavail <= TX_HEADROOM && fifo < TX_BCMC_FIFO &&
6878*b4c3e9b5SBjoern A. Zeeb 	    !ieee80211_queue_stopped(wlc->pub->ieee_hw, queue))
6879*b4c3e9b5SBjoern A. Zeeb 		ieee80211_stop_queue(wlc->pub->ieee_hw, queue);
6880*b4c3e9b5SBjoern A. Zeeb 
6881*b4c3e9b5SBjoern A. Zeeb 	return ret;
6882*b4c3e9b5SBjoern A. Zeeb }
6883*b4c3e9b5SBjoern A. Zeeb 
6884*b4c3e9b5SBjoern A. Zeeb u32
brcms_c_rspec_to_rts_rspec(struct brcms_c_info * wlc,u32 rspec,bool use_rspec,u16 mimo_ctlchbw)6885*b4c3e9b5SBjoern A. Zeeb brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
6886*b4c3e9b5SBjoern A. Zeeb 			   bool use_rspec, u16 mimo_ctlchbw)
6887*b4c3e9b5SBjoern A. Zeeb {
6888*b4c3e9b5SBjoern A. Zeeb 	u32 rts_rspec = 0;
6889*b4c3e9b5SBjoern A. Zeeb 
6890*b4c3e9b5SBjoern A. Zeeb 	if (use_rspec)
6891*b4c3e9b5SBjoern A. Zeeb 		/* use frame rate as rts rate */
6892*b4c3e9b5SBjoern A. Zeeb 		rts_rspec = rspec;
6893*b4c3e9b5SBjoern A. Zeeb 	else if (wlc->band->gmode && wlc->protection->_g && !is_cck_rate(rspec))
6894*b4c3e9b5SBjoern A. Zeeb 		/* Use 11Mbps as the g protection RTS target rate and fallback.
6895*b4c3e9b5SBjoern A. Zeeb 		 * Use the brcms_basic_rate() lookup to find the best basic rate
6896*b4c3e9b5SBjoern A. Zeeb 		 * under the target in case 11 Mbps is not Basic.
6897*b4c3e9b5SBjoern A. Zeeb 		 * 6 and 9 Mbps are not usually selected by rate selection, but
6898*b4c3e9b5SBjoern A. Zeeb 		 * even if the OFDM rate we are protecting is 6 or 9 Mbps, 11
6899*b4c3e9b5SBjoern A. Zeeb 		 * is more robust.
6900*b4c3e9b5SBjoern A. Zeeb 		 */
6901*b4c3e9b5SBjoern A. Zeeb 		rts_rspec = brcms_basic_rate(wlc, BRCM_RATE_11M);
6902*b4c3e9b5SBjoern A. Zeeb 	else
6903*b4c3e9b5SBjoern A. Zeeb 		/* calculate RTS rate and fallback rate based on the frame rate
6904*b4c3e9b5SBjoern A. Zeeb 		 * RTS must be sent at a basic rate since it is a
6905*b4c3e9b5SBjoern A. Zeeb 		 * control frame, sec 9.6 of 802.11 spec
6906*b4c3e9b5SBjoern A. Zeeb 		 */
6907*b4c3e9b5SBjoern A. Zeeb 		rts_rspec = brcms_basic_rate(wlc, rspec);
6908*b4c3e9b5SBjoern A. Zeeb 
6909*b4c3e9b5SBjoern A. Zeeb 	if (BRCMS_PHY_11N_CAP(wlc->band)) {
6910*b4c3e9b5SBjoern A. Zeeb 		/* set rts txbw to correct side band */
6911*b4c3e9b5SBjoern A. Zeeb 		rts_rspec &= ~RSPEC_BW_MASK;
6912*b4c3e9b5SBjoern A. Zeeb 
6913*b4c3e9b5SBjoern A. Zeeb 		/*
6914*b4c3e9b5SBjoern A. Zeeb 		 * if rspec/rspec_fallback is 40MHz, then send RTS on both
6915*b4c3e9b5SBjoern A. Zeeb 		 * 20MHz channel (DUP), otherwise send RTS on control channel
6916*b4c3e9b5SBjoern A. Zeeb 		 */
6917*b4c3e9b5SBjoern A. Zeeb 		if (rspec_is40mhz(rspec) && !is_cck_rate(rts_rspec))
6918*b4c3e9b5SBjoern A. Zeeb 			rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT);
6919*b4c3e9b5SBjoern A. Zeeb 		else
6920*b4c3e9b5SBjoern A. Zeeb 			rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
6921*b4c3e9b5SBjoern A. Zeeb 
6922*b4c3e9b5SBjoern A. Zeeb 		/* pick siso/cdd as default for ofdm */
6923*b4c3e9b5SBjoern A. Zeeb 		if (is_ofdm_rate(rts_rspec)) {
6924*b4c3e9b5SBjoern A. Zeeb 			rts_rspec &= ~RSPEC_STF_MASK;
6925*b4c3e9b5SBjoern A. Zeeb 			rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
6926*b4c3e9b5SBjoern A. Zeeb 		}
6927*b4c3e9b5SBjoern A. Zeeb 	}
6928*b4c3e9b5SBjoern A. Zeeb 	return rts_rspec;
6929*b4c3e9b5SBjoern A. Zeeb }
6930*b4c3e9b5SBjoern A. Zeeb 
6931*b4c3e9b5SBjoern A. Zeeb /* Update beacon listen interval in shared memory */
brcms_c_bcn_li_upd(struct brcms_c_info * wlc)6932*b4c3e9b5SBjoern A. Zeeb static void brcms_c_bcn_li_upd(struct brcms_c_info *wlc)
6933*b4c3e9b5SBjoern A. Zeeb {
6934*b4c3e9b5SBjoern A. Zeeb 	/* wake up every DTIM is the default */
6935*b4c3e9b5SBjoern A. Zeeb 	if (wlc->bcn_li_dtim == 1)
6936*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc->hw, M_BCN_LI, 0);
6937*b4c3e9b5SBjoern A. Zeeb 	else
6938*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc->hw, M_BCN_LI,
6939*b4c3e9b5SBjoern A. Zeeb 			      (wlc->bcn_li_dtim << 8) | wlc->bcn_li_bcn);
6940*b4c3e9b5SBjoern A. Zeeb }
6941*b4c3e9b5SBjoern A. Zeeb 
6942*b4c3e9b5SBjoern A. Zeeb static void
brcms_b_read_tsf(struct brcms_hardware * wlc_hw,u32 * tsf_l_ptr,u32 * tsf_h_ptr)6943*b4c3e9b5SBjoern A. Zeeb brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr,
6944*b4c3e9b5SBjoern A. Zeeb 		  u32 *tsf_h_ptr)
6945*b4c3e9b5SBjoern A. Zeeb {
6946*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
6947*b4c3e9b5SBjoern A. Zeeb 
6948*b4c3e9b5SBjoern A. Zeeb 	/* read the tsf timer low, then high to get an atomic read */
6949*b4c3e9b5SBjoern A. Zeeb 	*tsf_l_ptr = bcma_read32(core, D11REGOFFS(tsf_timerlow));
6950*b4c3e9b5SBjoern A. Zeeb 	*tsf_h_ptr = bcma_read32(core, D11REGOFFS(tsf_timerhigh));
6951*b4c3e9b5SBjoern A. Zeeb }
6952*b4c3e9b5SBjoern A. Zeeb 
6953*b4c3e9b5SBjoern A. Zeeb /*
6954*b4c3e9b5SBjoern A. Zeeb  * recover 64bit TSF value from the 16bit TSF value in the rx header
6955*b4c3e9b5SBjoern A. Zeeb  * given the assumption that the TSF passed in header is within 65ms
6956*b4c3e9b5SBjoern A. Zeeb  * of the current tsf.
6957*b4c3e9b5SBjoern A. Zeeb  *
6958*b4c3e9b5SBjoern A. Zeeb  * 6       5       4       4       3       2       1
6959*b4c3e9b5SBjoern A. Zeeb  * 3.......6.......8.......0.......2.......4.......6.......8......0
6960*b4c3e9b5SBjoern A. Zeeb  * |<---------- tsf_h ----------->||<--- tsf_l -->||<-RxTSFTime ->|
6961*b4c3e9b5SBjoern A. Zeeb  *
6962*b4c3e9b5SBjoern A. Zeeb  * The RxTSFTime are the lowest 16 bits and provided by the ucode. The
6963*b4c3e9b5SBjoern A. Zeeb  * tsf_l is filled in by brcms_b_recv, which is done earlier in the
6964*b4c3e9b5SBjoern A. Zeeb  * receive call sequence after rx interrupt. Only the higher 16 bits
6965*b4c3e9b5SBjoern A. Zeeb  * are used. Finally, the tsf_h is read from the tsf register.
6966*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_recover_tsf64(struct brcms_c_info * wlc,struct d11rxhdr * rxh)6967*b4c3e9b5SBjoern A. Zeeb static u64 brcms_c_recover_tsf64(struct brcms_c_info *wlc,
6968*b4c3e9b5SBjoern A. Zeeb 				 struct d11rxhdr *rxh)
6969*b4c3e9b5SBjoern A. Zeeb {
6970*b4c3e9b5SBjoern A. Zeeb 	u32 tsf_h, tsf_l;
6971*b4c3e9b5SBjoern A. Zeeb 	u16 rx_tsf_0_15, rx_tsf_16_31;
6972*b4c3e9b5SBjoern A. Zeeb 
6973*b4c3e9b5SBjoern A. Zeeb 	brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h);
6974*b4c3e9b5SBjoern A. Zeeb 
6975*b4c3e9b5SBjoern A. Zeeb 	rx_tsf_16_31 = (u16)(tsf_l >> 16);
6976*b4c3e9b5SBjoern A. Zeeb 	rx_tsf_0_15 = rxh->RxTSFTime;
6977*b4c3e9b5SBjoern A. Zeeb 
6978*b4c3e9b5SBjoern A. Zeeb 	/*
6979*b4c3e9b5SBjoern A. Zeeb 	 * a greater tsf time indicates the low 16 bits of
6980*b4c3e9b5SBjoern A. Zeeb 	 * tsf_l wrapped, so decrement the high 16 bits.
6981*b4c3e9b5SBjoern A. Zeeb 	 */
6982*b4c3e9b5SBjoern A. Zeeb 	if ((u16)tsf_l < rx_tsf_0_15) {
6983*b4c3e9b5SBjoern A. Zeeb 		rx_tsf_16_31 -= 1;
6984*b4c3e9b5SBjoern A. Zeeb 		if (rx_tsf_16_31 == 0xffff)
6985*b4c3e9b5SBjoern A. Zeeb 			tsf_h -= 1;
6986*b4c3e9b5SBjoern A. Zeeb 	}
6987*b4c3e9b5SBjoern A. Zeeb 
6988*b4c3e9b5SBjoern A. Zeeb 	return ((u64)tsf_h << 32) | (((u32)rx_tsf_16_31 << 16) + rx_tsf_0_15);
6989*b4c3e9b5SBjoern A. Zeeb }
6990*b4c3e9b5SBjoern A. Zeeb 
6991*b4c3e9b5SBjoern A. Zeeb static void
prep_mac80211_status(struct brcms_c_info * wlc,struct d11rxhdr * rxh,struct sk_buff * p,struct ieee80211_rx_status * rx_status)6992*b4c3e9b5SBjoern A. Zeeb prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
6993*b4c3e9b5SBjoern A. Zeeb 		     struct sk_buff *p,
6994*b4c3e9b5SBjoern A. Zeeb 		     struct ieee80211_rx_status *rx_status)
6995*b4c3e9b5SBjoern A. Zeeb {
6996*b4c3e9b5SBjoern A. Zeeb 	int channel;
6997*b4c3e9b5SBjoern A. Zeeb 	u32 rspec;
6998*b4c3e9b5SBjoern A. Zeeb 	unsigned char *plcp;
6999*b4c3e9b5SBjoern A. Zeeb 
7000*b4c3e9b5SBjoern A. Zeeb 	/* fill in TSF and flag its presence */
7001*b4c3e9b5SBjoern A. Zeeb 	rx_status->mactime = brcms_c_recover_tsf64(wlc, rxh);
7002*b4c3e9b5SBjoern A. Zeeb 	rx_status->flag |= RX_FLAG_MACTIME_START;
7003*b4c3e9b5SBjoern A. Zeeb 
7004*b4c3e9b5SBjoern A. Zeeb 	channel = BRCMS_CHAN_CHANNEL(rxh->RxChan);
7005*b4c3e9b5SBjoern A. Zeeb 
7006*b4c3e9b5SBjoern A. Zeeb 	rx_status->band =
7007*b4c3e9b5SBjoern A. Zeeb 		channel > 14 ? NL80211_BAND_5GHZ : NL80211_BAND_2GHZ;
7008*b4c3e9b5SBjoern A. Zeeb 	rx_status->freq =
7009*b4c3e9b5SBjoern A. Zeeb 		ieee80211_channel_to_frequency(channel, rx_status->band);
7010*b4c3e9b5SBjoern A. Zeeb 
7011*b4c3e9b5SBjoern A. Zeeb 	rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh);
7012*b4c3e9b5SBjoern A. Zeeb 
7013*b4c3e9b5SBjoern A. Zeeb 	/* noise */
7014*b4c3e9b5SBjoern A. Zeeb 	/* qual */
7015*b4c3e9b5SBjoern A. Zeeb 	rx_status->antenna =
7016*b4c3e9b5SBjoern A. Zeeb 		(rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0;
7017*b4c3e9b5SBjoern A. Zeeb 
7018*b4c3e9b5SBjoern A. Zeeb 	plcp = p->data;
7019*b4c3e9b5SBjoern A. Zeeb 
7020*b4c3e9b5SBjoern A. Zeeb 	rspec = brcms_c_compute_rspec(rxh, plcp);
7021*b4c3e9b5SBjoern A. Zeeb 	if (is_mcs_rate(rspec)) {
7022*b4c3e9b5SBjoern A. Zeeb 		rx_status->rate_idx = rspec & RSPEC_RATE_MASK;
7023*b4c3e9b5SBjoern A. Zeeb 		rx_status->encoding = RX_ENC_HT;
7024*b4c3e9b5SBjoern A. Zeeb 		if (rspec_is40mhz(rspec))
7025*b4c3e9b5SBjoern A. Zeeb 			rx_status->bw = RATE_INFO_BW_40;
7026*b4c3e9b5SBjoern A. Zeeb 	} else {
7027*b4c3e9b5SBjoern A. Zeeb 		switch (rspec2rate(rspec)) {
7028*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_1M:
7029*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 0;
7030*b4c3e9b5SBjoern A. Zeeb 			break;
7031*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_2M:
7032*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 1;
7033*b4c3e9b5SBjoern A. Zeeb 			break;
7034*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_5M5:
7035*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 2;
7036*b4c3e9b5SBjoern A. Zeeb 			break;
7037*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_11M:
7038*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 3;
7039*b4c3e9b5SBjoern A. Zeeb 			break;
7040*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_6M:
7041*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 4;
7042*b4c3e9b5SBjoern A. Zeeb 			break;
7043*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_9M:
7044*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 5;
7045*b4c3e9b5SBjoern A. Zeeb 			break;
7046*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_12M:
7047*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 6;
7048*b4c3e9b5SBjoern A. Zeeb 			break;
7049*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_18M:
7050*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 7;
7051*b4c3e9b5SBjoern A. Zeeb 			break;
7052*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_24M:
7053*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 8;
7054*b4c3e9b5SBjoern A. Zeeb 			break;
7055*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_36M:
7056*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 9;
7057*b4c3e9b5SBjoern A. Zeeb 			break;
7058*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_48M:
7059*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 10;
7060*b4c3e9b5SBjoern A. Zeeb 			break;
7061*b4c3e9b5SBjoern A. Zeeb 		case BRCM_RATE_54M:
7062*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx = 11;
7063*b4c3e9b5SBjoern A. Zeeb 			break;
7064*b4c3e9b5SBjoern A. Zeeb 		default:
7065*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc->hw->d11core,
7066*b4c3e9b5SBjoern A. Zeeb 				  "%s: Unknown rate\n", __func__);
7067*b4c3e9b5SBjoern A. Zeeb 		}
7068*b4c3e9b5SBjoern A. Zeeb 
7069*b4c3e9b5SBjoern A. Zeeb 		/*
7070*b4c3e9b5SBjoern A. Zeeb 		 * For 5GHz, we should decrease the index as it is
7071*b4c3e9b5SBjoern A. Zeeb 		 * a subset of the 2.4G rates. See bitrates field
7072*b4c3e9b5SBjoern A. Zeeb 		 * of brcms_band_5GHz_nphy (in mac80211_if.c).
7073*b4c3e9b5SBjoern A. Zeeb 		 */
7074*b4c3e9b5SBjoern A. Zeeb 		if (rx_status->band == NL80211_BAND_5GHZ)
7075*b4c3e9b5SBjoern A. Zeeb 			rx_status->rate_idx -= BRCMS_LEGACY_5G_RATE_OFFSET;
7076*b4c3e9b5SBjoern A. Zeeb 
7077*b4c3e9b5SBjoern A. Zeeb 		/* Determine short preamble and rate_idx */
7078*b4c3e9b5SBjoern A. Zeeb 		if (is_cck_rate(rspec)) {
7079*b4c3e9b5SBjoern A. Zeeb 			if (rxh->PhyRxStatus_0 & PRXS0_SHORTH)
7080*b4c3e9b5SBjoern A. Zeeb 				rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
7081*b4c3e9b5SBjoern A. Zeeb 		} else if (is_ofdm_rate(rspec)) {
7082*b4c3e9b5SBjoern A. Zeeb 			rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
7083*b4c3e9b5SBjoern A. Zeeb 		} else {
7084*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc->hw->d11core, "%s: Unknown modulation\n",
7085*b4c3e9b5SBjoern A. Zeeb 				  __func__);
7086*b4c3e9b5SBjoern A. Zeeb 		}
7087*b4c3e9b5SBjoern A. Zeeb 	}
7088*b4c3e9b5SBjoern A. Zeeb 
7089*b4c3e9b5SBjoern A. Zeeb 	if (plcp3_issgi(plcp[3]))
7090*b4c3e9b5SBjoern A. Zeeb 		rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
7091*b4c3e9b5SBjoern A. Zeeb 
7092*b4c3e9b5SBjoern A. Zeeb 	if (rxh->RxStatus1 & RXS_DECERR) {
7093*b4c3e9b5SBjoern A. Zeeb 		rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC;
7094*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "%s:  RX_FLAG_FAILED_PLCP_CRC\n",
7095*b4c3e9b5SBjoern A. Zeeb 			  __func__);
7096*b4c3e9b5SBjoern A. Zeeb 	}
7097*b4c3e9b5SBjoern A. Zeeb 	if (rxh->RxStatus1 & RXS_FCSERR) {
7098*b4c3e9b5SBjoern A. Zeeb 		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
7099*b4c3e9b5SBjoern A. Zeeb 		brcms_err(wlc->hw->d11core, "%s:  RX_FLAG_FAILED_FCS_CRC\n",
7100*b4c3e9b5SBjoern A. Zeeb 			  __func__);
7101*b4c3e9b5SBjoern A. Zeeb 	}
7102*b4c3e9b5SBjoern A. Zeeb }
7103*b4c3e9b5SBjoern A. Zeeb 
7104*b4c3e9b5SBjoern A. Zeeb static void
brcms_c_recvctl(struct brcms_c_info * wlc,struct d11rxhdr * rxh,struct sk_buff * p)7105*b4c3e9b5SBjoern A. Zeeb brcms_c_recvctl(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
7106*b4c3e9b5SBjoern A. Zeeb 		struct sk_buff *p)
7107*b4c3e9b5SBjoern A. Zeeb {
7108*b4c3e9b5SBjoern A. Zeeb 	int len_mpdu;
7109*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_rx_status rx_status;
7110*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_hdr *hdr;
7111*b4c3e9b5SBjoern A. Zeeb 
7112*b4c3e9b5SBjoern A. Zeeb 	memset(&rx_status, 0, sizeof(rx_status));
7113*b4c3e9b5SBjoern A. Zeeb 	prep_mac80211_status(wlc, rxh, p, &rx_status);
7114*b4c3e9b5SBjoern A. Zeeb 
7115*b4c3e9b5SBjoern A. Zeeb 	/* mac header+body length, exclude CRC and plcp header */
7116*b4c3e9b5SBjoern A. Zeeb 	len_mpdu = p->len - D11_PHY_HDR_LEN - FCS_LEN;
7117*b4c3e9b5SBjoern A. Zeeb 	skb_pull(p, D11_PHY_HDR_LEN);
7118*b4c3e9b5SBjoern A. Zeeb 	__skb_trim(p, len_mpdu);
7119*b4c3e9b5SBjoern A. Zeeb 
7120*b4c3e9b5SBjoern A. Zeeb 	/* unmute transmit */
7121*b4c3e9b5SBjoern A. Zeeb 	if (wlc->hw->suspended_fifos) {
7122*b4c3e9b5SBjoern A. Zeeb 		hdr = (struct ieee80211_hdr *)p->data;
7123*b4c3e9b5SBjoern A. Zeeb 		if (ieee80211_is_beacon(hdr->frame_control))
7124*b4c3e9b5SBjoern A. Zeeb 			brcms_b_mute(wlc->hw, false);
7125*b4c3e9b5SBjoern A. Zeeb 	}
7126*b4c3e9b5SBjoern A. Zeeb 
7127*b4c3e9b5SBjoern A. Zeeb 	memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status));
7128*b4c3e9b5SBjoern A. Zeeb 	ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p);
7129*b4c3e9b5SBjoern A. Zeeb }
7130*b4c3e9b5SBjoern A. Zeeb 
7131*b4c3e9b5SBjoern A. Zeeb /* calculate frame duration for Mixed-mode L-SIG spoofing, return
7132*b4c3e9b5SBjoern A. Zeeb  * number of bytes goes in the length field
7133*b4c3e9b5SBjoern A. Zeeb  *
7134*b4c3e9b5SBjoern A. Zeeb  * Formula given by HT PHY Spec v 1.13
7135*b4c3e9b5SBjoern A. Zeeb  *   len = 3(nsyms + nstream + 3) - 3
7136*b4c3e9b5SBjoern A. Zeeb  */
7137*b4c3e9b5SBjoern A. Zeeb u16
brcms_c_calc_lsig_len(struct brcms_c_info * wlc,u32 ratespec,uint mac_len)7138*b4c3e9b5SBjoern A. Zeeb brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
7139*b4c3e9b5SBjoern A. Zeeb 		      uint mac_len)
7140*b4c3e9b5SBjoern A. Zeeb {
7141*b4c3e9b5SBjoern A. Zeeb 	uint nsyms, len = 0, kNdps;
7142*b4c3e9b5SBjoern A. Zeeb 
7143*b4c3e9b5SBjoern A. Zeeb 	if (is_mcs_rate(ratespec)) {
7144*b4c3e9b5SBjoern A. Zeeb 		uint mcs = ratespec & RSPEC_RATE_MASK;
7145*b4c3e9b5SBjoern A. Zeeb 		int tot_streams = (mcs_2_txstreams(mcs) + 1) +
7146*b4c3e9b5SBjoern A. Zeeb 				  rspec_stc(ratespec);
7147*b4c3e9b5SBjoern A. Zeeb 
7148*b4c3e9b5SBjoern A. Zeeb 		/*
7149*b4c3e9b5SBjoern A. Zeeb 		 * the payload duration calculation matches that
7150*b4c3e9b5SBjoern A. Zeeb 		 * of regular ofdm
7151*b4c3e9b5SBjoern A. Zeeb 		 */
7152*b4c3e9b5SBjoern A. Zeeb 		/* 1000Ndbps = kbps * 4 */
7153*b4c3e9b5SBjoern A. Zeeb 		kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
7154*b4c3e9b5SBjoern A. Zeeb 				   rspec_issgi(ratespec)) * 4;
7155*b4c3e9b5SBjoern A. Zeeb 
7156*b4c3e9b5SBjoern A. Zeeb 		if (rspec_stc(ratespec) == 0)
7157*b4c3e9b5SBjoern A. Zeeb 			nsyms =
7158*b4c3e9b5SBjoern A. Zeeb 			    CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
7159*b4c3e9b5SBjoern A. Zeeb 				  APHY_TAIL_NBITS) * 1000, kNdps);
7160*b4c3e9b5SBjoern A. Zeeb 		else
7161*b4c3e9b5SBjoern A. Zeeb 			/* STBC needs to have even number of symbols */
7162*b4c3e9b5SBjoern A. Zeeb 			nsyms =
7163*b4c3e9b5SBjoern A. Zeeb 			    2 *
7164*b4c3e9b5SBjoern A. Zeeb 			    CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
7165*b4c3e9b5SBjoern A. Zeeb 				  APHY_TAIL_NBITS) * 1000, 2 * kNdps);
7166*b4c3e9b5SBjoern A. Zeeb 
7167*b4c3e9b5SBjoern A. Zeeb 		/* (+3) account for HT-SIG(2) and HT-STF(1) */
7168*b4c3e9b5SBjoern A. Zeeb 		nsyms += (tot_streams + 3);
7169*b4c3e9b5SBjoern A. Zeeb 		/*
7170*b4c3e9b5SBjoern A. Zeeb 		 * 3 bytes/symbol @ legacy 6Mbps rate
7171*b4c3e9b5SBjoern A. Zeeb 		 * (-3) excluding service bits and tail bits
7172*b4c3e9b5SBjoern A. Zeeb 		 */
7173*b4c3e9b5SBjoern A. Zeeb 		len = (3 * nsyms) - 3;
7174*b4c3e9b5SBjoern A. Zeeb 	}
7175*b4c3e9b5SBjoern A. Zeeb 
7176*b4c3e9b5SBjoern A. Zeeb 	return (u16) len;
7177*b4c3e9b5SBjoern A. Zeeb }
7178*b4c3e9b5SBjoern A. Zeeb 
7179*b4c3e9b5SBjoern A. Zeeb static void
brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info * wlc,uint frame_len)7180*b4c3e9b5SBjoern A. Zeeb brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
7181*b4c3e9b5SBjoern A. Zeeb {
7182*b4c3e9b5SBjoern A. Zeeb 	const struct brcms_c_rateset *rs_dflt;
7183*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_rateset rs;
7184*b4c3e9b5SBjoern A. Zeeb 	u8 rate;
7185*b4c3e9b5SBjoern A. Zeeb 	u16 entry_ptr;
7186*b4c3e9b5SBjoern A. Zeeb 	u8 plcp[D11_PHY_HDR_LEN];
7187*b4c3e9b5SBjoern A. Zeeb 	u16 dur, sifs;
7188*b4c3e9b5SBjoern A. Zeeb 	uint i;
7189*b4c3e9b5SBjoern A. Zeeb 
7190*b4c3e9b5SBjoern A. Zeeb 	sifs = get_sifs(wlc->band);
7191*b4c3e9b5SBjoern A. Zeeb 
7192*b4c3e9b5SBjoern A. Zeeb 	rs_dflt = brcms_c_rateset_get_hwrs(wlc);
7193*b4c3e9b5SBjoern A. Zeeb 
7194*b4c3e9b5SBjoern A. Zeeb 	brcms_c_rateset_copy(rs_dflt, &rs);
7195*b4c3e9b5SBjoern A. Zeeb 	brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
7196*b4c3e9b5SBjoern A. Zeeb 
7197*b4c3e9b5SBjoern A. Zeeb 	/*
7198*b4c3e9b5SBjoern A. Zeeb 	 * walk the phy rate table and update MAC core SHM
7199*b4c3e9b5SBjoern A. Zeeb 	 * basic rate table entries
7200*b4c3e9b5SBjoern A. Zeeb 	 */
7201*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < rs.count; i++) {
7202*b4c3e9b5SBjoern A. Zeeb 		rate = rs.rates[i] & BRCMS_RATE_MASK;
7203*b4c3e9b5SBjoern A. Zeeb 
7204*b4c3e9b5SBjoern A. Zeeb 		entry_ptr = brcms_b_rate_shm_offset(wlc->hw, rate);
7205*b4c3e9b5SBjoern A. Zeeb 
7206*b4c3e9b5SBjoern A. Zeeb 		/* Calculate the Probe Response PLCP for the given rate */
7207*b4c3e9b5SBjoern A. Zeeb 		brcms_c_compute_plcp(wlc, rate, frame_len, plcp);
7208*b4c3e9b5SBjoern A. Zeeb 
7209*b4c3e9b5SBjoern A. Zeeb 		/*
7210*b4c3e9b5SBjoern A. Zeeb 		 * Calculate the duration of the Probe Response
7211*b4c3e9b5SBjoern A. Zeeb 		 * frame plus SIFS for the MAC
7212*b4c3e9b5SBjoern A. Zeeb 		 */
7213*b4c3e9b5SBjoern A. Zeeb 		dur = (u16) brcms_c_calc_frame_time(wlc, rate,
7214*b4c3e9b5SBjoern A. Zeeb 						BRCMS_LONG_PREAMBLE, frame_len);
7215*b4c3e9b5SBjoern A. Zeeb 		dur += sifs;
7216*b4c3e9b5SBjoern A. Zeeb 
7217*b4c3e9b5SBjoern A. Zeeb 		/* Update the SHM Rate Table entry Probe Response values */
7218*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS,
7219*b4c3e9b5SBjoern A. Zeeb 			      (u16) (plcp[0] + (plcp[1] << 8)));
7220*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS + 2,
7221*b4c3e9b5SBjoern A. Zeeb 			      (u16) (plcp[2] + (plcp[3] << 8)));
7222*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_DUR_POS, dur);
7223*b4c3e9b5SBjoern A. Zeeb 	}
7224*b4c3e9b5SBjoern A. Zeeb }
7225*b4c3e9b5SBjoern A. Zeeb 
brcms_c_get_header_len(void)7226*b4c3e9b5SBjoern A. Zeeb int brcms_c_get_header_len(void)
7227*b4c3e9b5SBjoern A. Zeeb {
7228*b4c3e9b5SBjoern A. Zeeb 	return TXOFF;
7229*b4c3e9b5SBjoern A. Zeeb }
7230*b4c3e9b5SBjoern A. Zeeb 
brcms_c_beacon_write(struct brcms_c_info * wlc,struct sk_buff * beacon,u16 tim_offset,u16 dtim_period,bool bcn0,bool bcn1)7231*b4c3e9b5SBjoern A. Zeeb static void brcms_c_beacon_write(struct brcms_c_info *wlc,
7232*b4c3e9b5SBjoern A. Zeeb 				 struct sk_buff *beacon, u16 tim_offset,
7233*b4c3e9b5SBjoern A. Zeeb 				 u16 dtim_period, bool bcn0, bool bcn1)
7234*b4c3e9b5SBjoern A. Zeeb {
7235*b4c3e9b5SBjoern A. Zeeb 	size_t len;
7236*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_tx_info *tx_info;
7237*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
7238*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_hw *ieee_hw = brcms_c_pub(wlc)->ieee_hw;
7239*b4c3e9b5SBjoern A. Zeeb 
7240*b4c3e9b5SBjoern A. Zeeb 	/* Get tx_info */
7241*b4c3e9b5SBjoern A. Zeeb 	tx_info = IEEE80211_SKB_CB(beacon);
7242*b4c3e9b5SBjoern A. Zeeb 
7243*b4c3e9b5SBjoern A. Zeeb 	len = min_t(size_t, beacon->len, BCN_TMPL_LEN);
7244*b4c3e9b5SBjoern A. Zeeb 	wlc->bcn_rspec = ieee80211_get_tx_rate(ieee_hw, tx_info)->hw_value;
7245*b4c3e9b5SBjoern A. Zeeb 
7246*b4c3e9b5SBjoern A. Zeeb 	brcms_c_compute_plcp(wlc, wlc->bcn_rspec,
7247*b4c3e9b5SBjoern A. Zeeb 			     len + FCS_LEN - D11_PHY_HDR_LEN, beacon->data);
7248*b4c3e9b5SBjoern A. Zeeb 
7249*b4c3e9b5SBjoern A. Zeeb 	/* "Regular" and 16 MBSS but not for 4 MBSS */
7250*b4c3e9b5SBjoern A. Zeeb 	/* Update the phytxctl for the beacon based on the rspec */
7251*b4c3e9b5SBjoern A. Zeeb 	brcms_c_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec);
7252*b4c3e9b5SBjoern A. Zeeb 
7253*b4c3e9b5SBjoern A. Zeeb 	if (bcn0) {
7254*b4c3e9b5SBjoern A. Zeeb 		/* write the probe response into the template region */
7255*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_template_ram(wlc_hw, T_BCN0_TPL_BASE,
7256*b4c3e9b5SBjoern A. Zeeb 					    (len + 3) & ~3, beacon->data);
7257*b4c3e9b5SBjoern A. Zeeb 
7258*b4c3e9b5SBjoern A. Zeeb 		/* write beacon length to SCR */
7259*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc_hw, M_BCN0_FRM_BYTESZ, (u16) len);
7260*b4c3e9b5SBjoern A. Zeeb 	}
7261*b4c3e9b5SBjoern A. Zeeb 	if (bcn1) {
7262*b4c3e9b5SBjoern A. Zeeb 		/* write the probe response into the template region */
7263*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_template_ram(wlc_hw, T_BCN1_TPL_BASE,
7264*b4c3e9b5SBjoern A. Zeeb 					    (len + 3) & ~3, beacon->data);
7265*b4c3e9b5SBjoern A. Zeeb 
7266*b4c3e9b5SBjoern A. Zeeb 		/* write beacon length to SCR */
7267*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc_hw, M_BCN1_FRM_BYTESZ, (u16) len);
7268*b4c3e9b5SBjoern A. Zeeb 	}
7269*b4c3e9b5SBjoern A. Zeeb 
7270*b4c3e9b5SBjoern A. Zeeb 	if (tim_offset != 0) {
7271*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,
7272*b4c3e9b5SBjoern A. Zeeb 				  tim_offset + D11B_PHY_HDR_LEN);
7273*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, dtim_period);
7274*b4c3e9b5SBjoern A. Zeeb 	} else {
7275*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,
7276*b4c3e9b5SBjoern A. Zeeb 				  len + D11B_PHY_HDR_LEN);
7277*b4c3e9b5SBjoern A. Zeeb 		brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, 0);
7278*b4c3e9b5SBjoern A. Zeeb 	}
7279*b4c3e9b5SBjoern A. Zeeb }
7280*b4c3e9b5SBjoern A. Zeeb 
brcms_c_update_beacon_hw(struct brcms_c_info * wlc,struct sk_buff * beacon,u16 tim_offset,u16 dtim_period)7281*b4c3e9b5SBjoern A. Zeeb static void brcms_c_update_beacon_hw(struct brcms_c_info *wlc,
7282*b4c3e9b5SBjoern A. Zeeb 				     struct sk_buff *beacon, u16 tim_offset,
7283*b4c3e9b5SBjoern A. Zeeb 				     u16 dtim_period)
7284*b4c3e9b5SBjoern A. Zeeb {
7285*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
7286*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
7287*b4c3e9b5SBjoern A. Zeeb 
7288*b4c3e9b5SBjoern A. Zeeb 	/* Hardware beaconing for this config */
7289*b4c3e9b5SBjoern A. Zeeb 	u32 both_valid = MCMD_BCN0VLD | MCMD_BCN1VLD;
7290*b4c3e9b5SBjoern A. Zeeb 
7291*b4c3e9b5SBjoern A. Zeeb 	/* Check if both templates are in use, if so sched. an interrupt
7292*b4c3e9b5SBjoern A. Zeeb 	 *      that will call back into this routine
7293*b4c3e9b5SBjoern A. Zeeb 	 */
7294*b4c3e9b5SBjoern A. Zeeb 	if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid)
7295*b4c3e9b5SBjoern A. Zeeb 		/* clear any previous status */
7296*b4c3e9b5SBjoern A. Zeeb 		bcma_write32(core, D11REGOFFS(macintstatus), MI_BCNTPL);
7297*b4c3e9b5SBjoern A. Zeeb 
7298*b4c3e9b5SBjoern A. Zeeb 	if (wlc->beacon_template_virgin) {
7299*b4c3e9b5SBjoern A. Zeeb 		wlc->beacon_template_virgin = false;
7300*b4c3e9b5SBjoern A. Zeeb 		brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,
7301*b4c3e9b5SBjoern A. Zeeb 				     true);
7302*b4c3e9b5SBjoern A. Zeeb 		/* mark beacon0 valid */
7303*b4c3e9b5SBjoern A. Zeeb 		bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);
7304*b4c3e9b5SBjoern A. Zeeb 		return;
7305*b4c3e9b5SBjoern A. Zeeb 	}
7306*b4c3e9b5SBjoern A. Zeeb 
7307*b4c3e9b5SBjoern A. Zeeb 	/* Check that after scheduling the interrupt both of the
7308*b4c3e9b5SBjoern A. Zeeb 	 *      templates are still busy. if not clear the int. & remask
7309*b4c3e9b5SBjoern A. Zeeb 	 */
7310*b4c3e9b5SBjoern A. Zeeb 	if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid) {
7311*b4c3e9b5SBjoern A. Zeeb 		wlc->defmacintmask |= MI_BCNTPL;
7312*b4c3e9b5SBjoern A. Zeeb 		return;
7313*b4c3e9b5SBjoern A. Zeeb 	}
7314*b4c3e9b5SBjoern A. Zeeb 
7315*b4c3e9b5SBjoern A. Zeeb 	if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN0VLD)) {
7316*b4c3e9b5SBjoern A. Zeeb 		brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,
7317*b4c3e9b5SBjoern A. Zeeb 				     false);
7318*b4c3e9b5SBjoern A. Zeeb 		/* mark beacon0 valid */
7319*b4c3e9b5SBjoern A. Zeeb 		bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);
7320*b4c3e9b5SBjoern A. Zeeb 		return;
7321*b4c3e9b5SBjoern A. Zeeb 	}
7322*b4c3e9b5SBjoern A. Zeeb 	if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN1VLD)) {
7323*b4c3e9b5SBjoern A. Zeeb 		brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period,
7324*b4c3e9b5SBjoern A. Zeeb 				     false, true);
7325*b4c3e9b5SBjoern A. Zeeb 		/* mark beacon0 valid */
7326*b4c3e9b5SBjoern A. Zeeb 		bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN1VLD);
7327*b4c3e9b5SBjoern A. Zeeb 	}
7328*b4c3e9b5SBjoern A. Zeeb }
7329*b4c3e9b5SBjoern A. Zeeb 
7330*b4c3e9b5SBjoern A. Zeeb /*
7331*b4c3e9b5SBjoern A. Zeeb  * Update all beacons for the system.
7332*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_update_beacon(struct brcms_c_info * wlc)7333*b4c3e9b5SBjoern A. Zeeb void brcms_c_update_beacon(struct brcms_c_info *wlc)
7334*b4c3e9b5SBjoern A. Zeeb {
7335*b4c3e9b5SBjoern A. Zeeb 	struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
7336*b4c3e9b5SBjoern A. Zeeb 
7337*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->up && (bsscfg->type == BRCMS_TYPE_AP ||
7338*b4c3e9b5SBjoern A. Zeeb 			     bsscfg->type == BRCMS_TYPE_ADHOC)) {
7339*b4c3e9b5SBjoern A. Zeeb 		/* Clear the soft intmask */
7340*b4c3e9b5SBjoern A. Zeeb 		wlc->defmacintmask &= ~MI_BCNTPL;
7341*b4c3e9b5SBjoern A. Zeeb 		if (!wlc->beacon)
7342*b4c3e9b5SBjoern A. Zeeb 			return;
7343*b4c3e9b5SBjoern A. Zeeb 		brcms_c_update_beacon_hw(wlc, wlc->beacon,
7344*b4c3e9b5SBjoern A. Zeeb 					 wlc->beacon_tim_offset,
7345*b4c3e9b5SBjoern A. Zeeb 					 wlc->beacon_dtim_period);
7346*b4c3e9b5SBjoern A. Zeeb 	}
7347*b4c3e9b5SBjoern A. Zeeb }
7348*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_new_beacon(struct brcms_c_info * wlc,struct sk_buff * beacon,u16 tim_offset,u16 dtim_period)7349*b4c3e9b5SBjoern A. Zeeb void brcms_c_set_new_beacon(struct brcms_c_info *wlc, struct sk_buff *beacon,
7350*b4c3e9b5SBjoern A. Zeeb 			    u16 tim_offset, u16 dtim_period)
7351*b4c3e9b5SBjoern A. Zeeb {
7352*b4c3e9b5SBjoern A. Zeeb 	if (!beacon)
7353*b4c3e9b5SBjoern A. Zeeb 		return;
7354*b4c3e9b5SBjoern A. Zeeb 	if (wlc->beacon)
7355*b4c3e9b5SBjoern A. Zeeb 		dev_kfree_skb_any(wlc->beacon);
7356*b4c3e9b5SBjoern A. Zeeb 	wlc->beacon = beacon;
7357*b4c3e9b5SBjoern A. Zeeb 
7358*b4c3e9b5SBjoern A. Zeeb 	/* add PLCP */
7359*b4c3e9b5SBjoern A. Zeeb 	skb_push(wlc->beacon, D11_PHY_HDR_LEN);
7360*b4c3e9b5SBjoern A. Zeeb 	wlc->beacon_tim_offset = tim_offset;
7361*b4c3e9b5SBjoern A. Zeeb 	wlc->beacon_dtim_period = dtim_period;
7362*b4c3e9b5SBjoern A. Zeeb 	brcms_c_update_beacon(wlc);
7363*b4c3e9b5SBjoern A. Zeeb }
7364*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_new_probe_resp(struct brcms_c_info * wlc,struct sk_buff * probe_resp)7365*b4c3e9b5SBjoern A. Zeeb void brcms_c_set_new_probe_resp(struct brcms_c_info *wlc,
7366*b4c3e9b5SBjoern A. Zeeb 				struct sk_buff *probe_resp)
7367*b4c3e9b5SBjoern A. Zeeb {
7368*b4c3e9b5SBjoern A. Zeeb 	if (!probe_resp)
7369*b4c3e9b5SBjoern A. Zeeb 		return;
7370*b4c3e9b5SBjoern A. Zeeb 	if (wlc->probe_resp)
7371*b4c3e9b5SBjoern A. Zeeb 		dev_kfree_skb_any(wlc->probe_resp);
7372*b4c3e9b5SBjoern A. Zeeb 	wlc->probe_resp = probe_resp;
7373*b4c3e9b5SBjoern A. Zeeb 
7374*b4c3e9b5SBjoern A. Zeeb 	/* add PLCP */
7375*b4c3e9b5SBjoern A. Zeeb 	skb_push(wlc->probe_resp, D11_PHY_HDR_LEN);
7376*b4c3e9b5SBjoern A. Zeeb 	brcms_c_update_probe_resp(wlc, false);
7377*b4c3e9b5SBjoern A. Zeeb }
7378*b4c3e9b5SBjoern A. Zeeb 
brcms_c_enable_probe_resp(struct brcms_c_info * wlc,bool enable)7379*b4c3e9b5SBjoern A. Zeeb void brcms_c_enable_probe_resp(struct brcms_c_info *wlc, bool enable)
7380*b4c3e9b5SBjoern A. Zeeb {
7381*b4c3e9b5SBjoern A. Zeeb 	/*
7382*b4c3e9b5SBjoern A. Zeeb 	 * prevent ucode from sending probe responses by setting the timeout
7383*b4c3e9b5SBjoern A. Zeeb 	 * to 1, it can not send it in that time frame.
7384*b4c3e9b5SBjoern A. Zeeb 	 */
7385*b4c3e9b5SBjoern A. Zeeb 	wlc->prb_resp_timeout = enable ? BRCMS_PRB_RESP_TIMEOUT : 1;
7386*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);
7387*b4c3e9b5SBjoern A. Zeeb 	/* TODO: if (enable) => also deactivate receiving of probe request */
7388*b4c3e9b5SBjoern A. Zeeb }
7389*b4c3e9b5SBjoern A. Zeeb 
7390*b4c3e9b5SBjoern A. Zeeb /* Write ssid into shared memory */
7391*b4c3e9b5SBjoern A. Zeeb static void
brcms_c_shm_ssid_upd(struct brcms_c_info * wlc,struct brcms_bss_cfg * cfg)7392*b4c3e9b5SBjoern A. Zeeb brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)
7393*b4c3e9b5SBjoern A. Zeeb {
7394*b4c3e9b5SBjoern A. Zeeb 	u8 *ssidptr = cfg->SSID;
7395*b4c3e9b5SBjoern A. Zeeb 	u16 base = M_SSID;
7396*b4c3e9b5SBjoern A. Zeeb 	u8 ssidbuf[IEEE80211_MAX_SSID_LEN];
7397*b4c3e9b5SBjoern A. Zeeb 
7398*b4c3e9b5SBjoern A. Zeeb 	/* padding the ssid with zero and copy it into shm */
7399*b4c3e9b5SBjoern A. Zeeb 	memset(ssidbuf, 0, IEEE80211_MAX_SSID_LEN);
7400*b4c3e9b5SBjoern A. Zeeb 	memcpy(ssidbuf, ssidptr, cfg->SSID_len);
7401*b4c3e9b5SBjoern A. Zeeb 
7402*b4c3e9b5SBjoern A. Zeeb 	brcms_c_copyto_shm(wlc, base, ssidbuf, IEEE80211_MAX_SSID_LEN);
7403*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc->hw, M_SSIDLEN, (u16) cfg->SSID_len);
7404*b4c3e9b5SBjoern A. Zeeb }
7405*b4c3e9b5SBjoern A. Zeeb 
7406*b4c3e9b5SBjoern A. Zeeb static void
brcms_c_bss_update_probe_resp(struct brcms_c_info * wlc,struct brcms_bss_cfg * cfg,struct sk_buff * probe_resp,bool suspend)7407*b4c3e9b5SBjoern A. Zeeb brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
7408*b4c3e9b5SBjoern A. Zeeb 			      struct brcms_bss_cfg *cfg,
7409*b4c3e9b5SBjoern A. Zeeb 			      struct sk_buff *probe_resp,
7410*b4c3e9b5SBjoern A. Zeeb 			      bool suspend)
7411*b4c3e9b5SBjoern A. Zeeb {
7412*b4c3e9b5SBjoern A. Zeeb 	int len;
7413*b4c3e9b5SBjoern A. Zeeb 
7414*b4c3e9b5SBjoern A. Zeeb 	len = min_t(size_t, probe_resp->len, BCN_TMPL_LEN);
7415*b4c3e9b5SBjoern A. Zeeb 
7416*b4c3e9b5SBjoern A. Zeeb 	if (suspend)
7417*b4c3e9b5SBjoern A. Zeeb 		brcms_c_suspend_mac_and_wait(wlc);
7418*b4c3e9b5SBjoern A. Zeeb 
7419*b4c3e9b5SBjoern A. Zeeb 	/* write the probe response into the template region */
7420*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE,
7421*b4c3e9b5SBjoern A. Zeeb 				    (len + 3) & ~3, probe_resp->data);
7422*b4c3e9b5SBjoern A. Zeeb 
7423*b4c3e9b5SBjoern A. Zeeb 	/* write the length of the probe response frame (+PLCP/-FCS) */
7424*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len);
7425*b4c3e9b5SBjoern A. Zeeb 
7426*b4c3e9b5SBjoern A. Zeeb 	/* write the SSID and SSID length */
7427*b4c3e9b5SBjoern A. Zeeb 	brcms_c_shm_ssid_upd(wlc, cfg);
7428*b4c3e9b5SBjoern A. Zeeb 
7429*b4c3e9b5SBjoern A. Zeeb 	/*
7430*b4c3e9b5SBjoern A. Zeeb 	 * Write PLCP headers and durations for probe response frames
7431*b4c3e9b5SBjoern A. Zeeb 	 * at all rates. Use the actual frame length covered by the
7432*b4c3e9b5SBjoern A. Zeeb 	 * PLCP header for the call to brcms_c_mod_prb_rsp_rate_table()
7433*b4c3e9b5SBjoern A. Zeeb 	 * by subtracting the PLCP len and adding the FCS.
7434*b4c3e9b5SBjoern A. Zeeb 	 */
7435*b4c3e9b5SBjoern A. Zeeb 	brcms_c_mod_prb_rsp_rate_table(wlc,
7436*b4c3e9b5SBjoern A. Zeeb 				      (u16)len + FCS_LEN - D11_PHY_HDR_LEN);
7437*b4c3e9b5SBjoern A. Zeeb 
7438*b4c3e9b5SBjoern A. Zeeb 	if (suspend)
7439*b4c3e9b5SBjoern A. Zeeb 		brcms_c_enable_mac(wlc);
7440*b4c3e9b5SBjoern A. Zeeb }
7441*b4c3e9b5SBjoern A. Zeeb 
brcms_c_update_probe_resp(struct brcms_c_info * wlc,bool suspend)7442*b4c3e9b5SBjoern A. Zeeb void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
7443*b4c3e9b5SBjoern A. Zeeb {
7444*b4c3e9b5SBjoern A. Zeeb 	struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
7445*b4c3e9b5SBjoern A. Zeeb 
7446*b4c3e9b5SBjoern A. Zeeb 	/* update AP or IBSS probe responses */
7447*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->up && (bsscfg->type == BRCMS_TYPE_AP ||
7448*b4c3e9b5SBjoern A. Zeeb 			     bsscfg->type == BRCMS_TYPE_ADHOC)) {
7449*b4c3e9b5SBjoern A. Zeeb 		if (!wlc->probe_resp)
7450*b4c3e9b5SBjoern A. Zeeb 			return;
7451*b4c3e9b5SBjoern A. Zeeb 		brcms_c_bss_update_probe_resp(wlc, bsscfg, wlc->probe_resp,
7452*b4c3e9b5SBjoern A. Zeeb 					      suspend);
7453*b4c3e9b5SBjoern A. Zeeb 	}
7454*b4c3e9b5SBjoern A. Zeeb }
7455*b4c3e9b5SBjoern A. Zeeb 
brcms_b_xmtfifo_sz_get(struct brcms_hardware * wlc_hw,uint fifo,uint * blocks)7456*b4c3e9b5SBjoern A. Zeeb int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
7457*b4c3e9b5SBjoern A. Zeeb 			   uint *blocks)
7458*b4c3e9b5SBjoern A. Zeeb {
7459*b4c3e9b5SBjoern A. Zeeb 	if (fifo >= NFIFO)
7460*b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
7461*b4c3e9b5SBjoern A. Zeeb 
7462*b4c3e9b5SBjoern A. Zeeb 	*blocks = wlc_hw->xmtfifo_sz[fifo];
7463*b4c3e9b5SBjoern A. Zeeb 
7464*b4c3e9b5SBjoern A. Zeeb 	return 0;
7465*b4c3e9b5SBjoern A. Zeeb }
7466*b4c3e9b5SBjoern A. Zeeb 
7467*b4c3e9b5SBjoern A. Zeeb void
brcms_c_set_addrmatch(struct brcms_c_info * wlc,int match_reg_offset,const u8 * addr)7468*b4c3e9b5SBjoern A. Zeeb brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset,
7469*b4c3e9b5SBjoern A. Zeeb 		  const u8 *addr)
7470*b4c3e9b5SBjoern A. Zeeb {
7471*b4c3e9b5SBjoern A. Zeeb 	brcms_b_set_addrmatch(wlc->hw, match_reg_offset, addr);
7472*b4c3e9b5SBjoern A. Zeeb 	if (match_reg_offset == RCM_BSSID_OFFSET)
7473*b4c3e9b5SBjoern A. Zeeb 		memcpy(wlc->bsscfg->BSSID, addr, ETH_ALEN);
7474*b4c3e9b5SBjoern A. Zeeb }
7475*b4c3e9b5SBjoern A. Zeeb 
7476*b4c3e9b5SBjoern A. Zeeb /*
7477*b4c3e9b5SBjoern A. Zeeb  * Flag 'scan in progress' to withhold dynamic phy calibration
7478*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_scan_start(struct brcms_c_info * wlc)7479*b4c3e9b5SBjoern A. Zeeb void brcms_c_scan_start(struct brcms_c_info *wlc)
7480*b4c3e9b5SBjoern A. Zeeb {
7481*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true);
7482*b4c3e9b5SBjoern A. Zeeb }
7483*b4c3e9b5SBjoern A. Zeeb 
brcms_c_scan_stop(struct brcms_c_info * wlc)7484*b4c3e9b5SBjoern A. Zeeb void brcms_c_scan_stop(struct brcms_c_info *wlc)
7485*b4c3e9b5SBjoern A. Zeeb {
7486*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false);
7487*b4c3e9b5SBjoern A. Zeeb }
7488*b4c3e9b5SBjoern A. Zeeb 
brcms_c_associate_upd(struct brcms_c_info * wlc,bool state)7489*b4c3e9b5SBjoern A. Zeeb void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state)
7490*b4c3e9b5SBjoern A. Zeeb {
7491*b4c3e9b5SBjoern A. Zeeb 	wlc->pub->associated = state;
7492*b4c3e9b5SBjoern A. Zeeb }
7493*b4c3e9b5SBjoern A. Zeeb 
7494*b4c3e9b5SBjoern A. Zeeb /*
7495*b4c3e9b5SBjoern A. Zeeb  * When a remote STA/AP is removed by Mac80211, or when it can no longer accept
7496*b4c3e9b5SBjoern A. Zeeb  * AMPDU traffic, packets pending in hardware have to be invalidated so that
7497*b4c3e9b5SBjoern A. Zeeb  * when later on hardware releases them, they can be handled appropriately.
7498*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_inval_dma_pkts(struct brcms_hardware * hw,struct ieee80211_sta * sta,void (* dma_callback_fn))7499*b4c3e9b5SBjoern A. Zeeb void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
7500*b4c3e9b5SBjoern A. Zeeb 			       struct ieee80211_sta *sta,
7501*b4c3e9b5SBjoern A. Zeeb 			       void (*dma_callback_fn))
7502*b4c3e9b5SBjoern A. Zeeb {
7503*b4c3e9b5SBjoern A. Zeeb 	struct dma_pub *dmah;
7504*b4c3e9b5SBjoern A. Zeeb 	int i;
7505*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < NFIFO; i++) {
7506*b4c3e9b5SBjoern A. Zeeb 		dmah = hw->di[i];
7507*b4c3e9b5SBjoern A. Zeeb 		if (dmah != NULL)
7508*b4c3e9b5SBjoern A. Zeeb 			dma_walk_packets(dmah, dma_callback_fn, sta);
7509*b4c3e9b5SBjoern A. Zeeb 	}
7510*b4c3e9b5SBjoern A. Zeeb }
7511*b4c3e9b5SBjoern A. Zeeb 
brcms_c_get_curband(struct brcms_c_info * wlc)7512*b4c3e9b5SBjoern A. Zeeb int brcms_c_get_curband(struct brcms_c_info *wlc)
7513*b4c3e9b5SBjoern A. Zeeb {
7514*b4c3e9b5SBjoern A. Zeeb 	return wlc->band->bandunit;
7515*b4c3e9b5SBjoern A. Zeeb }
7516*b4c3e9b5SBjoern A. Zeeb 
brcms_c_tx_flush_completed(struct brcms_c_info * wlc)7517*b4c3e9b5SBjoern A. Zeeb bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc)
7518*b4c3e9b5SBjoern A. Zeeb {
7519*b4c3e9b5SBjoern A. Zeeb 	int i;
7520*b4c3e9b5SBjoern A. Zeeb 
7521*b4c3e9b5SBjoern A. Zeeb 	/* Kick DMA to send any pending AMPDU */
7522*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++)
7523*b4c3e9b5SBjoern A. Zeeb 		if (wlc->hw->di[i])
7524*b4c3e9b5SBjoern A. Zeeb 			dma_kick_tx(wlc->hw->di[i]);
7525*b4c3e9b5SBjoern A. Zeeb 
7526*b4c3e9b5SBjoern A. Zeeb 	return !brcms_txpktpendtot(wlc);
7527*b4c3e9b5SBjoern A. Zeeb }
7528*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_beacon_listen_interval(struct brcms_c_info * wlc,u8 interval)7529*b4c3e9b5SBjoern A. Zeeb void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
7530*b4c3e9b5SBjoern A. Zeeb {
7531*b4c3e9b5SBjoern A. Zeeb 	wlc->bcn_li_bcn = interval;
7532*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->up)
7533*b4c3e9b5SBjoern A. Zeeb 		brcms_c_bcn_li_upd(wlc);
7534*b4c3e9b5SBjoern A. Zeeb }
7535*b4c3e9b5SBjoern A. Zeeb 
brcms_c_tsf_get(struct brcms_c_info * wlc)7536*b4c3e9b5SBjoern A. Zeeb u64 brcms_c_tsf_get(struct brcms_c_info *wlc)
7537*b4c3e9b5SBjoern A. Zeeb {
7538*b4c3e9b5SBjoern A. Zeeb 	u32 tsf_h, tsf_l;
7539*b4c3e9b5SBjoern A. Zeeb 	u64 tsf;
7540*b4c3e9b5SBjoern A. Zeeb 
7541*b4c3e9b5SBjoern A. Zeeb 	brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h);
7542*b4c3e9b5SBjoern A. Zeeb 
7543*b4c3e9b5SBjoern A. Zeeb 	tsf = tsf_h;
7544*b4c3e9b5SBjoern A. Zeeb 	tsf <<= 32;
7545*b4c3e9b5SBjoern A. Zeeb 	tsf |= tsf_l;
7546*b4c3e9b5SBjoern A. Zeeb 
7547*b4c3e9b5SBjoern A. Zeeb 	return tsf;
7548*b4c3e9b5SBjoern A. Zeeb }
7549*b4c3e9b5SBjoern A. Zeeb 
brcms_c_tsf_set(struct brcms_c_info * wlc,u64 tsf)7550*b4c3e9b5SBjoern A. Zeeb void brcms_c_tsf_set(struct brcms_c_info *wlc, u64 tsf)
7551*b4c3e9b5SBjoern A. Zeeb {
7552*b4c3e9b5SBjoern A. Zeeb 	u32 tsf_h, tsf_l;
7553*b4c3e9b5SBjoern A. Zeeb 
7554*b4c3e9b5SBjoern A. Zeeb 	brcms_c_time_lock(wlc);
7555*b4c3e9b5SBjoern A. Zeeb 
7556*b4c3e9b5SBjoern A. Zeeb 	tsf_l = tsf;
7557*b4c3e9b5SBjoern A. Zeeb 	tsf_h = (tsf >> 32);
7558*b4c3e9b5SBjoern A. Zeeb 
7559*b4c3e9b5SBjoern A. Zeeb 	/* read the tsf timer low, then high to get an atomic read */
7560*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_timerlow), tsf_l);
7561*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_timerhigh), tsf_h);
7562*b4c3e9b5SBjoern A. Zeeb 
7563*b4c3e9b5SBjoern A. Zeeb 	brcms_c_time_unlock(wlc);
7564*b4c3e9b5SBjoern A. Zeeb }
7565*b4c3e9b5SBjoern A. Zeeb 
brcms_c_set_tx_power(struct brcms_c_info * wlc,int txpwr)7566*b4c3e9b5SBjoern A. Zeeb int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr)
7567*b4c3e9b5SBjoern A. Zeeb {
7568*b4c3e9b5SBjoern A. Zeeb 	uint qdbm;
7569*b4c3e9b5SBjoern A. Zeeb 
7570*b4c3e9b5SBjoern A. Zeeb 	/* Remove override bit and clip to max qdbm value */
7571*b4c3e9b5SBjoern A. Zeeb 	qdbm = min_t(uint, txpwr * BRCMS_TXPWR_DB_FACTOR, 0xff);
7572*b4c3e9b5SBjoern A. Zeeb 	return wlc_phy_txpower_set(wlc->band->pi, qdbm, false);
7573*b4c3e9b5SBjoern A. Zeeb }
7574*b4c3e9b5SBjoern A. Zeeb 
brcms_c_get_tx_power(struct brcms_c_info * wlc)7575*b4c3e9b5SBjoern A. Zeeb int brcms_c_get_tx_power(struct brcms_c_info *wlc)
7576*b4c3e9b5SBjoern A. Zeeb {
7577*b4c3e9b5SBjoern A. Zeeb 	uint qdbm;
7578*b4c3e9b5SBjoern A. Zeeb 	bool override;
7579*b4c3e9b5SBjoern A. Zeeb 
7580*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_txpower_get(wlc->band->pi, &qdbm, &override);
7581*b4c3e9b5SBjoern A. Zeeb 
7582*b4c3e9b5SBjoern A. Zeeb 	/* Return qdbm units */
7583*b4c3e9b5SBjoern A. Zeeb 	return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR);
7584*b4c3e9b5SBjoern A. Zeeb }
7585*b4c3e9b5SBjoern A. Zeeb 
7586*b4c3e9b5SBjoern A. Zeeb /* Process received frames */
7587*b4c3e9b5SBjoern A. Zeeb /*
7588*b4c3e9b5SBjoern A. Zeeb  * Return true if more frames need to be processed. false otherwise.
7589*b4c3e9b5SBjoern A. Zeeb  * Param 'bound' indicates max. # frames to process before break out.
7590*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_recv(struct brcms_c_info * wlc,struct sk_buff * p)7591*b4c3e9b5SBjoern A. Zeeb static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
7592*b4c3e9b5SBjoern A. Zeeb {
7593*b4c3e9b5SBjoern A. Zeeb 	struct d11rxhdr *rxh;
7594*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_hdr *h;
7595*b4c3e9b5SBjoern A. Zeeb 	uint len;
7596*b4c3e9b5SBjoern A. Zeeb 	bool is_amsdu;
7597*b4c3e9b5SBjoern A. Zeeb 
7598*b4c3e9b5SBjoern A. Zeeb 	/* frame starts with rxhdr */
7599*b4c3e9b5SBjoern A. Zeeb 	rxh = (struct d11rxhdr *) (p->data);
7600*b4c3e9b5SBjoern A. Zeeb 
7601*b4c3e9b5SBjoern A. Zeeb 	/* strip off rxhdr */
7602*b4c3e9b5SBjoern A. Zeeb 	skb_pull(p, BRCMS_HWRXOFF);
7603*b4c3e9b5SBjoern A. Zeeb 
7604*b4c3e9b5SBjoern A. Zeeb 	/* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
7605*b4c3e9b5SBjoern A. Zeeb 	if (rxh->RxStatus1 & RXS_PBPRES) {
7606*b4c3e9b5SBjoern A. Zeeb 		if (p->len < 2) {
7607*b4c3e9b5SBjoern A. Zeeb 			brcms_err(wlc->hw->d11core,
7608*b4c3e9b5SBjoern A. Zeeb 				  "wl%d: recv: rcvd runt of len %d\n",
7609*b4c3e9b5SBjoern A. Zeeb 				  wlc->pub->unit, p->len);
7610*b4c3e9b5SBjoern A. Zeeb 			goto toss;
7611*b4c3e9b5SBjoern A. Zeeb 		}
7612*b4c3e9b5SBjoern A. Zeeb 		skb_pull(p, 2);
7613*b4c3e9b5SBjoern A. Zeeb 	}
7614*b4c3e9b5SBjoern A. Zeeb 
7615*b4c3e9b5SBjoern A. Zeeb 	h = (struct ieee80211_hdr *)(p->data + D11_PHY_HDR_LEN);
7616*b4c3e9b5SBjoern A. Zeeb 	len = p->len;
7617*b4c3e9b5SBjoern A. Zeeb 
7618*b4c3e9b5SBjoern A. Zeeb 	if (rxh->RxStatus1 & RXS_FCSERR) {
7619*b4c3e9b5SBjoern A. Zeeb 		if (!(wlc->filter_flags & FIF_FCSFAIL))
7620*b4c3e9b5SBjoern A. Zeeb 			goto toss;
7621*b4c3e9b5SBjoern A. Zeeb 	}
7622*b4c3e9b5SBjoern A. Zeeb 
7623*b4c3e9b5SBjoern A. Zeeb 	/* check received pkt has at least frame control field */
7624*b4c3e9b5SBjoern A. Zeeb 	if (len < D11_PHY_HDR_LEN + sizeof(h->frame_control))
7625*b4c3e9b5SBjoern A. Zeeb 		goto toss;
7626*b4c3e9b5SBjoern A. Zeeb 
7627*b4c3e9b5SBjoern A. Zeeb 	/* not supporting A-MSDU */
7628*b4c3e9b5SBjoern A. Zeeb 	is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK;
7629*b4c3e9b5SBjoern A. Zeeb 	if (is_amsdu)
7630*b4c3e9b5SBjoern A. Zeeb 		goto toss;
7631*b4c3e9b5SBjoern A. Zeeb 
7632*b4c3e9b5SBjoern A. Zeeb 	brcms_c_recvctl(wlc, rxh, p);
7633*b4c3e9b5SBjoern A. Zeeb 	return;
7634*b4c3e9b5SBjoern A. Zeeb 
7635*b4c3e9b5SBjoern A. Zeeb  toss:
7636*b4c3e9b5SBjoern A. Zeeb 	brcmu_pkt_buf_free_skb(p);
7637*b4c3e9b5SBjoern A. Zeeb }
7638*b4c3e9b5SBjoern A. Zeeb 
7639*b4c3e9b5SBjoern A. Zeeb /* Process received frames */
7640*b4c3e9b5SBjoern A. Zeeb /*
7641*b4c3e9b5SBjoern A. Zeeb  * Return true if more frames need to be processed. false otherwise.
7642*b4c3e9b5SBjoern A. Zeeb  * Param 'bound' indicates max. # frames to process before break out.
7643*b4c3e9b5SBjoern A. Zeeb  */
7644*b4c3e9b5SBjoern A. Zeeb static bool
brcms_b_recv(struct brcms_hardware * wlc_hw,uint fifo,bool bound)7645*b4c3e9b5SBjoern A. Zeeb brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
7646*b4c3e9b5SBjoern A. Zeeb {
7647*b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *p;
7648*b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *next = NULL;
7649*b4c3e9b5SBjoern A. Zeeb 	struct sk_buff_head recv_frames;
7650*b4c3e9b5SBjoern A. Zeeb 
7651*b4c3e9b5SBjoern A. Zeeb 	uint n = 0;
7652*b4c3e9b5SBjoern A. Zeeb 	uint bound_limit = bound ? RXBND : -1;
7653*b4c3e9b5SBjoern A. Zeeb 	bool morepending = false;
7654*b4c3e9b5SBjoern A. Zeeb 
7655*b4c3e9b5SBjoern A. Zeeb 	skb_queue_head_init(&recv_frames);
7656*b4c3e9b5SBjoern A. Zeeb 
7657*b4c3e9b5SBjoern A. Zeeb 	/* gather received frames */
7658*b4c3e9b5SBjoern A. Zeeb 	do {
7659*b4c3e9b5SBjoern A. Zeeb 		/* !give others some time to run! */
7660*b4c3e9b5SBjoern A. Zeeb 		if (n >= bound_limit)
7661*b4c3e9b5SBjoern A. Zeeb 			break;
7662*b4c3e9b5SBjoern A. Zeeb 
7663*b4c3e9b5SBjoern A. Zeeb 		morepending = dma_rx(wlc_hw->di[fifo], &recv_frames);
7664*b4c3e9b5SBjoern A. Zeeb 		n++;
7665*b4c3e9b5SBjoern A. Zeeb 	} while (morepending);
7666*b4c3e9b5SBjoern A. Zeeb 
7667*b4c3e9b5SBjoern A. Zeeb 	/* post more rbufs */
7668*b4c3e9b5SBjoern A. Zeeb 	dma_rxfill(wlc_hw->di[fifo]);
7669*b4c3e9b5SBjoern A. Zeeb 
7670*b4c3e9b5SBjoern A. Zeeb 	/* process each frame */
7671*b4c3e9b5SBjoern A. Zeeb 	skb_queue_walk_safe(&recv_frames, p, next) {
7672*b4c3e9b5SBjoern A. Zeeb 		struct d11rxhdr_le *rxh_le;
7673*b4c3e9b5SBjoern A. Zeeb 		struct d11rxhdr *rxh;
7674*b4c3e9b5SBjoern A. Zeeb 
7675*b4c3e9b5SBjoern A. Zeeb 		skb_unlink(p, &recv_frames);
7676*b4c3e9b5SBjoern A. Zeeb 		rxh_le = (struct d11rxhdr_le *)p->data;
7677*b4c3e9b5SBjoern A. Zeeb 		rxh = (struct d11rxhdr *)p->data;
7678*b4c3e9b5SBjoern A. Zeeb 
7679*b4c3e9b5SBjoern A. Zeeb 		/* fixup rx header endianness */
7680*b4c3e9b5SBjoern A. Zeeb 		rxh->RxFrameSize = le16_to_cpu(rxh_le->RxFrameSize);
7681*b4c3e9b5SBjoern A. Zeeb 		rxh->PhyRxStatus_0 = le16_to_cpu(rxh_le->PhyRxStatus_0);
7682*b4c3e9b5SBjoern A. Zeeb 		rxh->PhyRxStatus_1 = le16_to_cpu(rxh_le->PhyRxStatus_1);
7683*b4c3e9b5SBjoern A. Zeeb 		rxh->PhyRxStatus_2 = le16_to_cpu(rxh_le->PhyRxStatus_2);
7684*b4c3e9b5SBjoern A. Zeeb 		rxh->PhyRxStatus_3 = le16_to_cpu(rxh_le->PhyRxStatus_3);
7685*b4c3e9b5SBjoern A. Zeeb 		rxh->PhyRxStatus_4 = le16_to_cpu(rxh_le->PhyRxStatus_4);
7686*b4c3e9b5SBjoern A. Zeeb 		rxh->PhyRxStatus_5 = le16_to_cpu(rxh_le->PhyRxStatus_5);
7687*b4c3e9b5SBjoern A. Zeeb 		rxh->RxStatus1 = le16_to_cpu(rxh_le->RxStatus1);
7688*b4c3e9b5SBjoern A. Zeeb 		rxh->RxStatus2 = le16_to_cpu(rxh_le->RxStatus2);
7689*b4c3e9b5SBjoern A. Zeeb 		rxh->RxTSFTime = le16_to_cpu(rxh_le->RxTSFTime);
7690*b4c3e9b5SBjoern A. Zeeb 		rxh->RxChan = le16_to_cpu(rxh_le->RxChan);
7691*b4c3e9b5SBjoern A. Zeeb 
7692*b4c3e9b5SBjoern A. Zeeb 		brcms_c_recv(wlc_hw->wlc, p);
7693*b4c3e9b5SBjoern A. Zeeb 	}
7694*b4c3e9b5SBjoern A. Zeeb 
7695*b4c3e9b5SBjoern A. Zeeb 	return morepending;
7696*b4c3e9b5SBjoern A. Zeeb }
7697*b4c3e9b5SBjoern A. Zeeb 
7698*b4c3e9b5SBjoern A. Zeeb /* second-level interrupt processing
7699*b4c3e9b5SBjoern A. Zeeb  *   Return true if another dpc needs to be re-scheduled. false otherwise.
7700*b4c3e9b5SBjoern A. Zeeb  *   Param 'bounded' indicates if applicable loops should be bounded.
7701*b4c3e9b5SBjoern A. Zeeb  */
brcms_c_dpc(struct brcms_c_info * wlc,bool bounded)7702*b4c3e9b5SBjoern A. Zeeb bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
7703*b4c3e9b5SBjoern A. Zeeb {
7704*b4c3e9b5SBjoern A. Zeeb 	u32 macintstatus;
7705*b4c3e9b5SBjoern A. Zeeb 	struct brcms_hardware *wlc_hw = wlc->hw;
7706*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc_hw->d11core;
7707*b4c3e9b5SBjoern A. Zeeb 
7708*b4c3e9b5SBjoern A. Zeeb 	if (brcms_deviceremoved(wlc)) {
7709*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
7710*b4c3e9b5SBjoern A. Zeeb 			  __func__);
7711*b4c3e9b5SBjoern A. Zeeb 		brcms_down(wlc->wl);
7712*b4c3e9b5SBjoern A. Zeeb 		return false;
7713*b4c3e9b5SBjoern A. Zeeb 	}
7714*b4c3e9b5SBjoern A. Zeeb 
7715*b4c3e9b5SBjoern A. Zeeb 	/* grab and clear the saved software intstatus bits */
7716*b4c3e9b5SBjoern A. Zeeb 	macintstatus = wlc->macintstatus;
7717*b4c3e9b5SBjoern A. Zeeb 	wlc->macintstatus = 0;
7718*b4c3e9b5SBjoern A. Zeeb 
7719*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_int(core, "wl%d: macintstatus 0x%x\n",
7720*b4c3e9b5SBjoern A. Zeeb 		      wlc_hw->unit, macintstatus);
7721*b4c3e9b5SBjoern A. Zeeb 
7722*b4c3e9b5SBjoern A. Zeeb 	WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */
7723*b4c3e9b5SBjoern A. Zeeb 
7724*b4c3e9b5SBjoern A. Zeeb 	/* tx status */
7725*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus & MI_TFS) {
7726*b4c3e9b5SBjoern A. Zeeb 		bool fatal;
7727*b4c3e9b5SBjoern A. Zeeb 		if (brcms_b_txstatus(wlc->hw, bounded, &fatal))
7728*b4c3e9b5SBjoern A. Zeeb 			wlc->macintstatus |= MI_TFS;
7729*b4c3e9b5SBjoern A. Zeeb 		if (fatal) {
7730*b4c3e9b5SBjoern A. Zeeb 			brcms_err(core, "MI_TFS: fatal\n");
7731*b4c3e9b5SBjoern A. Zeeb 			goto fatal;
7732*b4c3e9b5SBjoern A. Zeeb 		}
7733*b4c3e9b5SBjoern A. Zeeb 	}
7734*b4c3e9b5SBjoern A. Zeeb 
7735*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus & (MI_TBTT | MI_DTIM_TBTT))
7736*b4c3e9b5SBjoern A. Zeeb 		brcms_c_tbtt(wlc);
7737*b4c3e9b5SBjoern A. Zeeb 
7738*b4c3e9b5SBjoern A. Zeeb 	/* ATIM window end */
7739*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus & MI_ATIMWINEND) {
7740*b4c3e9b5SBjoern A. Zeeb 		brcms_dbg_info(core, "end of ATIM window\n");
7741*b4c3e9b5SBjoern A. Zeeb 		bcma_set32(core, D11REGOFFS(maccommand), wlc->qvalid);
7742*b4c3e9b5SBjoern A. Zeeb 		wlc->qvalid = 0;
7743*b4c3e9b5SBjoern A. Zeeb 	}
7744*b4c3e9b5SBjoern A. Zeeb 
7745*b4c3e9b5SBjoern A. Zeeb 	/*
7746*b4c3e9b5SBjoern A. Zeeb 	 * received data or control frame, MI_DMAINT is
7747*b4c3e9b5SBjoern A. Zeeb 	 * indication of RX_FIFO interrupt
7748*b4c3e9b5SBjoern A. Zeeb 	 */
7749*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus & MI_DMAINT)
7750*b4c3e9b5SBjoern A. Zeeb 		if (brcms_b_recv(wlc_hw, RX_FIFO, bounded))
7751*b4c3e9b5SBjoern A. Zeeb 			wlc->macintstatus |= MI_DMAINT;
7752*b4c3e9b5SBjoern A. Zeeb 
7753*b4c3e9b5SBjoern A. Zeeb 	/* noise sample collected */
7754*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus & MI_BG_NOISE)
7755*b4c3e9b5SBjoern A. Zeeb 		wlc_phy_noise_sample_intr(wlc_hw->band->pi);
7756*b4c3e9b5SBjoern A. Zeeb 
7757*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus & MI_GP0) {
7758*b4c3e9b5SBjoern A. Zeeb 		brcms_err(core, "wl%d: PSM microcode watchdog fired at %d "
7759*b4c3e9b5SBjoern A. Zeeb 			  "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now);
7760*b4c3e9b5SBjoern A. Zeeb 
7761*b4c3e9b5SBjoern A. Zeeb 		printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
7762*b4c3e9b5SBjoern A. Zeeb 			    __func__, ai_get_chip_id(wlc_hw->sih),
7763*b4c3e9b5SBjoern A. Zeeb 			    ai_get_chiprev(wlc_hw->sih));
7764*b4c3e9b5SBjoern A. Zeeb 		brcms_fatal_error(wlc_hw->wlc->wl);
7765*b4c3e9b5SBjoern A. Zeeb 	}
7766*b4c3e9b5SBjoern A. Zeeb 
7767*b4c3e9b5SBjoern A. Zeeb 	/* gptimer timeout */
7768*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus & MI_TO)
7769*b4c3e9b5SBjoern A. Zeeb 		bcma_write32(core, D11REGOFFS(gptimer), 0);
7770*b4c3e9b5SBjoern A. Zeeb 
7771*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus & MI_RFDISABLE) {
7772*b4c3e9b5SBjoern A. Zeeb 		brcms_dbg_info(core, "wl%d: BMAC Detected a change on the"
7773*b4c3e9b5SBjoern A. Zeeb 			       " RF Disable Input\n", wlc_hw->unit);
7774*b4c3e9b5SBjoern A. Zeeb 		brcms_rfkill_set_hw_state(wlc->wl);
7775*b4c3e9b5SBjoern A. Zeeb 	}
7776*b4c3e9b5SBjoern A. Zeeb 
7777*b4c3e9b5SBjoern A. Zeeb 	/* BCN template is available */
7778*b4c3e9b5SBjoern A. Zeeb 	if (macintstatus & MI_BCNTPL)
7779*b4c3e9b5SBjoern A. Zeeb 		brcms_c_update_beacon(wlc);
7780*b4c3e9b5SBjoern A. Zeeb 
7781*b4c3e9b5SBjoern A. Zeeb 	/* it isn't done and needs to be resched if macintstatus is non-zero */
7782*b4c3e9b5SBjoern A. Zeeb 	return wlc->macintstatus != 0;
7783*b4c3e9b5SBjoern A. Zeeb 
7784*b4c3e9b5SBjoern A. Zeeb  fatal:
7785*b4c3e9b5SBjoern A. Zeeb 	brcms_fatal_error(wlc_hw->wlc->wl);
7786*b4c3e9b5SBjoern A. Zeeb 	return wlc->macintstatus != 0;
7787*b4c3e9b5SBjoern A. Zeeb }
7788*b4c3e9b5SBjoern A. Zeeb 
brcms_c_init(struct brcms_c_info * wlc,bool mute_tx)7789*b4c3e9b5SBjoern A. Zeeb void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
7790*b4c3e9b5SBjoern A. Zeeb {
7791*b4c3e9b5SBjoern A. Zeeb 	struct bcma_device *core = wlc->hw->d11core;
7792*b4c3e9b5SBjoern A. Zeeb 	struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.chandef.chan;
7793*b4c3e9b5SBjoern A. Zeeb 	u16 chanspec;
7794*b4c3e9b5SBjoern A. Zeeb 
7795*b4c3e9b5SBjoern A. Zeeb 	brcms_dbg_info(core, "wl%d\n", wlc->pub->unit);
7796*b4c3e9b5SBjoern A. Zeeb 
7797*b4c3e9b5SBjoern A. Zeeb 	chanspec = ch20mhz_chspec(ch->hw_value);
7798*b4c3e9b5SBjoern A. Zeeb 
7799*b4c3e9b5SBjoern A. Zeeb 	brcms_b_init(wlc->hw, chanspec);
7800*b4c3e9b5SBjoern A. Zeeb 
7801*b4c3e9b5SBjoern A. Zeeb 	/* update beacon listen interval */
7802*b4c3e9b5SBjoern A. Zeeb 	brcms_c_bcn_li_upd(wlc);
7803*b4c3e9b5SBjoern A. Zeeb 
7804*b4c3e9b5SBjoern A. Zeeb 	/* write ethernet address to core */
7805*b4c3e9b5SBjoern A. Zeeb 	brcms_c_set_mac(wlc->bsscfg);
7806*b4c3e9b5SBjoern A. Zeeb 	brcms_c_set_bssid(wlc->bsscfg);
7807*b4c3e9b5SBjoern A. Zeeb 
7808*b4c3e9b5SBjoern A. Zeeb 	/* Update tsf_cfprep if associated and up */
7809*b4c3e9b5SBjoern A. Zeeb 	if (wlc->pub->associated && wlc->pub->up) {
7810*b4c3e9b5SBjoern A. Zeeb 		u32 bi;
7811*b4c3e9b5SBjoern A. Zeeb 
7812*b4c3e9b5SBjoern A. Zeeb 		/* get beacon period and convert to uS */
7813*b4c3e9b5SBjoern A. Zeeb 		bi = wlc->bsscfg->current_bss->beacon_period << 10;
7814*b4c3e9b5SBjoern A. Zeeb 		/*
7815*b4c3e9b5SBjoern A. Zeeb 		 * update since init path would reset
7816*b4c3e9b5SBjoern A. Zeeb 		 * to default value
7817*b4c3e9b5SBjoern A. Zeeb 		 */
7818*b4c3e9b5SBjoern A. Zeeb 		bcma_write32(core, D11REGOFFS(tsf_cfprep),
7819*b4c3e9b5SBjoern A. Zeeb 			     bi << CFPREP_CBI_SHIFT);
7820*b4c3e9b5SBjoern A. Zeeb 
7821*b4c3e9b5SBjoern A. Zeeb 		/* Update maccontrol PM related bits */
7822*b4c3e9b5SBjoern A. Zeeb 		brcms_c_set_ps_ctrl(wlc);
7823*b4c3e9b5SBjoern A. Zeeb 	}
7824*b4c3e9b5SBjoern A. Zeeb 
7825*b4c3e9b5SBjoern A. Zeeb 	brcms_c_bandinit_ordered(wlc, chanspec);
7826*b4c3e9b5SBjoern A. Zeeb 
7827*b4c3e9b5SBjoern A. Zeeb 	/* init probe response timeout */
7828*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);
7829*b4c3e9b5SBjoern A. Zeeb 
7830*b4c3e9b5SBjoern A. Zeeb 	/* init max burst txop (framebursting) */
7831*b4c3e9b5SBjoern A. Zeeb 	brcms_b_write_shm(wlc->hw, M_MBURST_TXOP,
7832*b4c3e9b5SBjoern A. Zeeb 		      (wlc->
7833*b4c3e9b5SBjoern A. Zeeb 		       _rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP));
7834*b4c3e9b5SBjoern A. Zeeb 
7835*b4c3e9b5SBjoern A. Zeeb 	/* initialize maximum allowed duty cycle */
7836*b4c3e9b5SBjoern A. Zeeb 	brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, true, true);
7837*b4c3e9b5SBjoern A. Zeeb 	brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, false, true);
7838*b4c3e9b5SBjoern A. Zeeb 
7839*b4c3e9b5SBjoern A. Zeeb 	/*
7840*b4c3e9b5SBjoern A. Zeeb 	 * Update some shared memory locations related to
7841*b4c3e9b5SBjoern A. Zeeb 	 * max AMPDU size allowed to received
7842*b4c3e9b5SBjoern A. Zeeb 	 */
7843*b4c3e9b5SBjoern A. Zeeb 	brcms_c_ampdu_shm_upd(wlc->ampdu);
7844*b4c3e9b5SBjoern A. Zeeb 
7845*b4c3e9b5SBjoern A. Zeeb 	/* band-specific inits */
7846*b4c3e9b5SBjoern A. Zeeb 	brcms_c_bsinit(wlc);
7847*b4c3e9b5SBjoern A. Zeeb 
7848*b4c3e9b5SBjoern A. Zeeb 	/* Enable EDCF mode (while the MAC is suspended) */
7849*b4c3e9b5SBjoern A. Zeeb 	bcma_set16(core, D11REGOFFS(ifs_ctl), IFS_USEEDCF);
7850*b4c3e9b5SBjoern A. Zeeb 	brcms_c_edcf_setparams(wlc, false);
7851*b4c3e9b5SBjoern A. Zeeb 
7852*b4c3e9b5SBjoern A. Zeeb 	/* read the ucode version if we have not yet done so */
7853*b4c3e9b5SBjoern A. Zeeb 	if (wlc->ucode_rev == 0) {
7854*b4c3e9b5SBjoern A. Zeeb 		u16 rev;
7855*b4c3e9b5SBjoern A. Zeeb 		u16 patch;
7856*b4c3e9b5SBjoern A. Zeeb 
7857*b4c3e9b5SBjoern A. Zeeb 		rev = brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR);
7858*b4c3e9b5SBjoern A. Zeeb 		patch = brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR);
7859*b4c3e9b5SBjoern A. Zeeb 		wlc->ucode_rev = (rev << NBITS(u16)) | patch;
7860*b4c3e9b5SBjoern A. Zeeb 		snprintf(wlc->wiphy->fw_version,
7861*b4c3e9b5SBjoern A. Zeeb 			 sizeof(wlc->wiphy->fw_version), "%u.%u", rev, patch);
7862*b4c3e9b5SBjoern A. Zeeb 	}
7863*b4c3e9b5SBjoern A. Zeeb 
7864*b4c3e9b5SBjoern A. Zeeb 	/* ..now really unleash hell (allow the MAC out of suspend) */
7865*b4c3e9b5SBjoern A. Zeeb 	brcms_c_enable_mac(wlc);
7866*b4c3e9b5SBjoern A. Zeeb 
7867*b4c3e9b5SBjoern A. Zeeb 	/* suspend the tx fifos and mute the phy for preism cac time */
7868*b4c3e9b5SBjoern A. Zeeb 	if (mute_tx)
7869*b4c3e9b5SBjoern A. Zeeb 		brcms_b_mute(wlc->hw, true);
7870*b4c3e9b5SBjoern A. Zeeb 
7871*b4c3e9b5SBjoern A. Zeeb 	/* enable the RF Disable Delay timer */
7872*b4c3e9b5SBjoern A. Zeeb 	bcma_write32(core, D11REGOFFS(rfdisabledly), RFDISABLE_DEFAULT);
7873*b4c3e9b5SBjoern A. Zeeb 
7874*b4c3e9b5SBjoern A. Zeeb 	/*
7875*b4c3e9b5SBjoern A. Zeeb 	 * Initialize WME parameters; if they haven't been set by some other
7876*b4c3e9b5SBjoern A. Zeeb 	 * mechanism (IOVar, etc) then read them from the hardware.
7877*b4c3e9b5SBjoern A. Zeeb 	 */
7878*b4c3e9b5SBjoern A. Zeeb 	if (GFIELD(wlc->wme_retries[0], EDCF_SHORT) == 0) {
7879*b4c3e9b5SBjoern A. Zeeb 		/* Uninitialized; read from HW */
7880*b4c3e9b5SBjoern A. Zeeb 		int ac;
7881*b4c3e9b5SBjoern A. Zeeb 
7882*b4c3e9b5SBjoern A. Zeeb 		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
7883*b4c3e9b5SBjoern A. Zeeb 			wlc->wme_retries[ac] =
7884*b4c3e9b5SBjoern A. Zeeb 			    brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac));
7885*b4c3e9b5SBjoern A. Zeeb 	}
7886*b4c3e9b5SBjoern A. Zeeb }
7887*b4c3e9b5SBjoern A. Zeeb 
7888*b4c3e9b5SBjoern A. Zeeb /*
7889*b4c3e9b5SBjoern A. Zeeb  * The common driver entry routine. Error codes should be unique
7890*b4c3e9b5SBjoern A. Zeeb  */
7891*b4c3e9b5SBjoern A. Zeeb struct brcms_c_info *
brcms_c_attach(struct brcms_info * wl,struct bcma_device * core,uint unit,bool piomode,uint * perr)7892*b4c3e9b5SBjoern A. Zeeb brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit,
7893*b4c3e9b5SBjoern A. Zeeb 	       bool piomode, uint *perr)
7894*b4c3e9b5SBjoern A. Zeeb {
7895*b4c3e9b5SBjoern A. Zeeb 	struct brcms_c_info *wlc;
7896*b4c3e9b5SBjoern A. Zeeb 	uint err = 0;
7897*b4c3e9b5SBjoern A. Zeeb 	uint i, j;
7898*b4c3e9b5SBjoern A. Zeeb 	struct brcms_pub *pub;
7899*b4c3e9b5SBjoern A. Zeeb 
7900*b4c3e9b5SBjoern A. Zeeb 	/* allocate struct brcms_c_info state and its substructures */
7901*b4c3e9b5SBjoern A. Zeeb 	wlc = brcms_c_attach_malloc(unit, &err, 0);
7902*b4c3e9b5SBjoern A. Zeeb 	if (wlc == NULL)
7903*b4c3e9b5SBjoern A. Zeeb 		goto fail;
7904*b4c3e9b5SBjoern A. Zeeb 	wlc->wiphy = wl->wiphy;
7905*b4c3e9b5SBjoern A. Zeeb 	pub = wlc->pub;
7906*b4c3e9b5SBjoern A. Zeeb 
7907*b4c3e9b5SBjoern A. Zeeb #if defined(DEBUG)
7908*b4c3e9b5SBjoern A. Zeeb 	wlc_info_dbg = wlc;
7909*b4c3e9b5SBjoern A. Zeeb #endif
7910*b4c3e9b5SBjoern A. Zeeb 
7911*b4c3e9b5SBjoern A. Zeeb 	wlc->band = wlc->bandstate[0];
7912*b4c3e9b5SBjoern A. Zeeb 	wlc->core = wlc->corestate;
7913*b4c3e9b5SBjoern A. Zeeb 	wlc->wl = wl;
7914*b4c3e9b5SBjoern A. Zeeb 	pub->unit = unit;
7915*b4c3e9b5SBjoern A. Zeeb 	pub->_piomode = piomode;
7916*b4c3e9b5SBjoern A. Zeeb 	wlc->bandinit_pending = false;
7917*b4c3e9b5SBjoern A. Zeeb 	wlc->beacon_template_virgin = true;
7918*b4c3e9b5SBjoern A. Zeeb 
7919*b4c3e9b5SBjoern A. Zeeb 	/* populate struct brcms_c_info with default values  */
7920*b4c3e9b5SBjoern A. Zeeb 	brcms_c_info_init(wlc, unit);
7921*b4c3e9b5SBjoern A. Zeeb 
7922*b4c3e9b5SBjoern A. Zeeb 	/* update sta/ap related parameters */
7923*b4c3e9b5SBjoern A. Zeeb 	brcms_c_ap_upd(wlc);
7924*b4c3e9b5SBjoern A. Zeeb 
7925*b4c3e9b5SBjoern A. Zeeb 	/*
7926*b4c3e9b5SBjoern A. Zeeb 	 * low level attach steps(all hw accesses go
7927*b4c3e9b5SBjoern A. Zeeb 	 * inside, no more in rest of the attach)
7928*b4c3e9b5SBjoern A. Zeeb 	 */
7929*b4c3e9b5SBjoern A. Zeeb 	err = brcms_b_attach(wlc, core, unit, piomode);
7930*b4c3e9b5SBjoern A. Zeeb 	if (err)
7931*b4c3e9b5SBjoern A. Zeeb 		goto fail;
7932*b4c3e9b5SBjoern A. Zeeb 
7933*b4c3e9b5SBjoern A. Zeeb 	brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, OFF);
7934*b4c3e9b5SBjoern A. Zeeb 
7935*b4c3e9b5SBjoern A. Zeeb 	pub->phy_11ncapable = BRCMS_PHY_11N_CAP(wlc->band);
7936*b4c3e9b5SBjoern A. Zeeb 
7937*b4c3e9b5SBjoern A. Zeeb 	/* disable allowed duty cycle */
7938*b4c3e9b5SBjoern A. Zeeb 	wlc->tx_duty_cycle_ofdm = 0;
7939*b4c3e9b5SBjoern A. Zeeb 	wlc->tx_duty_cycle_cck = 0;
7940*b4c3e9b5SBjoern A. Zeeb 
7941*b4c3e9b5SBjoern A. Zeeb 	brcms_c_stf_phy_chain_calc(wlc);
7942*b4c3e9b5SBjoern A. Zeeb 
7943*b4c3e9b5SBjoern A. Zeeb 	/* txchain 1: txant 0, txchain 2: txant 1 */
7944*b4c3e9b5SBjoern A. Zeeb 	if (BRCMS_ISNPHY(wlc->band) && (wlc->stf->txstreams == 1))
7945*b4c3e9b5SBjoern A. Zeeb 		wlc->stf->txant = wlc->stf->hw_txchain - 1;
7946*b4c3e9b5SBjoern A. Zeeb 
7947*b4c3e9b5SBjoern A. Zeeb 	/* push to BMAC driver */
7948*b4c3e9b5SBjoern A. Zeeb 	wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain,
7949*b4c3e9b5SBjoern A. Zeeb 			       wlc->stf->hw_rxchain);
7950*b4c3e9b5SBjoern A. Zeeb 
7951*b4c3e9b5SBjoern A. Zeeb 	/* pull up some info resulting from the low attach */
7952*b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < NFIFO; i++)
7953*b4c3e9b5SBjoern A. Zeeb 		wlc->core->txavail[i] = wlc->hw->txavail[i];
7954*b4c3e9b5SBjoern A. Zeeb 
7955*b4c3e9b5SBjoern A. Zeeb 	memcpy(&wlc->perm_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
7956*b4c3e9b5SBjoern A. Zeeb 	memcpy(&pub->cur_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
7957*b4c3e9b5SBjoern A. Zeeb 
7958*b4c3e9b5SBjoern A. Zeeb 	for (j = 0; j < wlc->pub->_nbands; j++) {
7959*b4c3e9b5SBjoern A. Zeeb 		wlc->band = wlc->bandstate[j];
7960*b4c3e9b5SBjoern A. Zeeb 
7961*b4c3e9b5SBjoern A. Zeeb 		if (!brcms_c_attach_stf_ant_init(wlc)) {
7962*b4c3e9b5SBjoern A. Zeeb 			err = 24;
7963*b4c3e9b5SBjoern A. Zeeb 			goto fail;
7964*b4c3e9b5SBjoern A. Zeeb 		}
7965*b4c3e9b5SBjoern A. Zeeb 
7966*b4c3e9b5SBjoern A. Zeeb 		/* default contention windows size limits */
7967*b4c3e9b5SBjoern A. Zeeb 		wlc->band->CWmin = APHY_CWMIN;
7968*b4c3e9b5SBjoern A. Zeeb 		wlc->band->CWmax = PHY_CWMAX;
7969*b4c3e9b5SBjoern A. Zeeb 
7970*b4c3e9b5SBjoern A. Zeeb 		/* init gmode value */
7971*b4c3e9b5SBjoern A. Zeeb 		if (wlc->band->bandtype == BRCM_BAND_2G) {
7972*b4c3e9b5SBjoern A. Zeeb 			wlc->band->gmode = GMODE_AUTO;
7973*b4c3e9b5SBjoern A. Zeeb 			brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER,
7974*b4c3e9b5SBjoern A. Zeeb 					   wlc->band->gmode);
7975*b4c3e9b5SBjoern A. Zeeb 		}
7976*b4c3e9b5SBjoern A. Zeeb 
7977*b4c3e9b5SBjoern A. Zeeb 		/* init _n_enab supported mode */
7978*b4c3e9b5SBjoern A. Zeeb 		if (BRCMS_PHY_11N_CAP(wlc->band)) {
7979*b4c3e9b5SBjoern A. Zeeb 			pub->_n_enab = SUPPORT_11N;
7980*b4c3e9b5SBjoern A. Zeeb 			brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER,
7981*b4c3e9b5SBjoern A. Zeeb 						   ((pub->_n_enab ==
7982*b4c3e9b5SBjoern A. Zeeb 						     SUPPORT_11N) ? WL_11N_2x2 :
7983*b4c3e9b5SBjoern A. Zeeb 						    WL_11N_3x3));
7984*b4c3e9b5SBjoern A. Zeeb 		}
7985*b4c3e9b5SBjoern A. Zeeb 
7986*b4c3e9b5SBjoern A. Zeeb 		/* init per-band default rateset, depend on band->gmode */
7987*b4c3e9b5SBjoern A. Zeeb 		brcms_default_rateset(wlc, &wlc->band->defrateset);
7988*b4c3e9b5SBjoern A. Zeeb 
7989*b4c3e9b5SBjoern A. Zeeb 		/* fill in hw_rateset */
7990*b4c3e9b5SBjoern A. Zeeb 		brcms_c_rateset_filter(&wlc->band->defrateset,
7991*b4c3e9b5SBjoern A. Zeeb 				   &wlc->band->hw_rateset, false,
7992*b4c3e9b5SBjoern A. Zeeb 				   BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
7993*b4c3e9b5SBjoern A. Zeeb 				   (bool) (wlc->pub->_n_enab & SUPPORT_11N));
7994*b4c3e9b5SBjoern A. Zeeb 	}
7995*b4c3e9b5SBjoern A. Zeeb 
7996*b4c3e9b5SBjoern A. Zeeb 	/*
7997*b4c3e9b5SBjoern A. Zeeb 	 * update antenna config due to
7998*b4c3e9b5SBjoern A. Zeeb 	 * wlc->stf->txant/txchain/ant_rx_ovr change
7999*b4c3e9b5SBjoern A. Zeeb 	 */
8000*b4c3e9b5SBjoern A. Zeeb 	brcms_c_stf_phy_txant_upd(wlc);
8001*b4c3e9b5SBjoern A. Zeeb 
8002*b4c3e9b5SBjoern A. Zeeb 	/* attach each modules */
8003*b4c3e9b5SBjoern A. Zeeb 	err = brcms_c_attach_module(wlc);
8004*b4c3e9b5SBjoern A. Zeeb 	if (err != 0)
8005*b4c3e9b5SBjoern A. Zeeb 		goto fail;
8006*b4c3e9b5SBjoern A. Zeeb 
8007*b4c3e9b5SBjoern A. Zeeb 	if (!brcms_c_timers_init(wlc, unit)) {
8008*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wl->wiphy, "wl%d: %s: init_timer failed\n", unit,
8009*b4c3e9b5SBjoern A. Zeeb 			  __func__);
8010*b4c3e9b5SBjoern A. Zeeb 		err = 32;
8011*b4c3e9b5SBjoern A. Zeeb 		goto fail;
8012*b4c3e9b5SBjoern A. Zeeb 	}
8013*b4c3e9b5SBjoern A. Zeeb 
8014*b4c3e9b5SBjoern A. Zeeb 	/* depend on rateset, gmode */
8015*b4c3e9b5SBjoern A. Zeeb 	wlc->cmi = brcms_c_channel_mgr_attach(wlc);
8016*b4c3e9b5SBjoern A. Zeeb 	if (!wlc->cmi) {
8017*b4c3e9b5SBjoern A. Zeeb 		wiphy_err(wl->wiphy, "wl%d: %s: channel_mgr_attach failed"
8018*b4c3e9b5SBjoern A. Zeeb 			  "\n", unit, __func__);
8019*b4c3e9b5SBjoern A. Zeeb 		err = 33;
8020*b4c3e9b5SBjoern A. Zeeb 		goto fail;
8021*b4c3e9b5SBjoern A. Zeeb 	}
8022*b4c3e9b5SBjoern A. Zeeb 
8023*b4c3e9b5SBjoern A. Zeeb 	/* init default when all parameters are ready, i.e. ->rateset */
8024*b4c3e9b5SBjoern A. Zeeb 	brcms_c_bss_default_init(wlc);
8025*b4c3e9b5SBjoern A. Zeeb 
8026*b4c3e9b5SBjoern A. Zeeb 	/*
8027*b4c3e9b5SBjoern A. Zeeb 	 * Complete the wlc default state initializations..
8028*b4c3e9b5SBjoern A. Zeeb 	 */
8029*b4c3e9b5SBjoern A. Zeeb 
8030*b4c3e9b5SBjoern A. Zeeb 	wlc->bsscfg->wlc = wlc;
8031*b4c3e9b5SBjoern A. Zeeb 
8032*b4c3e9b5SBjoern A. Zeeb 	wlc->mimoft = FT_HT;
8033*b4c3e9b5SBjoern A. Zeeb 	wlc->mimo_40txbw = AUTO;
8034*b4c3e9b5SBjoern A. Zeeb 	wlc->ofdm_40txbw = AUTO;
8035*b4c3e9b5SBjoern A. Zeeb 	wlc->cck_40txbw = AUTO;
8036*b4c3e9b5SBjoern A. Zeeb 	brcms_c_update_mimo_band_bwcap(wlc, BRCMS_N_BW_20IN2G_40IN5G);
8037*b4c3e9b5SBjoern A. Zeeb 
8038*b4c3e9b5SBjoern A. Zeeb 	/* Set default values of SGI */
8039*b4c3e9b5SBjoern A. Zeeb 	if (BRCMS_SGI_CAP_PHY(wlc)) {
8040*b4c3e9b5SBjoern A. Zeeb 		brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
8041*b4c3e9b5SBjoern A. Zeeb 					       BRCMS_N_SGI_40));
8042*b4c3e9b5SBjoern A. Zeeb 	} else if (BRCMS_ISSSLPNPHY(wlc->band)) {
8043*b4c3e9b5SBjoern A. Zeeb 		brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
8044*b4c3e9b5SBjoern A. Zeeb 					       BRCMS_N_SGI_40));
8045*b4c3e9b5SBjoern A. Zeeb 	} else {
8046*b4c3e9b5SBjoern A. Zeeb 		brcms_c_ht_update_sgi_rx(wlc, 0);
8047*b4c3e9b5SBjoern A. Zeeb 	}
8048*b4c3e9b5SBjoern A. Zeeb 
8049*b4c3e9b5SBjoern A. Zeeb 	brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail);
8050*b4c3e9b5SBjoern A. Zeeb 
8051*b4c3e9b5SBjoern A. Zeeb 	if (perr)
8052*b4c3e9b5SBjoern A. Zeeb 		*perr = 0;
8053*b4c3e9b5SBjoern A. Zeeb 
8054*b4c3e9b5SBjoern A. Zeeb 	return wlc;
8055*b4c3e9b5SBjoern A. Zeeb 
8056*b4c3e9b5SBjoern A. Zeeb  fail:
8057*b4c3e9b5SBjoern A. Zeeb 	wiphy_err(wl->wiphy, "wl%d: %s: failed with err %d\n",
8058*b4c3e9b5SBjoern A. Zeeb 		  unit, __func__, err);
8059*b4c3e9b5SBjoern A. Zeeb 	if (wlc)
8060*b4c3e9b5SBjoern A. Zeeb 		brcms_c_detach(wlc);
8061*b4c3e9b5SBjoern A. Zeeb 
8062*b4c3e9b5SBjoern A. Zeeb 	if (perr)
8063*b4c3e9b5SBjoern A. Zeeb 		*perr = err;
8064*b4c3e9b5SBjoern A. Zeeb 	return NULL;
8065*b4c3e9b5SBjoern A. Zeeb }
8066