1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun Broadcom B43 wireless driver
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
7*4882a593Smuzhiyun Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
8*4882a593Smuzhiyun Copyright (c) 2005-2009 Michael Buesch <m@bues.ch>
9*4882a593Smuzhiyun Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
10*4882a593Smuzhiyun Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
11*4882a593Smuzhiyun Copyright (c) 2010-2011 Rafał Miłecki <zajec5@gmail.com>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun SDIO support
14*4882a593Smuzhiyun Copyright (c) 2009 Albert Herranz <albert_herranz@yahoo.es>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun Some parts of the code in this file are derived from the ipw2200
17*4882a593Smuzhiyun driver Copyright(c) 2003 - 2004 Intel Corporation.
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include <linux/delay.h>
23*4882a593Smuzhiyun #include <linux/init.h>
24*4882a593Smuzhiyun #include <linux/module.h>
25*4882a593Smuzhiyun #include <linux/if_arp.h>
26*4882a593Smuzhiyun #include <linux/etherdevice.h>
27*4882a593Smuzhiyun #include <linux/firmware.h>
28*4882a593Smuzhiyun #include <linux/workqueue.h>
29*4882a593Smuzhiyun #include <linux/skbuff.h>
30*4882a593Smuzhiyun #include <linux/io.h>
31*4882a593Smuzhiyun #include <linux/dma-mapping.h>
32*4882a593Smuzhiyun #include <linux/slab.h>
33*4882a593Smuzhiyun #include <asm/unaligned.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #include "b43.h"
36*4882a593Smuzhiyun #include "main.h"
37*4882a593Smuzhiyun #include "debugfs.h"
38*4882a593Smuzhiyun #include "phy_common.h"
39*4882a593Smuzhiyun #include "phy_g.h"
40*4882a593Smuzhiyun #include "phy_n.h"
41*4882a593Smuzhiyun #include "dma.h"
42*4882a593Smuzhiyun #include "pio.h"
43*4882a593Smuzhiyun #include "sysfs.h"
44*4882a593Smuzhiyun #include "xmit.h"
45*4882a593Smuzhiyun #include "lo.h"
46*4882a593Smuzhiyun #include "sdio.h"
47*4882a593Smuzhiyun #include <linux/mmc/sdio_func.h>
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun MODULE_DESCRIPTION("Broadcom B43 wireless driver");
50*4882a593Smuzhiyun MODULE_AUTHOR("Martin Langer");
51*4882a593Smuzhiyun MODULE_AUTHOR("Stefano Brivio");
52*4882a593Smuzhiyun MODULE_AUTHOR("Michael Buesch");
53*4882a593Smuzhiyun MODULE_AUTHOR("Gábor Stefanik");
54*4882a593Smuzhiyun MODULE_AUTHOR("Rafał Miłecki");
55*4882a593Smuzhiyun MODULE_LICENSE("GPL");
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode11.fw");
58*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode13.fw");
59*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode14.fw");
60*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode15.fw");
61*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode16_lp.fw");
62*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode16_mimo.fw");
63*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode24_lcn.fw");
64*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode25_lcn.fw");
65*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode25_mimo.fw");
66*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode26_mimo.fw");
67*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode29_mimo.fw");
68*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode33_lcn40.fw");
69*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode30_mimo.fw");
70*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode5.fw");
71*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode40.fw");
72*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode42.fw");
73*4882a593Smuzhiyun MODULE_FIRMWARE("b43/ucode9.fw");
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun static int modparam_bad_frames_preempt;
76*4882a593Smuzhiyun module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
77*4882a593Smuzhiyun MODULE_PARM_DESC(bad_frames_preempt,
78*4882a593Smuzhiyun "enable(1) / disable(0) Bad Frames Preemption");
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun static char modparam_fwpostfix[16];
81*4882a593Smuzhiyun module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
82*4882a593Smuzhiyun MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun static int modparam_hwpctl;
85*4882a593Smuzhiyun module_param_named(hwpctl, modparam_hwpctl, int, 0444);
86*4882a593Smuzhiyun MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)");
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun static int modparam_nohwcrypt;
89*4882a593Smuzhiyun module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
90*4882a593Smuzhiyun MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static int modparam_hwtkip;
93*4882a593Smuzhiyun module_param_named(hwtkip, modparam_hwtkip, int, 0444);
94*4882a593Smuzhiyun MODULE_PARM_DESC(hwtkip, "Enable hardware tkip.");
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun static int modparam_qos = 1;
97*4882a593Smuzhiyun module_param_named(qos, modparam_qos, int, 0444);
98*4882a593Smuzhiyun MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun static int modparam_btcoex = 1;
101*4882a593Smuzhiyun module_param_named(btcoex, modparam_btcoex, int, 0444);
102*4882a593Smuzhiyun MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistence (default on)");
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
105*4882a593Smuzhiyun module_param_named(verbose, b43_modparam_verbose, int, 0644);
106*4882a593Smuzhiyun MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun static int b43_modparam_pio = 0;
109*4882a593Smuzhiyun module_param_named(pio, b43_modparam_pio, int, 0644);
110*4882a593Smuzhiyun MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun static int modparam_allhwsupport = !IS_ENABLED(CONFIG_BRCMSMAC);
113*4882a593Smuzhiyun module_param_named(allhwsupport, modparam_allhwsupport, int, 0444);
114*4882a593Smuzhiyun MODULE_PARM_DESC(allhwsupport, "Enable support for all hardware (even it if overlaps with the brcmsmac driver)");
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
117*4882a593Smuzhiyun static const struct bcma_device_id b43_bcma_tbl[] = {
118*4882a593Smuzhiyun BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x11, BCMA_ANY_CLASS),
119*4882a593Smuzhiyun BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x15, BCMA_ANY_CLASS),
120*4882a593Smuzhiyun BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS),
121*4882a593Smuzhiyun BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS),
122*4882a593Smuzhiyun BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1C, BCMA_ANY_CLASS),
123*4882a593Smuzhiyun BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS),
124*4882a593Smuzhiyun BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1E, BCMA_ANY_CLASS),
125*4882a593Smuzhiyun BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x28, BCMA_ANY_CLASS),
126*4882a593Smuzhiyun BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x2A, BCMA_ANY_CLASS),
127*4882a593Smuzhiyun {},
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun MODULE_DEVICE_TABLE(bcma, b43_bcma_tbl);
130*4882a593Smuzhiyun #endif
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
133*4882a593Smuzhiyun static const struct ssb_device_id b43_ssb_tbl[] = {
134*4882a593Smuzhiyun SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
135*4882a593Smuzhiyun SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
136*4882a593Smuzhiyun SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
137*4882a593Smuzhiyun SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
138*4882a593Smuzhiyun SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
139*4882a593Smuzhiyun SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
140*4882a593Smuzhiyun SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 12),
141*4882a593Smuzhiyun SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
142*4882a593Smuzhiyun SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15),
143*4882a593Smuzhiyun SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16),
144*4882a593Smuzhiyun {},
145*4882a593Smuzhiyun };
146*4882a593Smuzhiyun MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
147*4882a593Smuzhiyun #endif
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /* Channel and ratetables are shared for all devices.
150*4882a593Smuzhiyun * They can't be const, because ieee80211 puts some precalculated
151*4882a593Smuzhiyun * data in there. This data is the same for all devices, so we don't
152*4882a593Smuzhiyun * get concurrency issues */
153*4882a593Smuzhiyun #define RATETAB_ENT(_rateid, _flags) \
154*4882a593Smuzhiyun { \
155*4882a593Smuzhiyun .bitrate = B43_RATE_TO_BASE100KBPS(_rateid), \
156*4882a593Smuzhiyun .hw_value = (_rateid), \
157*4882a593Smuzhiyun .flags = (_flags), \
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /*
161*4882a593Smuzhiyun * NOTE: When changing this, sync with xmit.c's
162*4882a593Smuzhiyun * b43_plcp_get_bitrate_idx_* functions!
163*4882a593Smuzhiyun */
164*4882a593Smuzhiyun static struct ieee80211_rate __b43_ratetable[] = {
165*4882a593Smuzhiyun RATETAB_ENT(B43_CCK_RATE_1MB, 0),
166*4882a593Smuzhiyun RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
167*4882a593Smuzhiyun RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
168*4882a593Smuzhiyun RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
169*4882a593Smuzhiyun RATETAB_ENT(B43_OFDM_RATE_6MB, 0),
170*4882a593Smuzhiyun RATETAB_ENT(B43_OFDM_RATE_9MB, 0),
171*4882a593Smuzhiyun RATETAB_ENT(B43_OFDM_RATE_12MB, 0),
172*4882a593Smuzhiyun RATETAB_ENT(B43_OFDM_RATE_18MB, 0),
173*4882a593Smuzhiyun RATETAB_ENT(B43_OFDM_RATE_24MB, 0),
174*4882a593Smuzhiyun RATETAB_ENT(B43_OFDM_RATE_36MB, 0),
175*4882a593Smuzhiyun RATETAB_ENT(B43_OFDM_RATE_48MB, 0),
176*4882a593Smuzhiyun RATETAB_ENT(B43_OFDM_RATE_54MB, 0),
177*4882a593Smuzhiyun };
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun #define b43_a_ratetable (__b43_ratetable + 4)
180*4882a593Smuzhiyun #define b43_a_ratetable_size 8
181*4882a593Smuzhiyun #define b43_b_ratetable (__b43_ratetable + 0)
182*4882a593Smuzhiyun #define b43_b_ratetable_size 4
183*4882a593Smuzhiyun #define b43_g_ratetable (__b43_ratetable + 0)
184*4882a593Smuzhiyun #define b43_g_ratetable_size 12
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun #define CHAN2G(_channel, _freq, _flags) { \
187*4882a593Smuzhiyun .band = NL80211_BAND_2GHZ, \
188*4882a593Smuzhiyun .center_freq = (_freq), \
189*4882a593Smuzhiyun .hw_value = (_channel), \
190*4882a593Smuzhiyun .flags = (_flags), \
191*4882a593Smuzhiyun .max_antenna_gain = 0, \
192*4882a593Smuzhiyun .max_power = 30, \
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun static struct ieee80211_channel b43_2ghz_chantable[] = {
195*4882a593Smuzhiyun CHAN2G(1, 2412, 0),
196*4882a593Smuzhiyun CHAN2G(2, 2417, 0),
197*4882a593Smuzhiyun CHAN2G(3, 2422, 0),
198*4882a593Smuzhiyun CHAN2G(4, 2427, 0),
199*4882a593Smuzhiyun CHAN2G(5, 2432, 0),
200*4882a593Smuzhiyun CHAN2G(6, 2437, 0),
201*4882a593Smuzhiyun CHAN2G(7, 2442, 0),
202*4882a593Smuzhiyun CHAN2G(8, 2447, 0),
203*4882a593Smuzhiyun CHAN2G(9, 2452, 0),
204*4882a593Smuzhiyun CHAN2G(10, 2457, 0),
205*4882a593Smuzhiyun CHAN2G(11, 2462, 0),
206*4882a593Smuzhiyun CHAN2G(12, 2467, 0),
207*4882a593Smuzhiyun CHAN2G(13, 2472, 0),
208*4882a593Smuzhiyun CHAN2G(14, 2484, 0),
209*4882a593Smuzhiyun };
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun /* No support for the last 3 channels (12, 13, 14) */
212*4882a593Smuzhiyun #define b43_2ghz_chantable_limited_size 11
213*4882a593Smuzhiyun #undef CHAN2G
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun #define CHAN4G(_channel, _flags) { \
216*4882a593Smuzhiyun .band = NL80211_BAND_5GHZ, \
217*4882a593Smuzhiyun .center_freq = 4000 + (5 * (_channel)), \
218*4882a593Smuzhiyun .hw_value = (_channel), \
219*4882a593Smuzhiyun .flags = (_flags), \
220*4882a593Smuzhiyun .max_antenna_gain = 0, \
221*4882a593Smuzhiyun .max_power = 30, \
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun #define CHAN5G(_channel, _flags) { \
224*4882a593Smuzhiyun .band = NL80211_BAND_5GHZ, \
225*4882a593Smuzhiyun .center_freq = 5000 + (5 * (_channel)), \
226*4882a593Smuzhiyun .hw_value = (_channel), \
227*4882a593Smuzhiyun .flags = (_flags), \
228*4882a593Smuzhiyun .max_antenna_gain = 0, \
229*4882a593Smuzhiyun .max_power = 30, \
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun static struct ieee80211_channel b43_5ghz_nphy_chantable[] = {
232*4882a593Smuzhiyun CHAN4G(184, 0), CHAN4G(186, 0),
233*4882a593Smuzhiyun CHAN4G(188, 0), CHAN4G(190, 0),
234*4882a593Smuzhiyun CHAN4G(192, 0), CHAN4G(194, 0),
235*4882a593Smuzhiyun CHAN4G(196, 0), CHAN4G(198, 0),
236*4882a593Smuzhiyun CHAN4G(200, 0), CHAN4G(202, 0),
237*4882a593Smuzhiyun CHAN4G(204, 0), CHAN4G(206, 0),
238*4882a593Smuzhiyun CHAN4G(208, 0), CHAN4G(210, 0),
239*4882a593Smuzhiyun CHAN4G(212, 0), CHAN4G(214, 0),
240*4882a593Smuzhiyun CHAN4G(216, 0), CHAN4G(218, 0),
241*4882a593Smuzhiyun CHAN4G(220, 0), CHAN4G(222, 0),
242*4882a593Smuzhiyun CHAN4G(224, 0), CHAN4G(226, 0),
243*4882a593Smuzhiyun CHAN4G(228, 0),
244*4882a593Smuzhiyun CHAN5G(32, 0), CHAN5G(34, 0),
245*4882a593Smuzhiyun CHAN5G(36, 0), CHAN5G(38, 0),
246*4882a593Smuzhiyun CHAN5G(40, 0), CHAN5G(42, 0),
247*4882a593Smuzhiyun CHAN5G(44, 0), CHAN5G(46, 0),
248*4882a593Smuzhiyun CHAN5G(48, 0), CHAN5G(50, 0),
249*4882a593Smuzhiyun CHAN5G(52, 0), CHAN5G(54, 0),
250*4882a593Smuzhiyun CHAN5G(56, 0), CHAN5G(58, 0),
251*4882a593Smuzhiyun CHAN5G(60, 0), CHAN5G(62, 0),
252*4882a593Smuzhiyun CHAN5G(64, 0), CHAN5G(66, 0),
253*4882a593Smuzhiyun CHAN5G(68, 0), CHAN5G(70, 0),
254*4882a593Smuzhiyun CHAN5G(72, 0), CHAN5G(74, 0),
255*4882a593Smuzhiyun CHAN5G(76, 0), CHAN5G(78, 0),
256*4882a593Smuzhiyun CHAN5G(80, 0), CHAN5G(82, 0),
257*4882a593Smuzhiyun CHAN5G(84, 0), CHAN5G(86, 0),
258*4882a593Smuzhiyun CHAN5G(88, 0), CHAN5G(90, 0),
259*4882a593Smuzhiyun CHAN5G(92, 0), CHAN5G(94, 0),
260*4882a593Smuzhiyun CHAN5G(96, 0), CHAN5G(98, 0),
261*4882a593Smuzhiyun CHAN5G(100, 0), CHAN5G(102, 0),
262*4882a593Smuzhiyun CHAN5G(104, 0), CHAN5G(106, 0),
263*4882a593Smuzhiyun CHAN5G(108, 0), CHAN5G(110, 0),
264*4882a593Smuzhiyun CHAN5G(112, 0), CHAN5G(114, 0),
265*4882a593Smuzhiyun CHAN5G(116, 0), CHAN5G(118, 0),
266*4882a593Smuzhiyun CHAN5G(120, 0), CHAN5G(122, 0),
267*4882a593Smuzhiyun CHAN5G(124, 0), CHAN5G(126, 0),
268*4882a593Smuzhiyun CHAN5G(128, 0), CHAN5G(130, 0),
269*4882a593Smuzhiyun CHAN5G(132, 0), CHAN5G(134, 0),
270*4882a593Smuzhiyun CHAN5G(136, 0), CHAN5G(138, 0),
271*4882a593Smuzhiyun CHAN5G(140, 0), CHAN5G(142, 0),
272*4882a593Smuzhiyun CHAN5G(144, 0), CHAN5G(145, 0),
273*4882a593Smuzhiyun CHAN5G(146, 0), CHAN5G(147, 0),
274*4882a593Smuzhiyun CHAN5G(148, 0), CHAN5G(149, 0),
275*4882a593Smuzhiyun CHAN5G(150, 0), CHAN5G(151, 0),
276*4882a593Smuzhiyun CHAN5G(152, 0), CHAN5G(153, 0),
277*4882a593Smuzhiyun CHAN5G(154, 0), CHAN5G(155, 0),
278*4882a593Smuzhiyun CHAN5G(156, 0), CHAN5G(157, 0),
279*4882a593Smuzhiyun CHAN5G(158, 0), CHAN5G(159, 0),
280*4882a593Smuzhiyun CHAN5G(160, 0), CHAN5G(161, 0),
281*4882a593Smuzhiyun CHAN5G(162, 0), CHAN5G(163, 0),
282*4882a593Smuzhiyun CHAN5G(164, 0), CHAN5G(165, 0),
283*4882a593Smuzhiyun CHAN5G(166, 0), CHAN5G(168, 0),
284*4882a593Smuzhiyun CHAN5G(170, 0), CHAN5G(172, 0),
285*4882a593Smuzhiyun CHAN5G(174, 0), CHAN5G(176, 0),
286*4882a593Smuzhiyun CHAN5G(178, 0), CHAN5G(180, 0),
287*4882a593Smuzhiyun CHAN5G(182, 0),
288*4882a593Smuzhiyun };
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun static struct ieee80211_channel b43_5ghz_nphy_chantable_limited[] = {
291*4882a593Smuzhiyun CHAN5G(36, 0), CHAN5G(40, 0),
292*4882a593Smuzhiyun CHAN5G(44, 0), CHAN5G(48, 0),
293*4882a593Smuzhiyun CHAN5G(149, 0), CHAN5G(153, 0),
294*4882a593Smuzhiyun CHAN5G(157, 0), CHAN5G(161, 0),
295*4882a593Smuzhiyun CHAN5G(165, 0),
296*4882a593Smuzhiyun };
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun static struct ieee80211_channel b43_5ghz_aphy_chantable[] = {
299*4882a593Smuzhiyun CHAN5G(34, 0), CHAN5G(36, 0),
300*4882a593Smuzhiyun CHAN5G(38, 0), CHAN5G(40, 0),
301*4882a593Smuzhiyun CHAN5G(42, 0), CHAN5G(44, 0),
302*4882a593Smuzhiyun CHAN5G(46, 0), CHAN5G(48, 0),
303*4882a593Smuzhiyun CHAN5G(52, 0), CHAN5G(56, 0),
304*4882a593Smuzhiyun CHAN5G(60, 0), CHAN5G(64, 0),
305*4882a593Smuzhiyun CHAN5G(100, 0), CHAN5G(104, 0),
306*4882a593Smuzhiyun CHAN5G(108, 0), CHAN5G(112, 0),
307*4882a593Smuzhiyun CHAN5G(116, 0), CHAN5G(120, 0),
308*4882a593Smuzhiyun CHAN5G(124, 0), CHAN5G(128, 0),
309*4882a593Smuzhiyun CHAN5G(132, 0), CHAN5G(136, 0),
310*4882a593Smuzhiyun CHAN5G(140, 0), CHAN5G(149, 0),
311*4882a593Smuzhiyun CHAN5G(153, 0), CHAN5G(157, 0),
312*4882a593Smuzhiyun CHAN5G(161, 0), CHAN5G(165, 0),
313*4882a593Smuzhiyun CHAN5G(184, 0), CHAN5G(188, 0),
314*4882a593Smuzhiyun CHAN5G(192, 0), CHAN5G(196, 0),
315*4882a593Smuzhiyun CHAN5G(200, 0), CHAN5G(204, 0),
316*4882a593Smuzhiyun CHAN5G(208, 0), CHAN5G(212, 0),
317*4882a593Smuzhiyun CHAN5G(216, 0),
318*4882a593Smuzhiyun };
319*4882a593Smuzhiyun #undef CHAN4G
320*4882a593Smuzhiyun #undef CHAN5G
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun static struct ieee80211_supported_band b43_band_5GHz_nphy = {
323*4882a593Smuzhiyun .band = NL80211_BAND_5GHZ,
324*4882a593Smuzhiyun .channels = b43_5ghz_nphy_chantable,
325*4882a593Smuzhiyun .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable),
326*4882a593Smuzhiyun .bitrates = b43_a_ratetable,
327*4882a593Smuzhiyun .n_bitrates = b43_a_ratetable_size,
328*4882a593Smuzhiyun };
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun static struct ieee80211_supported_band b43_band_5GHz_nphy_limited = {
331*4882a593Smuzhiyun .band = NL80211_BAND_5GHZ,
332*4882a593Smuzhiyun .channels = b43_5ghz_nphy_chantable_limited,
333*4882a593Smuzhiyun .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable_limited),
334*4882a593Smuzhiyun .bitrates = b43_a_ratetable,
335*4882a593Smuzhiyun .n_bitrates = b43_a_ratetable_size,
336*4882a593Smuzhiyun };
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun static struct ieee80211_supported_band b43_band_5GHz_aphy = {
339*4882a593Smuzhiyun .band = NL80211_BAND_5GHZ,
340*4882a593Smuzhiyun .channels = b43_5ghz_aphy_chantable,
341*4882a593Smuzhiyun .n_channels = ARRAY_SIZE(b43_5ghz_aphy_chantable),
342*4882a593Smuzhiyun .bitrates = b43_a_ratetable,
343*4882a593Smuzhiyun .n_bitrates = b43_a_ratetable_size,
344*4882a593Smuzhiyun };
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun static struct ieee80211_supported_band b43_band_2GHz = {
347*4882a593Smuzhiyun .band = NL80211_BAND_2GHZ,
348*4882a593Smuzhiyun .channels = b43_2ghz_chantable,
349*4882a593Smuzhiyun .n_channels = ARRAY_SIZE(b43_2ghz_chantable),
350*4882a593Smuzhiyun .bitrates = b43_g_ratetable,
351*4882a593Smuzhiyun .n_bitrates = b43_g_ratetable_size,
352*4882a593Smuzhiyun };
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun static struct ieee80211_supported_band b43_band_2ghz_limited = {
355*4882a593Smuzhiyun .band = NL80211_BAND_2GHZ,
356*4882a593Smuzhiyun .channels = b43_2ghz_chantable,
357*4882a593Smuzhiyun .n_channels = b43_2ghz_chantable_limited_size,
358*4882a593Smuzhiyun .bitrates = b43_g_ratetable,
359*4882a593Smuzhiyun .n_bitrates = b43_g_ratetable_size,
360*4882a593Smuzhiyun };
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun static void b43_wireless_core_exit(struct b43_wldev *dev);
363*4882a593Smuzhiyun static int b43_wireless_core_init(struct b43_wldev *dev);
364*4882a593Smuzhiyun static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev);
365*4882a593Smuzhiyun static int b43_wireless_core_start(struct b43_wldev *dev);
366*4882a593Smuzhiyun static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
367*4882a593Smuzhiyun struct ieee80211_vif *vif,
368*4882a593Smuzhiyun struct ieee80211_bss_conf *conf,
369*4882a593Smuzhiyun u32 changed);
370*4882a593Smuzhiyun
b43_ratelimit(struct b43_wl * wl)371*4882a593Smuzhiyun static int b43_ratelimit(struct b43_wl *wl)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun if (!wl || !wl->current_dev)
374*4882a593Smuzhiyun return 1;
375*4882a593Smuzhiyun if (b43_status(wl->current_dev) < B43_STAT_STARTED)
376*4882a593Smuzhiyun return 1;
377*4882a593Smuzhiyun /* We are up and running.
378*4882a593Smuzhiyun * Ratelimit the messages to avoid DoS over the net. */
379*4882a593Smuzhiyun return net_ratelimit();
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
b43info(struct b43_wl * wl,const char * fmt,...)382*4882a593Smuzhiyun void b43info(struct b43_wl *wl, const char *fmt, ...)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun struct va_format vaf;
385*4882a593Smuzhiyun va_list args;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun if (b43_modparam_verbose < B43_VERBOSITY_INFO)
388*4882a593Smuzhiyun return;
389*4882a593Smuzhiyun if (!b43_ratelimit(wl))
390*4882a593Smuzhiyun return;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun va_start(args, fmt);
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun vaf.fmt = fmt;
395*4882a593Smuzhiyun vaf.va = &args;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun printk(KERN_INFO "b43-%s: %pV",
398*4882a593Smuzhiyun (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun va_end(args);
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
b43err(struct b43_wl * wl,const char * fmt,...)403*4882a593Smuzhiyun void b43err(struct b43_wl *wl, const char *fmt, ...)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun struct va_format vaf;
406*4882a593Smuzhiyun va_list args;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun if (b43_modparam_verbose < B43_VERBOSITY_ERROR)
409*4882a593Smuzhiyun return;
410*4882a593Smuzhiyun if (!b43_ratelimit(wl))
411*4882a593Smuzhiyun return;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun va_start(args, fmt);
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun vaf.fmt = fmt;
416*4882a593Smuzhiyun vaf.va = &args;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun printk(KERN_ERR "b43-%s ERROR: %pV",
419*4882a593Smuzhiyun (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun va_end(args);
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
b43warn(struct b43_wl * wl,const char * fmt,...)424*4882a593Smuzhiyun void b43warn(struct b43_wl *wl, const char *fmt, ...)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun struct va_format vaf;
427*4882a593Smuzhiyun va_list args;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun if (b43_modparam_verbose < B43_VERBOSITY_WARN)
430*4882a593Smuzhiyun return;
431*4882a593Smuzhiyun if (!b43_ratelimit(wl))
432*4882a593Smuzhiyun return;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun va_start(args, fmt);
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun vaf.fmt = fmt;
437*4882a593Smuzhiyun vaf.va = &args;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun printk(KERN_WARNING "b43-%s warning: %pV",
440*4882a593Smuzhiyun (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun va_end(args);
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
b43dbg(struct b43_wl * wl,const char * fmt,...)445*4882a593Smuzhiyun void b43dbg(struct b43_wl *wl, const char *fmt, ...)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun struct va_format vaf;
448*4882a593Smuzhiyun va_list args;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
451*4882a593Smuzhiyun return;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun va_start(args, fmt);
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun vaf.fmt = fmt;
456*4882a593Smuzhiyun vaf.va = &args;
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun printk(KERN_DEBUG "b43-%s debug: %pV",
459*4882a593Smuzhiyun (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun va_end(args);
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
b43_ram_write(struct b43_wldev * dev,u16 offset,u32 val)464*4882a593Smuzhiyun static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun u32 macctl;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun B43_WARN_ON(offset % 4 != 0);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun macctl = b43_read32(dev, B43_MMIO_MACCTL);
471*4882a593Smuzhiyun if (macctl & B43_MACCTL_BE)
472*4882a593Smuzhiyun val = swab32(val);
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_RAM_CONTROL, offset);
475*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_RAM_DATA, val);
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
b43_shm_control_word(struct b43_wldev * dev,u16 routing,u16 offset)478*4882a593Smuzhiyun static inline void b43_shm_control_word(struct b43_wldev *dev,
479*4882a593Smuzhiyun u16 routing, u16 offset)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun u32 control;
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun /* "offset" is the WORD offset. */
484*4882a593Smuzhiyun control = routing;
485*4882a593Smuzhiyun control <<= 16;
486*4882a593Smuzhiyun control |= offset;
487*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
b43_shm_read32(struct b43_wldev * dev,u16 routing,u16 offset)490*4882a593Smuzhiyun u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun u32 ret;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun if (routing == B43_SHM_SHARED) {
495*4882a593Smuzhiyun B43_WARN_ON(offset & 0x0001);
496*4882a593Smuzhiyun if (offset & 0x0003) {
497*4882a593Smuzhiyun /* Unaligned access */
498*4882a593Smuzhiyun b43_shm_control_word(dev, routing, offset >> 2);
499*4882a593Smuzhiyun ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
500*4882a593Smuzhiyun b43_shm_control_word(dev, routing, (offset >> 2) + 1);
501*4882a593Smuzhiyun ret |= ((u32)b43_read16(dev, B43_MMIO_SHM_DATA)) << 16;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun goto out;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun offset >>= 2;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun b43_shm_control_word(dev, routing, offset);
508*4882a593Smuzhiyun ret = b43_read32(dev, B43_MMIO_SHM_DATA);
509*4882a593Smuzhiyun out:
510*4882a593Smuzhiyun return ret;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
b43_shm_read16(struct b43_wldev * dev,u16 routing,u16 offset)513*4882a593Smuzhiyun u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun u16 ret;
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun if (routing == B43_SHM_SHARED) {
518*4882a593Smuzhiyun B43_WARN_ON(offset & 0x0001);
519*4882a593Smuzhiyun if (offset & 0x0003) {
520*4882a593Smuzhiyun /* Unaligned access */
521*4882a593Smuzhiyun b43_shm_control_word(dev, routing, offset >> 2);
522*4882a593Smuzhiyun ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun goto out;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun offset >>= 2;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun b43_shm_control_word(dev, routing, offset);
529*4882a593Smuzhiyun ret = b43_read16(dev, B43_MMIO_SHM_DATA);
530*4882a593Smuzhiyun out:
531*4882a593Smuzhiyun return ret;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
b43_shm_write32(struct b43_wldev * dev,u16 routing,u16 offset,u32 value)534*4882a593Smuzhiyun void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun if (routing == B43_SHM_SHARED) {
537*4882a593Smuzhiyun B43_WARN_ON(offset & 0x0001);
538*4882a593Smuzhiyun if (offset & 0x0003) {
539*4882a593Smuzhiyun /* Unaligned access */
540*4882a593Smuzhiyun b43_shm_control_word(dev, routing, offset >> 2);
541*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
542*4882a593Smuzhiyun value & 0xFFFF);
543*4882a593Smuzhiyun b43_shm_control_word(dev, routing, (offset >> 2) + 1);
544*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_SHM_DATA,
545*4882a593Smuzhiyun (value >> 16) & 0xFFFF);
546*4882a593Smuzhiyun return;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun offset >>= 2;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun b43_shm_control_word(dev, routing, offset);
551*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_SHM_DATA, value);
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun
b43_shm_write16(struct b43_wldev * dev,u16 routing,u16 offset,u16 value)554*4882a593Smuzhiyun void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun if (routing == B43_SHM_SHARED) {
557*4882a593Smuzhiyun B43_WARN_ON(offset & 0x0001);
558*4882a593Smuzhiyun if (offset & 0x0003) {
559*4882a593Smuzhiyun /* Unaligned access */
560*4882a593Smuzhiyun b43_shm_control_word(dev, routing, offset >> 2);
561*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
562*4882a593Smuzhiyun return;
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun offset >>= 2;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun b43_shm_control_word(dev, routing, offset);
567*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_SHM_DATA, value);
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun /* Read HostFlags */
b43_hf_read(struct b43_wldev * dev)571*4882a593Smuzhiyun u64 b43_hf_read(struct b43_wldev *dev)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun u64 ret;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF3);
576*4882a593Smuzhiyun ret <<= 16;
577*4882a593Smuzhiyun ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF2);
578*4882a593Smuzhiyun ret <<= 16;
579*4882a593Smuzhiyun ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1);
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun return ret;
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun /* Write HostFlags */
b43_hf_write(struct b43_wldev * dev,u64 value)585*4882a593Smuzhiyun void b43_hf_write(struct b43_wldev *dev, u64 value)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun u16 lo, mi, hi;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun lo = (value & 0x00000000FFFFULL);
590*4882a593Smuzhiyun mi = (value & 0x0000FFFF0000ULL) >> 16;
591*4882a593Smuzhiyun hi = (value & 0xFFFF00000000ULL) >> 32;
592*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1, lo);
593*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF2, mi);
594*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF3, hi);
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun /* Read the firmware capabilities bitmask (Opensource firmware only) */
b43_fwcapa_read(struct b43_wldev * dev)598*4882a593Smuzhiyun static u16 b43_fwcapa_read(struct b43_wldev *dev)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun B43_WARN_ON(!dev->fw.opensource);
601*4882a593Smuzhiyun return b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_FWCAPA);
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun
b43_tsf_read(struct b43_wldev * dev,u64 * tsf)604*4882a593Smuzhiyun void b43_tsf_read(struct b43_wldev *dev, u64 *tsf)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun u32 low, high;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun B43_WARN_ON(dev->dev->core_rev < 3);
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun /* The hardware guarantees us an atomic read, if we
611*4882a593Smuzhiyun * read the low register first. */
612*4882a593Smuzhiyun low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW);
613*4882a593Smuzhiyun high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun *tsf = high;
616*4882a593Smuzhiyun *tsf <<= 32;
617*4882a593Smuzhiyun *tsf |= low;
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun
b43_time_lock(struct b43_wldev * dev)620*4882a593Smuzhiyun static void b43_time_lock(struct b43_wldev *dev)
621*4882a593Smuzhiyun {
622*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~0, B43_MACCTL_TBTTHOLD);
623*4882a593Smuzhiyun /* Commit the write */
624*4882a593Smuzhiyun b43_read32(dev, B43_MMIO_MACCTL);
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun
b43_time_unlock(struct b43_wldev * dev)627*4882a593Smuzhiyun static void b43_time_unlock(struct b43_wldev *dev)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_TBTTHOLD, 0);
630*4882a593Smuzhiyun /* Commit the write */
631*4882a593Smuzhiyun b43_read32(dev, B43_MMIO_MACCTL);
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
b43_tsf_write_locked(struct b43_wldev * dev,u64 tsf)634*4882a593Smuzhiyun static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun u32 low, high;
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun B43_WARN_ON(dev->dev->core_rev < 3);
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun low = tsf;
641*4882a593Smuzhiyun high = (tsf >> 32);
642*4882a593Smuzhiyun /* The hardware guarantees us an atomic write, if we
643*4882a593Smuzhiyun * write the low register first. */
644*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, low);
645*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, high);
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun
b43_tsf_write(struct b43_wldev * dev,u64 tsf)648*4882a593Smuzhiyun void b43_tsf_write(struct b43_wldev *dev, u64 tsf)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun b43_time_lock(dev);
651*4882a593Smuzhiyun b43_tsf_write_locked(dev, tsf);
652*4882a593Smuzhiyun b43_time_unlock(dev);
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun static
b43_macfilter_set(struct b43_wldev * dev,u16 offset,const u8 * mac)656*4882a593Smuzhiyun void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 *mac)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun static const u8 zero_addr[ETH_ALEN] = { 0 };
659*4882a593Smuzhiyun u16 data;
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun if (!mac)
662*4882a593Smuzhiyun mac = zero_addr;
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun offset |= 0x0020;
665*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_MACFILTER_CONTROL, offset);
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun data = mac[0];
668*4882a593Smuzhiyun data |= mac[1] << 8;
669*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
670*4882a593Smuzhiyun data = mac[2];
671*4882a593Smuzhiyun data |= mac[3] << 8;
672*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
673*4882a593Smuzhiyun data = mac[4];
674*4882a593Smuzhiyun data |= mac[5] << 8;
675*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun
b43_write_mac_bssid_templates(struct b43_wldev * dev)678*4882a593Smuzhiyun static void b43_write_mac_bssid_templates(struct b43_wldev *dev)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun const u8 *mac;
681*4882a593Smuzhiyun const u8 *bssid;
682*4882a593Smuzhiyun u8 mac_bssid[ETH_ALEN * 2];
683*4882a593Smuzhiyun int i;
684*4882a593Smuzhiyun u32 tmp;
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun bssid = dev->wl->bssid;
687*4882a593Smuzhiyun mac = dev->wl->mac_addr;
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun b43_macfilter_set(dev, B43_MACFILTER_BSSID, bssid);
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun memcpy(mac_bssid, mac, ETH_ALEN);
692*4882a593Smuzhiyun memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun /* Write our MAC address and BSSID to template ram */
695*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
696*4882a593Smuzhiyun tmp = (u32) (mac_bssid[i + 0]);
697*4882a593Smuzhiyun tmp |= (u32) (mac_bssid[i + 1]) << 8;
698*4882a593Smuzhiyun tmp |= (u32) (mac_bssid[i + 2]) << 16;
699*4882a593Smuzhiyun tmp |= (u32) (mac_bssid[i + 3]) << 24;
700*4882a593Smuzhiyun b43_ram_write(dev, 0x20 + i, tmp);
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun
b43_upload_card_macaddress(struct b43_wldev * dev)704*4882a593Smuzhiyun static void b43_upload_card_macaddress(struct b43_wldev *dev)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun b43_write_mac_bssid_templates(dev);
707*4882a593Smuzhiyun b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr);
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun
b43_set_slot_time(struct b43_wldev * dev,u16 slot_time)710*4882a593Smuzhiyun static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
711*4882a593Smuzhiyun {
712*4882a593Smuzhiyun /* slot_time is in usec. */
713*4882a593Smuzhiyun /* This test used to exit for all but a G PHY. */
714*4882a593Smuzhiyun if (b43_current_band(dev->wl) == NL80211_BAND_5GHZ)
715*4882a593Smuzhiyun return;
716*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_IFSSLOT, 510 + slot_time);
717*4882a593Smuzhiyun /* Shared memory location 0x0010 is the slot time and should be
718*4882a593Smuzhiyun * set to slot_time; however, this register is initially 0 and changing
719*4882a593Smuzhiyun * the value adversely affects the transmit rate for BCM4311
720*4882a593Smuzhiyun * devices. Until this behavior is unterstood, delete this step
721*4882a593Smuzhiyun *
722*4882a593Smuzhiyun * b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
723*4882a593Smuzhiyun */
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun
b43_short_slot_timing_enable(struct b43_wldev * dev)726*4882a593Smuzhiyun static void b43_short_slot_timing_enable(struct b43_wldev *dev)
727*4882a593Smuzhiyun {
728*4882a593Smuzhiyun b43_set_slot_time(dev, 9);
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun
b43_short_slot_timing_disable(struct b43_wldev * dev)731*4882a593Smuzhiyun static void b43_short_slot_timing_disable(struct b43_wldev *dev)
732*4882a593Smuzhiyun {
733*4882a593Smuzhiyun b43_set_slot_time(dev, 20);
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun /* DummyTransmission function, as documented on
737*4882a593Smuzhiyun * https://bcm-v4.sipsolutions.net/802.11/DummyTransmission
738*4882a593Smuzhiyun */
b43_dummy_transmission(struct b43_wldev * dev,bool ofdm,bool pa_on)739*4882a593Smuzhiyun void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
740*4882a593Smuzhiyun {
741*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
742*4882a593Smuzhiyun unsigned int i, max_loop;
743*4882a593Smuzhiyun u16 value;
744*4882a593Smuzhiyun u32 buffer[5] = {
745*4882a593Smuzhiyun 0x00000000,
746*4882a593Smuzhiyun 0x00D40000,
747*4882a593Smuzhiyun 0x00000000,
748*4882a593Smuzhiyun 0x01000000,
749*4882a593Smuzhiyun 0x00000000,
750*4882a593Smuzhiyun };
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun if (ofdm) {
753*4882a593Smuzhiyun max_loop = 0x1E;
754*4882a593Smuzhiyun buffer[0] = 0x000201CC;
755*4882a593Smuzhiyun } else {
756*4882a593Smuzhiyun max_loop = 0xFA;
757*4882a593Smuzhiyun buffer[0] = 0x000B846E;
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun for (i = 0; i < 5; i++)
761*4882a593Smuzhiyun b43_ram_write(dev, i * 4, buffer[i]);
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_XMTSEL, 0x0000);
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun if (dev->dev->core_rev < 11)
766*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_WEPCTL, 0x0000);
767*4882a593Smuzhiyun else
768*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_WEPCTL, 0x0100);
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun value = (ofdm ? 0x41 : 0x40);
771*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TXE0_PHYCTL, value);
772*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_N || phy->type == B43_PHYTYPE_LP ||
773*4882a593Smuzhiyun phy->type == B43_PHYTYPE_LCN)
774*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TXE0_PHYCTL1, 0x1A02);
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TXE0_WM_0, 0x0000);
777*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TXE0_WM_1, 0x0000);
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_XMTTPLATETXPTR, 0x0000);
780*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_XMTTXCNT, 0x0014);
781*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_XMTSEL, 0x0826);
782*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TXE0_CTL, 0x0000);
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun if (!pa_on && phy->type == B43_PHYTYPE_N) {
785*4882a593Smuzhiyun ; /*b43_nphy_pa_override(dev, false) */
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun switch (phy->type) {
789*4882a593Smuzhiyun case B43_PHYTYPE_N:
790*4882a593Smuzhiyun case B43_PHYTYPE_LCN:
791*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TXE0_AUX, 0x00D0);
792*4882a593Smuzhiyun break;
793*4882a593Smuzhiyun case B43_PHYTYPE_LP:
794*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0050);
795*4882a593Smuzhiyun break;
796*4882a593Smuzhiyun default:
797*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0030);
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun b43_read16(dev, B43_MMIO_TXE0_AUX);
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
802*4882a593Smuzhiyun b43_radio_write16(dev, 0x0051, 0x0017);
803*4882a593Smuzhiyun for (i = 0x00; i < max_loop; i++) {
804*4882a593Smuzhiyun value = b43_read16(dev, B43_MMIO_TXE0_STATUS);
805*4882a593Smuzhiyun if (value & 0x0080)
806*4882a593Smuzhiyun break;
807*4882a593Smuzhiyun udelay(10);
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun for (i = 0x00; i < 0x0A; i++) {
810*4882a593Smuzhiyun value = b43_read16(dev, B43_MMIO_TXE0_STATUS);
811*4882a593Smuzhiyun if (value & 0x0400)
812*4882a593Smuzhiyun break;
813*4882a593Smuzhiyun udelay(10);
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun for (i = 0x00; i < 0x19; i++) {
816*4882a593Smuzhiyun value = b43_read16(dev, B43_MMIO_IFSSTAT);
817*4882a593Smuzhiyun if (!(value & 0x0100))
818*4882a593Smuzhiyun break;
819*4882a593Smuzhiyun udelay(10);
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
822*4882a593Smuzhiyun b43_radio_write16(dev, 0x0051, 0x0037);
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun
key_write(struct b43_wldev * dev,u8 index,u8 algorithm,const u8 * key)825*4882a593Smuzhiyun static void key_write(struct b43_wldev *dev,
826*4882a593Smuzhiyun u8 index, u8 algorithm, const u8 *key)
827*4882a593Smuzhiyun {
828*4882a593Smuzhiyun unsigned int i;
829*4882a593Smuzhiyun u32 offset;
830*4882a593Smuzhiyun u16 value;
831*4882a593Smuzhiyun u16 kidx;
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun /* Key index/algo block */
834*4882a593Smuzhiyun kidx = b43_kidx_to_fw(dev, index);
835*4882a593Smuzhiyun value = ((kidx << 4) | algorithm);
836*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED,
837*4882a593Smuzhiyun B43_SHM_SH_KEYIDXBLOCK + (kidx * 2), value);
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun /* Write the key to the Key Table Pointer offset */
840*4882a593Smuzhiyun offset = dev->ktp + (index * B43_SEC_KEYSIZE);
841*4882a593Smuzhiyun for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
842*4882a593Smuzhiyun value = key[i];
843*4882a593Smuzhiyun value |= (u16) (key[i + 1]) << 8;
844*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, offset + i, value);
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun
keymac_write(struct b43_wldev * dev,u8 index,const u8 * addr)848*4882a593Smuzhiyun static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
849*4882a593Smuzhiyun {
850*4882a593Smuzhiyun u32 addrtmp[2] = { 0, 0, };
851*4882a593Smuzhiyun u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun if (b43_new_kidx_api(dev))
854*4882a593Smuzhiyun pairwise_keys_start = B43_NR_GROUP_KEYS;
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun B43_WARN_ON(index < pairwise_keys_start);
857*4882a593Smuzhiyun /* We have four default TX keys and possibly four default RX keys.
858*4882a593Smuzhiyun * Physical mac 0 is mapped to physical key 4 or 8, depending
859*4882a593Smuzhiyun * on the firmware version.
860*4882a593Smuzhiyun * So we must adjust the index here.
861*4882a593Smuzhiyun */
862*4882a593Smuzhiyun index -= pairwise_keys_start;
863*4882a593Smuzhiyun B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun if (addr) {
866*4882a593Smuzhiyun addrtmp[0] = addr[0];
867*4882a593Smuzhiyun addrtmp[0] |= ((u32) (addr[1]) << 8);
868*4882a593Smuzhiyun addrtmp[0] |= ((u32) (addr[2]) << 16);
869*4882a593Smuzhiyun addrtmp[0] |= ((u32) (addr[3]) << 24);
870*4882a593Smuzhiyun addrtmp[1] = addr[4];
871*4882a593Smuzhiyun addrtmp[1] |= ((u32) (addr[5]) << 8);
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun /* Receive match transmitter address (RCMTA) mechanism */
875*4882a593Smuzhiyun b43_shm_write32(dev, B43_SHM_RCMTA,
876*4882a593Smuzhiyun (index * 2) + 0, addrtmp[0]);
877*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_RCMTA,
878*4882a593Smuzhiyun (index * 2) + 1, addrtmp[1]);
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun /* The ucode will use phase1 key with TEK key to decrypt rx packets.
882*4882a593Smuzhiyun * When a packet is received, the iv32 is checked.
883*4882a593Smuzhiyun * - if it doesn't the packet is returned without modification (and software
884*4882a593Smuzhiyun * decryption can be done). That's what happen when iv16 wrap.
885*4882a593Smuzhiyun * - if it does, the rc4 key is computed, and decryption is tried.
886*4882a593Smuzhiyun * Either it will success and B43_RX_MAC_DEC is returned,
887*4882a593Smuzhiyun * either it fails and B43_RX_MAC_DEC|B43_RX_MAC_DECERR is returned
888*4882a593Smuzhiyun * and the packet is not usable (it got modified by the ucode).
889*4882a593Smuzhiyun * So in order to never have B43_RX_MAC_DECERR, we should provide
890*4882a593Smuzhiyun * a iv32 and phase1key that match. Because we drop packets in case of
891*4882a593Smuzhiyun * B43_RX_MAC_DECERR, if we have a correct iv32 but a wrong phase1key, all
892*4882a593Smuzhiyun * packets will be lost without higher layer knowing (ie no resync possible
893*4882a593Smuzhiyun * until next wrap).
894*4882a593Smuzhiyun *
895*4882a593Smuzhiyun * NOTE : this should support 50 key like RCMTA because
896*4882a593Smuzhiyun * (B43_SHM_SH_KEYIDXBLOCK - B43_SHM_SH_TKIPTSCTTAK)/14 = 50
897*4882a593Smuzhiyun */
rx_tkip_phase1_write(struct b43_wldev * dev,u8 index,u32 iv32,u16 * phase1key)898*4882a593Smuzhiyun static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32,
899*4882a593Smuzhiyun u16 *phase1key)
900*4882a593Smuzhiyun {
901*4882a593Smuzhiyun unsigned int i;
902*4882a593Smuzhiyun u32 offset;
903*4882a593Smuzhiyun u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun if (!modparam_hwtkip)
906*4882a593Smuzhiyun return;
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun if (b43_new_kidx_api(dev))
909*4882a593Smuzhiyun pairwise_keys_start = B43_NR_GROUP_KEYS;
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun B43_WARN_ON(index < pairwise_keys_start);
912*4882a593Smuzhiyun /* We have four default TX keys and possibly four default RX keys.
913*4882a593Smuzhiyun * Physical mac 0 is mapped to physical key 4 or 8, depending
914*4882a593Smuzhiyun * on the firmware version.
915*4882a593Smuzhiyun * So we must adjust the index here.
916*4882a593Smuzhiyun */
917*4882a593Smuzhiyun index -= pairwise_keys_start;
918*4882a593Smuzhiyun B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun if (b43_debug(dev, B43_DBG_KEYS)) {
921*4882a593Smuzhiyun b43dbg(dev->wl, "rx_tkip_phase1_write : idx 0x%x, iv32 0x%x\n",
922*4882a593Smuzhiyun index, iv32);
923*4882a593Smuzhiyun }
924*4882a593Smuzhiyun /* Write the key to the RX tkip shared mem */
925*4882a593Smuzhiyun offset = B43_SHM_SH_TKIPTSCTTAK + index * (10 + 4);
926*4882a593Smuzhiyun for (i = 0; i < 10; i += 2) {
927*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, offset + i,
928*4882a593Smuzhiyun phase1key ? phase1key[i / 2] : 0);
929*4882a593Smuzhiyun }
930*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, offset + i, iv32);
931*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, offset + i + 2, iv32 >> 16);
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun
b43_op_update_tkip_key(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_key_conf * keyconf,struct ieee80211_sta * sta,u32 iv32,u16 * phase1key)934*4882a593Smuzhiyun static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
935*4882a593Smuzhiyun struct ieee80211_vif *vif,
936*4882a593Smuzhiyun struct ieee80211_key_conf *keyconf,
937*4882a593Smuzhiyun struct ieee80211_sta *sta,
938*4882a593Smuzhiyun u32 iv32, u16 *phase1key)
939*4882a593Smuzhiyun {
940*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
941*4882a593Smuzhiyun struct b43_wldev *dev;
942*4882a593Smuzhiyun int index = keyconf->hw_key_idx;
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun if (B43_WARN_ON(!modparam_hwtkip))
945*4882a593Smuzhiyun return;
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun /* This is only called from the RX path through mac80211, where
948*4882a593Smuzhiyun * our mutex is already locked. */
949*4882a593Smuzhiyun B43_WARN_ON(!mutex_is_locked(&wl->mutex));
950*4882a593Smuzhiyun dev = wl->current_dev;
951*4882a593Smuzhiyun B43_WARN_ON(!dev || b43_status(dev) < B43_STAT_INITIALIZED);
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun keymac_write(dev, index, NULL); /* First zero out mac to avoid race */
954*4882a593Smuzhiyun
955*4882a593Smuzhiyun rx_tkip_phase1_write(dev, index, iv32, phase1key);
956*4882a593Smuzhiyun /* only pairwise TKIP keys are supported right now */
957*4882a593Smuzhiyun if (WARN_ON(!sta))
958*4882a593Smuzhiyun return;
959*4882a593Smuzhiyun keymac_write(dev, index, sta->addr);
960*4882a593Smuzhiyun }
961*4882a593Smuzhiyun
do_key_write(struct b43_wldev * dev,u8 index,u8 algorithm,const u8 * key,size_t key_len,const u8 * mac_addr)962*4882a593Smuzhiyun static void do_key_write(struct b43_wldev *dev,
963*4882a593Smuzhiyun u8 index, u8 algorithm,
964*4882a593Smuzhiyun const u8 *key, size_t key_len, const u8 *mac_addr)
965*4882a593Smuzhiyun {
966*4882a593Smuzhiyun u8 buf[B43_SEC_KEYSIZE] = { 0, };
967*4882a593Smuzhiyun u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
968*4882a593Smuzhiyun
969*4882a593Smuzhiyun if (b43_new_kidx_api(dev))
970*4882a593Smuzhiyun pairwise_keys_start = B43_NR_GROUP_KEYS;
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun B43_WARN_ON(index >= ARRAY_SIZE(dev->key));
973*4882a593Smuzhiyun B43_WARN_ON(key_len > B43_SEC_KEYSIZE);
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun if (index >= pairwise_keys_start)
976*4882a593Smuzhiyun keymac_write(dev, index, NULL); /* First zero out mac. */
977*4882a593Smuzhiyun if (algorithm == B43_SEC_ALGO_TKIP) {
978*4882a593Smuzhiyun /*
979*4882a593Smuzhiyun * We should provide an initial iv32, phase1key pair.
980*4882a593Smuzhiyun * We could start with iv32=0 and compute the corresponding
981*4882a593Smuzhiyun * phase1key, but this means calling ieee80211_get_tkip_key
982*4882a593Smuzhiyun * with a fake skb (or export other tkip function).
983*4882a593Smuzhiyun * Because we are lazy we hope iv32 won't start with
984*4882a593Smuzhiyun * 0xffffffff and let's b43_op_update_tkip_key provide a
985*4882a593Smuzhiyun * correct pair.
986*4882a593Smuzhiyun */
987*4882a593Smuzhiyun rx_tkip_phase1_write(dev, index, 0xffffffff, (u16*)buf);
988*4882a593Smuzhiyun } else if (index >= pairwise_keys_start) /* clear it */
989*4882a593Smuzhiyun rx_tkip_phase1_write(dev, index, 0, NULL);
990*4882a593Smuzhiyun if (key)
991*4882a593Smuzhiyun memcpy(buf, key, key_len);
992*4882a593Smuzhiyun key_write(dev, index, algorithm, buf);
993*4882a593Smuzhiyun if (index >= pairwise_keys_start)
994*4882a593Smuzhiyun keymac_write(dev, index, mac_addr);
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun dev->key[index].algorithm = algorithm;
997*4882a593Smuzhiyun }
998*4882a593Smuzhiyun
b43_key_write(struct b43_wldev * dev,int index,u8 algorithm,const u8 * key,size_t key_len,const u8 * mac_addr,struct ieee80211_key_conf * keyconf)999*4882a593Smuzhiyun static int b43_key_write(struct b43_wldev *dev,
1000*4882a593Smuzhiyun int index, u8 algorithm,
1001*4882a593Smuzhiyun const u8 *key, size_t key_len,
1002*4882a593Smuzhiyun const u8 *mac_addr,
1003*4882a593Smuzhiyun struct ieee80211_key_conf *keyconf)
1004*4882a593Smuzhiyun {
1005*4882a593Smuzhiyun int i;
1006*4882a593Smuzhiyun int pairwise_keys_start;
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun /* For ALG_TKIP the key is encoded as a 256-bit (32 byte) data block:
1009*4882a593Smuzhiyun * - Temporal Encryption Key (128 bits)
1010*4882a593Smuzhiyun * - Temporal Authenticator Tx MIC Key (64 bits)
1011*4882a593Smuzhiyun * - Temporal Authenticator Rx MIC Key (64 bits)
1012*4882a593Smuzhiyun *
1013*4882a593Smuzhiyun * Hardware only store TEK
1014*4882a593Smuzhiyun */
1015*4882a593Smuzhiyun if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32)
1016*4882a593Smuzhiyun key_len = 16;
1017*4882a593Smuzhiyun if (key_len > B43_SEC_KEYSIZE)
1018*4882a593Smuzhiyun return -EINVAL;
1019*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(dev->key); i++) {
1020*4882a593Smuzhiyun /* Check that we don't already have this key. */
1021*4882a593Smuzhiyun B43_WARN_ON(dev->key[i].keyconf == keyconf);
1022*4882a593Smuzhiyun }
1023*4882a593Smuzhiyun if (index < 0) {
1024*4882a593Smuzhiyun /* Pairwise key. Get an empty slot for the key. */
1025*4882a593Smuzhiyun if (b43_new_kidx_api(dev))
1026*4882a593Smuzhiyun pairwise_keys_start = B43_NR_GROUP_KEYS;
1027*4882a593Smuzhiyun else
1028*4882a593Smuzhiyun pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
1029*4882a593Smuzhiyun for (i = pairwise_keys_start;
1030*4882a593Smuzhiyun i < pairwise_keys_start + B43_NR_PAIRWISE_KEYS;
1031*4882a593Smuzhiyun i++) {
1032*4882a593Smuzhiyun B43_WARN_ON(i >= ARRAY_SIZE(dev->key));
1033*4882a593Smuzhiyun if (!dev->key[i].keyconf) {
1034*4882a593Smuzhiyun /* found empty */
1035*4882a593Smuzhiyun index = i;
1036*4882a593Smuzhiyun break;
1037*4882a593Smuzhiyun }
1038*4882a593Smuzhiyun }
1039*4882a593Smuzhiyun if (index < 0) {
1040*4882a593Smuzhiyun b43warn(dev->wl, "Out of hardware key memory\n");
1041*4882a593Smuzhiyun return -ENOSPC;
1042*4882a593Smuzhiyun }
1043*4882a593Smuzhiyun } else
1044*4882a593Smuzhiyun B43_WARN_ON(index > 3);
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun do_key_write(dev, index, algorithm, key, key_len, mac_addr);
1047*4882a593Smuzhiyun if ((index <= 3) && !b43_new_kidx_api(dev)) {
1048*4882a593Smuzhiyun /* Default RX key */
1049*4882a593Smuzhiyun B43_WARN_ON(mac_addr);
1050*4882a593Smuzhiyun do_key_write(dev, index + 4, algorithm, key, key_len, NULL);
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun keyconf->hw_key_idx = index;
1053*4882a593Smuzhiyun dev->key[index].keyconf = keyconf;
1054*4882a593Smuzhiyun
1055*4882a593Smuzhiyun return 0;
1056*4882a593Smuzhiyun }
1057*4882a593Smuzhiyun
b43_key_clear(struct b43_wldev * dev,int index)1058*4882a593Smuzhiyun static int b43_key_clear(struct b43_wldev *dev, int index)
1059*4882a593Smuzhiyun {
1060*4882a593Smuzhiyun if (B43_WARN_ON((index < 0) || (index >= ARRAY_SIZE(dev->key))))
1061*4882a593Smuzhiyun return -EINVAL;
1062*4882a593Smuzhiyun do_key_write(dev, index, B43_SEC_ALGO_NONE,
1063*4882a593Smuzhiyun NULL, B43_SEC_KEYSIZE, NULL);
1064*4882a593Smuzhiyun if ((index <= 3) && !b43_new_kidx_api(dev)) {
1065*4882a593Smuzhiyun do_key_write(dev, index + 4, B43_SEC_ALGO_NONE,
1066*4882a593Smuzhiyun NULL, B43_SEC_KEYSIZE, NULL);
1067*4882a593Smuzhiyun }
1068*4882a593Smuzhiyun dev->key[index].keyconf = NULL;
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun return 0;
1071*4882a593Smuzhiyun }
1072*4882a593Smuzhiyun
b43_clear_keys(struct b43_wldev * dev)1073*4882a593Smuzhiyun static void b43_clear_keys(struct b43_wldev *dev)
1074*4882a593Smuzhiyun {
1075*4882a593Smuzhiyun int i, count;
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun if (b43_new_kidx_api(dev))
1078*4882a593Smuzhiyun count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
1079*4882a593Smuzhiyun else
1080*4882a593Smuzhiyun count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
1081*4882a593Smuzhiyun for (i = 0; i < count; i++)
1082*4882a593Smuzhiyun b43_key_clear(dev, i);
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun
b43_dump_keymemory(struct b43_wldev * dev)1085*4882a593Smuzhiyun static void b43_dump_keymemory(struct b43_wldev *dev)
1086*4882a593Smuzhiyun {
1087*4882a593Smuzhiyun unsigned int i, index, count, offset, pairwise_keys_start;
1088*4882a593Smuzhiyun u8 mac[ETH_ALEN];
1089*4882a593Smuzhiyun u16 algo;
1090*4882a593Smuzhiyun u32 rcmta0;
1091*4882a593Smuzhiyun u16 rcmta1;
1092*4882a593Smuzhiyun u64 hf;
1093*4882a593Smuzhiyun struct b43_key *key;
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun if (!b43_debug(dev, B43_DBG_KEYS))
1096*4882a593Smuzhiyun return;
1097*4882a593Smuzhiyun
1098*4882a593Smuzhiyun hf = b43_hf_read(dev);
1099*4882a593Smuzhiyun b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n",
1100*4882a593Smuzhiyun !!(hf & B43_HF_USEDEFKEYS));
1101*4882a593Smuzhiyun if (b43_new_kidx_api(dev)) {
1102*4882a593Smuzhiyun pairwise_keys_start = B43_NR_GROUP_KEYS;
1103*4882a593Smuzhiyun count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
1104*4882a593Smuzhiyun } else {
1105*4882a593Smuzhiyun pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
1106*4882a593Smuzhiyun count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
1107*4882a593Smuzhiyun }
1108*4882a593Smuzhiyun for (index = 0; index < count; index++) {
1109*4882a593Smuzhiyun key = &(dev->key[index]);
1110*4882a593Smuzhiyun printk(KERN_DEBUG "Key slot %02u: %s",
1111*4882a593Smuzhiyun index, (key->keyconf == NULL) ? " " : "*");
1112*4882a593Smuzhiyun offset = dev->ktp + (index * B43_SEC_KEYSIZE);
1113*4882a593Smuzhiyun for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
1114*4882a593Smuzhiyun u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
1115*4882a593Smuzhiyun printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
1116*4882a593Smuzhiyun }
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun algo = b43_shm_read16(dev, B43_SHM_SHARED,
1119*4882a593Smuzhiyun B43_SHM_SH_KEYIDXBLOCK + (index * 2));
1120*4882a593Smuzhiyun printk(" Algo: %04X/%02X", algo, key->algorithm);
1121*4882a593Smuzhiyun
1122*4882a593Smuzhiyun if (index >= pairwise_keys_start) {
1123*4882a593Smuzhiyun if (key->algorithm == B43_SEC_ALGO_TKIP) {
1124*4882a593Smuzhiyun printk(" TKIP: ");
1125*4882a593Smuzhiyun offset = B43_SHM_SH_TKIPTSCTTAK + (index - 4) * (10 + 4);
1126*4882a593Smuzhiyun for (i = 0; i < 14; i += 2) {
1127*4882a593Smuzhiyun u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
1128*4882a593Smuzhiyun printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun }
1131*4882a593Smuzhiyun rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
1132*4882a593Smuzhiyun ((index - pairwise_keys_start) * 2) + 0);
1133*4882a593Smuzhiyun rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
1134*4882a593Smuzhiyun ((index - pairwise_keys_start) * 2) + 1);
1135*4882a593Smuzhiyun *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
1136*4882a593Smuzhiyun *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
1137*4882a593Smuzhiyun printk(" MAC: %pM", mac);
1138*4882a593Smuzhiyun } else
1139*4882a593Smuzhiyun printk(" DEFAULT KEY");
1140*4882a593Smuzhiyun printk("\n");
1141*4882a593Smuzhiyun }
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun
b43_power_saving_ctl_bits(struct b43_wldev * dev,unsigned int ps_flags)1144*4882a593Smuzhiyun void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
1145*4882a593Smuzhiyun {
1146*4882a593Smuzhiyun u32 macctl;
1147*4882a593Smuzhiyun u16 ucstat;
1148*4882a593Smuzhiyun bool hwps;
1149*4882a593Smuzhiyun bool awake;
1150*4882a593Smuzhiyun int i;
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun B43_WARN_ON((ps_flags & B43_PS_ENABLED) &&
1153*4882a593Smuzhiyun (ps_flags & B43_PS_DISABLED));
1154*4882a593Smuzhiyun B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP));
1155*4882a593Smuzhiyun
1156*4882a593Smuzhiyun if (ps_flags & B43_PS_ENABLED) {
1157*4882a593Smuzhiyun hwps = true;
1158*4882a593Smuzhiyun } else if (ps_flags & B43_PS_DISABLED) {
1159*4882a593Smuzhiyun hwps = false;
1160*4882a593Smuzhiyun } else {
1161*4882a593Smuzhiyun //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
1162*4882a593Smuzhiyun // and thus is not an AP and we are associated, set bit 25
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun if (ps_flags & B43_PS_AWAKE) {
1165*4882a593Smuzhiyun awake = true;
1166*4882a593Smuzhiyun } else if (ps_flags & B43_PS_ASLEEP) {
1167*4882a593Smuzhiyun awake = false;
1168*4882a593Smuzhiyun } else {
1169*4882a593Smuzhiyun //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
1170*4882a593Smuzhiyun // or we are associated, or FIXME, or the latest PS-Poll packet sent was
1171*4882a593Smuzhiyun // successful, set bit26
1172*4882a593Smuzhiyun }
1173*4882a593Smuzhiyun
1174*4882a593Smuzhiyun /* FIXME: For now we force awake-on and hwps-off */
1175*4882a593Smuzhiyun hwps = false;
1176*4882a593Smuzhiyun awake = true;
1177*4882a593Smuzhiyun
1178*4882a593Smuzhiyun macctl = b43_read32(dev, B43_MMIO_MACCTL);
1179*4882a593Smuzhiyun if (hwps)
1180*4882a593Smuzhiyun macctl |= B43_MACCTL_HWPS;
1181*4882a593Smuzhiyun else
1182*4882a593Smuzhiyun macctl &= ~B43_MACCTL_HWPS;
1183*4882a593Smuzhiyun if (awake)
1184*4882a593Smuzhiyun macctl |= B43_MACCTL_AWAKE;
1185*4882a593Smuzhiyun else
1186*4882a593Smuzhiyun macctl &= ~B43_MACCTL_AWAKE;
1187*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_MACCTL, macctl);
1188*4882a593Smuzhiyun /* Commit write */
1189*4882a593Smuzhiyun b43_read32(dev, B43_MMIO_MACCTL);
1190*4882a593Smuzhiyun if (awake && dev->dev->core_rev >= 5) {
1191*4882a593Smuzhiyun /* Wait for the microcode to wake up. */
1192*4882a593Smuzhiyun for (i = 0; i < 100; i++) {
1193*4882a593Smuzhiyun ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
1194*4882a593Smuzhiyun B43_SHM_SH_UCODESTAT);
1195*4882a593Smuzhiyun if (ucstat != B43_SHM_SH_UCODESTAT_SLEEP)
1196*4882a593Smuzhiyun break;
1197*4882a593Smuzhiyun udelay(10);
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun }
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun /* https://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */
b43_wireless_core_phy_pll_reset(struct b43_wldev * dev)1203*4882a593Smuzhiyun void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev)
1204*4882a593Smuzhiyun {
1205*4882a593Smuzhiyun struct bcma_drv_cc *bcma_cc __maybe_unused;
1206*4882a593Smuzhiyun struct ssb_chipcommon *ssb_cc __maybe_unused;
1207*4882a593Smuzhiyun
1208*4882a593Smuzhiyun switch (dev->dev->bus_type) {
1209*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
1210*4882a593Smuzhiyun case B43_BUS_BCMA:
1211*4882a593Smuzhiyun bcma_cc = &dev->dev->bdev->bus->drv_cc;
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0);
1214*4882a593Smuzhiyun bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
1215*4882a593Smuzhiyun bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4);
1216*4882a593Smuzhiyun bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
1217*4882a593Smuzhiyun break;
1218*4882a593Smuzhiyun #endif
1219*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
1220*4882a593Smuzhiyun case B43_BUS_SSB:
1221*4882a593Smuzhiyun ssb_cc = &dev->dev->sdev->bus->chipco;
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun chipco_write32(ssb_cc, SSB_CHIPCO_CHIPCTL_ADDR, 0);
1224*4882a593Smuzhiyun chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
1225*4882a593Smuzhiyun chipco_set32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, 0x4);
1226*4882a593Smuzhiyun chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
1227*4882a593Smuzhiyun break;
1228*4882a593Smuzhiyun #endif
1229*4882a593Smuzhiyun }
1230*4882a593Smuzhiyun }
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
b43_bcma_phy_reset(struct b43_wldev * dev)1233*4882a593Smuzhiyun static void b43_bcma_phy_reset(struct b43_wldev *dev)
1234*4882a593Smuzhiyun {
1235*4882a593Smuzhiyun u32 flags;
1236*4882a593Smuzhiyun
1237*4882a593Smuzhiyun /* Put PHY into reset */
1238*4882a593Smuzhiyun flags = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
1239*4882a593Smuzhiyun flags |= B43_BCMA_IOCTL_PHY_RESET;
1240*4882a593Smuzhiyun flags |= B43_BCMA_IOCTL_PHY_BW_20MHZ; /* Make 20 MHz def */
1241*4882a593Smuzhiyun bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, flags);
1242*4882a593Smuzhiyun udelay(2);
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun b43_phy_take_out_of_reset(dev);
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun
b43_bcma_wireless_core_reset(struct b43_wldev * dev,bool gmode)1247*4882a593Smuzhiyun static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode)
1248*4882a593Smuzhiyun {
1249*4882a593Smuzhiyun u32 req = B43_BCMA_CLKCTLST_80211_PLL_REQ |
1250*4882a593Smuzhiyun B43_BCMA_CLKCTLST_PHY_PLL_REQ;
1251*4882a593Smuzhiyun u32 status = B43_BCMA_CLKCTLST_80211_PLL_ST |
1252*4882a593Smuzhiyun B43_BCMA_CLKCTLST_PHY_PLL_ST;
1253*4882a593Smuzhiyun u32 flags;
1254*4882a593Smuzhiyun
1255*4882a593Smuzhiyun flags = B43_BCMA_IOCTL_PHY_CLKEN;
1256*4882a593Smuzhiyun if (gmode)
1257*4882a593Smuzhiyun flags |= B43_BCMA_IOCTL_GMODE;
1258*4882a593Smuzhiyun b43_device_enable(dev, flags);
1259*4882a593Smuzhiyun
1260*4882a593Smuzhiyun if (dev->phy.type == B43_PHYTYPE_AC) {
1261*4882a593Smuzhiyun u16 tmp;
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
1264*4882a593Smuzhiyun tmp &= ~B43_BCMA_IOCTL_DAC;
1265*4882a593Smuzhiyun tmp |= 0x100;
1266*4882a593Smuzhiyun bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
1267*4882a593Smuzhiyun
1268*4882a593Smuzhiyun tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
1269*4882a593Smuzhiyun tmp &= ~B43_BCMA_IOCTL_PHY_CLKEN;
1270*4882a593Smuzhiyun bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
1273*4882a593Smuzhiyun tmp |= B43_BCMA_IOCTL_PHY_CLKEN;
1274*4882a593Smuzhiyun bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
1275*4882a593Smuzhiyun }
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST);
1278*4882a593Smuzhiyun b43_bcma_phy_reset(dev);
1279*4882a593Smuzhiyun bcma_core_pll_ctl(dev->dev->bdev, req, status, true);
1280*4882a593Smuzhiyun }
1281*4882a593Smuzhiyun #endif
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
b43_ssb_wireless_core_reset(struct b43_wldev * dev,bool gmode)1284*4882a593Smuzhiyun static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, bool gmode)
1285*4882a593Smuzhiyun {
1286*4882a593Smuzhiyun u32 flags = 0;
1287*4882a593Smuzhiyun
1288*4882a593Smuzhiyun if (gmode)
1289*4882a593Smuzhiyun flags |= B43_TMSLOW_GMODE;
1290*4882a593Smuzhiyun flags |= B43_TMSLOW_PHYCLKEN;
1291*4882a593Smuzhiyun flags |= B43_TMSLOW_PHYRESET;
1292*4882a593Smuzhiyun if (dev->phy.type == B43_PHYTYPE_N)
1293*4882a593Smuzhiyun flags |= B43_TMSLOW_PHY_BANDWIDTH_20MHZ; /* Make 20 MHz def */
1294*4882a593Smuzhiyun b43_device_enable(dev, flags);
1295*4882a593Smuzhiyun msleep(2); /* Wait for the PLL to turn on. */
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun b43_phy_take_out_of_reset(dev);
1298*4882a593Smuzhiyun }
1299*4882a593Smuzhiyun #endif
1300*4882a593Smuzhiyun
b43_wireless_core_reset(struct b43_wldev * dev,bool gmode)1301*4882a593Smuzhiyun void b43_wireless_core_reset(struct b43_wldev *dev, bool gmode)
1302*4882a593Smuzhiyun {
1303*4882a593Smuzhiyun u32 macctl;
1304*4882a593Smuzhiyun
1305*4882a593Smuzhiyun switch (dev->dev->bus_type) {
1306*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
1307*4882a593Smuzhiyun case B43_BUS_BCMA:
1308*4882a593Smuzhiyun b43_bcma_wireless_core_reset(dev, gmode);
1309*4882a593Smuzhiyun break;
1310*4882a593Smuzhiyun #endif
1311*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
1312*4882a593Smuzhiyun case B43_BUS_SSB:
1313*4882a593Smuzhiyun b43_ssb_wireless_core_reset(dev, gmode);
1314*4882a593Smuzhiyun break;
1315*4882a593Smuzhiyun #endif
1316*4882a593Smuzhiyun }
1317*4882a593Smuzhiyun
1318*4882a593Smuzhiyun /* Turn Analog ON, but only if we already know the PHY-type.
1319*4882a593Smuzhiyun * This protects against very early setup where we don't know the
1320*4882a593Smuzhiyun * PHY-type, yet. wireless_core_reset will be called once again later,
1321*4882a593Smuzhiyun * when we know the PHY-type. */
1322*4882a593Smuzhiyun if (dev->phy.ops)
1323*4882a593Smuzhiyun dev->phy.ops->switch_analog(dev, 1);
1324*4882a593Smuzhiyun
1325*4882a593Smuzhiyun macctl = b43_read32(dev, B43_MMIO_MACCTL);
1326*4882a593Smuzhiyun macctl &= ~B43_MACCTL_GMODE;
1327*4882a593Smuzhiyun if (gmode)
1328*4882a593Smuzhiyun macctl |= B43_MACCTL_GMODE;
1329*4882a593Smuzhiyun macctl |= B43_MACCTL_IHR_ENABLED;
1330*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_MACCTL, macctl);
1331*4882a593Smuzhiyun }
1332*4882a593Smuzhiyun
handle_irq_transmit_status(struct b43_wldev * dev)1333*4882a593Smuzhiyun static void handle_irq_transmit_status(struct b43_wldev *dev)
1334*4882a593Smuzhiyun {
1335*4882a593Smuzhiyun u32 v0, v1;
1336*4882a593Smuzhiyun u16 tmp;
1337*4882a593Smuzhiyun struct b43_txstatus stat;
1338*4882a593Smuzhiyun
1339*4882a593Smuzhiyun while (1) {
1340*4882a593Smuzhiyun v0 = b43_read32(dev, B43_MMIO_XMITSTAT_0);
1341*4882a593Smuzhiyun if (!(v0 & 0x00000001))
1342*4882a593Smuzhiyun break;
1343*4882a593Smuzhiyun v1 = b43_read32(dev, B43_MMIO_XMITSTAT_1);
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun stat.cookie = (v0 >> 16);
1346*4882a593Smuzhiyun stat.seq = (v1 & 0x0000FFFF);
1347*4882a593Smuzhiyun stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
1348*4882a593Smuzhiyun tmp = (v0 & 0x0000FFFF);
1349*4882a593Smuzhiyun stat.frame_count = ((tmp & 0xF000) >> 12);
1350*4882a593Smuzhiyun stat.rts_count = ((tmp & 0x0F00) >> 8);
1351*4882a593Smuzhiyun stat.supp_reason = ((tmp & 0x001C) >> 2);
1352*4882a593Smuzhiyun stat.pm_indicated = !!(tmp & 0x0080);
1353*4882a593Smuzhiyun stat.intermediate = !!(tmp & 0x0040);
1354*4882a593Smuzhiyun stat.for_ampdu = !!(tmp & 0x0020);
1355*4882a593Smuzhiyun stat.acked = !!(tmp & 0x0002);
1356*4882a593Smuzhiyun
1357*4882a593Smuzhiyun b43_handle_txstatus(dev, &stat);
1358*4882a593Smuzhiyun }
1359*4882a593Smuzhiyun }
1360*4882a593Smuzhiyun
drain_txstatus_queue(struct b43_wldev * dev)1361*4882a593Smuzhiyun static void drain_txstatus_queue(struct b43_wldev *dev)
1362*4882a593Smuzhiyun {
1363*4882a593Smuzhiyun u32 dummy;
1364*4882a593Smuzhiyun
1365*4882a593Smuzhiyun if (dev->dev->core_rev < 5)
1366*4882a593Smuzhiyun return;
1367*4882a593Smuzhiyun /* Read all entries from the microcode TXstatus FIFO
1368*4882a593Smuzhiyun * and throw them away.
1369*4882a593Smuzhiyun */
1370*4882a593Smuzhiyun while (1) {
1371*4882a593Smuzhiyun dummy = b43_read32(dev, B43_MMIO_XMITSTAT_0);
1372*4882a593Smuzhiyun if (!(dummy & 0x00000001))
1373*4882a593Smuzhiyun break;
1374*4882a593Smuzhiyun dummy = b43_read32(dev, B43_MMIO_XMITSTAT_1);
1375*4882a593Smuzhiyun }
1376*4882a593Smuzhiyun }
1377*4882a593Smuzhiyun
b43_jssi_read(struct b43_wldev * dev)1378*4882a593Smuzhiyun static u32 b43_jssi_read(struct b43_wldev *dev)
1379*4882a593Smuzhiyun {
1380*4882a593Smuzhiyun u32 val = 0;
1381*4882a593Smuzhiyun
1382*4882a593Smuzhiyun val = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI1);
1383*4882a593Smuzhiyun val <<= 16;
1384*4882a593Smuzhiyun val |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI0);
1385*4882a593Smuzhiyun
1386*4882a593Smuzhiyun return val;
1387*4882a593Smuzhiyun }
1388*4882a593Smuzhiyun
b43_jssi_write(struct b43_wldev * dev,u32 jssi)1389*4882a593Smuzhiyun static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
1390*4882a593Smuzhiyun {
1391*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI0,
1392*4882a593Smuzhiyun (jssi & 0x0000FFFF));
1393*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI1,
1394*4882a593Smuzhiyun (jssi & 0xFFFF0000) >> 16);
1395*4882a593Smuzhiyun }
1396*4882a593Smuzhiyun
b43_generate_noise_sample(struct b43_wldev * dev)1397*4882a593Smuzhiyun static void b43_generate_noise_sample(struct b43_wldev *dev)
1398*4882a593Smuzhiyun {
1399*4882a593Smuzhiyun b43_jssi_write(dev, 0x7F7F7F7F);
1400*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_MACCMD,
1401*4882a593Smuzhiyun b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE);
1402*4882a593Smuzhiyun }
1403*4882a593Smuzhiyun
b43_calculate_link_quality(struct b43_wldev * dev)1404*4882a593Smuzhiyun static void b43_calculate_link_quality(struct b43_wldev *dev)
1405*4882a593Smuzhiyun {
1406*4882a593Smuzhiyun /* Top half of Link Quality calculation. */
1407*4882a593Smuzhiyun
1408*4882a593Smuzhiyun if (dev->phy.type != B43_PHYTYPE_G)
1409*4882a593Smuzhiyun return;
1410*4882a593Smuzhiyun if (dev->noisecalc.calculation_running)
1411*4882a593Smuzhiyun return;
1412*4882a593Smuzhiyun dev->noisecalc.calculation_running = true;
1413*4882a593Smuzhiyun dev->noisecalc.nr_samples = 0;
1414*4882a593Smuzhiyun
1415*4882a593Smuzhiyun b43_generate_noise_sample(dev);
1416*4882a593Smuzhiyun }
1417*4882a593Smuzhiyun
handle_irq_noise(struct b43_wldev * dev)1418*4882a593Smuzhiyun static void handle_irq_noise(struct b43_wldev *dev)
1419*4882a593Smuzhiyun {
1420*4882a593Smuzhiyun struct b43_phy_g *phy = dev->phy.g;
1421*4882a593Smuzhiyun u16 tmp;
1422*4882a593Smuzhiyun u8 noise[4];
1423*4882a593Smuzhiyun u8 i, j;
1424*4882a593Smuzhiyun s32 average;
1425*4882a593Smuzhiyun
1426*4882a593Smuzhiyun /* Bottom half of Link Quality calculation. */
1427*4882a593Smuzhiyun
1428*4882a593Smuzhiyun if (dev->phy.type != B43_PHYTYPE_G)
1429*4882a593Smuzhiyun return;
1430*4882a593Smuzhiyun
1431*4882a593Smuzhiyun /* Possible race condition: It might be possible that the user
1432*4882a593Smuzhiyun * changed to a different channel in the meantime since we
1433*4882a593Smuzhiyun * started the calculation. We ignore that fact, since it's
1434*4882a593Smuzhiyun * not really that much of a problem. The background noise is
1435*4882a593Smuzhiyun * an estimation only anyway. Slightly wrong results will get damped
1436*4882a593Smuzhiyun * by the averaging of the 8 sample rounds. Additionally the
1437*4882a593Smuzhiyun * value is shortlived. So it will be replaced by the next noise
1438*4882a593Smuzhiyun * calculation round soon. */
1439*4882a593Smuzhiyun
1440*4882a593Smuzhiyun B43_WARN_ON(!dev->noisecalc.calculation_running);
1441*4882a593Smuzhiyun *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev));
1442*4882a593Smuzhiyun if (noise[0] == 0x7F || noise[1] == 0x7F ||
1443*4882a593Smuzhiyun noise[2] == 0x7F || noise[3] == 0x7F)
1444*4882a593Smuzhiyun goto generate_new;
1445*4882a593Smuzhiyun
1446*4882a593Smuzhiyun /* Get the noise samples. */
1447*4882a593Smuzhiyun B43_WARN_ON(dev->noisecalc.nr_samples >= 8);
1448*4882a593Smuzhiyun i = dev->noisecalc.nr_samples;
1449*4882a593Smuzhiyun noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1450*4882a593Smuzhiyun noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1451*4882a593Smuzhiyun noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1452*4882a593Smuzhiyun noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1453*4882a593Smuzhiyun dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
1454*4882a593Smuzhiyun dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
1455*4882a593Smuzhiyun dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
1456*4882a593Smuzhiyun dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
1457*4882a593Smuzhiyun dev->noisecalc.nr_samples++;
1458*4882a593Smuzhiyun if (dev->noisecalc.nr_samples == 8) {
1459*4882a593Smuzhiyun /* Calculate the Link Quality by the noise samples. */
1460*4882a593Smuzhiyun average = 0;
1461*4882a593Smuzhiyun for (i = 0; i < 8; i++) {
1462*4882a593Smuzhiyun for (j = 0; j < 4; j++)
1463*4882a593Smuzhiyun average += dev->noisecalc.samples[i][j];
1464*4882a593Smuzhiyun }
1465*4882a593Smuzhiyun average /= (8 * 4);
1466*4882a593Smuzhiyun average *= 125;
1467*4882a593Smuzhiyun average += 64;
1468*4882a593Smuzhiyun average /= 128;
1469*4882a593Smuzhiyun tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x40C);
1470*4882a593Smuzhiyun tmp = (tmp / 128) & 0x1F;
1471*4882a593Smuzhiyun if (tmp >= 8)
1472*4882a593Smuzhiyun average += 2;
1473*4882a593Smuzhiyun else
1474*4882a593Smuzhiyun average -= 25;
1475*4882a593Smuzhiyun if (tmp == 8)
1476*4882a593Smuzhiyun average -= 72;
1477*4882a593Smuzhiyun else
1478*4882a593Smuzhiyun average -= 48;
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun dev->stats.link_noise = average;
1481*4882a593Smuzhiyun dev->noisecalc.calculation_running = false;
1482*4882a593Smuzhiyun return;
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun generate_new:
1485*4882a593Smuzhiyun b43_generate_noise_sample(dev);
1486*4882a593Smuzhiyun }
1487*4882a593Smuzhiyun
handle_irq_tbtt_indication(struct b43_wldev * dev)1488*4882a593Smuzhiyun static void handle_irq_tbtt_indication(struct b43_wldev *dev)
1489*4882a593Smuzhiyun {
1490*4882a593Smuzhiyun if (b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) {
1491*4882a593Smuzhiyun ///TODO: PS TBTT
1492*4882a593Smuzhiyun } else {
1493*4882a593Smuzhiyun if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
1494*4882a593Smuzhiyun b43_power_saving_ctl_bits(dev, 0);
1495*4882a593Smuzhiyun }
1496*4882a593Smuzhiyun if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
1497*4882a593Smuzhiyun dev->dfq_valid = true;
1498*4882a593Smuzhiyun }
1499*4882a593Smuzhiyun
handle_irq_atim_end(struct b43_wldev * dev)1500*4882a593Smuzhiyun static void handle_irq_atim_end(struct b43_wldev *dev)
1501*4882a593Smuzhiyun {
1502*4882a593Smuzhiyun if (dev->dfq_valid) {
1503*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_MACCMD,
1504*4882a593Smuzhiyun b43_read32(dev, B43_MMIO_MACCMD)
1505*4882a593Smuzhiyun | B43_MACCMD_DFQ_VALID);
1506*4882a593Smuzhiyun dev->dfq_valid = false;
1507*4882a593Smuzhiyun }
1508*4882a593Smuzhiyun }
1509*4882a593Smuzhiyun
handle_irq_pmq(struct b43_wldev * dev)1510*4882a593Smuzhiyun static void handle_irq_pmq(struct b43_wldev *dev)
1511*4882a593Smuzhiyun {
1512*4882a593Smuzhiyun u32 tmp;
1513*4882a593Smuzhiyun
1514*4882a593Smuzhiyun //TODO: AP mode.
1515*4882a593Smuzhiyun
1516*4882a593Smuzhiyun while (1) {
1517*4882a593Smuzhiyun tmp = b43_read32(dev, B43_MMIO_PS_STATUS);
1518*4882a593Smuzhiyun if (!(tmp & 0x00000008))
1519*4882a593Smuzhiyun break;
1520*4882a593Smuzhiyun }
1521*4882a593Smuzhiyun /* 16bit write is odd, but correct. */
1522*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_PS_STATUS, 0x0002);
1523*4882a593Smuzhiyun }
1524*4882a593Smuzhiyun
b43_write_template_common(struct b43_wldev * dev,const u8 * data,u16 size,u16 ram_offset,u16 shm_size_offset,u8 rate)1525*4882a593Smuzhiyun static void b43_write_template_common(struct b43_wldev *dev,
1526*4882a593Smuzhiyun const u8 *data, u16 size,
1527*4882a593Smuzhiyun u16 ram_offset,
1528*4882a593Smuzhiyun u16 shm_size_offset, u8 rate)
1529*4882a593Smuzhiyun {
1530*4882a593Smuzhiyun u32 i, tmp;
1531*4882a593Smuzhiyun struct b43_plcp_hdr4 plcp;
1532*4882a593Smuzhiyun
1533*4882a593Smuzhiyun plcp.data = 0;
1534*4882a593Smuzhiyun b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
1535*4882a593Smuzhiyun b43_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
1536*4882a593Smuzhiyun ram_offset += sizeof(u32);
1537*4882a593Smuzhiyun /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
1538*4882a593Smuzhiyun * So leave the first two bytes of the next write blank.
1539*4882a593Smuzhiyun */
1540*4882a593Smuzhiyun tmp = (u32) (data[0]) << 16;
1541*4882a593Smuzhiyun tmp |= (u32) (data[1]) << 24;
1542*4882a593Smuzhiyun b43_ram_write(dev, ram_offset, tmp);
1543*4882a593Smuzhiyun ram_offset += sizeof(u32);
1544*4882a593Smuzhiyun for (i = 2; i < size; i += sizeof(u32)) {
1545*4882a593Smuzhiyun tmp = (u32) (data[i + 0]);
1546*4882a593Smuzhiyun if (i + 1 < size)
1547*4882a593Smuzhiyun tmp |= (u32) (data[i + 1]) << 8;
1548*4882a593Smuzhiyun if (i + 2 < size)
1549*4882a593Smuzhiyun tmp |= (u32) (data[i + 2]) << 16;
1550*4882a593Smuzhiyun if (i + 3 < size)
1551*4882a593Smuzhiyun tmp |= (u32) (data[i + 3]) << 24;
1552*4882a593Smuzhiyun b43_ram_write(dev, ram_offset + i - 2, tmp);
1553*4882a593Smuzhiyun }
1554*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, shm_size_offset,
1555*4882a593Smuzhiyun size + sizeof(struct b43_plcp_hdr6));
1556*4882a593Smuzhiyun }
1557*4882a593Smuzhiyun
1558*4882a593Smuzhiyun /* Check if the use of the antenna that ieee80211 told us to
1559*4882a593Smuzhiyun * use is possible. This will fall back to DEFAULT.
1560*4882a593Smuzhiyun * "antenna_nr" is the antenna identifier we got from ieee80211. */
b43_ieee80211_antenna_sanitize(struct b43_wldev * dev,u8 antenna_nr)1561*4882a593Smuzhiyun u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
1562*4882a593Smuzhiyun u8 antenna_nr)
1563*4882a593Smuzhiyun {
1564*4882a593Smuzhiyun u8 antenna_mask;
1565*4882a593Smuzhiyun
1566*4882a593Smuzhiyun if (antenna_nr == 0) {
1567*4882a593Smuzhiyun /* Zero means "use default antenna". That's always OK. */
1568*4882a593Smuzhiyun return 0;
1569*4882a593Smuzhiyun }
1570*4882a593Smuzhiyun
1571*4882a593Smuzhiyun /* Get the mask of available antennas. */
1572*4882a593Smuzhiyun if (dev->phy.gmode)
1573*4882a593Smuzhiyun antenna_mask = dev->dev->bus_sprom->ant_available_bg;
1574*4882a593Smuzhiyun else
1575*4882a593Smuzhiyun antenna_mask = dev->dev->bus_sprom->ant_available_a;
1576*4882a593Smuzhiyun
1577*4882a593Smuzhiyun if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
1578*4882a593Smuzhiyun /* This antenna is not available. Fall back to default. */
1579*4882a593Smuzhiyun return 0;
1580*4882a593Smuzhiyun }
1581*4882a593Smuzhiyun
1582*4882a593Smuzhiyun return antenna_nr;
1583*4882a593Smuzhiyun }
1584*4882a593Smuzhiyun
1585*4882a593Smuzhiyun /* Convert a b43 antenna number value to the PHY TX control value. */
b43_antenna_to_phyctl(int antenna)1586*4882a593Smuzhiyun static u16 b43_antenna_to_phyctl(int antenna)
1587*4882a593Smuzhiyun {
1588*4882a593Smuzhiyun switch (antenna) {
1589*4882a593Smuzhiyun case B43_ANTENNA0:
1590*4882a593Smuzhiyun return B43_TXH_PHY_ANT0;
1591*4882a593Smuzhiyun case B43_ANTENNA1:
1592*4882a593Smuzhiyun return B43_TXH_PHY_ANT1;
1593*4882a593Smuzhiyun case B43_ANTENNA2:
1594*4882a593Smuzhiyun return B43_TXH_PHY_ANT2;
1595*4882a593Smuzhiyun case B43_ANTENNA3:
1596*4882a593Smuzhiyun return B43_TXH_PHY_ANT3;
1597*4882a593Smuzhiyun case B43_ANTENNA_AUTO0:
1598*4882a593Smuzhiyun case B43_ANTENNA_AUTO1:
1599*4882a593Smuzhiyun return B43_TXH_PHY_ANT01AUTO;
1600*4882a593Smuzhiyun }
1601*4882a593Smuzhiyun B43_WARN_ON(1);
1602*4882a593Smuzhiyun return 0;
1603*4882a593Smuzhiyun }
1604*4882a593Smuzhiyun
b43_write_beacon_template(struct b43_wldev * dev,u16 ram_offset,u16 shm_size_offset)1605*4882a593Smuzhiyun static void b43_write_beacon_template(struct b43_wldev *dev,
1606*4882a593Smuzhiyun u16 ram_offset,
1607*4882a593Smuzhiyun u16 shm_size_offset)
1608*4882a593Smuzhiyun {
1609*4882a593Smuzhiyun unsigned int i, len, variable_len;
1610*4882a593Smuzhiyun const struct ieee80211_mgmt *bcn;
1611*4882a593Smuzhiyun const u8 *ie;
1612*4882a593Smuzhiyun bool tim_found = false;
1613*4882a593Smuzhiyun unsigned int rate;
1614*4882a593Smuzhiyun u16 ctl;
1615*4882a593Smuzhiyun int antenna;
1616*4882a593Smuzhiyun struct ieee80211_tx_info *info;
1617*4882a593Smuzhiyun unsigned long flags;
1618*4882a593Smuzhiyun struct sk_buff *beacon_skb;
1619*4882a593Smuzhiyun
1620*4882a593Smuzhiyun spin_lock_irqsave(&dev->wl->beacon_lock, flags);
1621*4882a593Smuzhiyun info = IEEE80211_SKB_CB(dev->wl->current_beacon);
1622*4882a593Smuzhiyun rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
1623*4882a593Smuzhiyun /* Clone the beacon, so it cannot go away, while we write it to hw. */
1624*4882a593Smuzhiyun beacon_skb = skb_clone(dev->wl->current_beacon, GFP_ATOMIC);
1625*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->wl->beacon_lock, flags);
1626*4882a593Smuzhiyun
1627*4882a593Smuzhiyun if (!beacon_skb) {
1628*4882a593Smuzhiyun b43dbg(dev->wl, "Could not upload beacon. "
1629*4882a593Smuzhiyun "Failed to clone beacon skb.");
1630*4882a593Smuzhiyun return;
1631*4882a593Smuzhiyun }
1632*4882a593Smuzhiyun
1633*4882a593Smuzhiyun bcn = (const struct ieee80211_mgmt *)(beacon_skb->data);
1634*4882a593Smuzhiyun len = min_t(size_t, beacon_skb->len,
1635*4882a593Smuzhiyun 0x200 - sizeof(struct b43_plcp_hdr6));
1636*4882a593Smuzhiyun
1637*4882a593Smuzhiyun b43_write_template_common(dev, (const u8 *)bcn,
1638*4882a593Smuzhiyun len, ram_offset, shm_size_offset, rate);
1639*4882a593Smuzhiyun
1640*4882a593Smuzhiyun /* Write the PHY TX control parameters. */
1641*4882a593Smuzhiyun antenna = B43_ANTENNA_DEFAULT;
1642*4882a593Smuzhiyun antenna = b43_antenna_to_phyctl(antenna);
1643*4882a593Smuzhiyun ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
1644*4882a593Smuzhiyun /* We can't send beacons with short preamble. Would get PHY errors. */
1645*4882a593Smuzhiyun ctl &= ~B43_TXH_PHY_SHORTPRMBL;
1646*4882a593Smuzhiyun ctl &= ~B43_TXH_PHY_ANT;
1647*4882a593Smuzhiyun ctl &= ~B43_TXH_PHY_ENC;
1648*4882a593Smuzhiyun ctl |= antenna;
1649*4882a593Smuzhiyun if (b43_is_cck_rate(rate))
1650*4882a593Smuzhiyun ctl |= B43_TXH_PHY_ENC_CCK;
1651*4882a593Smuzhiyun else
1652*4882a593Smuzhiyun ctl |= B43_TXH_PHY_ENC_OFDM;
1653*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);
1654*4882a593Smuzhiyun
1655*4882a593Smuzhiyun /* Find the position of the TIM and the DTIM_period value
1656*4882a593Smuzhiyun * and write them to SHM. */
1657*4882a593Smuzhiyun ie = bcn->u.beacon.variable;
1658*4882a593Smuzhiyun variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
1659*4882a593Smuzhiyun for (i = 0; i < variable_len - 2; ) {
1660*4882a593Smuzhiyun uint8_t ie_id, ie_len;
1661*4882a593Smuzhiyun
1662*4882a593Smuzhiyun ie_id = ie[i];
1663*4882a593Smuzhiyun ie_len = ie[i + 1];
1664*4882a593Smuzhiyun if (ie_id == 5) {
1665*4882a593Smuzhiyun u16 tim_position;
1666*4882a593Smuzhiyun u16 dtim_period;
1667*4882a593Smuzhiyun /* This is the TIM Information Element */
1668*4882a593Smuzhiyun
1669*4882a593Smuzhiyun /* Check whether the ie_len is in the beacon data range. */
1670*4882a593Smuzhiyun if (variable_len < ie_len + 2 + i)
1671*4882a593Smuzhiyun break;
1672*4882a593Smuzhiyun /* A valid TIM is at least 4 bytes long. */
1673*4882a593Smuzhiyun if (ie_len < 4)
1674*4882a593Smuzhiyun break;
1675*4882a593Smuzhiyun tim_found = true;
1676*4882a593Smuzhiyun
1677*4882a593Smuzhiyun tim_position = sizeof(struct b43_plcp_hdr6);
1678*4882a593Smuzhiyun tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable);
1679*4882a593Smuzhiyun tim_position += i;
1680*4882a593Smuzhiyun
1681*4882a593Smuzhiyun dtim_period = ie[i + 3];
1682*4882a593Smuzhiyun
1683*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED,
1684*4882a593Smuzhiyun B43_SHM_SH_TIMBPOS, tim_position);
1685*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED,
1686*4882a593Smuzhiyun B43_SHM_SH_DTIMPER, dtim_period);
1687*4882a593Smuzhiyun break;
1688*4882a593Smuzhiyun }
1689*4882a593Smuzhiyun i += ie_len + 2;
1690*4882a593Smuzhiyun }
1691*4882a593Smuzhiyun if (!tim_found) {
1692*4882a593Smuzhiyun /*
1693*4882a593Smuzhiyun * If ucode wants to modify TIM do it behind the beacon, this
1694*4882a593Smuzhiyun * will happen, for example, when doing mesh networking.
1695*4882a593Smuzhiyun */
1696*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED,
1697*4882a593Smuzhiyun B43_SHM_SH_TIMBPOS,
1698*4882a593Smuzhiyun len + sizeof(struct b43_plcp_hdr6));
1699*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED,
1700*4882a593Smuzhiyun B43_SHM_SH_DTIMPER, 0);
1701*4882a593Smuzhiyun }
1702*4882a593Smuzhiyun b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
1703*4882a593Smuzhiyun
1704*4882a593Smuzhiyun dev_kfree_skb_any(beacon_skb);
1705*4882a593Smuzhiyun }
1706*4882a593Smuzhiyun
b43_upload_beacon0(struct b43_wldev * dev)1707*4882a593Smuzhiyun static void b43_upload_beacon0(struct b43_wldev *dev)
1708*4882a593Smuzhiyun {
1709*4882a593Smuzhiyun struct b43_wl *wl = dev->wl;
1710*4882a593Smuzhiyun
1711*4882a593Smuzhiyun if (wl->beacon0_uploaded)
1712*4882a593Smuzhiyun return;
1713*4882a593Smuzhiyun b43_write_beacon_template(dev, B43_SHM_SH_BT_BASE0, B43_SHM_SH_BTL0);
1714*4882a593Smuzhiyun wl->beacon0_uploaded = true;
1715*4882a593Smuzhiyun }
1716*4882a593Smuzhiyun
b43_upload_beacon1(struct b43_wldev * dev)1717*4882a593Smuzhiyun static void b43_upload_beacon1(struct b43_wldev *dev)
1718*4882a593Smuzhiyun {
1719*4882a593Smuzhiyun struct b43_wl *wl = dev->wl;
1720*4882a593Smuzhiyun
1721*4882a593Smuzhiyun if (wl->beacon1_uploaded)
1722*4882a593Smuzhiyun return;
1723*4882a593Smuzhiyun b43_write_beacon_template(dev, B43_SHM_SH_BT_BASE1, B43_SHM_SH_BTL1);
1724*4882a593Smuzhiyun wl->beacon1_uploaded = true;
1725*4882a593Smuzhiyun }
1726*4882a593Smuzhiyun
handle_irq_beacon(struct b43_wldev * dev)1727*4882a593Smuzhiyun static void handle_irq_beacon(struct b43_wldev *dev)
1728*4882a593Smuzhiyun {
1729*4882a593Smuzhiyun struct b43_wl *wl = dev->wl;
1730*4882a593Smuzhiyun u32 cmd, beacon0_valid, beacon1_valid;
1731*4882a593Smuzhiyun
1732*4882a593Smuzhiyun if (!b43_is_mode(wl, NL80211_IFTYPE_AP) &&
1733*4882a593Smuzhiyun !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) &&
1734*4882a593Smuzhiyun !b43_is_mode(wl, NL80211_IFTYPE_ADHOC))
1735*4882a593Smuzhiyun return;
1736*4882a593Smuzhiyun
1737*4882a593Smuzhiyun /* This is the bottom half of the asynchronous beacon update. */
1738*4882a593Smuzhiyun
1739*4882a593Smuzhiyun /* Ignore interrupt in the future. */
1740*4882a593Smuzhiyun dev->irq_mask &= ~B43_IRQ_BEACON;
1741*4882a593Smuzhiyun
1742*4882a593Smuzhiyun cmd = b43_read32(dev, B43_MMIO_MACCMD);
1743*4882a593Smuzhiyun beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID);
1744*4882a593Smuzhiyun beacon1_valid = (cmd & B43_MACCMD_BEACON1_VALID);
1745*4882a593Smuzhiyun
1746*4882a593Smuzhiyun /* Schedule interrupt manually, if busy. */
1747*4882a593Smuzhiyun if (beacon0_valid && beacon1_valid) {
1748*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
1749*4882a593Smuzhiyun dev->irq_mask |= B43_IRQ_BEACON;
1750*4882a593Smuzhiyun return;
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun
1753*4882a593Smuzhiyun if (unlikely(wl->beacon_templates_virgin)) {
1754*4882a593Smuzhiyun /* We never uploaded a beacon before.
1755*4882a593Smuzhiyun * Upload both templates now, but only mark one valid. */
1756*4882a593Smuzhiyun wl->beacon_templates_virgin = false;
1757*4882a593Smuzhiyun b43_upload_beacon0(dev);
1758*4882a593Smuzhiyun b43_upload_beacon1(dev);
1759*4882a593Smuzhiyun cmd = b43_read32(dev, B43_MMIO_MACCMD);
1760*4882a593Smuzhiyun cmd |= B43_MACCMD_BEACON0_VALID;
1761*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_MACCMD, cmd);
1762*4882a593Smuzhiyun } else {
1763*4882a593Smuzhiyun if (!beacon0_valid) {
1764*4882a593Smuzhiyun b43_upload_beacon0(dev);
1765*4882a593Smuzhiyun cmd = b43_read32(dev, B43_MMIO_MACCMD);
1766*4882a593Smuzhiyun cmd |= B43_MACCMD_BEACON0_VALID;
1767*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_MACCMD, cmd);
1768*4882a593Smuzhiyun } else if (!beacon1_valid) {
1769*4882a593Smuzhiyun b43_upload_beacon1(dev);
1770*4882a593Smuzhiyun cmd = b43_read32(dev, B43_MMIO_MACCMD);
1771*4882a593Smuzhiyun cmd |= B43_MACCMD_BEACON1_VALID;
1772*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_MACCMD, cmd);
1773*4882a593Smuzhiyun }
1774*4882a593Smuzhiyun }
1775*4882a593Smuzhiyun }
1776*4882a593Smuzhiyun
b43_do_beacon_update_trigger_work(struct b43_wldev * dev)1777*4882a593Smuzhiyun static void b43_do_beacon_update_trigger_work(struct b43_wldev *dev)
1778*4882a593Smuzhiyun {
1779*4882a593Smuzhiyun u32 old_irq_mask = dev->irq_mask;
1780*4882a593Smuzhiyun
1781*4882a593Smuzhiyun /* update beacon right away or defer to irq */
1782*4882a593Smuzhiyun handle_irq_beacon(dev);
1783*4882a593Smuzhiyun if (old_irq_mask != dev->irq_mask) {
1784*4882a593Smuzhiyun /* The handler updated the IRQ mask. */
1785*4882a593Smuzhiyun B43_WARN_ON(!dev->irq_mask);
1786*4882a593Smuzhiyun if (b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)) {
1787*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
1788*4882a593Smuzhiyun } else {
1789*4882a593Smuzhiyun /* Device interrupts are currently disabled. That means
1790*4882a593Smuzhiyun * we just ran the hardirq handler and scheduled the
1791*4882a593Smuzhiyun * IRQ thread. The thread will write the IRQ mask when
1792*4882a593Smuzhiyun * it finished, so there's nothing to do here. Writing
1793*4882a593Smuzhiyun * the mask _here_ would incorrectly re-enable IRQs. */
1794*4882a593Smuzhiyun }
1795*4882a593Smuzhiyun }
1796*4882a593Smuzhiyun }
1797*4882a593Smuzhiyun
b43_beacon_update_trigger_work(struct work_struct * work)1798*4882a593Smuzhiyun static void b43_beacon_update_trigger_work(struct work_struct *work)
1799*4882a593Smuzhiyun {
1800*4882a593Smuzhiyun struct b43_wl *wl = container_of(work, struct b43_wl,
1801*4882a593Smuzhiyun beacon_update_trigger);
1802*4882a593Smuzhiyun struct b43_wldev *dev;
1803*4882a593Smuzhiyun
1804*4882a593Smuzhiyun mutex_lock(&wl->mutex);
1805*4882a593Smuzhiyun dev = wl->current_dev;
1806*4882a593Smuzhiyun if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
1807*4882a593Smuzhiyun if (b43_bus_host_is_sdio(dev->dev)) {
1808*4882a593Smuzhiyun /* wl->mutex is enough. */
1809*4882a593Smuzhiyun b43_do_beacon_update_trigger_work(dev);
1810*4882a593Smuzhiyun } else {
1811*4882a593Smuzhiyun spin_lock_irq(&wl->hardirq_lock);
1812*4882a593Smuzhiyun b43_do_beacon_update_trigger_work(dev);
1813*4882a593Smuzhiyun spin_unlock_irq(&wl->hardirq_lock);
1814*4882a593Smuzhiyun }
1815*4882a593Smuzhiyun }
1816*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
1817*4882a593Smuzhiyun }
1818*4882a593Smuzhiyun
1819*4882a593Smuzhiyun /* Asynchronously update the packet templates in template RAM. */
b43_update_templates(struct b43_wl * wl)1820*4882a593Smuzhiyun static void b43_update_templates(struct b43_wl *wl)
1821*4882a593Smuzhiyun {
1822*4882a593Smuzhiyun struct sk_buff *beacon, *old_beacon;
1823*4882a593Smuzhiyun unsigned long flags;
1824*4882a593Smuzhiyun
1825*4882a593Smuzhiyun /* This is the top half of the asynchronous beacon update.
1826*4882a593Smuzhiyun * The bottom half is the beacon IRQ.
1827*4882a593Smuzhiyun * Beacon update must be asynchronous to avoid sending an
1828*4882a593Smuzhiyun * invalid beacon. This can happen for example, if the firmware
1829*4882a593Smuzhiyun * transmits a beacon while we are updating it. */
1830*4882a593Smuzhiyun
1831*4882a593Smuzhiyun /* We could modify the existing beacon and set the aid bit in
1832*4882a593Smuzhiyun * the TIM field, but that would probably require resizing and
1833*4882a593Smuzhiyun * moving of data within the beacon template.
1834*4882a593Smuzhiyun * Simply request a new beacon and let mac80211 do the hard work. */
1835*4882a593Smuzhiyun beacon = ieee80211_beacon_get(wl->hw, wl->vif);
1836*4882a593Smuzhiyun if (unlikely(!beacon))
1837*4882a593Smuzhiyun return;
1838*4882a593Smuzhiyun
1839*4882a593Smuzhiyun spin_lock_irqsave(&wl->beacon_lock, flags);
1840*4882a593Smuzhiyun old_beacon = wl->current_beacon;
1841*4882a593Smuzhiyun wl->current_beacon = beacon;
1842*4882a593Smuzhiyun wl->beacon0_uploaded = false;
1843*4882a593Smuzhiyun wl->beacon1_uploaded = false;
1844*4882a593Smuzhiyun spin_unlock_irqrestore(&wl->beacon_lock, flags);
1845*4882a593Smuzhiyun
1846*4882a593Smuzhiyun ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
1847*4882a593Smuzhiyun
1848*4882a593Smuzhiyun if (old_beacon)
1849*4882a593Smuzhiyun dev_kfree_skb_any(old_beacon);
1850*4882a593Smuzhiyun }
1851*4882a593Smuzhiyun
b43_set_beacon_int(struct b43_wldev * dev,u16 beacon_int)1852*4882a593Smuzhiyun static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
1853*4882a593Smuzhiyun {
1854*4882a593Smuzhiyun b43_time_lock(dev);
1855*4882a593Smuzhiyun if (dev->dev->core_rev >= 3) {
1856*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16));
1857*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));
1858*4882a593Smuzhiyun } else {
1859*4882a593Smuzhiyun b43_write16(dev, 0x606, (beacon_int >> 6));
1860*4882a593Smuzhiyun b43_write16(dev, 0x610, beacon_int);
1861*4882a593Smuzhiyun }
1862*4882a593Smuzhiyun b43_time_unlock(dev);
1863*4882a593Smuzhiyun b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
1864*4882a593Smuzhiyun }
1865*4882a593Smuzhiyun
b43_handle_firmware_panic(struct b43_wldev * dev)1866*4882a593Smuzhiyun static void b43_handle_firmware_panic(struct b43_wldev *dev)
1867*4882a593Smuzhiyun {
1868*4882a593Smuzhiyun u16 reason;
1869*4882a593Smuzhiyun
1870*4882a593Smuzhiyun /* Read the register that contains the reason code for the panic. */
1871*4882a593Smuzhiyun reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG);
1872*4882a593Smuzhiyun b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason);
1873*4882a593Smuzhiyun
1874*4882a593Smuzhiyun switch (reason) {
1875*4882a593Smuzhiyun default:
1876*4882a593Smuzhiyun b43dbg(dev->wl, "The panic reason is unknown.\n");
1877*4882a593Smuzhiyun fallthrough;
1878*4882a593Smuzhiyun case B43_FWPANIC_DIE:
1879*4882a593Smuzhiyun /* Do not restart the controller or firmware.
1880*4882a593Smuzhiyun * The device is nonfunctional from now on.
1881*4882a593Smuzhiyun * Restarting would result in this panic to trigger again,
1882*4882a593Smuzhiyun * so we avoid that recursion. */
1883*4882a593Smuzhiyun break;
1884*4882a593Smuzhiyun case B43_FWPANIC_RESTART:
1885*4882a593Smuzhiyun b43_controller_restart(dev, "Microcode panic");
1886*4882a593Smuzhiyun break;
1887*4882a593Smuzhiyun }
1888*4882a593Smuzhiyun }
1889*4882a593Smuzhiyun
handle_irq_ucode_debug(struct b43_wldev * dev)1890*4882a593Smuzhiyun static void handle_irq_ucode_debug(struct b43_wldev *dev)
1891*4882a593Smuzhiyun {
1892*4882a593Smuzhiyun unsigned int i, cnt;
1893*4882a593Smuzhiyun u16 reason, marker_id, marker_line;
1894*4882a593Smuzhiyun __le16 *buf;
1895*4882a593Smuzhiyun
1896*4882a593Smuzhiyun /* The proprietary firmware doesn't have this IRQ. */
1897*4882a593Smuzhiyun if (!dev->fw.opensource)
1898*4882a593Smuzhiyun return;
1899*4882a593Smuzhiyun
1900*4882a593Smuzhiyun /* Read the register that contains the reason code for this IRQ. */
1901*4882a593Smuzhiyun reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG);
1902*4882a593Smuzhiyun
1903*4882a593Smuzhiyun switch (reason) {
1904*4882a593Smuzhiyun case B43_DEBUGIRQ_PANIC:
1905*4882a593Smuzhiyun b43_handle_firmware_panic(dev);
1906*4882a593Smuzhiyun break;
1907*4882a593Smuzhiyun case B43_DEBUGIRQ_DUMP_SHM:
1908*4882a593Smuzhiyun if (!B43_DEBUG)
1909*4882a593Smuzhiyun break; /* Only with driver debugging enabled. */
1910*4882a593Smuzhiyun buf = kmalloc(4096, GFP_ATOMIC);
1911*4882a593Smuzhiyun if (!buf) {
1912*4882a593Smuzhiyun b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n");
1913*4882a593Smuzhiyun goto out;
1914*4882a593Smuzhiyun }
1915*4882a593Smuzhiyun for (i = 0; i < 4096; i += 2) {
1916*4882a593Smuzhiyun u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i);
1917*4882a593Smuzhiyun buf[i / 2] = cpu_to_le16(tmp);
1918*4882a593Smuzhiyun }
1919*4882a593Smuzhiyun b43info(dev->wl, "Shared memory dump:\n");
1920*4882a593Smuzhiyun print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET,
1921*4882a593Smuzhiyun 16, 2, buf, 4096, 1);
1922*4882a593Smuzhiyun kfree(buf);
1923*4882a593Smuzhiyun break;
1924*4882a593Smuzhiyun case B43_DEBUGIRQ_DUMP_REGS:
1925*4882a593Smuzhiyun if (!B43_DEBUG)
1926*4882a593Smuzhiyun break; /* Only with driver debugging enabled. */
1927*4882a593Smuzhiyun b43info(dev->wl, "Microcode register dump:\n");
1928*4882a593Smuzhiyun for (i = 0, cnt = 0; i < 64; i++) {
1929*4882a593Smuzhiyun u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i);
1930*4882a593Smuzhiyun if (cnt == 0)
1931*4882a593Smuzhiyun printk(KERN_INFO);
1932*4882a593Smuzhiyun printk("r%02u: 0x%04X ", i, tmp);
1933*4882a593Smuzhiyun cnt++;
1934*4882a593Smuzhiyun if (cnt == 6) {
1935*4882a593Smuzhiyun printk("\n");
1936*4882a593Smuzhiyun cnt = 0;
1937*4882a593Smuzhiyun }
1938*4882a593Smuzhiyun }
1939*4882a593Smuzhiyun printk("\n");
1940*4882a593Smuzhiyun break;
1941*4882a593Smuzhiyun case B43_DEBUGIRQ_MARKER:
1942*4882a593Smuzhiyun if (!B43_DEBUG)
1943*4882a593Smuzhiyun break; /* Only with driver debugging enabled. */
1944*4882a593Smuzhiyun marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH,
1945*4882a593Smuzhiyun B43_MARKER_ID_REG);
1946*4882a593Smuzhiyun marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH,
1947*4882a593Smuzhiyun B43_MARKER_LINE_REG);
1948*4882a593Smuzhiyun b43info(dev->wl, "The firmware just executed the MARKER(%u) "
1949*4882a593Smuzhiyun "at line number %u\n",
1950*4882a593Smuzhiyun marker_id, marker_line);
1951*4882a593Smuzhiyun break;
1952*4882a593Smuzhiyun default:
1953*4882a593Smuzhiyun b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n",
1954*4882a593Smuzhiyun reason);
1955*4882a593Smuzhiyun }
1956*4882a593Smuzhiyun out:
1957*4882a593Smuzhiyun /* Acknowledge the debug-IRQ, so the firmware can continue. */
1958*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SCRATCH,
1959*4882a593Smuzhiyun B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK);
1960*4882a593Smuzhiyun }
1961*4882a593Smuzhiyun
b43_do_interrupt_thread(struct b43_wldev * dev)1962*4882a593Smuzhiyun static void b43_do_interrupt_thread(struct b43_wldev *dev)
1963*4882a593Smuzhiyun {
1964*4882a593Smuzhiyun u32 reason;
1965*4882a593Smuzhiyun u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
1966*4882a593Smuzhiyun u32 merged_dma_reason = 0;
1967*4882a593Smuzhiyun int i;
1968*4882a593Smuzhiyun
1969*4882a593Smuzhiyun if (unlikely(b43_status(dev) != B43_STAT_STARTED))
1970*4882a593Smuzhiyun return;
1971*4882a593Smuzhiyun
1972*4882a593Smuzhiyun reason = dev->irq_reason;
1973*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
1974*4882a593Smuzhiyun dma_reason[i] = dev->dma_reason[i];
1975*4882a593Smuzhiyun merged_dma_reason |= dma_reason[i];
1976*4882a593Smuzhiyun }
1977*4882a593Smuzhiyun
1978*4882a593Smuzhiyun if (unlikely(reason & B43_IRQ_MAC_TXERR))
1979*4882a593Smuzhiyun b43err(dev->wl, "MAC transmission error\n");
1980*4882a593Smuzhiyun
1981*4882a593Smuzhiyun if (unlikely(reason & B43_IRQ_PHY_TXERR)) {
1982*4882a593Smuzhiyun b43err(dev->wl, "PHY transmission error\n");
1983*4882a593Smuzhiyun rmb();
1984*4882a593Smuzhiyun if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) {
1985*4882a593Smuzhiyun atomic_set(&dev->phy.txerr_cnt,
1986*4882a593Smuzhiyun B43_PHY_TX_BADNESS_LIMIT);
1987*4882a593Smuzhiyun b43err(dev->wl, "Too many PHY TX errors, "
1988*4882a593Smuzhiyun "restarting the controller\n");
1989*4882a593Smuzhiyun b43_controller_restart(dev, "PHY TX errors");
1990*4882a593Smuzhiyun }
1991*4882a593Smuzhiyun }
1992*4882a593Smuzhiyun
1993*4882a593Smuzhiyun if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK))) {
1994*4882a593Smuzhiyun b43err(dev->wl,
1995*4882a593Smuzhiyun "Fatal DMA error: 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
1996*4882a593Smuzhiyun dma_reason[0], dma_reason[1],
1997*4882a593Smuzhiyun dma_reason[2], dma_reason[3],
1998*4882a593Smuzhiyun dma_reason[4], dma_reason[5]);
1999*4882a593Smuzhiyun b43err(dev->wl, "This device does not support DMA "
2000*4882a593Smuzhiyun "on your system. It will now be switched to PIO.\n");
2001*4882a593Smuzhiyun /* Fall back to PIO transfers if we get fatal DMA errors! */
2002*4882a593Smuzhiyun dev->use_pio = true;
2003*4882a593Smuzhiyun b43_controller_restart(dev, "DMA error");
2004*4882a593Smuzhiyun return;
2005*4882a593Smuzhiyun }
2006*4882a593Smuzhiyun
2007*4882a593Smuzhiyun if (unlikely(reason & B43_IRQ_UCODE_DEBUG))
2008*4882a593Smuzhiyun handle_irq_ucode_debug(dev);
2009*4882a593Smuzhiyun if (reason & B43_IRQ_TBTT_INDI)
2010*4882a593Smuzhiyun handle_irq_tbtt_indication(dev);
2011*4882a593Smuzhiyun if (reason & B43_IRQ_ATIM_END)
2012*4882a593Smuzhiyun handle_irq_atim_end(dev);
2013*4882a593Smuzhiyun if (reason & B43_IRQ_BEACON)
2014*4882a593Smuzhiyun handle_irq_beacon(dev);
2015*4882a593Smuzhiyun if (reason & B43_IRQ_PMQ)
2016*4882a593Smuzhiyun handle_irq_pmq(dev);
2017*4882a593Smuzhiyun if (reason & B43_IRQ_TXFIFO_FLUSH_OK) {
2018*4882a593Smuzhiyun ;/* TODO */
2019*4882a593Smuzhiyun }
2020*4882a593Smuzhiyun if (reason & B43_IRQ_NOISESAMPLE_OK)
2021*4882a593Smuzhiyun handle_irq_noise(dev);
2022*4882a593Smuzhiyun
2023*4882a593Smuzhiyun /* Check the DMA reason registers for received data. */
2024*4882a593Smuzhiyun if (dma_reason[0] & B43_DMAIRQ_RDESC_UFLOW) {
2025*4882a593Smuzhiyun if (B43_DEBUG)
2026*4882a593Smuzhiyun b43warn(dev->wl, "RX descriptor underrun\n");
2027*4882a593Smuzhiyun b43_dma_handle_rx_overflow(dev->dma.rx_ring);
2028*4882a593Smuzhiyun }
2029*4882a593Smuzhiyun if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
2030*4882a593Smuzhiyun if (b43_using_pio_transfers(dev))
2031*4882a593Smuzhiyun b43_pio_rx(dev->pio.rx_queue);
2032*4882a593Smuzhiyun else
2033*4882a593Smuzhiyun b43_dma_rx(dev->dma.rx_ring);
2034*4882a593Smuzhiyun }
2035*4882a593Smuzhiyun B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
2036*4882a593Smuzhiyun B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
2037*4882a593Smuzhiyun B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE);
2038*4882a593Smuzhiyun B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
2039*4882a593Smuzhiyun B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
2040*4882a593Smuzhiyun
2041*4882a593Smuzhiyun if (reason & B43_IRQ_TX_OK)
2042*4882a593Smuzhiyun handle_irq_transmit_status(dev);
2043*4882a593Smuzhiyun
2044*4882a593Smuzhiyun /* Re-enable interrupts on the device by restoring the current interrupt mask. */
2045*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
2046*4882a593Smuzhiyun
2047*4882a593Smuzhiyun #if B43_DEBUG
2048*4882a593Smuzhiyun if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
2049*4882a593Smuzhiyun dev->irq_count++;
2050*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
2051*4882a593Smuzhiyun if (reason & (1 << i))
2052*4882a593Smuzhiyun dev->irq_bit_count[i]++;
2053*4882a593Smuzhiyun }
2054*4882a593Smuzhiyun }
2055*4882a593Smuzhiyun #endif
2056*4882a593Smuzhiyun }
2057*4882a593Smuzhiyun
2058*4882a593Smuzhiyun /* Interrupt thread handler. Handles device interrupts in thread context. */
b43_interrupt_thread_handler(int irq,void * dev_id)2059*4882a593Smuzhiyun static irqreturn_t b43_interrupt_thread_handler(int irq, void *dev_id)
2060*4882a593Smuzhiyun {
2061*4882a593Smuzhiyun struct b43_wldev *dev = dev_id;
2062*4882a593Smuzhiyun
2063*4882a593Smuzhiyun mutex_lock(&dev->wl->mutex);
2064*4882a593Smuzhiyun b43_do_interrupt_thread(dev);
2065*4882a593Smuzhiyun mutex_unlock(&dev->wl->mutex);
2066*4882a593Smuzhiyun
2067*4882a593Smuzhiyun return IRQ_HANDLED;
2068*4882a593Smuzhiyun }
2069*4882a593Smuzhiyun
b43_do_interrupt(struct b43_wldev * dev)2070*4882a593Smuzhiyun static irqreturn_t b43_do_interrupt(struct b43_wldev *dev)
2071*4882a593Smuzhiyun {
2072*4882a593Smuzhiyun u32 reason;
2073*4882a593Smuzhiyun
2074*4882a593Smuzhiyun /* This code runs under wl->hardirq_lock, but _only_ on non-SDIO busses.
2075*4882a593Smuzhiyun * On SDIO, this runs under wl->mutex. */
2076*4882a593Smuzhiyun
2077*4882a593Smuzhiyun reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2078*4882a593Smuzhiyun if (reason == 0xffffffff) /* shared IRQ */
2079*4882a593Smuzhiyun return IRQ_NONE;
2080*4882a593Smuzhiyun reason &= dev->irq_mask;
2081*4882a593Smuzhiyun if (!reason)
2082*4882a593Smuzhiyun return IRQ_NONE;
2083*4882a593Smuzhiyun
2084*4882a593Smuzhiyun dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
2085*4882a593Smuzhiyun & 0x0001FC00;
2086*4882a593Smuzhiyun dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON)
2087*4882a593Smuzhiyun & 0x0000DC00;
2088*4882a593Smuzhiyun dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON)
2089*4882a593Smuzhiyun & 0x0000DC00;
2090*4882a593Smuzhiyun dev->dma_reason[3] = b43_read32(dev, B43_MMIO_DMA3_REASON)
2091*4882a593Smuzhiyun & 0x0001DC00;
2092*4882a593Smuzhiyun dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON)
2093*4882a593Smuzhiyun & 0x0000DC00;
2094*4882a593Smuzhiyun /* Unused ring
2095*4882a593Smuzhiyun dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON)
2096*4882a593Smuzhiyun & 0x0000DC00;
2097*4882a593Smuzhiyun */
2098*4882a593Smuzhiyun
2099*4882a593Smuzhiyun /* ACK the interrupt. */
2100*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
2101*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
2102*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]);
2103*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
2104*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
2105*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
2106*4882a593Smuzhiyun /* Unused ring
2107*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
2108*4882a593Smuzhiyun */
2109*4882a593Smuzhiyun
2110*4882a593Smuzhiyun /* Disable IRQs on the device. The IRQ thread handler will re-enable them. */
2111*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
2112*4882a593Smuzhiyun /* Save the reason bitmasks for the IRQ thread handler. */
2113*4882a593Smuzhiyun dev->irq_reason = reason;
2114*4882a593Smuzhiyun
2115*4882a593Smuzhiyun return IRQ_WAKE_THREAD;
2116*4882a593Smuzhiyun }
2117*4882a593Smuzhiyun
2118*4882a593Smuzhiyun /* Interrupt handler top-half. This runs with interrupts disabled. */
b43_interrupt_handler(int irq,void * dev_id)2119*4882a593Smuzhiyun static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
2120*4882a593Smuzhiyun {
2121*4882a593Smuzhiyun struct b43_wldev *dev = dev_id;
2122*4882a593Smuzhiyun irqreturn_t ret;
2123*4882a593Smuzhiyun
2124*4882a593Smuzhiyun if (unlikely(b43_status(dev) < B43_STAT_STARTED))
2125*4882a593Smuzhiyun return IRQ_NONE;
2126*4882a593Smuzhiyun
2127*4882a593Smuzhiyun spin_lock(&dev->wl->hardirq_lock);
2128*4882a593Smuzhiyun ret = b43_do_interrupt(dev);
2129*4882a593Smuzhiyun spin_unlock(&dev->wl->hardirq_lock);
2130*4882a593Smuzhiyun
2131*4882a593Smuzhiyun return ret;
2132*4882a593Smuzhiyun }
2133*4882a593Smuzhiyun
2134*4882a593Smuzhiyun /* SDIO interrupt handler. This runs in process context. */
b43_sdio_interrupt_handler(struct b43_wldev * dev)2135*4882a593Smuzhiyun static void b43_sdio_interrupt_handler(struct b43_wldev *dev)
2136*4882a593Smuzhiyun {
2137*4882a593Smuzhiyun struct b43_wl *wl = dev->wl;
2138*4882a593Smuzhiyun irqreturn_t ret;
2139*4882a593Smuzhiyun
2140*4882a593Smuzhiyun mutex_lock(&wl->mutex);
2141*4882a593Smuzhiyun
2142*4882a593Smuzhiyun ret = b43_do_interrupt(dev);
2143*4882a593Smuzhiyun if (ret == IRQ_WAKE_THREAD)
2144*4882a593Smuzhiyun b43_do_interrupt_thread(dev);
2145*4882a593Smuzhiyun
2146*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
2147*4882a593Smuzhiyun }
2148*4882a593Smuzhiyun
b43_do_release_fw(struct b43_firmware_file * fw)2149*4882a593Smuzhiyun void b43_do_release_fw(struct b43_firmware_file *fw)
2150*4882a593Smuzhiyun {
2151*4882a593Smuzhiyun release_firmware(fw->data);
2152*4882a593Smuzhiyun fw->data = NULL;
2153*4882a593Smuzhiyun fw->filename = NULL;
2154*4882a593Smuzhiyun }
2155*4882a593Smuzhiyun
b43_release_firmware(struct b43_wldev * dev)2156*4882a593Smuzhiyun static void b43_release_firmware(struct b43_wldev *dev)
2157*4882a593Smuzhiyun {
2158*4882a593Smuzhiyun complete(&dev->fw_load_complete);
2159*4882a593Smuzhiyun b43_do_release_fw(&dev->fw.ucode);
2160*4882a593Smuzhiyun b43_do_release_fw(&dev->fw.pcm);
2161*4882a593Smuzhiyun b43_do_release_fw(&dev->fw.initvals);
2162*4882a593Smuzhiyun b43_do_release_fw(&dev->fw.initvals_band);
2163*4882a593Smuzhiyun }
2164*4882a593Smuzhiyun
b43_print_fw_helptext(struct b43_wl * wl,bool error)2165*4882a593Smuzhiyun static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
2166*4882a593Smuzhiyun {
2167*4882a593Smuzhiyun const char text[] =
2168*4882a593Smuzhiyun "You must go to " \
2169*4882a593Smuzhiyun "https://wireless.wiki.kernel.org/en/users/Drivers/b43#devicefirmware " \
2170*4882a593Smuzhiyun "and download the correct firmware for this driver version. " \
2171*4882a593Smuzhiyun "Please carefully read all instructions on this website.\n";
2172*4882a593Smuzhiyun
2173*4882a593Smuzhiyun if (error)
2174*4882a593Smuzhiyun b43err(wl, text);
2175*4882a593Smuzhiyun else
2176*4882a593Smuzhiyun b43warn(wl, text);
2177*4882a593Smuzhiyun }
2178*4882a593Smuzhiyun
b43_fw_cb(const struct firmware * firmware,void * context)2179*4882a593Smuzhiyun static void b43_fw_cb(const struct firmware *firmware, void *context)
2180*4882a593Smuzhiyun {
2181*4882a593Smuzhiyun struct b43_request_fw_context *ctx = context;
2182*4882a593Smuzhiyun
2183*4882a593Smuzhiyun ctx->blob = firmware;
2184*4882a593Smuzhiyun complete(&ctx->dev->fw_load_complete);
2185*4882a593Smuzhiyun }
2186*4882a593Smuzhiyun
b43_do_request_fw(struct b43_request_fw_context * ctx,const char * name,struct b43_firmware_file * fw,bool async)2187*4882a593Smuzhiyun int b43_do_request_fw(struct b43_request_fw_context *ctx,
2188*4882a593Smuzhiyun const char *name,
2189*4882a593Smuzhiyun struct b43_firmware_file *fw, bool async)
2190*4882a593Smuzhiyun {
2191*4882a593Smuzhiyun struct b43_fw_header *hdr;
2192*4882a593Smuzhiyun u32 size;
2193*4882a593Smuzhiyun int err;
2194*4882a593Smuzhiyun
2195*4882a593Smuzhiyun if (!name) {
2196*4882a593Smuzhiyun /* Don't fetch anything. Free possibly cached firmware. */
2197*4882a593Smuzhiyun /* FIXME: We should probably keep it anyway, to save some headache
2198*4882a593Smuzhiyun * on suspend/resume with multiband devices. */
2199*4882a593Smuzhiyun b43_do_release_fw(fw);
2200*4882a593Smuzhiyun return 0;
2201*4882a593Smuzhiyun }
2202*4882a593Smuzhiyun if (fw->filename) {
2203*4882a593Smuzhiyun if ((fw->type == ctx->req_type) &&
2204*4882a593Smuzhiyun (strcmp(fw->filename, name) == 0))
2205*4882a593Smuzhiyun return 0; /* Already have this fw. */
2206*4882a593Smuzhiyun /* Free the cached firmware first. */
2207*4882a593Smuzhiyun /* FIXME: We should probably do this later after we successfully
2208*4882a593Smuzhiyun * got the new fw. This could reduce headache with multiband devices.
2209*4882a593Smuzhiyun * We could also redesign this to cache the firmware for all possible
2210*4882a593Smuzhiyun * bands all the time. */
2211*4882a593Smuzhiyun b43_do_release_fw(fw);
2212*4882a593Smuzhiyun }
2213*4882a593Smuzhiyun
2214*4882a593Smuzhiyun switch (ctx->req_type) {
2215*4882a593Smuzhiyun case B43_FWTYPE_PROPRIETARY:
2216*4882a593Smuzhiyun snprintf(ctx->fwname, sizeof(ctx->fwname),
2217*4882a593Smuzhiyun "b43%s/%s.fw",
2218*4882a593Smuzhiyun modparam_fwpostfix, name);
2219*4882a593Smuzhiyun break;
2220*4882a593Smuzhiyun case B43_FWTYPE_OPENSOURCE:
2221*4882a593Smuzhiyun snprintf(ctx->fwname, sizeof(ctx->fwname),
2222*4882a593Smuzhiyun "b43-open%s/%s.fw",
2223*4882a593Smuzhiyun modparam_fwpostfix, name);
2224*4882a593Smuzhiyun break;
2225*4882a593Smuzhiyun default:
2226*4882a593Smuzhiyun B43_WARN_ON(1);
2227*4882a593Smuzhiyun return -ENOSYS;
2228*4882a593Smuzhiyun }
2229*4882a593Smuzhiyun if (async) {
2230*4882a593Smuzhiyun /* do this part asynchronously */
2231*4882a593Smuzhiyun init_completion(&ctx->dev->fw_load_complete);
2232*4882a593Smuzhiyun err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname,
2233*4882a593Smuzhiyun ctx->dev->dev->dev, GFP_KERNEL,
2234*4882a593Smuzhiyun ctx, b43_fw_cb);
2235*4882a593Smuzhiyun if (err < 0) {
2236*4882a593Smuzhiyun pr_err("Unable to load firmware\n");
2237*4882a593Smuzhiyun return err;
2238*4882a593Smuzhiyun }
2239*4882a593Smuzhiyun wait_for_completion(&ctx->dev->fw_load_complete);
2240*4882a593Smuzhiyun if (ctx->blob)
2241*4882a593Smuzhiyun goto fw_ready;
2242*4882a593Smuzhiyun /* On some ARM systems, the async request will fail, but the next sync
2243*4882a593Smuzhiyun * request works. For this reason, we fall through here
2244*4882a593Smuzhiyun */
2245*4882a593Smuzhiyun }
2246*4882a593Smuzhiyun err = request_firmware(&ctx->blob, ctx->fwname,
2247*4882a593Smuzhiyun ctx->dev->dev->dev);
2248*4882a593Smuzhiyun if (err == -ENOENT) {
2249*4882a593Smuzhiyun snprintf(ctx->errors[ctx->req_type],
2250*4882a593Smuzhiyun sizeof(ctx->errors[ctx->req_type]),
2251*4882a593Smuzhiyun "Firmware file \"%s\" not found\n",
2252*4882a593Smuzhiyun ctx->fwname);
2253*4882a593Smuzhiyun return err;
2254*4882a593Smuzhiyun } else if (err) {
2255*4882a593Smuzhiyun snprintf(ctx->errors[ctx->req_type],
2256*4882a593Smuzhiyun sizeof(ctx->errors[ctx->req_type]),
2257*4882a593Smuzhiyun "Firmware file \"%s\" request failed (err=%d)\n",
2258*4882a593Smuzhiyun ctx->fwname, err);
2259*4882a593Smuzhiyun return err;
2260*4882a593Smuzhiyun }
2261*4882a593Smuzhiyun fw_ready:
2262*4882a593Smuzhiyun if (ctx->blob->size < sizeof(struct b43_fw_header))
2263*4882a593Smuzhiyun goto err_format;
2264*4882a593Smuzhiyun hdr = (struct b43_fw_header *)(ctx->blob->data);
2265*4882a593Smuzhiyun switch (hdr->type) {
2266*4882a593Smuzhiyun case B43_FW_TYPE_UCODE:
2267*4882a593Smuzhiyun case B43_FW_TYPE_PCM:
2268*4882a593Smuzhiyun size = be32_to_cpu(hdr->size);
2269*4882a593Smuzhiyun if (size != ctx->blob->size - sizeof(struct b43_fw_header))
2270*4882a593Smuzhiyun goto err_format;
2271*4882a593Smuzhiyun fallthrough;
2272*4882a593Smuzhiyun case B43_FW_TYPE_IV:
2273*4882a593Smuzhiyun if (hdr->ver != 1)
2274*4882a593Smuzhiyun goto err_format;
2275*4882a593Smuzhiyun break;
2276*4882a593Smuzhiyun default:
2277*4882a593Smuzhiyun goto err_format;
2278*4882a593Smuzhiyun }
2279*4882a593Smuzhiyun
2280*4882a593Smuzhiyun fw->data = ctx->blob;
2281*4882a593Smuzhiyun fw->filename = name;
2282*4882a593Smuzhiyun fw->type = ctx->req_type;
2283*4882a593Smuzhiyun
2284*4882a593Smuzhiyun return 0;
2285*4882a593Smuzhiyun
2286*4882a593Smuzhiyun err_format:
2287*4882a593Smuzhiyun snprintf(ctx->errors[ctx->req_type],
2288*4882a593Smuzhiyun sizeof(ctx->errors[ctx->req_type]),
2289*4882a593Smuzhiyun "Firmware file \"%s\" format error.\n", ctx->fwname);
2290*4882a593Smuzhiyun release_firmware(ctx->blob);
2291*4882a593Smuzhiyun
2292*4882a593Smuzhiyun return -EPROTO;
2293*4882a593Smuzhiyun }
2294*4882a593Smuzhiyun
2295*4882a593Smuzhiyun /* https://bcm-v4.sipsolutions.net/802.11/Init/Firmware */
b43_try_request_fw(struct b43_request_fw_context * ctx)2296*4882a593Smuzhiyun static int b43_try_request_fw(struct b43_request_fw_context *ctx)
2297*4882a593Smuzhiyun {
2298*4882a593Smuzhiyun struct b43_wldev *dev = ctx->dev;
2299*4882a593Smuzhiyun struct b43_firmware *fw = &ctx->dev->fw;
2300*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
2301*4882a593Smuzhiyun const u8 rev = ctx->dev->dev->core_rev;
2302*4882a593Smuzhiyun const char *filename;
2303*4882a593Smuzhiyun int err;
2304*4882a593Smuzhiyun
2305*4882a593Smuzhiyun /* Get microcode */
2306*4882a593Smuzhiyun filename = NULL;
2307*4882a593Smuzhiyun switch (rev) {
2308*4882a593Smuzhiyun case 42:
2309*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_AC)
2310*4882a593Smuzhiyun filename = "ucode42";
2311*4882a593Smuzhiyun break;
2312*4882a593Smuzhiyun case 40:
2313*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_AC)
2314*4882a593Smuzhiyun filename = "ucode40";
2315*4882a593Smuzhiyun break;
2316*4882a593Smuzhiyun case 33:
2317*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_LCN40)
2318*4882a593Smuzhiyun filename = "ucode33_lcn40";
2319*4882a593Smuzhiyun break;
2320*4882a593Smuzhiyun case 30:
2321*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_N)
2322*4882a593Smuzhiyun filename = "ucode30_mimo";
2323*4882a593Smuzhiyun break;
2324*4882a593Smuzhiyun case 29:
2325*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_HT)
2326*4882a593Smuzhiyun filename = "ucode29_mimo";
2327*4882a593Smuzhiyun break;
2328*4882a593Smuzhiyun case 26:
2329*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_HT)
2330*4882a593Smuzhiyun filename = "ucode26_mimo";
2331*4882a593Smuzhiyun break;
2332*4882a593Smuzhiyun case 28:
2333*4882a593Smuzhiyun case 25:
2334*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_N)
2335*4882a593Smuzhiyun filename = "ucode25_mimo";
2336*4882a593Smuzhiyun else if (phy->type == B43_PHYTYPE_LCN)
2337*4882a593Smuzhiyun filename = "ucode25_lcn";
2338*4882a593Smuzhiyun break;
2339*4882a593Smuzhiyun case 24:
2340*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_LCN)
2341*4882a593Smuzhiyun filename = "ucode24_lcn";
2342*4882a593Smuzhiyun break;
2343*4882a593Smuzhiyun case 23:
2344*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_N)
2345*4882a593Smuzhiyun filename = "ucode16_mimo";
2346*4882a593Smuzhiyun break;
2347*4882a593Smuzhiyun case 16 ... 19:
2348*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_N)
2349*4882a593Smuzhiyun filename = "ucode16_mimo";
2350*4882a593Smuzhiyun else if (phy->type == B43_PHYTYPE_LP)
2351*4882a593Smuzhiyun filename = "ucode16_lp";
2352*4882a593Smuzhiyun break;
2353*4882a593Smuzhiyun case 15:
2354*4882a593Smuzhiyun filename = "ucode15";
2355*4882a593Smuzhiyun break;
2356*4882a593Smuzhiyun case 14:
2357*4882a593Smuzhiyun filename = "ucode14";
2358*4882a593Smuzhiyun break;
2359*4882a593Smuzhiyun case 13:
2360*4882a593Smuzhiyun filename = "ucode13";
2361*4882a593Smuzhiyun break;
2362*4882a593Smuzhiyun case 11 ... 12:
2363*4882a593Smuzhiyun filename = "ucode11";
2364*4882a593Smuzhiyun break;
2365*4882a593Smuzhiyun case 5 ... 10:
2366*4882a593Smuzhiyun filename = "ucode5";
2367*4882a593Smuzhiyun break;
2368*4882a593Smuzhiyun }
2369*4882a593Smuzhiyun if (!filename)
2370*4882a593Smuzhiyun goto err_no_ucode;
2371*4882a593Smuzhiyun err = b43_do_request_fw(ctx, filename, &fw->ucode, true);
2372*4882a593Smuzhiyun if (err)
2373*4882a593Smuzhiyun goto err_load;
2374*4882a593Smuzhiyun
2375*4882a593Smuzhiyun /* Get PCM code */
2376*4882a593Smuzhiyun if ((rev >= 5) && (rev <= 10))
2377*4882a593Smuzhiyun filename = "pcm5";
2378*4882a593Smuzhiyun else if (rev >= 11)
2379*4882a593Smuzhiyun filename = NULL;
2380*4882a593Smuzhiyun else
2381*4882a593Smuzhiyun goto err_no_pcm;
2382*4882a593Smuzhiyun fw->pcm_request_failed = false;
2383*4882a593Smuzhiyun err = b43_do_request_fw(ctx, filename, &fw->pcm, false);
2384*4882a593Smuzhiyun if (err == -ENOENT) {
2385*4882a593Smuzhiyun /* We did not find a PCM file? Not fatal, but
2386*4882a593Smuzhiyun * core rev <= 10 must do without hwcrypto then. */
2387*4882a593Smuzhiyun fw->pcm_request_failed = true;
2388*4882a593Smuzhiyun } else if (err)
2389*4882a593Smuzhiyun goto err_load;
2390*4882a593Smuzhiyun
2391*4882a593Smuzhiyun /* Get initvals */
2392*4882a593Smuzhiyun filename = NULL;
2393*4882a593Smuzhiyun switch (dev->phy.type) {
2394*4882a593Smuzhiyun case B43_PHYTYPE_G:
2395*4882a593Smuzhiyun if (rev == 13)
2396*4882a593Smuzhiyun filename = "b0g0initvals13";
2397*4882a593Smuzhiyun else if (rev >= 5 && rev <= 10)
2398*4882a593Smuzhiyun filename = "b0g0initvals5";
2399*4882a593Smuzhiyun break;
2400*4882a593Smuzhiyun case B43_PHYTYPE_N:
2401*4882a593Smuzhiyun if (rev == 30)
2402*4882a593Smuzhiyun filename = "n16initvals30";
2403*4882a593Smuzhiyun else if (rev == 28 || rev == 25)
2404*4882a593Smuzhiyun filename = "n0initvals25";
2405*4882a593Smuzhiyun else if (rev == 24)
2406*4882a593Smuzhiyun filename = "n0initvals24";
2407*4882a593Smuzhiyun else if (rev == 23)
2408*4882a593Smuzhiyun filename = "n0initvals16"; /* What about n0initvals22? */
2409*4882a593Smuzhiyun else if (rev >= 16 && rev <= 18)
2410*4882a593Smuzhiyun filename = "n0initvals16";
2411*4882a593Smuzhiyun else if (rev >= 11 && rev <= 12)
2412*4882a593Smuzhiyun filename = "n0initvals11";
2413*4882a593Smuzhiyun break;
2414*4882a593Smuzhiyun case B43_PHYTYPE_LP:
2415*4882a593Smuzhiyun if (rev >= 16 && rev <= 18)
2416*4882a593Smuzhiyun filename = "lp0initvals16";
2417*4882a593Smuzhiyun else if (rev == 15)
2418*4882a593Smuzhiyun filename = "lp0initvals15";
2419*4882a593Smuzhiyun else if (rev == 14)
2420*4882a593Smuzhiyun filename = "lp0initvals14";
2421*4882a593Smuzhiyun else if (rev == 13)
2422*4882a593Smuzhiyun filename = "lp0initvals13";
2423*4882a593Smuzhiyun break;
2424*4882a593Smuzhiyun case B43_PHYTYPE_HT:
2425*4882a593Smuzhiyun if (rev == 29)
2426*4882a593Smuzhiyun filename = "ht0initvals29";
2427*4882a593Smuzhiyun else if (rev == 26)
2428*4882a593Smuzhiyun filename = "ht0initvals26";
2429*4882a593Smuzhiyun break;
2430*4882a593Smuzhiyun case B43_PHYTYPE_LCN:
2431*4882a593Smuzhiyun if (rev == 24)
2432*4882a593Smuzhiyun filename = "lcn0initvals24";
2433*4882a593Smuzhiyun break;
2434*4882a593Smuzhiyun case B43_PHYTYPE_LCN40:
2435*4882a593Smuzhiyun if (rev == 33)
2436*4882a593Smuzhiyun filename = "lcn400initvals33";
2437*4882a593Smuzhiyun break;
2438*4882a593Smuzhiyun case B43_PHYTYPE_AC:
2439*4882a593Smuzhiyun if (rev == 42)
2440*4882a593Smuzhiyun filename = "ac1initvals42";
2441*4882a593Smuzhiyun else if (rev == 40)
2442*4882a593Smuzhiyun filename = "ac0initvals40";
2443*4882a593Smuzhiyun break;
2444*4882a593Smuzhiyun }
2445*4882a593Smuzhiyun if (!filename)
2446*4882a593Smuzhiyun goto err_no_initvals;
2447*4882a593Smuzhiyun err = b43_do_request_fw(ctx, filename, &fw->initvals, false);
2448*4882a593Smuzhiyun if (err)
2449*4882a593Smuzhiyun goto err_load;
2450*4882a593Smuzhiyun
2451*4882a593Smuzhiyun /* Get bandswitch initvals */
2452*4882a593Smuzhiyun filename = NULL;
2453*4882a593Smuzhiyun switch (dev->phy.type) {
2454*4882a593Smuzhiyun case B43_PHYTYPE_G:
2455*4882a593Smuzhiyun if (rev == 13)
2456*4882a593Smuzhiyun filename = "b0g0bsinitvals13";
2457*4882a593Smuzhiyun else if (rev >= 5 && rev <= 10)
2458*4882a593Smuzhiyun filename = "b0g0bsinitvals5";
2459*4882a593Smuzhiyun break;
2460*4882a593Smuzhiyun case B43_PHYTYPE_N:
2461*4882a593Smuzhiyun if (rev == 30)
2462*4882a593Smuzhiyun filename = "n16bsinitvals30";
2463*4882a593Smuzhiyun else if (rev == 28 || rev == 25)
2464*4882a593Smuzhiyun filename = "n0bsinitvals25";
2465*4882a593Smuzhiyun else if (rev == 24)
2466*4882a593Smuzhiyun filename = "n0bsinitvals24";
2467*4882a593Smuzhiyun else if (rev == 23)
2468*4882a593Smuzhiyun filename = "n0bsinitvals16"; /* What about n0bsinitvals22? */
2469*4882a593Smuzhiyun else if (rev >= 16 && rev <= 18)
2470*4882a593Smuzhiyun filename = "n0bsinitvals16";
2471*4882a593Smuzhiyun else if (rev >= 11 && rev <= 12)
2472*4882a593Smuzhiyun filename = "n0bsinitvals11";
2473*4882a593Smuzhiyun break;
2474*4882a593Smuzhiyun case B43_PHYTYPE_LP:
2475*4882a593Smuzhiyun if (rev >= 16 && rev <= 18)
2476*4882a593Smuzhiyun filename = "lp0bsinitvals16";
2477*4882a593Smuzhiyun else if (rev == 15)
2478*4882a593Smuzhiyun filename = "lp0bsinitvals15";
2479*4882a593Smuzhiyun else if (rev == 14)
2480*4882a593Smuzhiyun filename = "lp0bsinitvals14";
2481*4882a593Smuzhiyun else if (rev == 13)
2482*4882a593Smuzhiyun filename = "lp0bsinitvals13";
2483*4882a593Smuzhiyun break;
2484*4882a593Smuzhiyun case B43_PHYTYPE_HT:
2485*4882a593Smuzhiyun if (rev == 29)
2486*4882a593Smuzhiyun filename = "ht0bsinitvals29";
2487*4882a593Smuzhiyun else if (rev == 26)
2488*4882a593Smuzhiyun filename = "ht0bsinitvals26";
2489*4882a593Smuzhiyun break;
2490*4882a593Smuzhiyun case B43_PHYTYPE_LCN:
2491*4882a593Smuzhiyun if (rev == 24)
2492*4882a593Smuzhiyun filename = "lcn0bsinitvals24";
2493*4882a593Smuzhiyun break;
2494*4882a593Smuzhiyun case B43_PHYTYPE_LCN40:
2495*4882a593Smuzhiyun if (rev == 33)
2496*4882a593Smuzhiyun filename = "lcn400bsinitvals33";
2497*4882a593Smuzhiyun break;
2498*4882a593Smuzhiyun case B43_PHYTYPE_AC:
2499*4882a593Smuzhiyun if (rev == 42)
2500*4882a593Smuzhiyun filename = "ac1bsinitvals42";
2501*4882a593Smuzhiyun else if (rev == 40)
2502*4882a593Smuzhiyun filename = "ac0bsinitvals40";
2503*4882a593Smuzhiyun break;
2504*4882a593Smuzhiyun }
2505*4882a593Smuzhiyun if (!filename)
2506*4882a593Smuzhiyun goto err_no_initvals;
2507*4882a593Smuzhiyun err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false);
2508*4882a593Smuzhiyun if (err)
2509*4882a593Smuzhiyun goto err_load;
2510*4882a593Smuzhiyun
2511*4882a593Smuzhiyun fw->opensource = (ctx->req_type == B43_FWTYPE_OPENSOURCE);
2512*4882a593Smuzhiyun
2513*4882a593Smuzhiyun return 0;
2514*4882a593Smuzhiyun
2515*4882a593Smuzhiyun err_no_ucode:
2516*4882a593Smuzhiyun err = ctx->fatal_failure = -EOPNOTSUPP;
2517*4882a593Smuzhiyun b43err(dev->wl, "The driver does not know which firmware (ucode) "
2518*4882a593Smuzhiyun "is required for your device (wl-core rev %u)\n", rev);
2519*4882a593Smuzhiyun goto error;
2520*4882a593Smuzhiyun
2521*4882a593Smuzhiyun err_no_pcm:
2522*4882a593Smuzhiyun err = ctx->fatal_failure = -EOPNOTSUPP;
2523*4882a593Smuzhiyun b43err(dev->wl, "The driver does not know which firmware (PCM) "
2524*4882a593Smuzhiyun "is required for your device (wl-core rev %u)\n", rev);
2525*4882a593Smuzhiyun goto error;
2526*4882a593Smuzhiyun
2527*4882a593Smuzhiyun err_no_initvals:
2528*4882a593Smuzhiyun err = ctx->fatal_failure = -EOPNOTSUPP;
2529*4882a593Smuzhiyun b43err(dev->wl, "The driver does not know which firmware (initvals) "
2530*4882a593Smuzhiyun "is required for your device (wl-core rev %u)\n", rev);
2531*4882a593Smuzhiyun goto error;
2532*4882a593Smuzhiyun
2533*4882a593Smuzhiyun err_load:
2534*4882a593Smuzhiyun /* We failed to load this firmware image. The error message
2535*4882a593Smuzhiyun * already is in ctx->errors. Return and let our caller decide
2536*4882a593Smuzhiyun * what to do. */
2537*4882a593Smuzhiyun goto error;
2538*4882a593Smuzhiyun
2539*4882a593Smuzhiyun error:
2540*4882a593Smuzhiyun b43_release_firmware(dev);
2541*4882a593Smuzhiyun return err;
2542*4882a593Smuzhiyun }
2543*4882a593Smuzhiyun
2544*4882a593Smuzhiyun static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl);
2545*4882a593Smuzhiyun static void b43_one_core_detach(struct b43_bus_dev *dev);
2546*4882a593Smuzhiyun static int b43_rng_init(struct b43_wl *wl);
2547*4882a593Smuzhiyun
b43_request_firmware(struct work_struct * work)2548*4882a593Smuzhiyun static void b43_request_firmware(struct work_struct *work)
2549*4882a593Smuzhiyun {
2550*4882a593Smuzhiyun struct b43_wl *wl = container_of(work,
2551*4882a593Smuzhiyun struct b43_wl, firmware_load);
2552*4882a593Smuzhiyun struct b43_wldev *dev = wl->current_dev;
2553*4882a593Smuzhiyun struct b43_request_fw_context *ctx;
2554*4882a593Smuzhiyun unsigned int i;
2555*4882a593Smuzhiyun int err;
2556*4882a593Smuzhiyun const char *errmsg;
2557*4882a593Smuzhiyun
2558*4882a593Smuzhiyun ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
2559*4882a593Smuzhiyun if (!ctx)
2560*4882a593Smuzhiyun return;
2561*4882a593Smuzhiyun ctx->dev = dev;
2562*4882a593Smuzhiyun
2563*4882a593Smuzhiyun ctx->req_type = B43_FWTYPE_PROPRIETARY;
2564*4882a593Smuzhiyun err = b43_try_request_fw(ctx);
2565*4882a593Smuzhiyun if (!err)
2566*4882a593Smuzhiyun goto start_ieee80211; /* Successfully loaded it. */
2567*4882a593Smuzhiyun /* Was fw version known? */
2568*4882a593Smuzhiyun if (ctx->fatal_failure)
2569*4882a593Smuzhiyun goto out;
2570*4882a593Smuzhiyun
2571*4882a593Smuzhiyun /* proprietary fw not found, try open source */
2572*4882a593Smuzhiyun ctx->req_type = B43_FWTYPE_OPENSOURCE;
2573*4882a593Smuzhiyun err = b43_try_request_fw(ctx);
2574*4882a593Smuzhiyun if (!err)
2575*4882a593Smuzhiyun goto start_ieee80211; /* Successfully loaded it. */
2576*4882a593Smuzhiyun if(ctx->fatal_failure)
2577*4882a593Smuzhiyun goto out;
2578*4882a593Smuzhiyun
2579*4882a593Smuzhiyun /* Could not find a usable firmware. Print the errors. */
2580*4882a593Smuzhiyun for (i = 0; i < B43_NR_FWTYPES; i++) {
2581*4882a593Smuzhiyun errmsg = ctx->errors[i];
2582*4882a593Smuzhiyun if (strlen(errmsg))
2583*4882a593Smuzhiyun b43err(dev->wl, "%s", errmsg);
2584*4882a593Smuzhiyun }
2585*4882a593Smuzhiyun b43_print_fw_helptext(dev->wl, 1);
2586*4882a593Smuzhiyun goto out;
2587*4882a593Smuzhiyun
2588*4882a593Smuzhiyun start_ieee80211:
2589*4882a593Smuzhiyun wl->hw->queues = B43_QOS_QUEUE_NUM;
2590*4882a593Smuzhiyun if (!modparam_qos || dev->fw.opensource)
2591*4882a593Smuzhiyun wl->hw->queues = 1;
2592*4882a593Smuzhiyun
2593*4882a593Smuzhiyun err = ieee80211_register_hw(wl->hw);
2594*4882a593Smuzhiyun if (err)
2595*4882a593Smuzhiyun goto out;
2596*4882a593Smuzhiyun wl->hw_registered = true;
2597*4882a593Smuzhiyun b43_leds_register(wl->current_dev);
2598*4882a593Smuzhiyun
2599*4882a593Smuzhiyun /* Register HW RNG driver */
2600*4882a593Smuzhiyun b43_rng_init(wl);
2601*4882a593Smuzhiyun
2602*4882a593Smuzhiyun out:
2603*4882a593Smuzhiyun kfree(ctx);
2604*4882a593Smuzhiyun }
2605*4882a593Smuzhiyun
b43_upload_microcode(struct b43_wldev * dev)2606*4882a593Smuzhiyun static int b43_upload_microcode(struct b43_wldev *dev)
2607*4882a593Smuzhiyun {
2608*4882a593Smuzhiyun struct wiphy *wiphy = dev->wl->hw->wiphy;
2609*4882a593Smuzhiyun const size_t hdr_len = sizeof(struct b43_fw_header);
2610*4882a593Smuzhiyun const __be32 *data;
2611*4882a593Smuzhiyun unsigned int i, len;
2612*4882a593Smuzhiyun u16 fwrev, fwpatch, fwdate, fwtime;
2613*4882a593Smuzhiyun u32 tmp, macctl;
2614*4882a593Smuzhiyun int err = 0;
2615*4882a593Smuzhiyun
2616*4882a593Smuzhiyun /* Jump the microcode PSM to offset 0 */
2617*4882a593Smuzhiyun macctl = b43_read32(dev, B43_MMIO_MACCTL);
2618*4882a593Smuzhiyun B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN);
2619*4882a593Smuzhiyun macctl |= B43_MACCTL_PSM_JMP0;
2620*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_MACCTL, macctl);
2621*4882a593Smuzhiyun /* Zero out all microcode PSM registers and shared memory. */
2622*4882a593Smuzhiyun for (i = 0; i < 64; i++)
2623*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0);
2624*4882a593Smuzhiyun for (i = 0; i < 4096; i += 2)
2625*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, i, 0);
2626*4882a593Smuzhiyun
2627*4882a593Smuzhiyun /* Upload Microcode. */
2628*4882a593Smuzhiyun data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
2629*4882a593Smuzhiyun len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
2630*4882a593Smuzhiyun b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
2631*4882a593Smuzhiyun for (i = 0; i < len; i++) {
2632*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
2633*4882a593Smuzhiyun udelay(10);
2634*4882a593Smuzhiyun }
2635*4882a593Smuzhiyun
2636*4882a593Smuzhiyun if (dev->fw.pcm.data) {
2637*4882a593Smuzhiyun /* Upload PCM data. */
2638*4882a593Smuzhiyun data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
2639*4882a593Smuzhiyun len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
2640*4882a593Smuzhiyun b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
2641*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
2642*4882a593Smuzhiyun /* No need for autoinc bit in SHM_HW */
2643*4882a593Smuzhiyun b43_shm_control_word(dev, B43_SHM_HW, 0x01EB);
2644*4882a593Smuzhiyun for (i = 0; i < len; i++) {
2645*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
2646*4882a593Smuzhiyun udelay(10);
2647*4882a593Smuzhiyun }
2648*4882a593Smuzhiyun }
2649*4882a593Smuzhiyun
2650*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
2651*4882a593Smuzhiyun
2652*4882a593Smuzhiyun /* Start the microcode PSM */
2653*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_PSM_JMP0,
2654*4882a593Smuzhiyun B43_MACCTL_PSM_RUN);
2655*4882a593Smuzhiyun
2656*4882a593Smuzhiyun /* Wait for the microcode to load and respond */
2657*4882a593Smuzhiyun i = 0;
2658*4882a593Smuzhiyun while (1) {
2659*4882a593Smuzhiyun tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2660*4882a593Smuzhiyun if (tmp == B43_IRQ_MAC_SUSPENDED)
2661*4882a593Smuzhiyun break;
2662*4882a593Smuzhiyun i++;
2663*4882a593Smuzhiyun if (i >= 20) {
2664*4882a593Smuzhiyun b43err(dev->wl, "Microcode not responding\n");
2665*4882a593Smuzhiyun b43_print_fw_helptext(dev->wl, 1);
2666*4882a593Smuzhiyun err = -ENODEV;
2667*4882a593Smuzhiyun goto error;
2668*4882a593Smuzhiyun }
2669*4882a593Smuzhiyun msleep(50);
2670*4882a593Smuzhiyun }
2671*4882a593Smuzhiyun b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */
2672*4882a593Smuzhiyun
2673*4882a593Smuzhiyun /* Get and check the revisions. */
2674*4882a593Smuzhiyun fwrev = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEREV);
2675*4882a593Smuzhiyun fwpatch = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEPATCH);
2676*4882a593Smuzhiyun fwdate = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEDATE);
2677*4882a593Smuzhiyun fwtime = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODETIME);
2678*4882a593Smuzhiyun
2679*4882a593Smuzhiyun if (fwrev <= 0x128) {
2680*4882a593Smuzhiyun b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
2681*4882a593Smuzhiyun "binary drivers older than version 4.x is unsupported. "
2682*4882a593Smuzhiyun "You must upgrade your firmware files.\n");
2683*4882a593Smuzhiyun b43_print_fw_helptext(dev->wl, 1);
2684*4882a593Smuzhiyun err = -EOPNOTSUPP;
2685*4882a593Smuzhiyun goto error;
2686*4882a593Smuzhiyun }
2687*4882a593Smuzhiyun dev->fw.rev = fwrev;
2688*4882a593Smuzhiyun dev->fw.patch = fwpatch;
2689*4882a593Smuzhiyun if (dev->fw.rev >= 598)
2690*4882a593Smuzhiyun dev->fw.hdr_format = B43_FW_HDR_598;
2691*4882a593Smuzhiyun else if (dev->fw.rev >= 410)
2692*4882a593Smuzhiyun dev->fw.hdr_format = B43_FW_HDR_410;
2693*4882a593Smuzhiyun else
2694*4882a593Smuzhiyun dev->fw.hdr_format = B43_FW_HDR_351;
2695*4882a593Smuzhiyun WARN_ON(dev->fw.opensource != (fwdate == 0xFFFF));
2696*4882a593Smuzhiyun
2697*4882a593Smuzhiyun dev->qos_enabled = dev->wl->hw->queues > 1;
2698*4882a593Smuzhiyun /* Default to firmware/hardware crypto acceleration. */
2699*4882a593Smuzhiyun dev->hwcrypto_enabled = true;
2700*4882a593Smuzhiyun
2701*4882a593Smuzhiyun if (dev->fw.opensource) {
2702*4882a593Smuzhiyun u16 fwcapa;
2703*4882a593Smuzhiyun
2704*4882a593Smuzhiyun /* Patchlevel info is encoded in the "time" field. */
2705*4882a593Smuzhiyun dev->fw.patch = fwtime;
2706*4882a593Smuzhiyun b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n",
2707*4882a593Smuzhiyun dev->fw.rev, dev->fw.patch);
2708*4882a593Smuzhiyun
2709*4882a593Smuzhiyun fwcapa = b43_fwcapa_read(dev);
2710*4882a593Smuzhiyun if (!(fwcapa & B43_FWCAPA_HWCRYPTO) || dev->fw.pcm_request_failed) {
2711*4882a593Smuzhiyun b43info(dev->wl, "Hardware crypto acceleration not supported by firmware\n");
2712*4882a593Smuzhiyun /* Disable hardware crypto and fall back to software crypto. */
2713*4882a593Smuzhiyun dev->hwcrypto_enabled = false;
2714*4882a593Smuzhiyun }
2715*4882a593Smuzhiyun /* adding QoS support should use an offline discovery mechanism */
2716*4882a593Smuzhiyun WARN(fwcapa & B43_FWCAPA_QOS, "QoS in OpenFW not supported\n");
2717*4882a593Smuzhiyun } else {
2718*4882a593Smuzhiyun b43info(dev->wl, "Loading firmware version %u.%u "
2719*4882a593Smuzhiyun "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
2720*4882a593Smuzhiyun fwrev, fwpatch,
2721*4882a593Smuzhiyun (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
2722*4882a593Smuzhiyun (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
2723*4882a593Smuzhiyun if (dev->fw.pcm_request_failed) {
2724*4882a593Smuzhiyun b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. "
2725*4882a593Smuzhiyun "Hardware accelerated cryptography is disabled.\n");
2726*4882a593Smuzhiyun b43_print_fw_helptext(dev->wl, 0);
2727*4882a593Smuzhiyun }
2728*4882a593Smuzhiyun }
2729*4882a593Smuzhiyun
2730*4882a593Smuzhiyun snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
2731*4882a593Smuzhiyun dev->fw.rev, dev->fw.patch);
2732*4882a593Smuzhiyun wiphy->hw_version = dev->dev->core_id;
2733*4882a593Smuzhiyun
2734*4882a593Smuzhiyun if (dev->fw.hdr_format == B43_FW_HDR_351) {
2735*4882a593Smuzhiyun /* We're over the deadline, but we keep support for old fw
2736*4882a593Smuzhiyun * until it turns out to be in major conflict with something new. */
2737*4882a593Smuzhiyun b43warn(dev->wl, "You are using an old firmware image. "
2738*4882a593Smuzhiyun "Support for old firmware will be removed soon "
2739*4882a593Smuzhiyun "(official deadline was July 2008).\n");
2740*4882a593Smuzhiyun b43_print_fw_helptext(dev->wl, 0);
2741*4882a593Smuzhiyun }
2742*4882a593Smuzhiyun
2743*4882a593Smuzhiyun return 0;
2744*4882a593Smuzhiyun
2745*4882a593Smuzhiyun error:
2746*4882a593Smuzhiyun /* Stop the microcode PSM. */
2747*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_PSM_RUN,
2748*4882a593Smuzhiyun B43_MACCTL_PSM_JMP0);
2749*4882a593Smuzhiyun
2750*4882a593Smuzhiyun return err;
2751*4882a593Smuzhiyun }
2752*4882a593Smuzhiyun
b43_write_initvals(struct b43_wldev * dev,const struct b43_iv * ivals,size_t count,size_t array_size)2753*4882a593Smuzhiyun static int b43_write_initvals(struct b43_wldev *dev,
2754*4882a593Smuzhiyun const struct b43_iv *ivals,
2755*4882a593Smuzhiyun size_t count,
2756*4882a593Smuzhiyun size_t array_size)
2757*4882a593Smuzhiyun {
2758*4882a593Smuzhiyun const struct b43_iv *iv;
2759*4882a593Smuzhiyun u16 offset;
2760*4882a593Smuzhiyun size_t i;
2761*4882a593Smuzhiyun bool bit32;
2762*4882a593Smuzhiyun
2763*4882a593Smuzhiyun BUILD_BUG_ON(sizeof(struct b43_iv) != 6);
2764*4882a593Smuzhiyun iv = ivals;
2765*4882a593Smuzhiyun for (i = 0; i < count; i++) {
2766*4882a593Smuzhiyun if (array_size < sizeof(iv->offset_size))
2767*4882a593Smuzhiyun goto err_format;
2768*4882a593Smuzhiyun array_size -= sizeof(iv->offset_size);
2769*4882a593Smuzhiyun offset = be16_to_cpu(iv->offset_size);
2770*4882a593Smuzhiyun bit32 = !!(offset & B43_IV_32BIT);
2771*4882a593Smuzhiyun offset &= B43_IV_OFFSET_MASK;
2772*4882a593Smuzhiyun if (offset >= 0x1000)
2773*4882a593Smuzhiyun goto err_format;
2774*4882a593Smuzhiyun if (bit32) {
2775*4882a593Smuzhiyun u32 value;
2776*4882a593Smuzhiyun
2777*4882a593Smuzhiyun if (array_size < sizeof(iv->data.d32))
2778*4882a593Smuzhiyun goto err_format;
2779*4882a593Smuzhiyun array_size -= sizeof(iv->data.d32);
2780*4882a593Smuzhiyun
2781*4882a593Smuzhiyun value = get_unaligned_be32(&iv->data.d32);
2782*4882a593Smuzhiyun b43_write32(dev, offset, value);
2783*4882a593Smuzhiyun
2784*4882a593Smuzhiyun iv = (const struct b43_iv *)((const uint8_t *)iv +
2785*4882a593Smuzhiyun sizeof(__be16) +
2786*4882a593Smuzhiyun sizeof(__be32));
2787*4882a593Smuzhiyun } else {
2788*4882a593Smuzhiyun u16 value;
2789*4882a593Smuzhiyun
2790*4882a593Smuzhiyun if (array_size < sizeof(iv->data.d16))
2791*4882a593Smuzhiyun goto err_format;
2792*4882a593Smuzhiyun array_size -= sizeof(iv->data.d16);
2793*4882a593Smuzhiyun
2794*4882a593Smuzhiyun value = be16_to_cpu(iv->data.d16);
2795*4882a593Smuzhiyun b43_write16(dev, offset, value);
2796*4882a593Smuzhiyun
2797*4882a593Smuzhiyun iv = (const struct b43_iv *)((const uint8_t *)iv +
2798*4882a593Smuzhiyun sizeof(__be16) +
2799*4882a593Smuzhiyun sizeof(__be16));
2800*4882a593Smuzhiyun }
2801*4882a593Smuzhiyun }
2802*4882a593Smuzhiyun if (array_size)
2803*4882a593Smuzhiyun goto err_format;
2804*4882a593Smuzhiyun
2805*4882a593Smuzhiyun return 0;
2806*4882a593Smuzhiyun
2807*4882a593Smuzhiyun err_format:
2808*4882a593Smuzhiyun b43err(dev->wl, "Initial Values Firmware file-format error.\n");
2809*4882a593Smuzhiyun b43_print_fw_helptext(dev->wl, 1);
2810*4882a593Smuzhiyun
2811*4882a593Smuzhiyun return -EPROTO;
2812*4882a593Smuzhiyun }
2813*4882a593Smuzhiyun
b43_upload_initvals(struct b43_wldev * dev)2814*4882a593Smuzhiyun static int b43_upload_initvals(struct b43_wldev *dev)
2815*4882a593Smuzhiyun {
2816*4882a593Smuzhiyun const size_t hdr_len = sizeof(struct b43_fw_header);
2817*4882a593Smuzhiyun const struct b43_fw_header *hdr;
2818*4882a593Smuzhiyun struct b43_firmware *fw = &dev->fw;
2819*4882a593Smuzhiyun const struct b43_iv *ivals;
2820*4882a593Smuzhiyun size_t count;
2821*4882a593Smuzhiyun
2822*4882a593Smuzhiyun hdr = (const struct b43_fw_header *)(fw->initvals.data->data);
2823*4882a593Smuzhiyun ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len);
2824*4882a593Smuzhiyun count = be32_to_cpu(hdr->size);
2825*4882a593Smuzhiyun return b43_write_initvals(dev, ivals, count,
2826*4882a593Smuzhiyun fw->initvals.data->size - hdr_len);
2827*4882a593Smuzhiyun }
2828*4882a593Smuzhiyun
b43_upload_initvals_band(struct b43_wldev * dev)2829*4882a593Smuzhiyun static int b43_upload_initvals_band(struct b43_wldev *dev)
2830*4882a593Smuzhiyun {
2831*4882a593Smuzhiyun const size_t hdr_len = sizeof(struct b43_fw_header);
2832*4882a593Smuzhiyun const struct b43_fw_header *hdr;
2833*4882a593Smuzhiyun struct b43_firmware *fw = &dev->fw;
2834*4882a593Smuzhiyun const struct b43_iv *ivals;
2835*4882a593Smuzhiyun size_t count;
2836*4882a593Smuzhiyun
2837*4882a593Smuzhiyun if (!fw->initvals_band.data)
2838*4882a593Smuzhiyun return 0;
2839*4882a593Smuzhiyun
2840*4882a593Smuzhiyun hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data);
2841*4882a593Smuzhiyun ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len);
2842*4882a593Smuzhiyun count = be32_to_cpu(hdr->size);
2843*4882a593Smuzhiyun return b43_write_initvals(dev, ivals, count,
2844*4882a593Smuzhiyun fw->initvals_band.data->size - hdr_len);
2845*4882a593Smuzhiyun }
2846*4882a593Smuzhiyun
2847*4882a593Smuzhiyun /* Initialize the GPIOs
2848*4882a593Smuzhiyun * https://bcm-specs.sipsolutions.net/GPIO
2849*4882a593Smuzhiyun */
2850*4882a593Smuzhiyun
2851*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
b43_ssb_gpio_dev(struct b43_wldev * dev)2852*4882a593Smuzhiyun static struct ssb_device *b43_ssb_gpio_dev(struct b43_wldev *dev)
2853*4882a593Smuzhiyun {
2854*4882a593Smuzhiyun struct ssb_bus *bus = dev->dev->sdev->bus;
2855*4882a593Smuzhiyun
2856*4882a593Smuzhiyun #ifdef CONFIG_SSB_DRIVER_PCICORE
2857*4882a593Smuzhiyun return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
2858*4882a593Smuzhiyun #else
2859*4882a593Smuzhiyun return bus->chipco.dev;
2860*4882a593Smuzhiyun #endif
2861*4882a593Smuzhiyun }
2862*4882a593Smuzhiyun #endif
2863*4882a593Smuzhiyun
b43_gpio_init(struct b43_wldev * dev)2864*4882a593Smuzhiyun static int b43_gpio_init(struct b43_wldev *dev)
2865*4882a593Smuzhiyun {
2866*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
2867*4882a593Smuzhiyun struct ssb_device *gpiodev;
2868*4882a593Smuzhiyun #endif
2869*4882a593Smuzhiyun u32 mask, set;
2870*4882a593Smuzhiyun
2871*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_GPOUTSMSK, 0);
2872*4882a593Smuzhiyun b43_maskset16(dev, B43_MMIO_GPIO_MASK, ~0, 0xF);
2873*4882a593Smuzhiyun
2874*4882a593Smuzhiyun mask = 0x0000001F;
2875*4882a593Smuzhiyun set = 0x0000000F;
2876*4882a593Smuzhiyun if (dev->dev->chip_id == 0x4301) {
2877*4882a593Smuzhiyun mask |= 0x0060;
2878*4882a593Smuzhiyun set |= 0x0060;
2879*4882a593Smuzhiyun } else if (dev->dev->chip_id == 0x5354) {
2880*4882a593Smuzhiyun /* Don't allow overtaking buttons GPIOs */
2881*4882a593Smuzhiyun set &= 0x2; /* 0x2 is LED GPIO on BCM5354 */
2882*4882a593Smuzhiyun }
2883*4882a593Smuzhiyun
2884*4882a593Smuzhiyun if (0 /* FIXME: conditional unknown */ ) {
2885*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_GPIO_MASK,
2886*4882a593Smuzhiyun b43_read16(dev, B43_MMIO_GPIO_MASK)
2887*4882a593Smuzhiyun | 0x0100);
2888*4882a593Smuzhiyun /* BT Coexistance Input */
2889*4882a593Smuzhiyun mask |= 0x0080;
2890*4882a593Smuzhiyun set |= 0x0080;
2891*4882a593Smuzhiyun /* BT Coexistance Out */
2892*4882a593Smuzhiyun mask |= 0x0100;
2893*4882a593Smuzhiyun set |= 0x0100;
2894*4882a593Smuzhiyun }
2895*4882a593Smuzhiyun if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL) {
2896*4882a593Smuzhiyun /* PA is controlled by gpio 9, let ucode handle it */
2897*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_GPIO_MASK,
2898*4882a593Smuzhiyun b43_read16(dev, B43_MMIO_GPIO_MASK)
2899*4882a593Smuzhiyun | 0x0200);
2900*4882a593Smuzhiyun mask |= 0x0200;
2901*4882a593Smuzhiyun set |= 0x0200;
2902*4882a593Smuzhiyun }
2903*4882a593Smuzhiyun
2904*4882a593Smuzhiyun switch (dev->dev->bus_type) {
2905*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
2906*4882a593Smuzhiyun case B43_BUS_BCMA:
2907*4882a593Smuzhiyun bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, mask, set);
2908*4882a593Smuzhiyun break;
2909*4882a593Smuzhiyun #endif
2910*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
2911*4882a593Smuzhiyun case B43_BUS_SSB:
2912*4882a593Smuzhiyun gpiodev = b43_ssb_gpio_dev(dev);
2913*4882a593Smuzhiyun if (gpiodev)
2914*4882a593Smuzhiyun ssb_write32(gpiodev, B43_GPIO_CONTROL,
2915*4882a593Smuzhiyun (ssb_read32(gpiodev, B43_GPIO_CONTROL)
2916*4882a593Smuzhiyun & ~mask) | set);
2917*4882a593Smuzhiyun break;
2918*4882a593Smuzhiyun #endif
2919*4882a593Smuzhiyun }
2920*4882a593Smuzhiyun
2921*4882a593Smuzhiyun return 0;
2922*4882a593Smuzhiyun }
2923*4882a593Smuzhiyun
2924*4882a593Smuzhiyun /* Turn off all GPIO stuff. Call this on module unload, for example. */
b43_gpio_cleanup(struct b43_wldev * dev)2925*4882a593Smuzhiyun static void b43_gpio_cleanup(struct b43_wldev *dev)
2926*4882a593Smuzhiyun {
2927*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
2928*4882a593Smuzhiyun struct ssb_device *gpiodev;
2929*4882a593Smuzhiyun #endif
2930*4882a593Smuzhiyun
2931*4882a593Smuzhiyun switch (dev->dev->bus_type) {
2932*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
2933*4882a593Smuzhiyun case B43_BUS_BCMA:
2934*4882a593Smuzhiyun bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, ~0, 0);
2935*4882a593Smuzhiyun break;
2936*4882a593Smuzhiyun #endif
2937*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
2938*4882a593Smuzhiyun case B43_BUS_SSB:
2939*4882a593Smuzhiyun gpiodev = b43_ssb_gpio_dev(dev);
2940*4882a593Smuzhiyun if (gpiodev)
2941*4882a593Smuzhiyun ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
2942*4882a593Smuzhiyun break;
2943*4882a593Smuzhiyun #endif
2944*4882a593Smuzhiyun }
2945*4882a593Smuzhiyun }
2946*4882a593Smuzhiyun
2947*4882a593Smuzhiyun /* http://bcm-specs.sipsolutions.net/EnableMac */
b43_mac_enable(struct b43_wldev * dev)2948*4882a593Smuzhiyun void b43_mac_enable(struct b43_wldev *dev)
2949*4882a593Smuzhiyun {
2950*4882a593Smuzhiyun if (b43_debug(dev, B43_DBG_FIRMWARE)) {
2951*4882a593Smuzhiyun u16 fwstate;
2952*4882a593Smuzhiyun
2953*4882a593Smuzhiyun fwstate = b43_shm_read16(dev, B43_SHM_SHARED,
2954*4882a593Smuzhiyun B43_SHM_SH_UCODESTAT);
2955*4882a593Smuzhiyun if ((fwstate != B43_SHM_SH_UCODESTAT_SUSP) &&
2956*4882a593Smuzhiyun (fwstate != B43_SHM_SH_UCODESTAT_SLEEP)) {
2957*4882a593Smuzhiyun b43err(dev->wl, "b43_mac_enable(): The firmware "
2958*4882a593Smuzhiyun "should be suspended, but current state is %u\n",
2959*4882a593Smuzhiyun fwstate);
2960*4882a593Smuzhiyun }
2961*4882a593Smuzhiyun }
2962*4882a593Smuzhiyun
2963*4882a593Smuzhiyun dev->mac_suspended--;
2964*4882a593Smuzhiyun B43_WARN_ON(dev->mac_suspended < 0);
2965*4882a593Smuzhiyun if (dev->mac_suspended == 0) {
2966*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~0, B43_MACCTL_ENABLED);
2967*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_GEN_IRQ_REASON,
2968*4882a593Smuzhiyun B43_IRQ_MAC_SUSPENDED);
2969*4882a593Smuzhiyun /* Commit writes */
2970*4882a593Smuzhiyun b43_read32(dev, B43_MMIO_MACCTL);
2971*4882a593Smuzhiyun b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2972*4882a593Smuzhiyun b43_power_saving_ctl_bits(dev, 0);
2973*4882a593Smuzhiyun }
2974*4882a593Smuzhiyun }
2975*4882a593Smuzhiyun
2976*4882a593Smuzhiyun /* https://bcm-specs.sipsolutions.net/SuspendMAC */
b43_mac_suspend(struct b43_wldev * dev)2977*4882a593Smuzhiyun void b43_mac_suspend(struct b43_wldev *dev)
2978*4882a593Smuzhiyun {
2979*4882a593Smuzhiyun int i;
2980*4882a593Smuzhiyun u32 tmp;
2981*4882a593Smuzhiyun
2982*4882a593Smuzhiyun might_sleep();
2983*4882a593Smuzhiyun B43_WARN_ON(dev->mac_suspended < 0);
2984*4882a593Smuzhiyun
2985*4882a593Smuzhiyun if (dev->mac_suspended == 0) {
2986*4882a593Smuzhiyun b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
2987*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_ENABLED, 0);
2988*4882a593Smuzhiyun /* force pci to flush the write */
2989*4882a593Smuzhiyun b43_read32(dev, B43_MMIO_MACCTL);
2990*4882a593Smuzhiyun for (i = 35; i; i--) {
2991*4882a593Smuzhiyun tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2992*4882a593Smuzhiyun if (tmp & B43_IRQ_MAC_SUSPENDED)
2993*4882a593Smuzhiyun goto out;
2994*4882a593Smuzhiyun udelay(10);
2995*4882a593Smuzhiyun }
2996*4882a593Smuzhiyun /* Hm, it seems this will take some time. Use msleep(). */
2997*4882a593Smuzhiyun for (i = 40; i; i--) {
2998*4882a593Smuzhiyun tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2999*4882a593Smuzhiyun if (tmp & B43_IRQ_MAC_SUSPENDED)
3000*4882a593Smuzhiyun goto out;
3001*4882a593Smuzhiyun msleep(1);
3002*4882a593Smuzhiyun }
3003*4882a593Smuzhiyun b43err(dev->wl, "MAC suspend failed\n");
3004*4882a593Smuzhiyun }
3005*4882a593Smuzhiyun out:
3006*4882a593Smuzhiyun dev->mac_suspended++;
3007*4882a593Smuzhiyun }
3008*4882a593Smuzhiyun
3009*4882a593Smuzhiyun /* https://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
b43_mac_phy_clock_set(struct b43_wldev * dev,bool on)3010*4882a593Smuzhiyun void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on)
3011*4882a593Smuzhiyun {
3012*4882a593Smuzhiyun u32 tmp;
3013*4882a593Smuzhiyun
3014*4882a593Smuzhiyun switch (dev->dev->bus_type) {
3015*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
3016*4882a593Smuzhiyun case B43_BUS_BCMA:
3017*4882a593Smuzhiyun tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
3018*4882a593Smuzhiyun if (on)
3019*4882a593Smuzhiyun tmp |= B43_BCMA_IOCTL_MACPHYCLKEN;
3020*4882a593Smuzhiyun else
3021*4882a593Smuzhiyun tmp &= ~B43_BCMA_IOCTL_MACPHYCLKEN;
3022*4882a593Smuzhiyun bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
3023*4882a593Smuzhiyun break;
3024*4882a593Smuzhiyun #endif
3025*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
3026*4882a593Smuzhiyun case B43_BUS_SSB:
3027*4882a593Smuzhiyun tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
3028*4882a593Smuzhiyun if (on)
3029*4882a593Smuzhiyun tmp |= B43_TMSLOW_MACPHYCLKEN;
3030*4882a593Smuzhiyun else
3031*4882a593Smuzhiyun tmp &= ~B43_TMSLOW_MACPHYCLKEN;
3032*4882a593Smuzhiyun ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
3033*4882a593Smuzhiyun break;
3034*4882a593Smuzhiyun #endif
3035*4882a593Smuzhiyun }
3036*4882a593Smuzhiyun }
3037*4882a593Smuzhiyun
3038*4882a593Smuzhiyun /* brcms_b_switch_macfreq */
b43_mac_switch_freq(struct b43_wldev * dev,u8 spurmode)3039*4882a593Smuzhiyun void b43_mac_switch_freq(struct b43_wldev *dev, u8 spurmode)
3040*4882a593Smuzhiyun {
3041*4882a593Smuzhiyun u16 chip_id = dev->dev->chip_id;
3042*4882a593Smuzhiyun
3043*4882a593Smuzhiyun if (chip_id == BCMA_CHIP_ID_BCM4331) {
3044*4882a593Smuzhiyun switch (spurmode) {
3045*4882a593Smuzhiyun case 2: /* 168 Mhz: 2^26/168 = 0x61862 */
3046*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x1862);
3047*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
3048*4882a593Smuzhiyun break;
3049*4882a593Smuzhiyun case 1: /* 164 Mhz: 2^26/164 = 0x63e70 */
3050*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x3e70);
3051*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
3052*4882a593Smuzhiyun break;
3053*4882a593Smuzhiyun default: /* 160 Mhz: 2^26/160 = 0x66666 */
3054*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x6666);
3055*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
3056*4882a593Smuzhiyun break;
3057*4882a593Smuzhiyun }
3058*4882a593Smuzhiyun } else if (chip_id == BCMA_CHIP_ID_BCM43131 ||
3059*4882a593Smuzhiyun chip_id == BCMA_CHIP_ID_BCM43217 ||
3060*4882a593Smuzhiyun chip_id == BCMA_CHIP_ID_BCM43222 ||
3061*4882a593Smuzhiyun chip_id == BCMA_CHIP_ID_BCM43224 ||
3062*4882a593Smuzhiyun chip_id == BCMA_CHIP_ID_BCM43225 ||
3063*4882a593Smuzhiyun chip_id == BCMA_CHIP_ID_BCM43227 ||
3064*4882a593Smuzhiyun chip_id == BCMA_CHIP_ID_BCM43228) {
3065*4882a593Smuzhiyun switch (spurmode) {
3066*4882a593Smuzhiyun case 2: /* 126 Mhz */
3067*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x2082);
3068*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
3069*4882a593Smuzhiyun break;
3070*4882a593Smuzhiyun case 1: /* 123 Mhz */
3071*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x5341);
3072*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
3073*4882a593Smuzhiyun break;
3074*4882a593Smuzhiyun default: /* 120 Mhz */
3075*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x8889);
3076*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
3077*4882a593Smuzhiyun break;
3078*4882a593Smuzhiyun }
3079*4882a593Smuzhiyun } else if (dev->phy.type == B43_PHYTYPE_LCN) {
3080*4882a593Smuzhiyun switch (spurmode) {
3081*4882a593Smuzhiyun case 1: /* 82 Mhz */
3082*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x7CE0);
3083*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
3084*4882a593Smuzhiyun break;
3085*4882a593Smuzhiyun default: /* 80 Mhz */
3086*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0xCCCD);
3087*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
3088*4882a593Smuzhiyun break;
3089*4882a593Smuzhiyun }
3090*4882a593Smuzhiyun }
3091*4882a593Smuzhiyun }
3092*4882a593Smuzhiyun
b43_adjust_opmode(struct b43_wldev * dev)3093*4882a593Smuzhiyun static void b43_adjust_opmode(struct b43_wldev *dev)
3094*4882a593Smuzhiyun {
3095*4882a593Smuzhiyun struct b43_wl *wl = dev->wl;
3096*4882a593Smuzhiyun u32 ctl;
3097*4882a593Smuzhiyun u16 cfp_pretbtt;
3098*4882a593Smuzhiyun
3099*4882a593Smuzhiyun ctl = b43_read32(dev, B43_MMIO_MACCTL);
3100*4882a593Smuzhiyun /* Reset status to STA infrastructure mode. */
3101*4882a593Smuzhiyun ctl &= ~B43_MACCTL_AP;
3102*4882a593Smuzhiyun ctl &= ~B43_MACCTL_KEEP_CTL;
3103*4882a593Smuzhiyun ctl &= ~B43_MACCTL_KEEP_BADPLCP;
3104*4882a593Smuzhiyun ctl &= ~B43_MACCTL_KEEP_BAD;
3105*4882a593Smuzhiyun ctl &= ~B43_MACCTL_PROMISC;
3106*4882a593Smuzhiyun ctl &= ~B43_MACCTL_BEACPROMISC;
3107*4882a593Smuzhiyun ctl |= B43_MACCTL_INFRA;
3108*4882a593Smuzhiyun
3109*4882a593Smuzhiyun if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
3110*4882a593Smuzhiyun b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
3111*4882a593Smuzhiyun ctl |= B43_MACCTL_AP;
3112*4882a593Smuzhiyun else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC))
3113*4882a593Smuzhiyun ctl &= ~B43_MACCTL_INFRA;
3114*4882a593Smuzhiyun
3115*4882a593Smuzhiyun if (wl->filter_flags & FIF_CONTROL)
3116*4882a593Smuzhiyun ctl |= B43_MACCTL_KEEP_CTL;
3117*4882a593Smuzhiyun if (wl->filter_flags & FIF_FCSFAIL)
3118*4882a593Smuzhiyun ctl |= B43_MACCTL_KEEP_BAD;
3119*4882a593Smuzhiyun if (wl->filter_flags & FIF_PLCPFAIL)
3120*4882a593Smuzhiyun ctl |= B43_MACCTL_KEEP_BADPLCP;
3121*4882a593Smuzhiyun if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
3122*4882a593Smuzhiyun ctl |= B43_MACCTL_BEACPROMISC;
3123*4882a593Smuzhiyun
3124*4882a593Smuzhiyun /* Workaround: On old hardware the HW-MAC-address-filter
3125*4882a593Smuzhiyun * doesn't work properly, so always run promisc in filter
3126*4882a593Smuzhiyun * it in software. */
3127*4882a593Smuzhiyun if (dev->dev->core_rev <= 4)
3128*4882a593Smuzhiyun ctl |= B43_MACCTL_PROMISC;
3129*4882a593Smuzhiyun
3130*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_MACCTL, ctl);
3131*4882a593Smuzhiyun
3132*4882a593Smuzhiyun cfp_pretbtt = 2;
3133*4882a593Smuzhiyun if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
3134*4882a593Smuzhiyun if (dev->dev->chip_id == 0x4306 &&
3135*4882a593Smuzhiyun dev->dev->chip_rev == 3)
3136*4882a593Smuzhiyun cfp_pretbtt = 100;
3137*4882a593Smuzhiyun else
3138*4882a593Smuzhiyun cfp_pretbtt = 50;
3139*4882a593Smuzhiyun }
3140*4882a593Smuzhiyun b43_write16(dev, 0x612, cfp_pretbtt);
3141*4882a593Smuzhiyun
3142*4882a593Smuzhiyun /* FIXME: We don't currently implement the PMQ mechanism,
3143*4882a593Smuzhiyun * so always disable it. If we want to implement PMQ,
3144*4882a593Smuzhiyun * we need to enable it here (clear DISCPMQ) in AP mode.
3145*4882a593Smuzhiyun */
3146*4882a593Smuzhiyun if (0 /* ctl & B43_MACCTL_AP */)
3147*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_DISCPMQ, 0);
3148*4882a593Smuzhiyun else
3149*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~0, B43_MACCTL_DISCPMQ);
3150*4882a593Smuzhiyun }
3151*4882a593Smuzhiyun
b43_rate_memory_write(struct b43_wldev * dev,u16 rate,int is_ofdm)3152*4882a593Smuzhiyun static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm)
3153*4882a593Smuzhiyun {
3154*4882a593Smuzhiyun u16 offset;
3155*4882a593Smuzhiyun
3156*4882a593Smuzhiyun if (is_ofdm) {
3157*4882a593Smuzhiyun offset = 0x480;
3158*4882a593Smuzhiyun offset += (b43_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
3159*4882a593Smuzhiyun } else {
3160*4882a593Smuzhiyun offset = 0x4C0;
3161*4882a593Smuzhiyun offset += (b43_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
3162*4882a593Smuzhiyun }
3163*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, offset + 0x20,
3164*4882a593Smuzhiyun b43_shm_read16(dev, B43_SHM_SHARED, offset));
3165*4882a593Smuzhiyun }
3166*4882a593Smuzhiyun
b43_rate_memory_init(struct b43_wldev * dev)3167*4882a593Smuzhiyun static void b43_rate_memory_init(struct b43_wldev *dev)
3168*4882a593Smuzhiyun {
3169*4882a593Smuzhiyun switch (dev->phy.type) {
3170*4882a593Smuzhiyun case B43_PHYTYPE_G:
3171*4882a593Smuzhiyun case B43_PHYTYPE_N:
3172*4882a593Smuzhiyun case B43_PHYTYPE_LP:
3173*4882a593Smuzhiyun case B43_PHYTYPE_HT:
3174*4882a593Smuzhiyun case B43_PHYTYPE_LCN:
3175*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
3176*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_OFDM_RATE_9MB, 1);
3177*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
3178*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
3179*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1);
3180*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_OFDM_RATE_36MB, 1);
3181*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_OFDM_RATE_48MB, 1);
3182*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_OFDM_RATE_54MB, 1);
3183*4882a593Smuzhiyun fallthrough;
3184*4882a593Smuzhiyun case B43_PHYTYPE_B:
3185*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_CCK_RATE_1MB, 0);
3186*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_CCK_RATE_2MB, 0);
3187*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_CCK_RATE_5MB, 0);
3188*4882a593Smuzhiyun b43_rate_memory_write(dev, B43_CCK_RATE_11MB, 0);
3189*4882a593Smuzhiyun break;
3190*4882a593Smuzhiyun default:
3191*4882a593Smuzhiyun B43_WARN_ON(1);
3192*4882a593Smuzhiyun }
3193*4882a593Smuzhiyun }
3194*4882a593Smuzhiyun
3195*4882a593Smuzhiyun /* Set the default values for the PHY TX Control Words. */
b43_set_phytxctl_defaults(struct b43_wldev * dev)3196*4882a593Smuzhiyun static void b43_set_phytxctl_defaults(struct b43_wldev *dev)
3197*4882a593Smuzhiyun {
3198*4882a593Smuzhiyun u16 ctl = 0;
3199*4882a593Smuzhiyun
3200*4882a593Smuzhiyun ctl |= B43_TXH_PHY_ENC_CCK;
3201*4882a593Smuzhiyun ctl |= B43_TXH_PHY_ANT01AUTO;
3202*4882a593Smuzhiyun ctl |= B43_TXH_PHY_TXPWR;
3203*4882a593Smuzhiyun
3204*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);
3205*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, ctl);
3206*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, ctl);
3207*4882a593Smuzhiyun }
3208*4882a593Smuzhiyun
3209*4882a593Smuzhiyun /* Set the TX-Antenna for management frames sent by firmware. */
b43_mgmtframe_txantenna(struct b43_wldev * dev,int antenna)3210*4882a593Smuzhiyun static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
3211*4882a593Smuzhiyun {
3212*4882a593Smuzhiyun u16 ant;
3213*4882a593Smuzhiyun u16 tmp;
3214*4882a593Smuzhiyun
3215*4882a593Smuzhiyun ant = b43_antenna_to_phyctl(antenna);
3216*4882a593Smuzhiyun
3217*4882a593Smuzhiyun /* For ACK/CTS */
3218*4882a593Smuzhiyun tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
3219*4882a593Smuzhiyun tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
3220*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
3221*4882a593Smuzhiyun /* For Probe Resposes */
3222*4882a593Smuzhiyun tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
3223*4882a593Smuzhiyun tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
3224*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
3225*4882a593Smuzhiyun }
3226*4882a593Smuzhiyun
3227*4882a593Smuzhiyun /* This is the opposite of b43_chip_init() */
b43_chip_exit(struct b43_wldev * dev)3228*4882a593Smuzhiyun static void b43_chip_exit(struct b43_wldev *dev)
3229*4882a593Smuzhiyun {
3230*4882a593Smuzhiyun b43_phy_exit(dev);
3231*4882a593Smuzhiyun b43_gpio_cleanup(dev);
3232*4882a593Smuzhiyun /* firmware is released later */
3233*4882a593Smuzhiyun }
3234*4882a593Smuzhiyun
3235*4882a593Smuzhiyun /* Initialize the chip
3236*4882a593Smuzhiyun * https://bcm-specs.sipsolutions.net/ChipInit
3237*4882a593Smuzhiyun */
b43_chip_init(struct b43_wldev * dev)3238*4882a593Smuzhiyun static int b43_chip_init(struct b43_wldev *dev)
3239*4882a593Smuzhiyun {
3240*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
3241*4882a593Smuzhiyun int err;
3242*4882a593Smuzhiyun u32 macctl;
3243*4882a593Smuzhiyun u16 value16;
3244*4882a593Smuzhiyun
3245*4882a593Smuzhiyun /* Initialize the MAC control */
3246*4882a593Smuzhiyun macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED;
3247*4882a593Smuzhiyun if (dev->phy.gmode)
3248*4882a593Smuzhiyun macctl |= B43_MACCTL_GMODE;
3249*4882a593Smuzhiyun macctl |= B43_MACCTL_INFRA;
3250*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_MACCTL, macctl);
3251*4882a593Smuzhiyun
3252*4882a593Smuzhiyun err = b43_upload_microcode(dev);
3253*4882a593Smuzhiyun if (err)
3254*4882a593Smuzhiyun goto out; /* firmware is released later */
3255*4882a593Smuzhiyun
3256*4882a593Smuzhiyun err = b43_gpio_init(dev);
3257*4882a593Smuzhiyun if (err)
3258*4882a593Smuzhiyun goto out; /* firmware is released later */
3259*4882a593Smuzhiyun
3260*4882a593Smuzhiyun err = b43_upload_initvals(dev);
3261*4882a593Smuzhiyun if (err)
3262*4882a593Smuzhiyun goto err_gpio_clean;
3263*4882a593Smuzhiyun
3264*4882a593Smuzhiyun err = b43_upload_initvals_band(dev);
3265*4882a593Smuzhiyun if (err)
3266*4882a593Smuzhiyun goto err_gpio_clean;
3267*4882a593Smuzhiyun
3268*4882a593Smuzhiyun /* Turn the Analog on and initialize the PHY. */
3269*4882a593Smuzhiyun phy->ops->switch_analog(dev, 1);
3270*4882a593Smuzhiyun err = b43_phy_init(dev);
3271*4882a593Smuzhiyun if (err)
3272*4882a593Smuzhiyun goto err_gpio_clean;
3273*4882a593Smuzhiyun
3274*4882a593Smuzhiyun /* Disable Interference Mitigation. */
3275*4882a593Smuzhiyun if (phy->ops->interf_mitigation)
3276*4882a593Smuzhiyun phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
3277*4882a593Smuzhiyun
3278*4882a593Smuzhiyun /* Select the antennae */
3279*4882a593Smuzhiyun if (phy->ops->set_rx_antenna)
3280*4882a593Smuzhiyun phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
3281*4882a593Smuzhiyun b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
3282*4882a593Smuzhiyun
3283*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_B) {
3284*4882a593Smuzhiyun value16 = b43_read16(dev, 0x005E);
3285*4882a593Smuzhiyun value16 |= 0x0004;
3286*4882a593Smuzhiyun b43_write16(dev, 0x005E, value16);
3287*4882a593Smuzhiyun }
3288*4882a593Smuzhiyun b43_write32(dev, 0x0100, 0x01000000);
3289*4882a593Smuzhiyun if (dev->dev->core_rev < 5)
3290*4882a593Smuzhiyun b43_write32(dev, 0x010C, 0x01000000);
3291*4882a593Smuzhiyun
3292*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_INFRA, 0);
3293*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~0, B43_MACCTL_INFRA);
3294*4882a593Smuzhiyun
3295*4882a593Smuzhiyun /* Probe Response Timeout value */
3296*4882a593Smuzhiyun /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
3297*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 0);
3298*4882a593Smuzhiyun
3299*4882a593Smuzhiyun /* Initially set the wireless operation mode. */
3300*4882a593Smuzhiyun b43_adjust_opmode(dev);
3301*4882a593Smuzhiyun
3302*4882a593Smuzhiyun if (dev->dev->core_rev < 3) {
3303*4882a593Smuzhiyun b43_write16(dev, 0x060E, 0x0000);
3304*4882a593Smuzhiyun b43_write16(dev, 0x0610, 0x8000);
3305*4882a593Smuzhiyun b43_write16(dev, 0x0604, 0x0000);
3306*4882a593Smuzhiyun b43_write16(dev, 0x0606, 0x0200);
3307*4882a593Smuzhiyun } else {
3308*4882a593Smuzhiyun b43_write32(dev, 0x0188, 0x80000000);
3309*4882a593Smuzhiyun b43_write32(dev, 0x018C, 0x02000000);
3310*4882a593Smuzhiyun }
3311*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, 0x00004000);
3312*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001FC00);
3313*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
3314*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
3315*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
3316*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
3317*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
3318*4882a593Smuzhiyun
3319*4882a593Smuzhiyun b43_mac_phy_clock_set(dev, true);
3320*4882a593Smuzhiyun
3321*4882a593Smuzhiyun switch (dev->dev->bus_type) {
3322*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
3323*4882a593Smuzhiyun case B43_BUS_BCMA:
3324*4882a593Smuzhiyun /* FIXME: 0xE74 is quite common, but should be read from CC */
3325*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_POWERUP_DELAY, 0xE74);
3326*4882a593Smuzhiyun break;
3327*4882a593Smuzhiyun #endif
3328*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
3329*4882a593Smuzhiyun case B43_BUS_SSB:
3330*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_POWERUP_DELAY,
3331*4882a593Smuzhiyun dev->dev->sdev->bus->chipco.fast_pwrup_delay);
3332*4882a593Smuzhiyun break;
3333*4882a593Smuzhiyun #endif
3334*4882a593Smuzhiyun }
3335*4882a593Smuzhiyun
3336*4882a593Smuzhiyun err = 0;
3337*4882a593Smuzhiyun b43dbg(dev->wl, "Chip initialized\n");
3338*4882a593Smuzhiyun out:
3339*4882a593Smuzhiyun return err;
3340*4882a593Smuzhiyun
3341*4882a593Smuzhiyun err_gpio_clean:
3342*4882a593Smuzhiyun b43_gpio_cleanup(dev);
3343*4882a593Smuzhiyun return err;
3344*4882a593Smuzhiyun }
3345*4882a593Smuzhiyun
b43_periodic_every60sec(struct b43_wldev * dev)3346*4882a593Smuzhiyun static void b43_periodic_every60sec(struct b43_wldev *dev)
3347*4882a593Smuzhiyun {
3348*4882a593Smuzhiyun const struct b43_phy_operations *ops = dev->phy.ops;
3349*4882a593Smuzhiyun
3350*4882a593Smuzhiyun if (ops->pwork_60sec)
3351*4882a593Smuzhiyun ops->pwork_60sec(dev);
3352*4882a593Smuzhiyun
3353*4882a593Smuzhiyun /* Force check the TX power emission now. */
3354*4882a593Smuzhiyun b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME);
3355*4882a593Smuzhiyun }
3356*4882a593Smuzhiyun
b43_periodic_every30sec(struct b43_wldev * dev)3357*4882a593Smuzhiyun static void b43_periodic_every30sec(struct b43_wldev *dev)
3358*4882a593Smuzhiyun {
3359*4882a593Smuzhiyun /* Update device statistics. */
3360*4882a593Smuzhiyun b43_calculate_link_quality(dev);
3361*4882a593Smuzhiyun }
3362*4882a593Smuzhiyun
b43_periodic_every15sec(struct b43_wldev * dev)3363*4882a593Smuzhiyun static void b43_periodic_every15sec(struct b43_wldev *dev)
3364*4882a593Smuzhiyun {
3365*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
3366*4882a593Smuzhiyun u16 wdr;
3367*4882a593Smuzhiyun
3368*4882a593Smuzhiyun if (dev->fw.opensource) {
3369*4882a593Smuzhiyun /* Check if the firmware is still alive.
3370*4882a593Smuzhiyun * It will reset the watchdog counter to 0 in its idle loop. */
3371*4882a593Smuzhiyun wdr = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_WATCHDOG_REG);
3372*4882a593Smuzhiyun if (unlikely(wdr)) {
3373*4882a593Smuzhiyun b43err(dev->wl, "Firmware watchdog: The firmware died!\n");
3374*4882a593Smuzhiyun b43_controller_restart(dev, "Firmware watchdog");
3375*4882a593Smuzhiyun return;
3376*4882a593Smuzhiyun } else {
3377*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SCRATCH,
3378*4882a593Smuzhiyun B43_WATCHDOG_REG, 1);
3379*4882a593Smuzhiyun }
3380*4882a593Smuzhiyun }
3381*4882a593Smuzhiyun
3382*4882a593Smuzhiyun if (phy->ops->pwork_15sec)
3383*4882a593Smuzhiyun phy->ops->pwork_15sec(dev);
3384*4882a593Smuzhiyun
3385*4882a593Smuzhiyun atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
3386*4882a593Smuzhiyun wmb();
3387*4882a593Smuzhiyun
3388*4882a593Smuzhiyun #if B43_DEBUG
3389*4882a593Smuzhiyun if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
3390*4882a593Smuzhiyun unsigned int i;
3391*4882a593Smuzhiyun
3392*4882a593Smuzhiyun b43dbg(dev->wl, "Stats: %7u IRQs/sec, %7u TX/sec, %7u RX/sec\n",
3393*4882a593Smuzhiyun dev->irq_count / 15,
3394*4882a593Smuzhiyun dev->tx_count / 15,
3395*4882a593Smuzhiyun dev->rx_count / 15);
3396*4882a593Smuzhiyun dev->irq_count = 0;
3397*4882a593Smuzhiyun dev->tx_count = 0;
3398*4882a593Smuzhiyun dev->rx_count = 0;
3399*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
3400*4882a593Smuzhiyun if (dev->irq_bit_count[i]) {
3401*4882a593Smuzhiyun b43dbg(dev->wl, "Stats: %7u IRQ-%02u/sec (0x%08X)\n",
3402*4882a593Smuzhiyun dev->irq_bit_count[i] / 15, i, (1 << i));
3403*4882a593Smuzhiyun dev->irq_bit_count[i] = 0;
3404*4882a593Smuzhiyun }
3405*4882a593Smuzhiyun }
3406*4882a593Smuzhiyun }
3407*4882a593Smuzhiyun #endif
3408*4882a593Smuzhiyun }
3409*4882a593Smuzhiyun
do_periodic_work(struct b43_wldev * dev)3410*4882a593Smuzhiyun static void do_periodic_work(struct b43_wldev *dev)
3411*4882a593Smuzhiyun {
3412*4882a593Smuzhiyun unsigned int state;
3413*4882a593Smuzhiyun
3414*4882a593Smuzhiyun state = dev->periodic_state;
3415*4882a593Smuzhiyun if (state % 4 == 0)
3416*4882a593Smuzhiyun b43_periodic_every60sec(dev);
3417*4882a593Smuzhiyun if (state % 2 == 0)
3418*4882a593Smuzhiyun b43_periodic_every30sec(dev);
3419*4882a593Smuzhiyun b43_periodic_every15sec(dev);
3420*4882a593Smuzhiyun }
3421*4882a593Smuzhiyun
3422*4882a593Smuzhiyun /* Periodic work locking policy:
3423*4882a593Smuzhiyun * The whole periodic work handler is protected by
3424*4882a593Smuzhiyun * wl->mutex. If another lock is needed somewhere in the
3425*4882a593Smuzhiyun * pwork callchain, it's acquired in-place, where it's needed.
3426*4882a593Smuzhiyun */
b43_periodic_work_handler(struct work_struct * work)3427*4882a593Smuzhiyun static void b43_periodic_work_handler(struct work_struct *work)
3428*4882a593Smuzhiyun {
3429*4882a593Smuzhiyun struct b43_wldev *dev = container_of(work, struct b43_wldev,
3430*4882a593Smuzhiyun periodic_work.work);
3431*4882a593Smuzhiyun struct b43_wl *wl = dev->wl;
3432*4882a593Smuzhiyun unsigned long delay;
3433*4882a593Smuzhiyun
3434*4882a593Smuzhiyun mutex_lock(&wl->mutex);
3435*4882a593Smuzhiyun
3436*4882a593Smuzhiyun if (unlikely(b43_status(dev) != B43_STAT_STARTED))
3437*4882a593Smuzhiyun goto out;
3438*4882a593Smuzhiyun if (b43_debug(dev, B43_DBG_PWORK_STOP))
3439*4882a593Smuzhiyun goto out_requeue;
3440*4882a593Smuzhiyun
3441*4882a593Smuzhiyun do_periodic_work(dev);
3442*4882a593Smuzhiyun
3443*4882a593Smuzhiyun dev->periodic_state++;
3444*4882a593Smuzhiyun out_requeue:
3445*4882a593Smuzhiyun if (b43_debug(dev, B43_DBG_PWORK_FAST))
3446*4882a593Smuzhiyun delay = msecs_to_jiffies(50);
3447*4882a593Smuzhiyun else
3448*4882a593Smuzhiyun delay = round_jiffies_relative(HZ * 15);
3449*4882a593Smuzhiyun ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay);
3450*4882a593Smuzhiyun out:
3451*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
3452*4882a593Smuzhiyun }
3453*4882a593Smuzhiyun
b43_periodic_tasks_setup(struct b43_wldev * dev)3454*4882a593Smuzhiyun static void b43_periodic_tasks_setup(struct b43_wldev *dev)
3455*4882a593Smuzhiyun {
3456*4882a593Smuzhiyun struct delayed_work *work = &dev->periodic_work;
3457*4882a593Smuzhiyun
3458*4882a593Smuzhiyun dev->periodic_state = 0;
3459*4882a593Smuzhiyun INIT_DELAYED_WORK(work, b43_periodic_work_handler);
3460*4882a593Smuzhiyun ieee80211_queue_delayed_work(dev->wl->hw, work, 0);
3461*4882a593Smuzhiyun }
3462*4882a593Smuzhiyun
3463*4882a593Smuzhiyun /* Check if communication with the device works correctly. */
b43_validate_chipaccess(struct b43_wldev * dev)3464*4882a593Smuzhiyun static int b43_validate_chipaccess(struct b43_wldev *dev)
3465*4882a593Smuzhiyun {
3466*4882a593Smuzhiyun u32 v, backup0, backup4;
3467*4882a593Smuzhiyun
3468*4882a593Smuzhiyun backup0 = b43_shm_read32(dev, B43_SHM_SHARED, 0);
3469*4882a593Smuzhiyun backup4 = b43_shm_read32(dev, B43_SHM_SHARED, 4);
3470*4882a593Smuzhiyun
3471*4882a593Smuzhiyun /* Check for read/write and endianness problems. */
3472*4882a593Smuzhiyun b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
3473*4882a593Smuzhiyun if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55)
3474*4882a593Smuzhiyun goto error;
3475*4882a593Smuzhiyun b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
3476*4882a593Smuzhiyun if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
3477*4882a593Smuzhiyun goto error;
3478*4882a593Smuzhiyun
3479*4882a593Smuzhiyun /* Check if unaligned 32bit SHM_SHARED access works properly.
3480*4882a593Smuzhiyun * However, don't bail out on failure, because it's noncritical. */
3481*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, 0, 0x1122);
3482*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, 2, 0x3344);
3483*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, 4, 0x5566);
3484*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, 6, 0x7788);
3485*4882a593Smuzhiyun if (b43_shm_read32(dev, B43_SHM_SHARED, 2) != 0x55663344)
3486*4882a593Smuzhiyun b43warn(dev->wl, "Unaligned 32bit SHM read access is broken\n");
3487*4882a593Smuzhiyun b43_shm_write32(dev, B43_SHM_SHARED, 2, 0xAABBCCDD);
3488*4882a593Smuzhiyun if (b43_shm_read16(dev, B43_SHM_SHARED, 0) != 0x1122 ||
3489*4882a593Smuzhiyun b43_shm_read16(dev, B43_SHM_SHARED, 2) != 0xCCDD ||
3490*4882a593Smuzhiyun b43_shm_read16(dev, B43_SHM_SHARED, 4) != 0xAABB ||
3491*4882a593Smuzhiyun b43_shm_read16(dev, B43_SHM_SHARED, 6) != 0x7788)
3492*4882a593Smuzhiyun b43warn(dev->wl, "Unaligned 32bit SHM write access is broken\n");
3493*4882a593Smuzhiyun
3494*4882a593Smuzhiyun b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0);
3495*4882a593Smuzhiyun b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4);
3496*4882a593Smuzhiyun
3497*4882a593Smuzhiyun if ((dev->dev->core_rev >= 3) && (dev->dev->core_rev <= 10)) {
3498*4882a593Smuzhiyun /* The 32bit register shadows the two 16bit registers
3499*4882a593Smuzhiyun * with update sideeffects. Validate this. */
3500*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
3501*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_TSF_CFP_START, 0xCCCCBBBB);
3502*4882a593Smuzhiyun if (b43_read16(dev, B43_MMIO_TSF_CFP_START_LOW) != 0xBBBB)
3503*4882a593Smuzhiyun goto error;
3504*4882a593Smuzhiyun if (b43_read16(dev, B43_MMIO_TSF_CFP_START_HIGH) != 0xCCCC)
3505*4882a593Smuzhiyun goto error;
3506*4882a593Smuzhiyun }
3507*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_TSF_CFP_START, 0);
3508*4882a593Smuzhiyun
3509*4882a593Smuzhiyun v = b43_read32(dev, B43_MMIO_MACCTL);
3510*4882a593Smuzhiyun v |= B43_MACCTL_GMODE;
3511*4882a593Smuzhiyun if (v != (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
3512*4882a593Smuzhiyun goto error;
3513*4882a593Smuzhiyun
3514*4882a593Smuzhiyun return 0;
3515*4882a593Smuzhiyun error:
3516*4882a593Smuzhiyun b43err(dev->wl, "Failed to validate the chipaccess\n");
3517*4882a593Smuzhiyun return -ENODEV;
3518*4882a593Smuzhiyun }
3519*4882a593Smuzhiyun
b43_security_init(struct b43_wldev * dev)3520*4882a593Smuzhiyun static void b43_security_init(struct b43_wldev *dev)
3521*4882a593Smuzhiyun {
3522*4882a593Smuzhiyun dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP);
3523*4882a593Smuzhiyun /* KTP is a word address, but we address SHM bytewise.
3524*4882a593Smuzhiyun * So multiply by two.
3525*4882a593Smuzhiyun */
3526*4882a593Smuzhiyun dev->ktp *= 2;
3527*4882a593Smuzhiyun /* Number of RCMTA address slots */
3528*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_RCMTA_COUNT, B43_NR_PAIRWISE_KEYS);
3529*4882a593Smuzhiyun /* Clear the key memory. */
3530*4882a593Smuzhiyun b43_clear_keys(dev);
3531*4882a593Smuzhiyun }
3532*4882a593Smuzhiyun
3533*4882a593Smuzhiyun #ifdef CONFIG_B43_HWRNG
b43_rng_read(struct hwrng * rng,u32 * data)3534*4882a593Smuzhiyun static int b43_rng_read(struct hwrng *rng, u32 *data)
3535*4882a593Smuzhiyun {
3536*4882a593Smuzhiyun struct b43_wl *wl = (struct b43_wl *)rng->priv;
3537*4882a593Smuzhiyun struct b43_wldev *dev;
3538*4882a593Smuzhiyun int count = -ENODEV;
3539*4882a593Smuzhiyun
3540*4882a593Smuzhiyun mutex_lock(&wl->mutex);
3541*4882a593Smuzhiyun dev = wl->current_dev;
3542*4882a593Smuzhiyun if (likely(dev && b43_status(dev) >= B43_STAT_INITIALIZED)) {
3543*4882a593Smuzhiyun *data = b43_read16(dev, B43_MMIO_RNG);
3544*4882a593Smuzhiyun count = sizeof(u16);
3545*4882a593Smuzhiyun }
3546*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
3547*4882a593Smuzhiyun
3548*4882a593Smuzhiyun return count;
3549*4882a593Smuzhiyun }
3550*4882a593Smuzhiyun #endif /* CONFIG_B43_HWRNG */
3551*4882a593Smuzhiyun
b43_rng_exit(struct b43_wl * wl)3552*4882a593Smuzhiyun static void b43_rng_exit(struct b43_wl *wl)
3553*4882a593Smuzhiyun {
3554*4882a593Smuzhiyun #ifdef CONFIG_B43_HWRNG
3555*4882a593Smuzhiyun if (wl->rng_initialized)
3556*4882a593Smuzhiyun hwrng_unregister(&wl->rng);
3557*4882a593Smuzhiyun #endif /* CONFIG_B43_HWRNG */
3558*4882a593Smuzhiyun }
3559*4882a593Smuzhiyun
b43_rng_init(struct b43_wl * wl)3560*4882a593Smuzhiyun static int b43_rng_init(struct b43_wl *wl)
3561*4882a593Smuzhiyun {
3562*4882a593Smuzhiyun int err = 0;
3563*4882a593Smuzhiyun
3564*4882a593Smuzhiyun #ifdef CONFIG_B43_HWRNG
3565*4882a593Smuzhiyun snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
3566*4882a593Smuzhiyun "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
3567*4882a593Smuzhiyun wl->rng.name = wl->rng_name;
3568*4882a593Smuzhiyun wl->rng.data_read = b43_rng_read;
3569*4882a593Smuzhiyun wl->rng.priv = (unsigned long)wl;
3570*4882a593Smuzhiyun wl->rng_initialized = true;
3571*4882a593Smuzhiyun err = hwrng_register(&wl->rng);
3572*4882a593Smuzhiyun if (err) {
3573*4882a593Smuzhiyun wl->rng_initialized = false;
3574*4882a593Smuzhiyun b43err(wl, "Failed to register the random "
3575*4882a593Smuzhiyun "number generator (%d)\n", err);
3576*4882a593Smuzhiyun }
3577*4882a593Smuzhiyun #endif /* CONFIG_B43_HWRNG */
3578*4882a593Smuzhiyun
3579*4882a593Smuzhiyun return err;
3580*4882a593Smuzhiyun }
3581*4882a593Smuzhiyun
b43_tx_work(struct work_struct * work)3582*4882a593Smuzhiyun static void b43_tx_work(struct work_struct *work)
3583*4882a593Smuzhiyun {
3584*4882a593Smuzhiyun struct b43_wl *wl = container_of(work, struct b43_wl, tx_work);
3585*4882a593Smuzhiyun struct b43_wldev *dev;
3586*4882a593Smuzhiyun struct sk_buff *skb;
3587*4882a593Smuzhiyun int queue_num;
3588*4882a593Smuzhiyun int err = 0;
3589*4882a593Smuzhiyun
3590*4882a593Smuzhiyun mutex_lock(&wl->mutex);
3591*4882a593Smuzhiyun dev = wl->current_dev;
3592*4882a593Smuzhiyun if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED)) {
3593*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
3594*4882a593Smuzhiyun return;
3595*4882a593Smuzhiyun }
3596*4882a593Smuzhiyun
3597*4882a593Smuzhiyun for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) {
3598*4882a593Smuzhiyun while (skb_queue_len(&wl->tx_queue[queue_num])) {
3599*4882a593Smuzhiyun skb = skb_dequeue(&wl->tx_queue[queue_num]);
3600*4882a593Smuzhiyun if (b43_using_pio_transfers(dev))
3601*4882a593Smuzhiyun err = b43_pio_tx(dev, skb);
3602*4882a593Smuzhiyun else
3603*4882a593Smuzhiyun err = b43_dma_tx(dev, skb);
3604*4882a593Smuzhiyun if (err == -ENOSPC) {
3605*4882a593Smuzhiyun wl->tx_queue_stopped[queue_num] = true;
3606*4882a593Smuzhiyun ieee80211_stop_queue(wl->hw, queue_num);
3607*4882a593Smuzhiyun skb_queue_head(&wl->tx_queue[queue_num], skb);
3608*4882a593Smuzhiyun break;
3609*4882a593Smuzhiyun }
3610*4882a593Smuzhiyun if (unlikely(err))
3611*4882a593Smuzhiyun ieee80211_free_txskb(wl->hw, skb);
3612*4882a593Smuzhiyun err = 0;
3613*4882a593Smuzhiyun }
3614*4882a593Smuzhiyun
3615*4882a593Smuzhiyun if (!err)
3616*4882a593Smuzhiyun wl->tx_queue_stopped[queue_num] = false;
3617*4882a593Smuzhiyun }
3618*4882a593Smuzhiyun
3619*4882a593Smuzhiyun #if B43_DEBUG
3620*4882a593Smuzhiyun dev->tx_count++;
3621*4882a593Smuzhiyun #endif
3622*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
3623*4882a593Smuzhiyun }
3624*4882a593Smuzhiyun
b43_op_tx(struct ieee80211_hw * hw,struct ieee80211_tx_control * control,struct sk_buff * skb)3625*4882a593Smuzhiyun static void b43_op_tx(struct ieee80211_hw *hw,
3626*4882a593Smuzhiyun struct ieee80211_tx_control *control,
3627*4882a593Smuzhiyun struct sk_buff *skb)
3628*4882a593Smuzhiyun {
3629*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
3630*4882a593Smuzhiyun
3631*4882a593Smuzhiyun if (unlikely(skb->len < 2 + 2 + 6)) {
3632*4882a593Smuzhiyun /* Too short, this can't be a valid frame. */
3633*4882a593Smuzhiyun ieee80211_free_txskb(hw, skb);
3634*4882a593Smuzhiyun return;
3635*4882a593Smuzhiyun }
3636*4882a593Smuzhiyun B43_WARN_ON(skb_shinfo(skb)->nr_frags);
3637*4882a593Smuzhiyun
3638*4882a593Smuzhiyun skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb);
3639*4882a593Smuzhiyun if (!wl->tx_queue_stopped[skb->queue_mapping]) {
3640*4882a593Smuzhiyun ieee80211_queue_work(wl->hw, &wl->tx_work);
3641*4882a593Smuzhiyun } else {
3642*4882a593Smuzhiyun ieee80211_stop_queue(wl->hw, skb->queue_mapping);
3643*4882a593Smuzhiyun }
3644*4882a593Smuzhiyun }
3645*4882a593Smuzhiyun
b43_qos_params_upload(struct b43_wldev * dev,const struct ieee80211_tx_queue_params * p,u16 shm_offset)3646*4882a593Smuzhiyun static void b43_qos_params_upload(struct b43_wldev *dev,
3647*4882a593Smuzhiyun const struct ieee80211_tx_queue_params *p,
3648*4882a593Smuzhiyun u16 shm_offset)
3649*4882a593Smuzhiyun {
3650*4882a593Smuzhiyun u16 params[B43_NR_QOSPARAMS];
3651*4882a593Smuzhiyun int bslots, tmp;
3652*4882a593Smuzhiyun unsigned int i;
3653*4882a593Smuzhiyun
3654*4882a593Smuzhiyun if (!dev->qos_enabled)
3655*4882a593Smuzhiyun return;
3656*4882a593Smuzhiyun
3657*4882a593Smuzhiyun bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min;
3658*4882a593Smuzhiyun
3659*4882a593Smuzhiyun memset(¶ms, 0, sizeof(params));
3660*4882a593Smuzhiyun
3661*4882a593Smuzhiyun params[B43_QOSPARAM_TXOP] = p->txop * 32;
3662*4882a593Smuzhiyun params[B43_QOSPARAM_CWMIN] = p->cw_min;
3663*4882a593Smuzhiyun params[B43_QOSPARAM_CWMAX] = p->cw_max;
3664*4882a593Smuzhiyun params[B43_QOSPARAM_CWCUR] = p->cw_min;
3665*4882a593Smuzhiyun params[B43_QOSPARAM_AIFS] = p->aifs;
3666*4882a593Smuzhiyun params[B43_QOSPARAM_BSLOTS] = bslots;
3667*4882a593Smuzhiyun params[B43_QOSPARAM_REGGAP] = bslots + p->aifs;
3668*4882a593Smuzhiyun
3669*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(params); i++) {
3670*4882a593Smuzhiyun if (i == B43_QOSPARAM_STATUS) {
3671*4882a593Smuzhiyun tmp = b43_shm_read16(dev, B43_SHM_SHARED,
3672*4882a593Smuzhiyun shm_offset + (i * 2));
3673*4882a593Smuzhiyun /* Mark the parameters as updated. */
3674*4882a593Smuzhiyun tmp |= 0x100;
3675*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED,
3676*4882a593Smuzhiyun shm_offset + (i * 2),
3677*4882a593Smuzhiyun tmp);
3678*4882a593Smuzhiyun } else {
3679*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED,
3680*4882a593Smuzhiyun shm_offset + (i * 2),
3681*4882a593Smuzhiyun params[i]);
3682*4882a593Smuzhiyun }
3683*4882a593Smuzhiyun }
3684*4882a593Smuzhiyun }
3685*4882a593Smuzhiyun
3686*4882a593Smuzhiyun /* Mapping of mac80211 queue numbers to b43 QoS SHM offsets. */
3687*4882a593Smuzhiyun static const u16 b43_qos_shm_offsets[] = {
3688*4882a593Smuzhiyun /* [mac80211-queue-nr] = SHM_OFFSET, */
3689*4882a593Smuzhiyun [0] = B43_QOS_VOICE,
3690*4882a593Smuzhiyun [1] = B43_QOS_VIDEO,
3691*4882a593Smuzhiyun [2] = B43_QOS_BESTEFFORT,
3692*4882a593Smuzhiyun [3] = B43_QOS_BACKGROUND,
3693*4882a593Smuzhiyun };
3694*4882a593Smuzhiyun
3695*4882a593Smuzhiyun /* Update all QOS parameters in hardware. */
b43_qos_upload_all(struct b43_wldev * dev)3696*4882a593Smuzhiyun static void b43_qos_upload_all(struct b43_wldev *dev)
3697*4882a593Smuzhiyun {
3698*4882a593Smuzhiyun struct b43_wl *wl = dev->wl;
3699*4882a593Smuzhiyun struct b43_qos_params *params;
3700*4882a593Smuzhiyun unsigned int i;
3701*4882a593Smuzhiyun
3702*4882a593Smuzhiyun if (!dev->qos_enabled)
3703*4882a593Smuzhiyun return;
3704*4882a593Smuzhiyun
3705*4882a593Smuzhiyun BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
3706*4882a593Smuzhiyun ARRAY_SIZE(wl->qos_params));
3707*4882a593Smuzhiyun
3708*4882a593Smuzhiyun b43_mac_suspend(dev);
3709*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
3710*4882a593Smuzhiyun params = &(wl->qos_params[i]);
3711*4882a593Smuzhiyun b43_qos_params_upload(dev, &(params->p),
3712*4882a593Smuzhiyun b43_qos_shm_offsets[i]);
3713*4882a593Smuzhiyun }
3714*4882a593Smuzhiyun b43_mac_enable(dev);
3715*4882a593Smuzhiyun }
3716*4882a593Smuzhiyun
b43_qos_clear(struct b43_wl * wl)3717*4882a593Smuzhiyun static void b43_qos_clear(struct b43_wl *wl)
3718*4882a593Smuzhiyun {
3719*4882a593Smuzhiyun struct b43_qos_params *params;
3720*4882a593Smuzhiyun unsigned int i;
3721*4882a593Smuzhiyun
3722*4882a593Smuzhiyun /* Initialize QoS parameters to sane defaults. */
3723*4882a593Smuzhiyun
3724*4882a593Smuzhiyun BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
3725*4882a593Smuzhiyun ARRAY_SIZE(wl->qos_params));
3726*4882a593Smuzhiyun
3727*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
3728*4882a593Smuzhiyun params = &(wl->qos_params[i]);
3729*4882a593Smuzhiyun
3730*4882a593Smuzhiyun switch (b43_qos_shm_offsets[i]) {
3731*4882a593Smuzhiyun case B43_QOS_VOICE:
3732*4882a593Smuzhiyun params->p.txop = 0;
3733*4882a593Smuzhiyun params->p.aifs = 2;
3734*4882a593Smuzhiyun params->p.cw_min = 0x0001;
3735*4882a593Smuzhiyun params->p.cw_max = 0x0001;
3736*4882a593Smuzhiyun break;
3737*4882a593Smuzhiyun case B43_QOS_VIDEO:
3738*4882a593Smuzhiyun params->p.txop = 0;
3739*4882a593Smuzhiyun params->p.aifs = 2;
3740*4882a593Smuzhiyun params->p.cw_min = 0x0001;
3741*4882a593Smuzhiyun params->p.cw_max = 0x0001;
3742*4882a593Smuzhiyun break;
3743*4882a593Smuzhiyun case B43_QOS_BESTEFFORT:
3744*4882a593Smuzhiyun params->p.txop = 0;
3745*4882a593Smuzhiyun params->p.aifs = 3;
3746*4882a593Smuzhiyun params->p.cw_min = 0x0001;
3747*4882a593Smuzhiyun params->p.cw_max = 0x03FF;
3748*4882a593Smuzhiyun break;
3749*4882a593Smuzhiyun case B43_QOS_BACKGROUND:
3750*4882a593Smuzhiyun params->p.txop = 0;
3751*4882a593Smuzhiyun params->p.aifs = 7;
3752*4882a593Smuzhiyun params->p.cw_min = 0x0001;
3753*4882a593Smuzhiyun params->p.cw_max = 0x03FF;
3754*4882a593Smuzhiyun break;
3755*4882a593Smuzhiyun default:
3756*4882a593Smuzhiyun B43_WARN_ON(1);
3757*4882a593Smuzhiyun }
3758*4882a593Smuzhiyun }
3759*4882a593Smuzhiyun }
3760*4882a593Smuzhiyun
3761*4882a593Smuzhiyun /* Initialize the core's QOS capabilities */
b43_qos_init(struct b43_wldev * dev)3762*4882a593Smuzhiyun static void b43_qos_init(struct b43_wldev *dev)
3763*4882a593Smuzhiyun {
3764*4882a593Smuzhiyun if (!dev->qos_enabled) {
3765*4882a593Smuzhiyun /* Disable QOS support. */
3766*4882a593Smuzhiyun b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_EDCF);
3767*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_IFSCTL,
3768*4882a593Smuzhiyun b43_read16(dev, B43_MMIO_IFSCTL)
3769*4882a593Smuzhiyun & ~B43_MMIO_IFSCTL_USE_EDCF);
3770*4882a593Smuzhiyun b43dbg(dev->wl, "QoS disabled\n");
3771*4882a593Smuzhiyun return;
3772*4882a593Smuzhiyun }
3773*4882a593Smuzhiyun
3774*4882a593Smuzhiyun /* Upload the current QOS parameters. */
3775*4882a593Smuzhiyun b43_qos_upload_all(dev);
3776*4882a593Smuzhiyun
3777*4882a593Smuzhiyun /* Enable QOS support. */
3778*4882a593Smuzhiyun b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
3779*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_IFSCTL,
3780*4882a593Smuzhiyun b43_read16(dev, B43_MMIO_IFSCTL)
3781*4882a593Smuzhiyun | B43_MMIO_IFSCTL_USE_EDCF);
3782*4882a593Smuzhiyun b43dbg(dev->wl, "QoS enabled\n");
3783*4882a593Smuzhiyun }
3784*4882a593Smuzhiyun
b43_op_conf_tx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,u16 _queue,const struct ieee80211_tx_queue_params * params)3785*4882a593Smuzhiyun static int b43_op_conf_tx(struct ieee80211_hw *hw,
3786*4882a593Smuzhiyun struct ieee80211_vif *vif, u16 _queue,
3787*4882a593Smuzhiyun const struct ieee80211_tx_queue_params *params)
3788*4882a593Smuzhiyun {
3789*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
3790*4882a593Smuzhiyun struct b43_wldev *dev;
3791*4882a593Smuzhiyun unsigned int queue = (unsigned int)_queue;
3792*4882a593Smuzhiyun int err = -ENODEV;
3793*4882a593Smuzhiyun
3794*4882a593Smuzhiyun if (queue >= ARRAY_SIZE(wl->qos_params)) {
3795*4882a593Smuzhiyun /* Queue not available or don't support setting
3796*4882a593Smuzhiyun * params on this queue. Return success to not
3797*4882a593Smuzhiyun * confuse mac80211. */
3798*4882a593Smuzhiyun return 0;
3799*4882a593Smuzhiyun }
3800*4882a593Smuzhiyun BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
3801*4882a593Smuzhiyun ARRAY_SIZE(wl->qos_params));
3802*4882a593Smuzhiyun
3803*4882a593Smuzhiyun mutex_lock(&wl->mutex);
3804*4882a593Smuzhiyun dev = wl->current_dev;
3805*4882a593Smuzhiyun if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED)))
3806*4882a593Smuzhiyun goto out_unlock;
3807*4882a593Smuzhiyun
3808*4882a593Smuzhiyun memcpy(&(wl->qos_params[queue].p), params, sizeof(*params));
3809*4882a593Smuzhiyun b43_mac_suspend(dev);
3810*4882a593Smuzhiyun b43_qos_params_upload(dev, &(wl->qos_params[queue].p),
3811*4882a593Smuzhiyun b43_qos_shm_offsets[queue]);
3812*4882a593Smuzhiyun b43_mac_enable(dev);
3813*4882a593Smuzhiyun err = 0;
3814*4882a593Smuzhiyun
3815*4882a593Smuzhiyun out_unlock:
3816*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
3817*4882a593Smuzhiyun
3818*4882a593Smuzhiyun return err;
3819*4882a593Smuzhiyun }
3820*4882a593Smuzhiyun
b43_op_get_stats(struct ieee80211_hw * hw,struct ieee80211_low_level_stats * stats)3821*4882a593Smuzhiyun static int b43_op_get_stats(struct ieee80211_hw *hw,
3822*4882a593Smuzhiyun struct ieee80211_low_level_stats *stats)
3823*4882a593Smuzhiyun {
3824*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
3825*4882a593Smuzhiyun
3826*4882a593Smuzhiyun mutex_lock(&wl->mutex);
3827*4882a593Smuzhiyun memcpy(stats, &wl->ieee_stats, sizeof(*stats));
3828*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
3829*4882a593Smuzhiyun
3830*4882a593Smuzhiyun return 0;
3831*4882a593Smuzhiyun }
3832*4882a593Smuzhiyun
b43_op_get_tsf(struct ieee80211_hw * hw,struct ieee80211_vif * vif)3833*4882a593Smuzhiyun static u64 b43_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
3834*4882a593Smuzhiyun {
3835*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
3836*4882a593Smuzhiyun struct b43_wldev *dev;
3837*4882a593Smuzhiyun u64 tsf;
3838*4882a593Smuzhiyun
3839*4882a593Smuzhiyun mutex_lock(&wl->mutex);
3840*4882a593Smuzhiyun dev = wl->current_dev;
3841*4882a593Smuzhiyun
3842*4882a593Smuzhiyun if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED))
3843*4882a593Smuzhiyun b43_tsf_read(dev, &tsf);
3844*4882a593Smuzhiyun else
3845*4882a593Smuzhiyun tsf = 0;
3846*4882a593Smuzhiyun
3847*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
3848*4882a593Smuzhiyun
3849*4882a593Smuzhiyun return tsf;
3850*4882a593Smuzhiyun }
3851*4882a593Smuzhiyun
b43_op_set_tsf(struct ieee80211_hw * hw,struct ieee80211_vif * vif,u64 tsf)3852*4882a593Smuzhiyun static void b43_op_set_tsf(struct ieee80211_hw *hw,
3853*4882a593Smuzhiyun struct ieee80211_vif *vif, u64 tsf)
3854*4882a593Smuzhiyun {
3855*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
3856*4882a593Smuzhiyun struct b43_wldev *dev;
3857*4882a593Smuzhiyun
3858*4882a593Smuzhiyun mutex_lock(&wl->mutex);
3859*4882a593Smuzhiyun dev = wl->current_dev;
3860*4882a593Smuzhiyun
3861*4882a593Smuzhiyun if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED))
3862*4882a593Smuzhiyun b43_tsf_write(dev, tsf);
3863*4882a593Smuzhiyun
3864*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
3865*4882a593Smuzhiyun }
3866*4882a593Smuzhiyun
band_to_string(enum nl80211_band band)3867*4882a593Smuzhiyun static const char *band_to_string(enum nl80211_band band)
3868*4882a593Smuzhiyun {
3869*4882a593Smuzhiyun switch (band) {
3870*4882a593Smuzhiyun case NL80211_BAND_5GHZ:
3871*4882a593Smuzhiyun return "5";
3872*4882a593Smuzhiyun case NL80211_BAND_2GHZ:
3873*4882a593Smuzhiyun return "2.4";
3874*4882a593Smuzhiyun default:
3875*4882a593Smuzhiyun break;
3876*4882a593Smuzhiyun }
3877*4882a593Smuzhiyun B43_WARN_ON(1);
3878*4882a593Smuzhiyun return "";
3879*4882a593Smuzhiyun }
3880*4882a593Smuzhiyun
3881*4882a593Smuzhiyun /* Expects wl->mutex locked */
b43_switch_band(struct b43_wldev * dev,struct ieee80211_channel * chan)3882*4882a593Smuzhiyun static int b43_switch_band(struct b43_wldev *dev,
3883*4882a593Smuzhiyun struct ieee80211_channel *chan)
3884*4882a593Smuzhiyun {
3885*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
3886*4882a593Smuzhiyun bool gmode;
3887*4882a593Smuzhiyun u32 tmp;
3888*4882a593Smuzhiyun
3889*4882a593Smuzhiyun switch (chan->band) {
3890*4882a593Smuzhiyun case NL80211_BAND_5GHZ:
3891*4882a593Smuzhiyun gmode = false;
3892*4882a593Smuzhiyun break;
3893*4882a593Smuzhiyun case NL80211_BAND_2GHZ:
3894*4882a593Smuzhiyun gmode = true;
3895*4882a593Smuzhiyun break;
3896*4882a593Smuzhiyun default:
3897*4882a593Smuzhiyun B43_WARN_ON(1);
3898*4882a593Smuzhiyun return -EINVAL;
3899*4882a593Smuzhiyun }
3900*4882a593Smuzhiyun
3901*4882a593Smuzhiyun if (!((gmode && phy->supports_2ghz) ||
3902*4882a593Smuzhiyun (!gmode && phy->supports_5ghz))) {
3903*4882a593Smuzhiyun b43err(dev->wl, "This device doesn't support %s-GHz band\n",
3904*4882a593Smuzhiyun band_to_string(chan->band));
3905*4882a593Smuzhiyun return -ENODEV;
3906*4882a593Smuzhiyun }
3907*4882a593Smuzhiyun
3908*4882a593Smuzhiyun if (!!phy->gmode == !!gmode) {
3909*4882a593Smuzhiyun /* This device is already running. */
3910*4882a593Smuzhiyun return 0;
3911*4882a593Smuzhiyun }
3912*4882a593Smuzhiyun
3913*4882a593Smuzhiyun b43dbg(dev->wl, "Switching to %s GHz band\n",
3914*4882a593Smuzhiyun band_to_string(chan->band));
3915*4882a593Smuzhiyun
3916*4882a593Smuzhiyun /* Some new devices don't need disabling radio for band switching */
3917*4882a593Smuzhiyun if (!(phy->type == B43_PHYTYPE_N && phy->rev >= 3))
3918*4882a593Smuzhiyun b43_software_rfkill(dev, true);
3919*4882a593Smuzhiyun
3920*4882a593Smuzhiyun phy->gmode = gmode;
3921*4882a593Smuzhiyun b43_phy_put_into_reset(dev);
3922*4882a593Smuzhiyun switch (dev->dev->bus_type) {
3923*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
3924*4882a593Smuzhiyun case B43_BUS_BCMA:
3925*4882a593Smuzhiyun tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
3926*4882a593Smuzhiyun if (gmode)
3927*4882a593Smuzhiyun tmp |= B43_BCMA_IOCTL_GMODE;
3928*4882a593Smuzhiyun else
3929*4882a593Smuzhiyun tmp &= ~B43_BCMA_IOCTL_GMODE;
3930*4882a593Smuzhiyun bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
3931*4882a593Smuzhiyun break;
3932*4882a593Smuzhiyun #endif
3933*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
3934*4882a593Smuzhiyun case B43_BUS_SSB:
3935*4882a593Smuzhiyun tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
3936*4882a593Smuzhiyun if (gmode)
3937*4882a593Smuzhiyun tmp |= B43_TMSLOW_GMODE;
3938*4882a593Smuzhiyun else
3939*4882a593Smuzhiyun tmp &= ~B43_TMSLOW_GMODE;
3940*4882a593Smuzhiyun ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
3941*4882a593Smuzhiyun break;
3942*4882a593Smuzhiyun #endif
3943*4882a593Smuzhiyun }
3944*4882a593Smuzhiyun b43_phy_take_out_of_reset(dev);
3945*4882a593Smuzhiyun
3946*4882a593Smuzhiyun b43_upload_initvals_band(dev);
3947*4882a593Smuzhiyun
3948*4882a593Smuzhiyun b43_phy_init(dev);
3949*4882a593Smuzhiyun
3950*4882a593Smuzhiyun return 0;
3951*4882a593Smuzhiyun }
3952*4882a593Smuzhiyun
b43_set_beacon_listen_interval(struct b43_wldev * dev,u16 interval)3953*4882a593Smuzhiyun static void b43_set_beacon_listen_interval(struct b43_wldev *dev, u16 interval)
3954*4882a593Smuzhiyun {
3955*4882a593Smuzhiyun interval = min_t(u16, interval, (u16)0xFF);
3956*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BCN_LI, interval);
3957*4882a593Smuzhiyun }
3958*4882a593Smuzhiyun
3959*4882a593Smuzhiyun /* Write the short and long frame retry limit values. */
b43_set_retry_limits(struct b43_wldev * dev,unsigned int short_retry,unsigned int long_retry)3960*4882a593Smuzhiyun static void b43_set_retry_limits(struct b43_wldev *dev,
3961*4882a593Smuzhiyun unsigned int short_retry,
3962*4882a593Smuzhiyun unsigned int long_retry)
3963*4882a593Smuzhiyun {
3964*4882a593Smuzhiyun /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
3965*4882a593Smuzhiyun * the chip-internal counter. */
3966*4882a593Smuzhiyun short_retry = min(short_retry, (unsigned int)0xF);
3967*4882a593Smuzhiyun long_retry = min(long_retry, (unsigned int)0xF);
3968*4882a593Smuzhiyun
3969*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
3970*4882a593Smuzhiyun short_retry);
3971*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
3972*4882a593Smuzhiyun long_retry);
3973*4882a593Smuzhiyun }
3974*4882a593Smuzhiyun
b43_op_config(struct ieee80211_hw * hw,u32 changed)3975*4882a593Smuzhiyun static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
3976*4882a593Smuzhiyun {
3977*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
3978*4882a593Smuzhiyun struct b43_wldev *dev = wl->current_dev;
3979*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
3980*4882a593Smuzhiyun struct ieee80211_conf *conf = &hw->conf;
3981*4882a593Smuzhiyun int antenna;
3982*4882a593Smuzhiyun int err = 0;
3983*4882a593Smuzhiyun
3984*4882a593Smuzhiyun mutex_lock(&wl->mutex);
3985*4882a593Smuzhiyun b43_mac_suspend(dev);
3986*4882a593Smuzhiyun
3987*4882a593Smuzhiyun if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL)
3988*4882a593Smuzhiyun b43_set_beacon_listen_interval(dev, conf->listen_interval);
3989*4882a593Smuzhiyun
3990*4882a593Smuzhiyun if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
3991*4882a593Smuzhiyun phy->chandef = &conf->chandef;
3992*4882a593Smuzhiyun phy->channel = conf->chandef.chan->hw_value;
3993*4882a593Smuzhiyun
3994*4882a593Smuzhiyun /* Switch the band (if necessary). */
3995*4882a593Smuzhiyun err = b43_switch_band(dev, conf->chandef.chan);
3996*4882a593Smuzhiyun if (err)
3997*4882a593Smuzhiyun goto out_mac_enable;
3998*4882a593Smuzhiyun
3999*4882a593Smuzhiyun /* Switch to the requested channel.
4000*4882a593Smuzhiyun * The firmware takes care of races with the TX handler.
4001*4882a593Smuzhiyun */
4002*4882a593Smuzhiyun b43_switch_channel(dev, phy->channel);
4003*4882a593Smuzhiyun }
4004*4882a593Smuzhiyun
4005*4882a593Smuzhiyun if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
4006*4882a593Smuzhiyun b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
4007*4882a593Smuzhiyun conf->long_frame_max_tx_count);
4008*4882a593Smuzhiyun changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
4009*4882a593Smuzhiyun if (!changed)
4010*4882a593Smuzhiyun goto out_mac_enable;
4011*4882a593Smuzhiyun
4012*4882a593Smuzhiyun dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR);
4013*4882a593Smuzhiyun
4014*4882a593Smuzhiyun /* Adjust the desired TX power level. */
4015*4882a593Smuzhiyun if (conf->power_level != 0) {
4016*4882a593Smuzhiyun if (conf->power_level != phy->desired_txpower) {
4017*4882a593Smuzhiyun phy->desired_txpower = conf->power_level;
4018*4882a593Smuzhiyun b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME |
4019*4882a593Smuzhiyun B43_TXPWR_IGNORE_TSSI);
4020*4882a593Smuzhiyun }
4021*4882a593Smuzhiyun }
4022*4882a593Smuzhiyun
4023*4882a593Smuzhiyun /* Antennas for RX and management frame TX. */
4024*4882a593Smuzhiyun antenna = B43_ANTENNA_DEFAULT;
4025*4882a593Smuzhiyun b43_mgmtframe_txantenna(dev, antenna);
4026*4882a593Smuzhiyun antenna = B43_ANTENNA_DEFAULT;
4027*4882a593Smuzhiyun if (phy->ops->set_rx_antenna)
4028*4882a593Smuzhiyun phy->ops->set_rx_antenna(dev, antenna);
4029*4882a593Smuzhiyun
4030*4882a593Smuzhiyun if (wl->radio_enabled != phy->radio_on) {
4031*4882a593Smuzhiyun if (wl->radio_enabled) {
4032*4882a593Smuzhiyun b43_software_rfkill(dev, false);
4033*4882a593Smuzhiyun b43info(dev->wl, "Radio turned on by software\n");
4034*4882a593Smuzhiyun if (!dev->radio_hw_enable) {
4035*4882a593Smuzhiyun b43info(dev->wl, "The hardware RF-kill button "
4036*4882a593Smuzhiyun "still turns the radio physically off. "
4037*4882a593Smuzhiyun "Press the button to turn it on.\n");
4038*4882a593Smuzhiyun }
4039*4882a593Smuzhiyun } else {
4040*4882a593Smuzhiyun b43_software_rfkill(dev, true);
4041*4882a593Smuzhiyun b43info(dev->wl, "Radio turned off by software\n");
4042*4882a593Smuzhiyun }
4043*4882a593Smuzhiyun }
4044*4882a593Smuzhiyun
4045*4882a593Smuzhiyun out_mac_enable:
4046*4882a593Smuzhiyun b43_mac_enable(dev);
4047*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
4048*4882a593Smuzhiyun
4049*4882a593Smuzhiyun return err;
4050*4882a593Smuzhiyun }
4051*4882a593Smuzhiyun
b43_update_basic_rates(struct b43_wldev * dev,u32 brates)4052*4882a593Smuzhiyun static void b43_update_basic_rates(struct b43_wldev *dev, u32 brates)
4053*4882a593Smuzhiyun {
4054*4882a593Smuzhiyun struct ieee80211_supported_band *sband =
4055*4882a593Smuzhiyun dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)];
4056*4882a593Smuzhiyun struct ieee80211_rate *rate;
4057*4882a593Smuzhiyun int i;
4058*4882a593Smuzhiyun u16 basic, direct, offset, basic_offset, rateptr;
4059*4882a593Smuzhiyun
4060*4882a593Smuzhiyun for (i = 0; i < sband->n_bitrates; i++) {
4061*4882a593Smuzhiyun rate = &sband->bitrates[i];
4062*4882a593Smuzhiyun
4063*4882a593Smuzhiyun if (b43_is_cck_rate(rate->hw_value)) {
4064*4882a593Smuzhiyun direct = B43_SHM_SH_CCKDIRECT;
4065*4882a593Smuzhiyun basic = B43_SHM_SH_CCKBASIC;
4066*4882a593Smuzhiyun offset = b43_plcp_get_ratecode_cck(rate->hw_value);
4067*4882a593Smuzhiyun offset &= 0xF;
4068*4882a593Smuzhiyun } else {
4069*4882a593Smuzhiyun direct = B43_SHM_SH_OFDMDIRECT;
4070*4882a593Smuzhiyun basic = B43_SHM_SH_OFDMBASIC;
4071*4882a593Smuzhiyun offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
4072*4882a593Smuzhiyun offset &= 0xF;
4073*4882a593Smuzhiyun }
4074*4882a593Smuzhiyun
4075*4882a593Smuzhiyun rate = ieee80211_get_response_rate(sband, brates, rate->bitrate);
4076*4882a593Smuzhiyun
4077*4882a593Smuzhiyun if (b43_is_cck_rate(rate->hw_value)) {
4078*4882a593Smuzhiyun basic_offset = b43_plcp_get_ratecode_cck(rate->hw_value);
4079*4882a593Smuzhiyun basic_offset &= 0xF;
4080*4882a593Smuzhiyun } else {
4081*4882a593Smuzhiyun basic_offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
4082*4882a593Smuzhiyun basic_offset &= 0xF;
4083*4882a593Smuzhiyun }
4084*4882a593Smuzhiyun
4085*4882a593Smuzhiyun /*
4086*4882a593Smuzhiyun * Get the pointer that we need to point to
4087*4882a593Smuzhiyun * from the direct map
4088*4882a593Smuzhiyun */
4089*4882a593Smuzhiyun rateptr = b43_shm_read16(dev, B43_SHM_SHARED,
4090*4882a593Smuzhiyun direct + 2 * basic_offset);
4091*4882a593Smuzhiyun /* and write it to the basic map */
4092*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, basic + 2 * offset,
4093*4882a593Smuzhiyun rateptr);
4094*4882a593Smuzhiyun }
4095*4882a593Smuzhiyun }
4096*4882a593Smuzhiyun
b43_op_bss_info_changed(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * conf,u32 changed)4097*4882a593Smuzhiyun static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
4098*4882a593Smuzhiyun struct ieee80211_vif *vif,
4099*4882a593Smuzhiyun struct ieee80211_bss_conf *conf,
4100*4882a593Smuzhiyun u32 changed)
4101*4882a593Smuzhiyun {
4102*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
4103*4882a593Smuzhiyun struct b43_wldev *dev;
4104*4882a593Smuzhiyun
4105*4882a593Smuzhiyun mutex_lock(&wl->mutex);
4106*4882a593Smuzhiyun
4107*4882a593Smuzhiyun dev = wl->current_dev;
4108*4882a593Smuzhiyun if (!dev || b43_status(dev) < B43_STAT_STARTED)
4109*4882a593Smuzhiyun goto out_unlock_mutex;
4110*4882a593Smuzhiyun
4111*4882a593Smuzhiyun B43_WARN_ON(wl->vif != vif);
4112*4882a593Smuzhiyun
4113*4882a593Smuzhiyun if (changed & BSS_CHANGED_BSSID) {
4114*4882a593Smuzhiyun if (conf->bssid)
4115*4882a593Smuzhiyun memcpy(wl->bssid, conf->bssid, ETH_ALEN);
4116*4882a593Smuzhiyun else
4117*4882a593Smuzhiyun eth_zero_addr(wl->bssid);
4118*4882a593Smuzhiyun }
4119*4882a593Smuzhiyun
4120*4882a593Smuzhiyun if (b43_status(dev) >= B43_STAT_INITIALIZED) {
4121*4882a593Smuzhiyun if (changed & BSS_CHANGED_BEACON &&
4122*4882a593Smuzhiyun (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
4123*4882a593Smuzhiyun b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) ||
4124*4882a593Smuzhiyun b43_is_mode(wl, NL80211_IFTYPE_ADHOC)))
4125*4882a593Smuzhiyun b43_update_templates(wl);
4126*4882a593Smuzhiyun
4127*4882a593Smuzhiyun if (changed & BSS_CHANGED_BSSID)
4128*4882a593Smuzhiyun b43_write_mac_bssid_templates(dev);
4129*4882a593Smuzhiyun }
4130*4882a593Smuzhiyun
4131*4882a593Smuzhiyun b43_mac_suspend(dev);
4132*4882a593Smuzhiyun
4133*4882a593Smuzhiyun /* Update templates for AP/mesh mode. */
4134*4882a593Smuzhiyun if (changed & BSS_CHANGED_BEACON_INT &&
4135*4882a593Smuzhiyun (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
4136*4882a593Smuzhiyun b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) ||
4137*4882a593Smuzhiyun b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) &&
4138*4882a593Smuzhiyun conf->beacon_int)
4139*4882a593Smuzhiyun b43_set_beacon_int(dev, conf->beacon_int);
4140*4882a593Smuzhiyun
4141*4882a593Smuzhiyun if (changed & BSS_CHANGED_BASIC_RATES)
4142*4882a593Smuzhiyun b43_update_basic_rates(dev, conf->basic_rates);
4143*4882a593Smuzhiyun
4144*4882a593Smuzhiyun if (changed & BSS_CHANGED_ERP_SLOT) {
4145*4882a593Smuzhiyun if (conf->use_short_slot)
4146*4882a593Smuzhiyun b43_short_slot_timing_enable(dev);
4147*4882a593Smuzhiyun else
4148*4882a593Smuzhiyun b43_short_slot_timing_disable(dev);
4149*4882a593Smuzhiyun }
4150*4882a593Smuzhiyun
4151*4882a593Smuzhiyun b43_mac_enable(dev);
4152*4882a593Smuzhiyun out_unlock_mutex:
4153*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
4154*4882a593Smuzhiyun }
4155*4882a593Smuzhiyun
b43_op_set_key(struct ieee80211_hw * hw,enum set_key_cmd cmd,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key)4156*4882a593Smuzhiyun static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
4157*4882a593Smuzhiyun struct ieee80211_vif *vif, struct ieee80211_sta *sta,
4158*4882a593Smuzhiyun struct ieee80211_key_conf *key)
4159*4882a593Smuzhiyun {
4160*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
4161*4882a593Smuzhiyun struct b43_wldev *dev;
4162*4882a593Smuzhiyun u8 algorithm;
4163*4882a593Smuzhiyun u8 index;
4164*4882a593Smuzhiyun int err;
4165*4882a593Smuzhiyun static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
4166*4882a593Smuzhiyun
4167*4882a593Smuzhiyun if (modparam_nohwcrypt)
4168*4882a593Smuzhiyun return -ENOSPC; /* User disabled HW-crypto */
4169*4882a593Smuzhiyun
4170*4882a593Smuzhiyun if ((vif->type == NL80211_IFTYPE_ADHOC ||
4171*4882a593Smuzhiyun vif->type == NL80211_IFTYPE_MESH_POINT) &&
4172*4882a593Smuzhiyun (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
4173*4882a593Smuzhiyun key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
4174*4882a593Smuzhiyun !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
4175*4882a593Smuzhiyun /*
4176*4882a593Smuzhiyun * For now, disable hw crypto for the RSN IBSS group keys. This
4177*4882a593Smuzhiyun * could be optimized in the future, but until that gets
4178*4882a593Smuzhiyun * implemented, use of software crypto for group addressed
4179*4882a593Smuzhiyun * frames is a acceptable to allow RSN IBSS to be used.
4180*4882a593Smuzhiyun */
4181*4882a593Smuzhiyun return -EOPNOTSUPP;
4182*4882a593Smuzhiyun }
4183*4882a593Smuzhiyun
4184*4882a593Smuzhiyun mutex_lock(&wl->mutex);
4185*4882a593Smuzhiyun
4186*4882a593Smuzhiyun dev = wl->current_dev;
4187*4882a593Smuzhiyun err = -ENODEV;
4188*4882a593Smuzhiyun if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
4189*4882a593Smuzhiyun goto out_unlock;
4190*4882a593Smuzhiyun
4191*4882a593Smuzhiyun if (dev->fw.pcm_request_failed || !dev->hwcrypto_enabled) {
4192*4882a593Smuzhiyun /* We don't have firmware for the crypto engine.
4193*4882a593Smuzhiyun * Must use software-crypto. */
4194*4882a593Smuzhiyun err = -EOPNOTSUPP;
4195*4882a593Smuzhiyun goto out_unlock;
4196*4882a593Smuzhiyun }
4197*4882a593Smuzhiyun
4198*4882a593Smuzhiyun err = -EINVAL;
4199*4882a593Smuzhiyun switch (key->cipher) {
4200*4882a593Smuzhiyun case WLAN_CIPHER_SUITE_WEP40:
4201*4882a593Smuzhiyun algorithm = B43_SEC_ALGO_WEP40;
4202*4882a593Smuzhiyun break;
4203*4882a593Smuzhiyun case WLAN_CIPHER_SUITE_WEP104:
4204*4882a593Smuzhiyun algorithm = B43_SEC_ALGO_WEP104;
4205*4882a593Smuzhiyun break;
4206*4882a593Smuzhiyun case WLAN_CIPHER_SUITE_TKIP:
4207*4882a593Smuzhiyun algorithm = B43_SEC_ALGO_TKIP;
4208*4882a593Smuzhiyun break;
4209*4882a593Smuzhiyun case WLAN_CIPHER_SUITE_CCMP:
4210*4882a593Smuzhiyun algorithm = B43_SEC_ALGO_AES;
4211*4882a593Smuzhiyun break;
4212*4882a593Smuzhiyun default:
4213*4882a593Smuzhiyun B43_WARN_ON(1);
4214*4882a593Smuzhiyun goto out_unlock;
4215*4882a593Smuzhiyun }
4216*4882a593Smuzhiyun index = (u8) (key->keyidx);
4217*4882a593Smuzhiyun if (index > 3)
4218*4882a593Smuzhiyun goto out_unlock;
4219*4882a593Smuzhiyun
4220*4882a593Smuzhiyun switch (cmd) {
4221*4882a593Smuzhiyun case SET_KEY:
4222*4882a593Smuzhiyun if (algorithm == B43_SEC_ALGO_TKIP &&
4223*4882a593Smuzhiyun (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
4224*4882a593Smuzhiyun !modparam_hwtkip)) {
4225*4882a593Smuzhiyun /* We support only pairwise key */
4226*4882a593Smuzhiyun err = -EOPNOTSUPP;
4227*4882a593Smuzhiyun goto out_unlock;
4228*4882a593Smuzhiyun }
4229*4882a593Smuzhiyun
4230*4882a593Smuzhiyun if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
4231*4882a593Smuzhiyun if (WARN_ON(!sta)) {
4232*4882a593Smuzhiyun err = -EOPNOTSUPP;
4233*4882a593Smuzhiyun goto out_unlock;
4234*4882a593Smuzhiyun }
4235*4882a593Smuzhiyun /* Pairwise key with an assigned MAC address. */
4236*4882a593Smuzhiyun err = b43_key_write(dev, -1, algorithm,
4237*4882a593Smuzhiyun key->key, key->keylen,
4238*4882a593Smuzhiyun sta->addr, key);
4239*4882a593Smuzhiyun } else {
4240*4882a593Smuzhiyun /* Group key */
4241*4882a593Smuzhiyun err = b43_key_write(dev, index, algorithm,
4242*4882a593Smuzhiyun key->key, key->keylen, NULL, key);
4243*4882a593Smuzhiyun }
4244*4882a593Smuzhiyun if (err)
4245*4882a593Smuzhiyun goto out_unlock;
4246*4882a593Smuzhiyun
4247*4882a593Smuzhiyun if (algorithm == B43_SEC_ALGO_WEP40 ||
4248*4882a593Smuzhiyun algorithm == B43_SEC_ALGO_WEP104) {
4249*4882a593Smuzhiyun b43_hf_write(dev, b43_hf_read(dev) | B43_HF_USEDEFKEYS);
4250*4882a593Smuzhiyun } else {
4251*4882a593Smuzhiyun b43_hf_write(dev,
4252*4882a593Smuzhiyun b43_hf_read(dev) & ~B43_HF_USEDEFKEYS);
4253*4882a593Smuzhiyun }
4254*4882a593Smuzhiyun key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
4255*4882a593Smuzhiyun if (algorithm == B43_SEC_ALGO_TKIP)
4256*4882a593Smuzhiyun key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
4257*4882a593Smuzhiyun break;
4258*4882a593Smuzhiyun case DISABLE_KEY: {
4259*4882a593Smuzhiyun err = b43_key_clear(dev, key->hw_key_idx);
4260*4882a593Smuzhiyun if (err)
4261*4882a593Smuzhiyun goto out_unlock;
4262*4882a593Smuzhiyun break;
4263*4882a593Smuzhiyun }
4264*4882a593Smuzhiyun default:
4265*4882a593Smuzhiyun B43_WARN_ON(1);
4266*4882a593Smuzhiyun }
4267*4882a593Smuzhiyun
4268*4882a593Smuzhiyun out_unlock:
4269*4882a593Smuzhiyun if (!err) {
4270*4882a593Smuzhiyun b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
4271*4882a593Smuzhiyun "mac: %pM\n",
4272*4882a593Smuzhiyun cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
4273*4882a593Smuzhiyun sta ? sta->addr : bcast_addr);
4274*4882a593Smuzhiyun b43_dump_keymemory(dev);
4275*4882a593Smuzhiyun }
4276*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
4277*4882a593Smuzhiyun
4278*4882a593Smuzhiyun return err;
4279*4882a593Smuzhiyun }
4280*4882a593Smuzhiyun
b43_op_configure_filter(struct ieee80211_hw * hw,unsigned int changed,unsigned int * fflags,u64 multicast)4281*4882a593Smuzhiyun static void b43_op_configure_filter(struct ieee80211_hw *hw,
4282*4882a593Smuzhiyun unsigned int changed, unsigned int *fflags,
4283*4882a593Smuzhiyun u64 multicast)
4284*4882a593Smuzhiyun {
4285*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
4286*4882a593Smuzhiyun struct b43_wldev *dev;
4287*4882a593Smuzhiyun
4288*4882a593Smuzhiyun mutex_lock(&wl->mutex);
4289*4882a593Smuzhiyun dev = wl->current_dev;
4290*4882a593Smuzhiyun if (!dev) {
4291*4882a593Smuzhiyun *fflags = 0;
4292*4882a593Smuzhiyun goto out_unlock;
4293*4882a593Smuzhiyun }
4294*4882a593Smuzhiyun
4295*4882a593Smuzhiyun *fflags &= FIF_ALLMULTI |
4296*4882a593Smuzhiyun FIF_FCSFAIL |
4297*4882a593Smuzhiyun FIF_PLCPFAIL |
4298*4882a593Smuzhiyun FIF_CONTROL |
4299*4882a593Smuzhiyun FIF_OTHER_BSS |
4300*4882a593Smuzhiyun FIF_BCN_PRBRESP_PROMISC;
4301*4882a593Smuzhiyun
4302*4882a593Smuzhiyun changed &= FIF_ALLMULTI |
4303*4882a593Smuzhiyun FIF_FCSFAIL |
4304*4882a593Smuzhiyun FIF_PLCPFAIL |
4305*4882a593Smuzhiyun FIF_CONTROL |
4306*4882a593Smuzhiyun FIF_OTHER_BSS |
4307*4882a593Smuzhiyun FIF_BCN_PRBRESP_PROMISC;
4308*4882a593Smuzhiyun
4309*4882a593Smuzhiyun wl->filter_flags = *fflags;
4310*4882a593Smuzhiyun
4311*4882a593Smuzhiyun if (changed && b43_status(dev) >= B43_STAT_INITIALIZED)
4312*4882a593Smuzhiyun b43_adjust_opmode(dev);
4313*4882a593Smuzhiyun
4314*4882a593Smuzhiyun out_unlock:
4315*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
4316*4882a593Smuzhiyun }
4317*4882a593Smuzhiyun
4318*4882a593Smuzhiyun /* Locking: wl->mutex
4319*4882a593Smuzhiyun * Returns the current dev. This might be different from the passed in dev,
4320*4882a593Smuzhiyun * because the core might be gone away while we unlocked the mutex. */
b43_wireless_core_stop(struct b43_wldev * dev)4321*4882a593Smuzhiyun static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev)
4322*4882a593Smuzhiyun {
4323*4882a593Smuzhiyun struct b43_wl *wl;
4324*4882a593Smuzhiyun struct b43_wldev *orig_dev;
4325*4882a593Smuzhiyun u32 mask;
4326*4882a593Smuzhiyun int queue_num;
4327*4882a593Smuzhiyun
4328*4882a593Smuzhiyun if (!dev)
4329*4882a593Smuzhiyun return NULL;
4330*4882a593Smuzhiyun wl = dev->wl;
4331*4882a593Smuzhiyun redo:
4332*4882a593Smuzhiyun if (!dev || b43_status(dev) < B43_STAT_STARTED)
4333*4882a593Smuzhiyun return dev;
4334*4882a593Smuzhiyun
4335*4882a593Smuzhiyun /* Cancel work. Unlock to avoid deadlocks. */
4336*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
4337*4882a593Smuzhiyun cancel_delayed_work_sync(&dev->periodic_work);
4338*4882a593Smuzhiyun cancel_work_sync(&wl->tx_work);
4339*4882a593Smuzhiyun b43_leds_stop(dev);
4340*4882a593Smuzhiyun mutex_lock(&wl->mutex);
4341*4882a593Smuzhiyun dev = wl->current_dev;
4342*4882a593Smuzhiyun if (!dev || b43_status(dev) < B43_STAT_STARTED) {
4343*4882a593Smuzhiyun /* Whoops, aliens ate up the device while we were unlocked. */
4344*4882a593Smuzhiyun return dev;
4345*4882a593Smuzhiyun }
4346*4882a593Smuzhiyun
4347*4882a593Smuzhiyun /* Disable interrupts on the device. */
4348*4882a593Smuzhiyun b43_set_status(dev, B43_STAT_INITIALIZED);
4349*4882a593Smuzhiyun if (b43_bus_host_is_sdio(dev->dev)) {
4350*4882a593Smuzhiyun /* wl->mutex is locked. That is enough. */
4351*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
4352*4882a593Smuzhiyun b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
4353*4882a593Smuzhiyun } else {
4354*4882a593Smuzhiyun spin_lock_irq(&wl->hardirq_lock);
4355*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
4356*4882a593Smuzhiyun b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
4357*4882a593Smuzhiyun spin_unlock_irq(&wl->hardirq_lock);
4358*4882a593Smuzhiyun }
4359*4882a593Smuzhiyun /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
4360*4882a593Smuzhiyun orig_dev = dev;
4361*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
4362*4882a593Smuzhiyun if (b43_bus_host_is_sdio(dev->dev))
4363*4882a593Smuzhiyun b43_sdio_free_irq(dev);
4364*4882a593Smuzhiyun else
4365*4882a593Smuzhiyun free_irq(dev->dev->irq, dev);
4366*4882a593Smuzhiyun mutex_lock(&wl->mutex);
4367*4882a593Smuzhiyun dev = wl->current_dev;
4368*4882a593Smuzhiyun if (!dev)
4369*4882a593Smuzhiyun return dev;
4370*4882a593Smuzhiyun if (dev != orig_dev) {
4371*4882a593Smuzhiyun if (b43_status(dev) >= B43_STAT_STARTED)
4372*4882a593Smuzhiyun goto redo;
4373*4882a593Smuzhiyun return dev;
4374*4882a593Smuzhiyun }
4375*4882a593Smuzhiyun mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
4376*4882a593Smuzhiyun B43_WARN_ON(mask != 0xFFFFFFFF && mask);
4377*4882a593Smuzhiyun
4378*4882a593Smuzhiyun /* Drain all TX queues. */
4379*4882a593Smuzhiyun for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) {
4380*4882a593Smuzhiyun while (skb_queue_len(&wl->tx_queue[queue_num])) {
4381*4882a593Smuzhiyun struct sk_buff *skb;
4382*4882a593Smuzhiyun
4383*4882a593Smuzhiyun skb = skb_dequeue(&wl->tx_queue[queue_num]);
4384*4882a593Smuzhiyun ieee80211_free_txskb(wl->hw, skb);
4385*4882a593Smuzhiyun }
4386*4882a593Smuzhiyun }
4387*4882a593Smuzhiyun
4388*4882a593Smuzhiyun b43_mac_suspend(dev);
4389*4882a593Smuzhiyun b43_leds_exit(dev);
4390*4882a593Smuzhiyun b43dbg(wl, "Wireless interface stopped\n");
4391*4882a593Smuzhiyun
4392*4882a593Smuzhiyun return dev;
4393*4882a593Smuzhiyun }
4394*4882a593Smuzhiyun
4395*4882a593Smuzhiyun /* Locking: wl->mutex */
b43_wireless_core_start(struct b43_wldev * dev)4396*4882a593Smuzhiyun static int b43_wireless_core_start(struct b43_wldev *dev)
4397*4882a593Smuzhiyun {
4398*4882a593Smuzhiyun int err;
4399*4882a593Smuzhiyun
4400*4882a593Smuzhiyun B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
4401*4882a593Smuzhiyun
4402*4882a593Smuzhiyun drain_txstatus_queue(dev);
4403*4882a593Smuzhiyun if (b43_bus_host_is_sdio(dev->dev)) {
4404*4882a593Smuzhiyun err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler);
4405*4882a593Smuzhiyun if (err) {
4406*4882a593Smuzhiyun b43err(dev->wl, "Cannot request SDIO IRQ\n");
4407*4882a593Smuzhiyun goto out;
4408*4882a593Smuzhiyun }
4409*4882a593Smuzhiyun } else {
4410*4882a593Smuzhiyun err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
4411*4882a593Smuzhiyun b43_interrupt_thread_handler,
4412*4882a593Smuzhiyun IRQF_SHARED, KBUILD_MODNAME, dev);
4413*4882a593Smuzhiyun if (err) {
4414*4882a593Smuzhiyun b43err(dev->wl, "Cannot request IRQ-%d\n",
4415*4882a593Smuzhiyun dev->dev->irq);
4416*4882a593Smuzhiyun goto out;
4417*4882a593Smuzhiyun }
4418*4882a593Smuzhiyun }
4419*4882a593Smuzhiyun
4420*4882a593Smuzhiyun /* We are ready to run. */
4421*4882a593Smuzhiyun ieee80211_wake_queues(dev->wl->hw);
4422*4882a593Smuzhiyun b43_set_status(dev, B43_STAT_STARTED);
4423*4882a593Smuzhiyun
4424*4882a593Smuzhiyun /* Start data flow (TX/RX). */
4425*4882a593Smuzhiyun b43_mac_enable(dev);
4426*4882a593Smuzhiyun b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
4427*4882a593Smuzhiyun
4428*4882a593Smuzhiyun /* Start maintenance work */
4429*4882a593Smuzhiyun b43_periodic_tasks_setup(dev);
4430*4882a593Smuzhiyun
4431*4882a593Smuzhiyun b43_leds_init(dev);
4432*4882a593Smuzhiyun
4433*4882a593Smuzhiyun b43dbg(dev->wl, "Wireless interface started\n");
4434*4882a593Smuzhiyun out:
4435*4882a593Smuzhiyun return err;
4436*4882a593Smuzhiyun }
4437*4882a593Smuzhiyun
b43_phy_name(struct b43_wldev * dev,u8 phy_type)4438*4882a593Smuzhiyun static char *b43_phy_name(struct b43_wldev *dev, u8 phy_type)
4439*4882a593Smuzhiyun {
4440*4882a593Smuzhiyun switch (phy_type) {
4441*4882a593Smuzhiyun case B43_PHYTYPE_A:
4442*4882a593Smuzhiyun return "A";
4443*4882a593Smuzhiyun case B43_PHYTYPE_B:
4444*4882a593Smuzhiyun return "B";
4445*4882a593Smuzhiyun case B43_PHYTYPE_G:
4446*4882a593Smuzhiyun return "G";
4447*4882a593Smuzhiyun case B43_PHYTYPE_N:
4448*4882a593Smuzhiyun return "N";
4449*4882a593Smuzhiyun case B43_PHYTYPE_LP:
4450*4882a593Smuzhiyun return "LP";
4451*4882a593Smuzhiyun case B43_PHYTYPE_SSLPN:
4452*4882a593Smuzhiyun return "SSLPN";
4453*4882a593Smuzhiyun case B43_PHYTYPE_HT:
4454*4882a593Smuzhiyun return "HT";
4455*4882a593Smuzhiyun case B43_PHYTYPE_LCN:
4456*4882a593Smuzhiyun return "LCN";
4457*4882a593Smuzhiyun case B43_PHYTYPE_LCNXN:
4458*4882a593Smuzhiyun return "LCNXN";
4459*4882a593Smuzhiyun case B43_PHYTYPE_LCN40:
4460*4882a593Smuzhiyun return "LCN40";
4461*4882a593Smuzhiyun case B43_PHYTYPE_AC:
4462*4882a593Smuzhiyun return "AC";
4463*4882a593Smuzhiyun }
4464*4882a593Smuzhiyun return "UNKNOWN";
4465*4882a593Smuzhiyun }
4466*4882a593Smuzhiyun
4467*4882a593Smuzhiyun /* Get PHY and RADIO versioning numbers */
b43_phy_versioning(struct b43_wldev * dev)4468*4882a593Smuzhiyun static int b43_phy_versioning(struct b43_wldev *dev)
4469*4882a593Smuzhiyun {
4470*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
4471*4882a593Smuzhiyun const u8 core_rev = dev->dev->core_rev;
4472*4882a593Smuzhiyun u32 tmp;
4473*4882a593Smuzhiyun u8 analog_type;
4474*4882a593Smuzhiyun u8 phy_type;
4475*4882a593Smuzhiyun u8 phy_rev;
4476*4882a593Smuzhiyun u16 radio_manuf;
4477*4882a593Smuzhiyun u16 radio_id;
4478*4882a593Smuzhiyun u16 radio_rev;
4479*4882a593Smuzhiyun u8 radio_ver;
4480*4882a593Smuzhiyun int unsupported = 0;
4481*4882a593Smuzhiyun
4482*4882a593Smuzhiyun /* Get PHY versioning */
4483*4882a593Smuzhiyun tmp = b43_read16(dev, B43_MMIO_PHY_VER);
4484*4882a593Smuzhiyun analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT;
4485*4882a593Smuzhiyun phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT;
4486*4882a593Smuzhiyun phy_rev = (tmp & B43_PHYVER_VERSION);
4487*4882a593Smuzhiyun
4488*4882a593Smuzhiyun /* LCNXN is continuation of N which run out of revisions */
4489*4882a593Smuzhiyun if (phy_type == B43_PHYTYPE_LCNXN) {
4490*4882a593Smuzhiyun phy_type = B43_PHYTYPE_N;
4491*4882a593Smuzhiyun phy_rev += 16;
4492*4882a593Smuzhiyun }
4493*4882a593Smuzhiyun
4494*4882a593Smuzhiyun switch (phy_type) {
4495*4882a593Smuzhiyun #ifdef CONFIG_B43_PHY_G
4496*4882a593Smuzhiyun case B43_PHYTYPE_G:
4497*4882a593Smuzhiyun if (phy_rev > 9)
4498*4882a593Smuzhiyun unsupported = 1;
4499*4882a593Smuzhiyun break;
4500*4882a593Smuzhiyun #endif
4501*4882a593Smuzhiyun #ifdef CONFIG_B43_PHY_N
4502*4882a593Smuzhiyun case B43_PHYTYPE_N:
4503*4882a593Smuzhiyun if (phy_rev >= 19)
4504*4882a593Smuzhiyun unsupported = 1;
4505*4882a593Smuzhiyun break;
4506*4882a593Smuzhiyun #endif
4507*4882a593Smuzhiyun #ifdef CONFIG_B43_PHY_LP
4508*4882a593Smuzhiyun case B43_PHYTYPE_LP:
4509*4882a593Smuzhiyun if (phy_rev > 2)
4510*4882a593Smuzhiyun unsupported = 1;
4511*4882a593Smuzhiyun break;
4512*4882a593Smuzhiyun #endif
4513*4882a593Smuzhiyun #ifdef CONFIG_B43_PHY_HT
4514*4882a593Smuzhiyun case B43_PHYTYPE_HT:
4515*4882a593Smuzhiyun if (phy_rev > 1)
4516*4882a593Smuzhiyun unsupported = 1;
4517*4882a593Smuzhiyun break;
4518*4882a593Smuzhiyun #endif
4519*4882a593Smuzhiyun #ifdef CONFIG_B43_PHY_LCN
4520*4882a593Smuzhiyun case B43_PHYTYPE_LCN:
4521*4882a593Smuzhiyun if (phy_rev > 1)
4522*4882a593Smuzhiyun unsupported = 1;
4523*4882a593Smuzhiyun break;
4524*4882a593Smuzhiyun #endif
4525*4882a593Smuzhiyun #ifdef CONFIG_B43_PHY_AC
4526*4882a593Smuzhiyun case B43_PHYTYPE_AC:
4527*4882a593Smuzhiyun if (phy_rev > 1)
4528*4882a593Smuzhiyun unsupported = 1;
4529*4882a593Smuzhiyun break;
4530*4882a593Smuzhiyun #endif
4531*4882a593Smuzhiyun default:
4532*4882a593Smuzhiyun unsupported = 1;
4533*4882a593Smuzhiyun }
4534*4882a593Smuzhiyun if (unsupported) {
4535*4882a593Smuzhiyun b43err(dev->wl, "FOUND UNSUPPORTED PHY (Analog %u, Type %d (%s), Revision %u)\n",
4536*4882a593Smuzhiyun analog_type, phy_type, b43_phy_name(dev, phy_type),
4537*4882a593Smuzhiyun phy_rev);
4538*4882a593Smuzhiyun return -EOPNOTSUPP;
4539*4882a593Smuzhiyun }
4540*4882a593Smuzhiyun b43info(dev->wl, "Found PHY: Analog %u, Type %d (%s), Revision %u\n",
4541*4882a593Smuzhiyun analog_type, phy_type, b43_phy_name(dev, phy_type), phy_rev);
4542*4882a593Smuzhiyun
4543*4882a593Smuzhiyun /* Get RADIO versioning */
4544*4882a593Smuzhiyun if (core_rev == 40 || core_rev == 42) {
4545*4882a593Smuzhiyun radio_manuf = 0x17F;
4546*4882a593Smuzhiyun
4547*4882a593Smuzhiyun b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 0);
4548*4882a593Smuzhiyun radio_rev = b43_read16(dev, B43_MMIO_RADIO24_DATA);
4549*4882a593Smuzhiyun
4550*4882a593Smuzhiyun b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 1);
4551*4882a593Smuzhiyun radio_id = b43_read16(dev, B43_MMIO_RADIO24_DATA);
4552*4882a593Smuzhiyun
4553*4882a593Smuzhiyun radio_ver = 0; /* Is there version somewhere? */
4554*4882a593Smuzhiyun } else if (core_rev >= 24) {
4555*4882a593Smuzhiyun u16 radio24[3];
4556*4882a593Smuzhiyun
4557*4882a593Smuzhiyun for (tmp = 0; tmp < 3; tmp++) {
4558*4882a593Smuzhiyun b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, tmp);
4559*4882a593Smuzhiyun radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA);
4560*4882a593Smuzhiyun }
4561*4882a593Smuzhiyun
4562*4882a593Smuzhiyun radio_manuf = 0x17F;
4563*4882a593Smuzhiyun radio_id = (radio24[2] << 8) | radio24[1];
4564*4882a593Smuzhiyun radio_rev = (radio24[0] & 0xF);
4565*4882a593Smuzhiyun radio_ver = (radio24[0] & 0xF0) >> 4;
4566*4882a593Smuzhiyun } else {
4567*4882a593Smuzhiyun if (dev->dev->chip_id == 0x4317) {
4568*4882a593Smuzhiyun if (dev->dev->chip_rev == 0)
4569*4882a593Smuzhiyun tmp = 0x3205017F;
4570*4882a593Smuzhiyun else if (dev->dev->chip_rev == 1)
4571*4882a593Smuzhiyun tmp = 0x4205017F;
4572*4882a593Smuzhiyun else
4573*4882a593Smuzhiyun tmp = 0x5205017F;
4574*4882a593Smuzhiyun } else {
4575*4882a593Smuzhiyun b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
4576*4882a593Smuzhiyun B43_RADIOCTL_ID);
4577*4882a593Smuzhiyun tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
4578*4882a593Smuzhiyun b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
4579*4882a593Smuzhiyun B43_RADIOCTL_ID);
4580*4882a593Smuzhiyun tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
4581*4882a593Smuzhiyun }
4582*4882a593Smuzhiyun radio_manuf = (tmp & 0x00000FFF);
4583*4882a593Smuzhiyun radio_id = (tmp & 0x0FFFF000) >> 12;
4584*4882a593Smuzhiyun radio_rev = (tmp & 0xF0000000) >> 28;
4585*4882a593Smuzhiyun radio_ver = 0; /* Probably not available on old hw */
4586*4882a593Smuzhiyun }
4587*4882a593Smuzhiyun
4588*4882a593Smuzhiyun if (radio_manuf != 0x17F /* Broadcom */)
4589*4882a593Smuzhiyun unsupported = 1;
4590*4882a593Smuzhiyun switch (phy_type) {
4591*4882a593Smuzhiyun case B43_PHYTYPE_B:
4592*4882a593Smuzhiyun if ((radio_id & 0xFFF0) != 0x2050)
4593*4882a593Smuzhiyun unsupported = 1;
4594*4882a593Smuzhiyun break;
4595*4882a593Smuzhiyun case B43_PHYTYPE_G:
4596*4882a593Smuzhiyun if (radio_id != 0x2050)
4597*4882a593Smuzhiyun unsupported = 1;
4598*4882a593Smuzhiyun break;
4599*4882a593Smuzhiyun case B43_PHYTYPE_N:
4600*4882a593Smuzhiyun if (radio_id != 0x2055 && radio_id != 0x2056 &&
4601*4882a593Smuzhiyun radio_id != 0x2057)
4602*4882a593Smuzhiyun unsupported = 1;
4603*4882a593Smuzhiyun if (radio_id == 0x2057 &&
4604*4882a593Smuzhiyun !(radio_rev == 9 || radio_rev == 14))
4605*4882a593Smuzhiyun unsupported = 1;
4606*4882a593Smuzhiyun break;
4607*4882a593Smuzhiyun case B43_PHYTYPE_LP:
4608*4882a593Smuzhiyun if (radio_id != 0x2062 && radio_id != 0x2063)
4609*4882a593Smuzhiyun unsupported = 1;
4610*4882a593Smuzhiyun break;
4611*4882a593Smuzhiyun case B43_PHYTYPE_HT:
4612*4882a593Smuzhiyun if (radio_id != 0x2059)
4613*4882a593Smuzhiyun unsupported = 1;
4614*4882a593Smuzhiyun break;
4615*4882a593Smuzhiyun case B43_PHYTYPE_LCN:
4616*4882a593Smuzhiyun if (radio_id != 0x2064)
4617*4882a593Smuzhiyun unsupported = 1;
4618*4882a593Smuzhiyun break;
4619*4882a593Smuzhiyun case B43_PHYTYPE_AC:
4620*4882a593Smuzhiyun if (radio_id != 0x2069)
4621*4882a593Smuzhiyun unsupported = 1;
4622*4882a593Smuzhiyun break;
4623*4882a593Smuzhiyun default:
4624*4882a593Smuzhiyun B43_WARN_ON(1);
4625*4882a593Smuzhiyun }
4626*4882a593Smuzhiyun if (unsupported) {
4627*4882a593Smuzhiyun b43err(dev->wl,
4628*4882a593Smuzhiyun "FOUND UNSUPPORTED RADIO (Manuf 0x%X, ID 0x%X, Revision %u, Version %u)\n",
4629*4882a593Smuzhiyun radio_manuf, radio_id, radio_rev, radio_ver);
4630*4882a593Smuzhiyun return -EOPNOTSUPP;
4631*4882a593Smuzhiyun }
4632*4882a593Smuzhiyun b43info(dev->wl,
4633*4882a593Smuzhiyun "Found Radio: Manuf 0x%X, ID 0x%X, Revision %u, Version %u\n",
4634*4882a593Smuzhiyun radio_manuf, radio_id, radio_rev, radio_ver);
4635*4882a593Smuzhiyun
4636*4882a593Smuzhiyun /* FIXME: b43 treats "id" as "ver" and ignores the real "ver" */
4637*4882a593Smuzhiyun phy->radio_manuf = radio_manuf;
4638*4882a593Smuzhiyun phy->radio_ver = radio_id;
4639*4882a593Smuzhiyun phy->radio_rev = radio_rev;
4640*4882a593Smuzhiyun
4641*4882a593Smuzhiyun phy->analog = analog_type;
4642*4882a593Smuzhiyun phy->type = phy_type;
4643*4882a593Smuzhiyun phy->rev = phy_rev;
4644*4882a593Smuzhiyun
4645*4882a593Smuzhiyun return 0;
4646*4882a593Smuzhiyun }
4647*4882a593Smuzhiyun
setup_struct_phy_for_init(struct b43_wldev * dev,struct b43_phy * phy)4648*4882a593Smuzhiyun static void setup_struct_phy_for_init(struct b43_wldev *dev,
4649*4882a593Smuzhiyun struct b43_phy *phy)
4650*4882a593Smuzhiyun {
4651*4882a593Smuzhiyun phy->hardware_power_control = !!modparam_hwpctl;
4652*4882a593Smuzhiyun phy->next_txpwr_check_time = jiffies;
4653*4882a593Smuzhiyun /* PHY TX errors counter. */
4654*4882a593Smuzhiyun atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
4655*4882a593Smuzhiyun
4656*4882a593Smuzhiyun #if B43_DEBUG
4657*4882a593Smuzhiyun phy->phy_locked = false;
4658*4882a593Smuzhiyun phy->radio_locked = false;
4659*4882a593Smuzhiyun #endif
4660*4882a593Smuzhiyun }
4661*4882a593Smuzhiyun
setup_struct_wldev_for_init(struct b43_wldev * dev)4662*4882a593Smuzhiyun static void setup_struct_wldev_for_init(struct b43_wldev *dev)
4663*4882a593Smuzhiyun {
4664*4882a593Smuzhiyun dev->dfq_valid = false;
4665*4882a593Smuzhiyun
4666*4882a593Smuzhiyun /* Assume the radio is enabled. If it's not enabled, the state will
4667*4882a593Smuzhiyun * immediately get fixed on the first periodic work run. */
4668*4882a593Smuzhiyun dev->radio_hw_enable = true;
4669*4882a593Smuzhiyun
4670*4882a593Smuzhiyun /* Stats */
4671*4882a593Smuzhiyun memset(&dev->stats, 0, sizeof(dev->stats));
4672*4882a593Smuzhiyun
4673*4882a593Smuzhiyun setup_struct_phy_for_init(dev, &dev->phy);
4674*4882a593Smuzhiyun
4675*4882a593Smuzhiyun /* IRQ related flags */
4676*4882a593Smuzhiyun dev->irq_reason = 0;
4677*4882a593Smuzhiyun memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
4678*4882a593Smuzhiyun dev->irq_mask = B43_IRQ_MASKTEMPLATE;
4679*4882a593Smuzhiyun if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
4680*4882a593Smuzhiyun dev->irq_mask &= ~B43_IRQ_PHY_TXERR;
4681*4882a593Smuzhiyun
4682*4882a593Smuzhiyun dev->mac_suspended = 1;
4683*4882a593Smuzhiyun
4684*4882a593Smuzhiyun /* Noise calculation context */
4685*4882a593Smuzhiyun memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
4686*4882a593Smuzhiyun }
4687*4882a593Smuzhiyun
b43_bluetooth_coext_enable(struct b43_wldev * dev)4688*4882a593Smuzhiyun static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
4689*4882a593Smuzhiyun {
4690*4882a593Smuzhiyun struct ssb_sprom *sprom = dev->dev->bus_sprom;
4691*4882a593Smuzhiyun u64 hf;
4692*4882a593Smuzhiyun
4693*4882a593Smuzhiyun if (!modparam_btcoex)
4694*4882a593Smuzhiyun return;
4695*4882a593Smuzhiyun if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST))
4696*4882a593Smuzhiyun return;
4697*4882a593Smuzhiyun if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
4698*4882a593Smuzhiyun return;
4699*4882a593Smuzhiyun
4700*4882a593Smuzhiyun hf = b43_hf_read(dev);
4701*4882a593Smuzhiyun if (sprom->boardflags_lo & B43_BFL_BTCMOD)
4702*4882a593Smuzhiyun hf |= B43_HF_BTCOEXALT;
4703*4882a593Smuzhiyun else
4704*4882a593Smuzhiyun hf |= B43_HF_BTCOEX;
4705*4882a593Smuzhiyun b43_hf_write(dev, hf);
4706*4882a593Smuzhiyun }
4707*4882a593Smuzhiyun
b43_bluetooth_coext_disable(struct b43_wldev * dev)4708*4882a593Smuzhiyun static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
4709*4882a593Smuzhiyun {
4710*4882a593Smuzhiyun if (!modparam_btcoex)
4711*4882a593Smuzhiyun return;
4712*4882a593Smuzhiyun //TODO
4713*4882a593Smuzhiyun }
4714*4882a593Smuzhiyun
b43_imcfglo_timeouts_workaround(struct b43_wldev * dev)4715*4882a593Smuzhiyun static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
4716*4882a593Smuzhiyun {
4717*4882a593Smuzhiyun struct ssb_bus *bus;
4718*4882a593Smuzhiyun u32 tmp;
4719*4882a593Smuzhiyun
4720*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
4721*4882a593Smuzhiyun if (dev->dev->bus_type != B43_BUS_SSB)
4722*4882a593Smuzhiyun return;
4723*4882a593Smuzhiyun #else
4724*4882a593Smuzhiyun return;
4725*4882a593Smuzhiyun #endif
4726*4882a593Smuzhiyun
4727*4882a593Smuzhiyun bus = dev->dev->sdev->bus;
4728*4882a593Smuzhiyun
4729*4882a593Smuzhiyun if ((bus->chip_id == 0x4311 && bus->chip_rev == 2) ||
4730*4882a593Smuzhiyun (bus->chip_id == 0x4312)) {
4731*4882a593Smuzhiyun tmp = ssb_read32(dev->dev->sdev, SSB_IMCFGLO);
4732*4882a593Smuzhiyun tmp &= ~SSB_IMCFGLO_REQTO;
4733*4882a593Smuzhiyun tmp &= ~SSB_IMCFGLO_SERTO;
4734*4882a593Smuzhiyun tmp |= 0x3;
4735*4882a593Smuzhiyun ssb_write32(dev->dev->sdev, SSB_IMCFGLO, tmp);
4736*4882a593Smuzhiyun ssb_commit_settings(bus);
4737*4882a593Smuzhiyun }
4738*4882a593Smuzhiyun }
4739*4882a593Smuzhiyun
b43_set_synth_pu_delay(struct b43_wldev * dev,bool idle)4740*4882a593Smuzhiyun static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
4741*4882a593Smuzhiyun {
4742*4882a593Smuzhiyun u16 pu_delay;
4743*4882a593Smuzhiyun
4744*4882a593Smuzhiyun /* The time value is in microseconds. */
4745*4882a593Smuzhiyun pu_delay = 1050;
4746*4882a593Smuzhiyun if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle)
4747*4882a593Smuzhiyun pu_delay = 500;
4748*4882a593Smuzhiyun if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
4749*4882a593Smuzhiyun pu_delay = max(pu_delay, (u16)2400);
4750*4882a593Smuzhiyun
4751*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SPUWKUP, pu_delay);
4752*4882a593Smuzhiyun }
4753*4882a593Smuzhiyun
4754*4882a593Smuzhiyun /* Set the TSF CFP pre-TargetBeaconTransmissionTime. */
b43_set_pretbtt(struct b43_wldev * dev)4755*4882a593Smuzhiyun static void b43_set_pretbtt(struct b43_wldev *dev)
4756*4882a593Smuzhiyun {
4757*4882a593Smuzhiyun u16 pretbtt;
4758*4882a593Smuzhiyun
4759*4882a593Smuzhiyun /* The time value is in microseconds. */
4760*4882a593Smuzhiyun if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
4761*4882a593Smuzhiyun pretbtt = 2;
4762*4882a593Smuzhiyun else
4763*4882a593Smuzhiyun pretbtt = 250;
4764*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRETBTT, pretbtt);
4765*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_TSF_CFP_PRETBTT, pretbtt);
4766*4882a593Smuzhiyun }
4767*4882a593Smuzhiyun
4768*4882a593Smuzhiyun /* Shutdown a wireless core */
4769*4882a593Smuzhiyun /* Locking: wl->mutex */
b43_wireless_core_exit(struct b43_wldev * dev)4770*4882a593Smuzhiyun static void b43_wireless_core_exit(struct b43_wldev *dev)
4771*4882a593Smuzhiyun {
4772*4882a593Smuzhiyun B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED);
4773*4882a593Smuzhiyun if (!dev || b43_status(dev) != B43_STAT_INITIALIZED)
4774*4882a593Smuzhiyun return;
4775*4882a593Smuzhiyun
4776*4882a593Smuzhiyun b43_set_status(dev, B43_STAT_UNINIT);
4777*4882a593Smuzhiyun
4778*4882a593Smuzhiyun /* Stop the microcode PSM. */
4779*4882a593Smuzhiyun b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_PSM_RUN,
4780*4882a593Smuzhiyun B43_MACCTL_PSM_JMP0);
4781*4882a593Smuzhiyun
4782*4882a593Smuzhiyun switch (dev->dev->bus_type) {
4783*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
4784*4882a593Smuzhiyun case B43_BUS_BCMA:
4785*4882a593Smuzhiyun bcma_host_pci_down(dev->dev->bdev->bus);
4786*4882a593Smuzhiyun break;
4787*4882a593Smuzhiyun #endif
4788*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
4789*4882a593Smuzhiyun case B43_BUS_SSB:
4790*4882a593Smuzhiyun /* TODO */
4791*4882a593Smuzhiyun break;
4792*4882a593Smuzhiyun #endif
4793*4882a593Smuzhiyun }
4794*4882a593Smuzhiyun
4795*4882a593Smuzhiyun b43_dma_free(dev);
4796*4882a593Smuzhiyun b43_pio_free(dev);
4797*4882a593Smuzhiyun b43_chip_exit(dev);
4798*4882a593Smuzhiyun dev->phy.ops->switch_analog(dev, 0);
4799*4882a593Smuzhiyun if (dev->wl->current_beacon) {
4800*4882a593Smuzhiyun dev_kfree_skb_any(dev->wl->current_beacon);
4801*4882a593Smuzhiyun dev->wl->current_beacon = NULL;
4802*4882a593Smuzhiyun }
4803*4882a593Smuzhiyun
4804*4882a593Smuzhiyun b43_device_disable(dev, 0);
4805*4882a593Smuzhiyun b43_bus_may_powerdown(dev);
4806*4882a593Smuzhiyun }
4807*4882a593Smuzhiyun
4808*4882a593Smuzhiyun /* Initialize a wireless core */
b43_wireless_core_init(struct b43_wldev * dev)4809*4882a593Smuzhiyun static int b43_wireless_core_init(struct b43_wldev *dev)
4810*4882a593Smuzhiyun {
4811*4882a593Smuzhiyun struct ssb_sprom *sprom = dev->dev->bus_sprom;
4812*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
4813*4882a593Smuzhiyun int err;
4814*4882a593Smuzhiyun u64 hf;
4815*4882a593Smuzhiyun
4816*4882a593Smuzhiyun B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
4817*4882a593Smuzhiyun
4818*4882a593Smuzhiyun err = b43_bus_powerup(dev, 0);
4819*4882a593Smuzhiyun if (err)
4820*4882a593Smuzhiyun goto out;
4821*4882a593Smuzhiyun if (!b43_device_is_enabled(dev))
4822*4882a593Smuzhiyun b43_wireless_core_reset(dev, phy->gmode);
4823*4882a593Smuzhiyun
4824*4882a593Smuzhiyun /* Reset all data structures. */
4825*4882a593Smuzhiyun setup_struct_wldev_for_init(dev);
4826*4882a593Smuzhiyun phy->ops->prepare_structs(dev);
4827*4882a593Smuzhiyun
4828*4882a593Smuzhiyun /* Enable IRQ routing to this device. */
4829*4882a593Smuzhiyun switch (dev->dev->bus_type) {
4830*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
4831*4882a593Smuzhiyun case B43_BUS_BCMA:
4832*4882a593Smuzhiyun bcma_host_pci_irq_ctl(dev->dev->bdev->bus,
4833*4882a593Smuzhiyun dev->dev->bdev, true);
4834*4882a593Smuzhiyun bcma_host_pci_up(dev->dev->bdev->bus);
4835*4882a593Smuzhiyun break;
4836*4882a593Smuzhiyun #endif
4837*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
4838*4882a593Smuzhiyun case B43_BUS_SSB:
4839*4882a593Smuzhiyun ssb_pcicore_dev_irqvecs_enable(&dev->dev->sdev->bus->pcicore,
4840*4882a593Smuzhiyun dev->dev->sdev);
4841*4882a593Smuzhiyun break;
4842*4882a593Smuzhiyun #endif
4843*4882a593Smuzhiyun }
4844*4882a593Smuzhiyun
4845*4882a593Smuzhiyun b43_imcfglo_timeouts_workaround(dev);
4846*4882a593Smuzhiyun b43_bluetooth_coext_disable(dev);
4847*4882a593Smuzhiyun if (phy->ops->prepare_hardware) {
4848*4882a593Smuzhiyun err = phy->ops->prepare_hardware(dev);
4849*4882a593Smuzhiyun if (err)
4850*4882a593Smuzhiyun goto err_busdown;
4851*4882a593Smuzhiyun }
4852*4882a593Smuzhiyun err = b43_chip_init(dev);
4853*4882a593Smuzhiyun if (err)
4854*4882a593Smuzhiyun goto err_busdown;
4855*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED,
4856*4882a593Smuzhiyun B43_SHM_SH_WLCOREREV, dev->dev->core_rev);
4857*4882a593Smuzhiyun hf = b43_hf_read(dev);
4858*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_G) {
4859*4882a593Smuzhiyun hf |= B43_HF_SYMW;
4860*4882a593Smuzhiyun if (phy->rev == 1)
4861*4882a593Smuzhiyun hf |= B43_HF_GDCW;
4862*4882a593Smuzhiyun if (sprom->boardflags_lo & B43_BFL_PACTRL)
4863*4882a593Smuzhiyun hf |= B43_HF_OFDMPABOOST;
4864*4882a593Smuzhiyun }
4865*4882a593Smuzhiyun if (phy->radio_ver == 0x2050) {
4866*4882a593Smuzhiyun if (phy->radio_rev == 6)
4867*4882a593Smuzhiyun hf |= B43_HF_4318TSSI;
4868*4882a593Smuzhiyun if (phy->radio_rev < 6)
4869*4882a593Smuzhiyun hf |= B43_HF_VCORECALC;
4870*4882a593Smuzhiyun }
4871*4882a593Smuzhiyun if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
4872*4882a593Smuzhiyun hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
4873*4882a593Smuzhiyun #if defined(CONFIG_B43_SSB) && defined(CONFIG_SSB_DRIVER_PCICORE)
4874*4882a593Smuzhiyun if (dev->dev->bus_type == B43_BUS_SSB &&
4875*4882a593Smuzhiyun dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
4876*4882a593Smuzhiyun dev->dev->sdev->bus->pcicore.dev->id.revision <= 10)
4877*4882a593Smuzhiyun hf |= B43_HF_PCISCW; /* PCI slow clock workaround. */
4878*4882a593Smuzhiyun #endif
4879*4882a593Smuzhiyun hf &= ~B43_HF_SKCFPUP;
4880*4882a593Smuzhiyun b43_hf_write(dev, hf);
4881*4882a593Smuzhiyun
4882*4882a593Smuzhiyun /* tell the ucode MAC capabilities */
4883*4882a593Smuzhiyun if (dev->dev->core_rev >= 13) {
4884*4882a593Smuzhiyun u32 mac_hw_cap = b43_read32(dev, B43_MMIO_MAC_HW_CAP);
4885*4882a593Smuzhiyun
4886*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_L,
4887*4882a593Smuzhiyun mac_hw_cap & 0xffff);
4888*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_H,
4889*4882a593Smuzhiyun (mac_hw_cap >> 16) & 0xffff);
4890*4882a593Smuzhiyun }
4891*4882a593Smuzhiyun
4892*4882a593Smuzhiyun b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
4893*4882a593Smuzhiyun B43_DEFAULT_LONG_RETRY_LIMIT);
4894*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
4895*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2);
4896*4882a593Smuzhiyun
4897*4882a593Smuzhiyun /* Disable sending probe responses from firmware.
4898*4882a593Smuzhiyun * Setting the MaxTime to one usec will always trigger
4899*4882a593Smuzhiyun * a timeout, so we never send any probe resp.
4900*4882a593Smuzhiyun * A timeout of zero is infinite. */
4901*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1);
4902*4882a593Smuzhiyun
4903*4882a593Smuzhiyun b43_rate_memory_init(dev);
4904*4882a593Smuzhiyun b43_set_phytxctl_defaults(dev);
4905*4882a593Smuzhiyun
4906*4882a593Smuzhiyun /* Minimum Contention Window */
4907*4882a593Smuzhiyun if (phy->type == B43_PHYTYPE_B)
4908*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F);
4909*4882a593Smuzhiyun else
4910*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF);
4911*4882a593Smuzhiyun /* Maximum Contention Window */
4912*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
4913*4882a593Smuzhiyun
4914*4882a593Smuzhiyun /* write phytype and phyvers */
4915*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYTYPE, phy->type);
4916*4882a593Smuzhiyun b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYVER, phy->rev);
4917*4882a593Smuzhiyun
4918*4882a593Smuzhiyun if (b43_bus_host_is_pcmcia(dev->dev) ||
4919*4882a593Smuzhiyun b43_bus_host_is_sdio(dev->dev)) {
4920*4882a593Smuzhiyun dev->__using_pio_transfers = true;
4921*4882a593Smuzhiyun err = b43_pio_init(dev);
4922*4882a593Smuzhiyun } else if (dev->use_pio) {
4923*4882a593Smuzhiyun b43warn(dev->wl, "Forced PIO by use_pio module parameter. "
4924*4882a593Smuzhiyun "This should not be needed and will result in lower "
4925*4882a593Smuzhiyun "performance.\n");
4926*4882a593Smuzhiyun dev->__using_pio_transfers = true;
4927*4882a593Smuzhiyun err = b43_pio_init(dev);
4928*4882a593Smuzhiyun } else {
4929*4882a593Smuzhiyun dev->__using_pio_transfers = false;
4930*4882a593Smuzhiyun err = b43_dma_init(dev);
4931*4882a593Smuzhiyun }
4932*4882a593Smuzhiyun if (err)
4933*4882a593Smuzhiyun goto err_chip_exit;
4934*4882a593Smuzhiyun b43_qos_init(dev);
4935*4882a593Smuzhiyun b43_set_synth_pu_delay(dev, 1);
4936*4882a593Smuzhiyun b43_bluetooth_coext_enable(dev);
4937*4882a593Smuzhiyun
4938*4882a593Smuzhiyun b43_bus_powerup(dev, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
4939*4882a593Smuzhiyun b43_upload_card_macaddress(dev);
4940*4882a593Smuzhiyun b43_security_init(dev);
4941*4882a593Smuzhiyun
4942*4882a593Smuzhiyun ieee80211_wake_queues(dev->wl->hw);
4943*4882a593Smuzhiyun
4944*4882a593Smuzhiyun b43_set_status(dev, B43_STAT_INITIALIZED);
4945*4882a593Smuzhiyun
4946*4882a593Smuzhiyun out:
4947*4882a593Smuzhiyun return err;
4948*4882a593Smuzhiyun
4949*4882a593Smuzhiyun err_chip_exit:
4950*4882a593Smuzhiyun b43_chip_exit(dev);
4951*4882a593Smuzhiyun err_busdown:
4952*4882a593Smuzhiyun b43_bus_may_powerdown(dev);
4953*4882a593Smuzhiyun B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
4954*4882a593Smuzhiyun return err;
4955*4882a593Smuzhiyun }
4956*4882a593Smuzhiyun
b43_op_add_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)4957*4882a593Smuzhiyun static int b43_op_add_interface(struct ieee80211_hw *hw,
4958*4882a593Smuzhiyun struct ieee80211_vif *vif)
4959*4882a593Smuzhiyun {
4960*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
4961*4882a593Smuzhiyun struct b43_wldev *dev;
4962*4882a593Smuzhiyun int err = -EOPNOTSUPP;
4963*4882a593Smuzhiyun
4964*4882a593Smuzhiyun /* TODO: allow WDS/AP devices to coexist */
4965*4882a593Smuzhiyun
4966*4882a593Smuzhiyun if (vif->type != NL80211_IFTYPE_AP &&
4967*4882a593Smuzhiyun vif->type != NL80211_IFTYPE_MESH_POINT &&
4968*4882a593Smuzhiyun vif->type != NL80211_IFTYPE_STATION &&
4969*4882a593Smuzhiyun vif->type != NL80211_IFTYPE_WDS &&
4970*4882a593Smuzhiyun vif->type != NL80211_IFTYPE_ADHOC)
4971*4882a593Smuzhiyun return -EOPNOTSUPP;
4972*4882a593Smuzhiyun
4973*4882a593Smuzhiyun mutex_lock(&wl->mutex);
4974*4882a593Smuzhiyun if (wl->operating)
4975*4882a593Smuzhiyun goto out_mutex_unlock;
4976*4882a593Smuzhiyun
4977*4882a593Smuzhiyun b43dbg(wl, "Adding Interface type %d\n", vif->type);
4978*4882a593Smuzhiyun
4979*4882a593Smuzhiyun dev = wl->current_dev;
4980*4882a593Smuzhiyun wl->operating = true;
4981*4882a593Smuzhiyun wl->vif = vif;
4982*4882a593Smuzhiyun wl->if_type = vif->type;
4983*4882a593Smuzhiyun memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
4984*4882a593Smuzhiyun
4985*4882a593Smuzhiyun b43_adjust_opmode(dev);
4986*4882a593Smuzhiyun b43_set_pretbtt(dev);
4987*4882a593Smuzhiyun b43_set_synth_pu_delay(dev, 0);
4988*4882a593Smuzhiyun b43_upload_card_macaddress(dev);
4989*4882a593Smuzhiyun
4990*4882a593Smuzhiyun err = 0;
4991*4882a593Smuzhiyun out_mutex_unlock:
4992*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
4993*4882a593Smuzhiyun
4994*4882a593Smuzhiyun if (err == 0)
4995*4882a593Smuzhiyun b43_op_bss_info_changed(hw, vif, &vif->bss_conf, ~0);
4996*4882a593Smuzhiyun
4997*4882a593Smuzhiyun return err;
4998*4882a593Smuzhiyun }
4999*4882a593Smuzhiyun
b43_op_remove_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)5000*4882a593Smuzhiyun static void b43_op_remove_interface(struct ieee80211_hw *hw,
5001*4882a593Smuzhiyun struct ieee80211_vif *vif)
5002*4882a593Smuzhiyun {
5003*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
5004*4882a593Smuzhiyun struct b43_wldev *dev = wl->current_dev;
5005*4882a593Smuzhiyun
5006*4882a593Smuzhiyun b43dbg(wl, "Removing Interface type %d\n", vif->type);
5007*4882a593Smuzhiyun
5008*4882a593Smuzhiyun mutex_lock(&wl->mutex);
5009*4882a593Smuzhiyun
5010*4882a593Smuzhiyun B43_WARN_ON(!wl->operating);
5011*4882a593Smuzhiyun B43_WARN_ON(wl->vif != vif);
5012*4882a593Smuzhiyun wl->vif = NULL;
5013*4882a593Smuzhiyun
5014*4882a593Smuzhiyun wl->operating = false;
5015*4882a593Smuzhiyun
5016*4882a593Smuzhiyun b43_adjust_opmode(dev);
5017*4882a593Smuzhiyun eth_zero_addr(wl->mac_addr);
5018*4882a593Smuzhiyun b43_upload_card_macaddress(dev);
5019*4882a593Smuzhiyun
5020*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
5021*4882a593Smuzhiyun }
5022*4882a593Smuzhiyun
b43_op_start(struct ieee80211_hw * hw)5023*4882a593Smuzhiyun static int b43_op_start(struct ieee80211_hw *hw)
5024*4882a593Smuzhiyun {
5025*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
5026*4882a593Smuzhiyun struct b43_wldev *dev = wl->current_dev;
5027*4882a593Smuzhiyun int did_init = 0;
5028*4882a593Smuzhiyun int err = 0;
5029*4882a593Smuzhiyun
5030*4882a593Smuzhiyun /* Kill all old instance specific information to make sure
5031*4882a593Smuzhiyun * the card won't use it in the short timeframe between start
5032*4882a593Smuzhiyun * and mac80211 reconfiguring it. */
5033*4882a593Smuzhiyun eth_zero_addr(wl->bssid);
5034*4882a593Smuzhiyun eth_zero_addr(wl->mac_addr);
5035*4882a593Smuzhiyun wl->filter_flags = 0;
5036*4882a593Smuzhiyun wl->radiotap_enabled = false;
5037*4882a593Smuzhiyun b43_qos_clear(wl);
5038*4882a593Smuzhiyun wl->beacon0_uploaded = false;
5039*4882a593Smuzhiyun wl->beacon1_uploaded = false;
5040*4882a593Smuzhiyun wl->beacon_templates_virgin = true;
5041*4882a593Smuzhiyun wl->radio_enabled = true;
5042*4882a593Smuzhiyun
5043*4882a593Smuzhiyun mutex_lock(&wl->mutex);
5044*4882a593Smuzhiyun
5045*4882a593Smuzhiyun if (b43_status(dev) < B43_STAT_INITIALIZED) {
5046*4882a593Smuzhiyun err = b43_wireless_core_init(dev);
5047*4882a593Smuzhiyun if (err)
5048*4882a593Smuzhiyun goto out_mutex_unlock;
5049*4882a593Smuzhiyun did_init = 1;
5050*4882a593Smuzhiyun }
5051*4882a593Smuzhiyun
5052*4882a593Smuzhiyun if (b43_status(dev) < B43_STAT_STARTED) {
5053*4882a593Smuzhiyun err = b43_wireless_core_start(dev);
5054*4882a593Smuzhiyun if (err) {
5055*4882a593Smuzhiyun if (did_init)
5056*4882a593Smuzhiyun b43_wireless_core_exit(dev);
5057*4882a593Smuzhiyun goto out_mutex_unlock;
5058*4882a593Smuzhiyun }
5059*4882a593Smuzhiyun }
5060*4882a593Smuzhiyun
5061*4882a593Smuzhiyun /* XXX: only do if device doesn't support rfkill irq */
5062*4882a593Smuzhiyun wiphy_rfkill_start_polling(hw->wiphy);
5063*4882a593Smuzhiyun
5064*4882a593Smuzhiyun out_mutex_unlock:
5065*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
5066*4882a593Smuzhiyun
5067*4882a593Smuzhiyun /*
5068*4882a593Smuzhiyun * Configuration may have been overwritten during initialization.
5069*4882a593Smuzhiyun * Reload the configuration, but only if initialization was
5070*4882a593Smuzhiyun * successful. Reloading the configuration after a failed init
5071*4882a593Smuzhiyun * may hang the system.
5072*4882a593Smuzhiyun */
5073*4882a593Smuzhiyun if (!err)
5074*4882a593Smuzhiyun b43_op_config(hw, ~0);
5075*4882a593Smuzhiyun
5076*4882a593Smuzhiyun return err;
5077*4882a593Smuzhiyun }
5078*4882a593Smuzhiyun
b43_op_stop(struct ieee80211_hw * hw)5079*4882a593Smuzhiyun static void b43_op_stop(struct ieee80211_hw *hw)
5080*4882a593Smuzhiyun {
5081*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
5082*4882a593Smuzhiyun struct b43_wldev *dev = wl->current_dev;
5083*4882a593Smuzhiyun
5084*4882a593Smuzhiyun cancel_work_sync(&(wl->beacon_update_trigger));
5085*4882a593Smuzhiyun
5086*4882a593Smuzhiyun if (!dev)
5087*4882a593Smuzhiyun goto out;
5088*4882a593Smuzhiyun
5089*4882a593Smuzhiyun mutex_lock(&wl->mutex);
5090*4882a593Smuzhiyun if (b43_status(dev) >= B43_STAT_STARTED) {
5091*4882a593Smuzhiyun dev = b43_wireless_core_stop(dev);
5092*4882a593Smuzhiyun if (!dev)
5093*4882a593Smuzhiyun goto out_unlock;
5094*4882a593Smuzhiyun }
5095*4882a593Smuzhiyun b43_wireless_core_exit(dev);
5096*4882a593Smuzhiyun wl->radio_enabled = false;
5097*4882a593Smuzhiyun
5098*4882a593Smuzhiyun out_unlock:
5099*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
5100*4882a593Smuzhiyun out:
5101*4882a593Smuzhiyun cancel_work_sync(&(wl->txpower_adjust_work));
5102*4882a593Smuzhiyun }
5103*4882a593Smuzhiyun
b43_op_beacon_set_tim(struct ieee80211_hw * hw,struct ieee80211_sta * sta,bool set)5104*4882a593Smuzhiyun static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
5105*4882a593Smuzhiyun struct ieee80211_sta *sta, bool set)
5106*4882a593Smuzhiyun {
5107*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
5108*4882a593Smuzhiyun
5109*4882a593Smuzhiyun b43_update_templates(wl);
5110*4882a593Smuzhiyun
5111*4882a593Smuzhiyun return 0;
5112*4882a593Smuzhiyun }
5113*4882a593Smuzhiyun
b43_op_sta_notify(struct ieee80211_hw * hw,struct ieee80211_vif * vif,enum sta_notify_cmd notify_cmd,struct ieee80211_sta * sta)5114*4882a593Smuzhiyun static void b43_op_sta_notify(struct ieee80211_hw *hw,
5115*4882a593Smuzhiyun struct ieee80211_vif *vif,
5116*4882a593Smuzhiyun enum sta_notify_cmd notify_cmd,
5117*4882a593Smuzhiyun struct ieee80211_sta *sta)
5118*4882a593Smuzhiyun {
5119*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
5120*4882a593Smuzhiyun
5121*4882a593Smuzhiyun B43_WARN_ON(!vif || wl->vif != vif);
5122*4882a593Smuzhiyun }
5123*4882a593Smuzhiyun
b43_op_sw_scan_start_notifier(struct ieee80211_hw * hw,struct ieee80211_vif * vif,const u8 * mac_addr)5124*4882a593Smuzhiyun static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw,
5125*4882a593Smuzhiyun struct ieee80211_vif *vif,
5126*4882a593Smuzhiyun const u8 *mac_addr)
5127*4882a593Smuzhiyun {
5128*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
5129*4882a593Smuzhiyun struct b43_wldev *dev;
5130*4882a593Smuzhiyun
5131*4882a593Smuzhiyun mutex_lock(&wl->mutex);
5132*4882a593Smuzhiyun dev = wl->current_dev;
5133*4882a593Smuzhiyun if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) {
5134*4882a593Smuzhiyun /* Disable CFP update during scan on other channels. */
5135*4882a593Smuzhiyun b43_hf_write(dev, b43_hf_read(dev) | B43_HF_SKCFPUP);
5136*4882a593Smuzhiyun }
5137*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
5138*4882a593Smuzhiyun }
5139*4882a593Smuzhiyun
b43_op_sw_scan_complete_notifier(struct ieee80211_hw * hw,struct ieee80211_vif * vif)5140*4882a593Smuzhiyun static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw,
5141*4882a593Smuzhiyun struct ieee80211_vif *vif)
5142*4882a593Smuzhiyun {
5143*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
5144*4882a593Smuzhiyun struct b43_wldev *dev;
5145*4882a593Smuzhiyun
5146*4882a593Smuzhiyun mutex_lock(&wl->mutex);
5147*4882a593Smuzhiyun dev = wl->current_dev;
5148*4882a593Smuzhiyun if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) {
5149*4882a593Smuzhiyun /* Re-enable CFP update. */
5150*4882a593Smuzhiyun b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_SKCFPUP);
5151*4882a593Smuzhiyun }
5152*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
5153*4882a593Smuzhiyun }
5154*4882a593Smuzhiyun
b43_op_get_survey(struct ieee80211_hw * hw,int idx,struct survey_info * survey)5155*4882a593Smuzhiyun static int b43_op_get_survey(struct ieee80211_hw *hw, int idx,
5156*4882a593Smuzhiyun struct survey_info *survey)
5157*4882a593Smuzhiyun {
5158*4882a593Smuzhiyun struct b43_wl *wl = hw_to_b43_wl(hw);
5159*4882a593Smuzhiyun struct b43_wldev *dev = wl->current_dev;
5160*4882a593Smuzhiyun struct ieee80211_conf *conf = &hw->conf;
5161*4882a593Smuzhiyun
5162*4882a593Smuzhiyun if (idx != 0)
5163*4882a593Smuzhiyun return -ENOENT;
5164*4882a593Smuzhiyun
5165*4882a593Smuzhiyun survey->channel = conf->chandef.chan;
5166*4882a593Smuzhiyun survey->filled = SURVEY_INFO_NOISE_DBM;
5167*4882a593Smuzhiyun survey->noise = dev->stats.link_noise;
5168*4882a593Smuzhiyun
5169*4882a593Smuzhiyun return 0;
5170*4882a593Smuzhiyun }
5171*4882a593Smuzhiyun
5172*4882a593Smuzhiyun static const struct ieee80211_ops b43_hw_ops = {
5173*4882a593Smuzhiyun .tx = b43_op_tx,
5174*4882a593Smuzhiyun .conf_tx = b43_op_conf_tx,
5175*4882a593Smuzhiyun .add_interface = b43_op_add_interface,
5176*4882a593Smuzhiyun .remove_interface = b43_op_remove_interface,
5177*4882a593Smuzhiyun .config = b43_op_config,
5178*4882a593Smuzhiyun .bss_info_changed = b43_op_bss_info_changed,
5179*4882a593Smuzhiyun .configure_filter = b43_op_configure_filter,
5180*4882a593Smuzhiyun .set_key = b43_op_set_key,
5181*4882a593Smuzhiyun .update_tkip_key = b43_op_update_tkip_key,
5182*4882a593Smuzhiyun .get_stats = b43_op_get_stats,
5183*4882a593Smuzhiyun .get_tsf = b43_op_get_tsf,
5184*4882a593Smuzhiyun .set_tsf = b43_op_set_tsf,
5185*4882a593Smuzhiyun .start = b43_op_start,
5186*4882a593Smuzhiyun .stop = b43_op_stop,
5187*4882a593Smuzhiyun .set_tim = b43_op_beacon_set_tim,
5188*4882a593Smuzhiyun .sta_notify = b43_op_sta_notify,
5189*4882a593Smuzhiyun .sw_scan_start = b43_op_sw_scan_start_notifier,
5190*4882a593Smuzhiyun .sw_scan_complete = b43_op_sw_scan_complete_notifier,
5191*4882a593Smuzhiyun .get_survey = b43_op_get_survey,
5192*4882a593Smuzhiyun .rfkill_poll = b43_rfkill_poll,
5193*4882a593Smuzhiyun };
5194*4882a593Smuzhiyun
5195*4882a593Smuzhiyun /* Hard-reset the chip. Do not call this directly.
5196*4882a593Smuzhiyun * Use b43_controller_restart()
5197*4882a593Smuzhiyun */
b43_chip_reset(struct work_struct * work)5198*4882a593Smuzhiyun static void b43_chip_reset(struct work_struct *work)
5199*4882a593Smuzhiyun {
5200*4882a593Smuzhiyun struct b43_wldev *dev =
5201*4882a593Smuzhiyun container_of(work, struct b43_wldev, restart_work);
5202*4882a593Smuzhiyun struct b43_wl *wl = dev->wl;
5203*4882a593Smuzhiyun int err = 0;
5204*4882a593Smuzhiyun int prev_status;
5205*4882a593Smuzhiyun
5206*4882a593Smuzhiyun mutex_lock(&wl->mutex);
5207*4882a593Smuzhiyun
5208*4882a593Smuzhiyun prev_status = b43_status(dev);
5209*4882a593Smuzhiyun /* Bring the device down... */
5210*4882a593Smuzhiyun if (prev_status >= B43_STAT_STARTED) {
5211*4882a593Smuzhiyun dev = b43_wireless_core_stop(dev);
5212*4882a593Smuzhiyun if (!dev) {
5213*4882a593Smuzhiyun err = -ENODEV;
5214*4882a593Smuzhiyun goto out;
5215*4882a593Smuzhiyun }
5216*4882a593Smuzhiyun }
5217*4882a593Smuzhiyun if (prev_status >= B43_STAT_INITIALIZED)
5218*4882a593Smuzhiyun b43_wireless_core_exit(dev);
5219*4882a593Smuzhiyun
5220*4882a593Smuzhiyun /* ...and up again. */
5221*4882a593Smuzhiyun if (prev_status >= B43_STAT_INITIALIZED) {
5222*4882a593Smuzhiyun err = b43_wireless_core_init(dev);
5223*4882a593Smuzhiyun if (err)
5224*4882a593Smuzhiyun goto out;
5225*4882a593Smuzhiyun }
5226*4882a593Smuzhiyun if (prev_status >= B43_STAT_STARTED) {
5227*4882a593Smuzhiyun err = b43_wireless_core_start(dev);
5228*4882a593Smuzhiyun if (err) {
5229*4882a593Smuzhiyun b43_wireless_core_exit(dev);
5230*4882a593Smuzhiyun goto out;
5231*4882a593Smuzhiyun }
5232*4882a593Smuzhiyun }
5233*4882a593Smuzhiyun out:
5234*4882a593Smuzhiyun if (err)
5235*4882a593Smuzhiyun wl->current_dev = NULL; /* Failed to init the dev. */
5236*4882a593Smuzhiyun mutex_unlock(&wl->mutex);
5237*4882a593Smuzhiyun
5238*4882a593Smuzhiyun if (err) {
5239*4882a593Smuzhiyun b43err(wl, "Controller restart FAILED\n");
5240*4882a593Smuzhiyun return;
5241*4882a593Smuzhiyun }
5242*4882a593Smuzhiyun
5243*4882a593Smuzhiyun /* reload configuration */
5244*4882a593Smuzhiyun b43_op_config(wl->hw, ~0);
5245*4882a593Smuzhiyun if (wl->vif)
5246*4882a593Smuzhiyun b43_op_bss_info_changed(wl->hw, wl->vif, &wl->vif->bss_conf, ~0);
5247*4882a593Smuzhiyun
5248*4882a593Smuzhiyun b43info(wl, "Controller restarted\n");
5249*4882a593Smuzhiyun }
5250*4882a593Smuzhiyun
b43_setup_bands(struct b43_wldev * dev,bool have_2ghz_phy,bool have_5ghz_phy)5251*4882a593Smuzhiyun static int b43_setup_bands(struct b43_wldev *dev,
5252*4882a593Smuzhiyun bool have_2ghz_phy, bool have_5ghz_phy)
5253*4882a593Smuzhiyun {
5254*4882a593Smuzhiyun struct ieee80211_hw *hw = dev->wl->hw;
5255*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
5256*4882a593Smuzhiyun bool limited_2g;
5257*4882a593Smuzhiyun bool limited_5g;
5258*4882a593Smuzhiyun
5259*4882a593Smuzhiyun /* We don't support all 2 GHz channels on some devices */
5260*4882a593Smuzhiyun limited_2g = phy->radio_ver == 0x2057 &&
5261*4882a593Smuzhiyun (phy->radio_rev == 9 || phy->radio_rev == 14);
5262*4882a593Smuzhiyun limited_5g = phy->radio_ver == 0x2057 &&
5263*4882a593Smuzhiyun phy->radio_rev == 9;
5264*4882a593Smuzhiyun
5265*4882a593Smuzhiyun if (have_2ghz_phy)
5266*4882a593Smuzhiyun hw->wiphy->bands[NL80211_BAND_2GHZ] = limited_2g ?
5267*4882a593Smuzhiyun &b43_band_2ghz_limited : &b43_band_2GHz;
5268*4882a593Smuzhiyun if (dev->phy.type == B43_PHYTYPE_N) {
5269*4882a593Smuzhiyun if (have_5ghz_phy)
5270*4882a593Smuzhiyun hw->wiphy->bands[NL80211_BAND_5GHZ] = limited_5g ?
5271*4882a593Smuzhiyun &b43_band_5GHz_nphy_limited :
5272*4882a593Smuzhiyun &b43_band_5GHz_nphy;
5273*4882a593Smuzhiyun } else {
5274*4882a593Smuzhiyun if (have_5ghz_phy)
5275*4882a593Smuzhiyun hw->wiphy->bands[NL80211_BAND_5GHZ] = &b43_band_5GHz_aphy;
5276*4882a593Smuzhiyun }
5277*4882a593Smuzhiyun
5278*4882a593Smuzhiyun dev->phy.supports_2ghz = have_2ghz_phy;
5279*4882a593Smuzhiyun dev->phy.supports_5ghz = have_5ghz_phy;
5280*4882a593Smuzhiyun
5281*4882a593Smuzhiyun return 0;
5282*4882a593Smuzhiyun }
5283*4882a593Smuzhiyun
b43_wireless_core_detach(struct b43_wldev * dev)5284*4882a593Smuzhiyun static void b43_wireless_core_detach(struct b43_wldev *dev)
5285*4882a593Smuzhiyun {
5286*4882a593Smuzhiyun /* We release firmware that late to not be required to re-request
5287*4882a593Smuzhiyun * is all the time when we reinit the core. */
5288*4882a593Smuzhiyun b43_release_firmware(dev);
5289*4882a593Smuzhiyun b43_phy_free(dev);
5290*4882a593Smuzhiyun }
5291*4882a593Smuzhiyun
b43_supported_bands(struct b43_wldev * dev,bool * have_2ghz_phy,bool * have_5ghz_phy)5292*4882a593Smuzhiyun static void b43_supported_bands(struct b43_wldev *dev, bool *have_2ghz_phy,
5293*4882a593Smuzhiyun bool *have_5ghz_phy)
5294*4882a593Smuzhiyun {
5295*4882a593Smuzhiyun u16 dev_id = 0;
5296*4882a593Smuzhiyun
5297*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
5298*4882a593Smuzhiyun if (dev->dev->bus_type == B43_BUS_BCMA &&
5299*4882a593Smuzhiyun dev->dev->bdev->bus->hosttype == BCMA_HOSTTYPE_PCI)
5300*4882a593Smuzhiyun dev_id = dev->dev->bdev->bus->host_pci->device;
5301*4882a593Smuzhiyun #endif
5302*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
5303*4882a593Smuzhiyun if (dev->dev->bus_type == B43_BUS_SSB &&
5304*4882a593Smuzhiyun dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI)
5305*4882a593Smuzhiyun dev_id = dev->dev->sdev->bus->host_pci->device;
5306*4882a593Smuzhiyun #endif
5307*4882a593Smuzhiyun /* Override with SPROM value if available */
5308*4882a593Smuzhiyun if (dev->dev->bus_sprom->dev_id)
5309*4882a593Smuzhiyun dev_id = dev->dev->bus_sprom->dev_id;
5310*4882a593Smuzhiyun
5311*4882a593Smuzhiyun /* Note: below IDs can be "virtual" (not maching e.g. real PCI ID) */
5312*4882a593Smuzhiyun switch (dev_id) {
5313*4882a593Smuzhiyun case 0x4324: /* BCM4306 */
5314*4882a593Smuzhiyun case 0x4312: /* BCM4311 */
5315*4882a593Smuzhiyun case 0x4319: /* BCM4318 */
5316*4882a593Smuzhiyun case 0x4328: /* BCM4321 */
5317*4882a593Smuzhiyun case 0x432b: /* BCM4322 */
5318*4882a593Smuzhiyun case 0x4350: /* BCM43222 */
5319*4882a593Smuzhiyun case 0x4353: /* BCM43224 */
5320*4882a593Smuzhiyun case 0x0576: /* BCM43224 */
5321*4882a593Smuzhiyun case 0x435f: /* BCM6362 */
5322*4882a593Smuzhiyun case 0x4331: /* BCM4331 */
5323*4882a593Smuzhiyun case 0x4359: /* BCM43228 */
5324*4882a593Smuzhiyun case 0x43a0: /* BCM4360 */
5325*4882a593Smuzhiyun case 0x43b1: /* BCM4352 */
5326*4882a593Smuzhiyun /* Dual band devices */
5327*4882a593Smuzhiyun *have_2ghz_phy = true;
5328*4882a593Smuzhiyun *have_5ghz_phy = true;
5329*4882a593Smuzhiyun return;
5330*4882a593Smuzhiyun case 0x4321: /* BCM4306 */
5331*4882a593Smuzhiyun /* There are 14e4:4321 PCI devs with 2.4 GHz BCM4321 (N-PHY) */
5332*4882a593Smuzhiyun if (dev->phy.type != B43_PHYTYPE_G)
5333*4882a593Smuzhiyun break;
5334*4882a593Smuzhiyun fallthrough;
5335*4882a593Smuzhiyun case 0x4313: /* BCM4311 */
5336*4882a593Smuzhiyun case 0x431a: /* BCM4318 */
5337*4882a593Smuzhiyun case 0x432a: /* BCM4321 */
5338*4882a593Smuzhiyun case 0x432d: /* BCM4322 */
5339*4882a593Smuzhiyun case 0x4352: /* BCM43222 */
5340*4882a593Smuzhiyun case 0x435a: /* BCM43228 */
5341*4882a593Smuzhiyun case 0x4333: /* BCM4331 */
5342*4882a593Smuzhiyun case 0x43a2: /* BCM4360 */
5343*4882a593Smuzhiyun case 0x43b3: /* BCM4352 */
5344*4882a593Smuzhiyun /* 5 GHz only devices */
5345*4882a593Smuzhiyun *have_2ghz_phy = false;
5346*4882a593Smuzhiyun *have_5ghz_phy = true;
5347*4882a593Smuzhiyun return;
5348*4882a593Smuzhiyun }
5349*4882a593Smuzhiyun
5350*4882a593Smuzhiyun /* As a fallback, try to guess using PHY type */
5351*4882a593Smuzhiyun switch (dev->phy.type) {
5352*4882a593Smuzhiyun case B43_PHYTYPE_G:
5353*4882a593Smuzhiyun case B43_PHYTYPE_N:
5354*4882a593Smuzhiyun case B43_PHYTYPE_LP:
5355*4882a593Smuzhiyun case B43_PHYTYPE_HT:
5356*4882a593Smuzhiyun case B43_PHYTYPE_LCN:
5357*4882a593Smuzhiyun *have_2ghz_phy = true;
5358*4882a593Smuzhiyun *have_5ghz_phy = false;
5359*4882a593Smuzhiyun return;
5360*4882a593Smuzhiyun }
5361*4882a593Smuzhiyun
5362*4882a593Smuzhiyun B43_WARN_ON(1);
5363*4882a593Smuzhiyun }
5364*4882a593Smuzhiyun
b43_wireless_core_attach(struct b43_wldev * dev)5365*4882a593Smuzhiyun static int b43_wireless_core_attach(struct b43_wldev *dev)
5366*4882a593Smuzhiyun {
5367*4882a593Smuzhiyun struct b43_wl *wl = dev->wl;
5368*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
5369*4882a593Smuzhiyun int err;
5370*4882a593Smuzhiyun u32 tmp;
5371*4882a593Smuzhiyun bool have_2ghz_phy = false, have_5ghz_phy = false;
5372*4882a593Smuzhiyun
5373*4882a593Smuzhiyun /* Do NOT do any device initialization here.
5374*4882a593Smuzhiyun * Do it in wireless_core_init() instead.
5375*4882a593Smuzhiyun * This function is for gathering basic information about the HW, only.
5376*4882a593Smuzhiyun * Also some structs may be set up here. But most likely you want to have
5377*4882a593Smuzhiyun * that in core_init(), too.
5378*4882a593Smuzhiyun */
5379*4882a593Smuzhiyun
5380*4882a593Smuzhiyun err = b43_bus_powerup(dev, 0);
5381*4882a593Smuzhiyun if (err) {
5382*4882a593Smuzhiyun b43err(wl, "Bus powerup failed\n");
5383*4882a593Smuzhiyun goto out;
5384*4882a593Smuzhiyun }
5385*4882a593Smuzhiyun
5386*4882a593Smuzhiyun phy->do_full_init = true;
5387*4882a593Smuzhiyun
5388*4882a593Smuzhiyun /* Try to guess supported bands for the first init needs */
5389*4882a593Smuzhiyun switch (dev->dev->bus_type) {
5390*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
5391*4882a593Smuzhiyun case B43_BUS_BCMA:
5392*4882a593Smuzhiyun tmp = bcma_aread32(dev->dev->bdev, BCMA_IOST);
5393*4882a593Smuzhiyun have_2ghz_phy = !!(tmp & B43_BCMA_IOST_2G_PHY);
5394*4882a593Smuzhiyun have_5ghz_phy = !!(tmp & B43_BCMA_IOST_5G_PHY);
5395*4882a593Smuzhiyun break;
5396*4882a593Smuzhiyun #endif
5397*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
5398*4882a593Smuzhiyun case B43_BUS_SSB:
5399*4882a593Smuzhiyun if (dev->dev->core_rev >= 5) {
5400*4882a593Smuzhiyun tmp = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
5401*4882a593Smuzhiyun have_2ghz_phy = !!(tmp & B43_TMSHIGH_HAVE_2GHZ_PHY);
5402*4882a593Smuzhiyun have_5ghz_phy = !!(tmp & B43_TMSHIGH_HAVE_5GHZ_PHY);
5403*4882a593Smuzhiyun } else
5404*4882a593Smuzhiyun B43_WARN_ON(1);
5405*4882a593Smuzhiyun break;
5406*4882a593Smuzhiyun #endif
5407*4882a593Smuzhiyun }
5408*4882a593Smuzhiyun
5409*4882a593Smuzhiyun dev->phy.gmode = have_2ghz_phy;
5410*4882a593Smuzhiyun b43_wireless_core_reset(dev, dev->phy.gmode);
5411*4882a593Smuzhiyun
5412*4882a593Smuzhiyun /* Get the PHY type. */
5413*4882a593Smuzhiyun err = b43_phy_versioning(dev);
5414*4882a593Smuzhiyun if (err)
5415*4882a593Smuzhiyun goto err_powerdown;
5416*4882a593Smuzhiyun
5417*4882a593Smuzhiyun /* Get real info about supported bands */
5418*4882a593Smuzhiyun b43_supported_bands(dev, &have_2ghz_phy, &have_5ghz_phy);
5419*4882a593Smuzhiyun
5420*4882a593Smuzhiyun /* We don't support 5 GHz on some PHYs yet */
5421*4882a593Smuzhiyun if (have_5ghz_phy) {
5422*4882a593Smuzhiyun switch (dev->phy.type) {
5423*4882a593Smuzhiyun case B43_PHYTYPE_G:
5424*4882a593Smuzhiyun case B43_PHYTYPE_LP:
5425*4882a593Smuzhiyun case B43_PHYTYPE_HT:
5426*4882a593Smuzhiyun b43warn(wl, "5 GHz band is unsupported on this PHY\n");
5427*4882a593Smuzhiyun have_5ghz_phy = false;
5428*4882a593Smuzhiyun }
5429*4882a593Smuzhiyun }
5430*4882a593Smuzhiyun
5431*4882a593Smuzhiyun if (!have_2ghz_phy && !have_5ghz_phy) {
5432*4882a593Smuzhiyun b43err(wl, "b43 can't support any band on this device\n");
5433*4882a593Smuzhiyun err = -EOPNOTSUPP;
5434*4882a593Smuzhiyun goto err_powerdown;
5435*4882a593Smuzhiyun }
5436*4882a593Smuzhiyun
5437*4882a593Smuzhiyun err = b43_phy_allocate(dev);
5438*4882a593Smuzhiyun if (err)
5439*4882a593Smuzhiyun goto err_powerdown;
5440*4882a593Smuzhiyun
5441*4882a593Smuzhiyun dev->phy.gmode = have_2ghz_phy;
5442*4882a593Smuzhiyun b43_wireless_core_reset(dev, dev->phy.gmode);
5443*4882a593Smuzhiyun
5444*4882a593Smuzhiyun err = b43_validate_chipaccess(dev);
5445*4882a593Smuzhiyun if (err)
5446*4882a593Smuzhiyun goto err_phy_free;
5447*4882a593Smuzhiyun err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy);
5448*4882a593Smuzhiyun if (err)
5449*4882a593Smuzhiyun goto err_phy_free;
5450*4882a593Smuzhiyun
5451*4882a593Smuzhiyun /* Now set some default "current_dev" */
5452*4882a593Smuzhiyun if (!wl->current_dev)
5453*4882a593Smuzhiyun wl->current_dev = dev;
5454*4882a593Smuzhiyun INIT_WORK(&dev->restart_work, b43_chip_reset);
5455*4882a593Smuzhiyun
5456*4882a593Smuzhiyun dev->phy.ops->switch_analog(dev, 0);
5457*4882a593Smuzhiyun b43_device_disable(dev, 0);
5458*4882a593Smuzhiyun b43_bus_may_powerdown(dev);
5459*4882a593Smuzhiyun
5460*4882a593Smuzhiyun out:
5461*4882a593Smuzhiyun return err;
5462*4882a593Smuzhiyun
5463*4882a593Smuzhiyun err_phy_free:
5464*4882a593Smuzhiyun b43_phy_free(dev);
5465*4882a593Smuzhiyun err_powerdown:
5466*4882a593Smuzhiyun b43_bus_may_powerdown(dev);
5467*4882a593Smuzhiyun return err;
5468*4882a593Smuzhiyun }
5469*4882a593Smuzhiyun
b43_one_core_detach(struct b43_bus_dev * dev)5470*4882a593Smuzhiyun static void b43_one_core_detach(struct b43_bus_dev *dev)
5471*4882a593Smuzhiyun {
5472*4882a593Smuzhiyun struct b43_wldev *wldev;
5473*4882a593Smuzhiyun
5474*4882a593Smuzhiyun /* Do not cancel ieee80211-workqueue based work here.
5475*4882a593Smuzhiyun * See comment in b43_remove(). */
5476*4882a593Smuzhiyun
5477*4882a593Smuzhiyun wldev = b43_bus_get_wldev(dev);
5478*4882a593Smuzhiyun b43_debugfs_remove_device(wldev);
5479*4882a593Smuzhiyun b43_wireless_core_detach(wldev);
5480*4882a593Smuzhiyun list_del(&wldev->list);
5481*4882a593Smuzhiyun b43_bus_set_wldev(dev, NULL);
5482*4882a593Smuzhiyun kfree(wldev);
5483*4882a593Smuzhiyun }
5484*4882a593Smuzhiyun
b43_one_core_attach(struct b43_bus_dev * dev,struct b43_wl * wl)5485*4882a593Smuzhiyun static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl)
5486*4882a593Smuzhiyun {
5487*4882a593Smuzhiyun struct b43_wldev *wldev;
5488*4882a593Smuzhiyun int err = -ENOMEM;
5489*4882a593Smuzhiyun
5490*4882a593Smuzhiyun wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
5491*4882a593Smuzhiyun if (!wldev)
5492*4882a593Smuzhiyun goto out;
5493*4882a593Smuzhiyun
5494*4882a593Smuzhiyun wldev->use_pio = b43_modparam_pio;
5495*4882a593Smuzhiyun wldev->dev = dev;
5496*4882a593Smuzhiyun wldev->wl = wl;
5497*4882a593Smuzhiyun b43_set_status(wldev, B43_STAT_UNINIT);
5498*4882a593Smuzhiyun wldev->bad_frames_preempt = modparam_bad_frames_preempt;
5499*4882a593Smuzhiyun INIT_LIST_HEAD(&wldev->list);
5500*4882a593Smuzhiyun
5501*4882a593Smuzhiyun err = b43_wireless_core_attach(wldev);
5502*4882a593Smuzhiyun if (err)
5503*4882a593Smuzhiyun goto err_kfree_wldev;
5504*4882a593Smuzhiyun
5505*4882a593Smuzhiyun b43_bus_set_wldev(dev, wldev);
5506*4882a593Smuzhiyun b43_debugfs_add_device(wldev);
5507*4882a593Smuzhiyun
5508*4882a593Smuzhiyun out:
5509*4882a593Smuzhiyun return err;
5510*4882a593Smuzhiyun
5511*4882a593Smuzhiyun err_kfree_wldev:
5512*4882a593Smuzhiyun kfree(wldev);
5513*4882a593Smuzhiyun return err;
5514*4882a593Smuzhiyun }
5515*4882a593Smuzhiyun
5516*4882a593Smuzhiyun #define IS_PDEV(pdev, _vendor, _device, _subvendor, _subdevice) ( \
5517*4882a593Smuzhiyun (pdev->vendor == PCI_VENDOR_ID_##_vendor) && \
5518*4882a593Smuzhiyun (pdev->device == _device) && \
5519*4882a593Smuzhiyun (pdev->subsystem_vendor == PCI_VENDOR_ID_##_subvendor) && \
5520*4882a593Smuzhiyun (pdev->subsystem_device == _subdevice) )
5521*4882a593Smuzhiyun
5522*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
b43_sprom_fixup(struct ssb_bus * bus)5523*4882a593Smuzhiyun static void b43_sprom_fixup(struct ssb_bus *bus)
5524*4882a593Smuzhiyun {
5525*4882a593Smuzhiyun struct pci_dev *pdev;
5526*4882a593Smuzhiyun
5527*4882a593Smuzhiyun /* boardflags workarounds */
5528*4882a593Smuzhiyun if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
5529*4882a593Smuzhiyun bus->chip_id == 0x4301 && bus->sprom.board_rev == 0x74)
5530*4882a593Smuzhiyun bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST;
5531*4882a593Smuzhiyun if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
5532*4882a593Smuzhiyun bus->boardinfo.type == 0x4E && bus->sprom.board_rev > 0x40)
5533*4882a593Smuzhiyun bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
5534*4882a593Smuzhiyun if (bus->bustype == SSB_BUSTYPE_PCI) {
5535*4882a593Smuzhiyun pdev = bus->host_pci;
5536*4882a593Smuzhiyun if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) ||
5537*4882a593Smuzhiyun IS_PDEV(pdev, BROADCOM, 0x4320, DELL, 0x0003) ||
5538*4882a593Smuzhiyun IS_PDEV(pdev, BROADCOM, 0x4320, HP, 0x12f8) ||
5539*4882a593Smuzhiyun IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) ||
5540*4882a593Smuzhiyun IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0014) ||
5541*4882a593Smuzhiyun IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013) ||
5542*4882a593Smuzhiyun IS_PDEV(pdev, BROADCOM, 0x4320, MOTOROLA, 0x7010))
5543*4882a593Smuzhiyun bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST;
5544*4882a593Smuzhiyun }
5545*4882a593Smuzhiyun }
5546*4882a593Smuzhiyun
b43_wireless_exit(struct b43_bus_dev * dev,struct b43_wl * wl)5547*4882a593Smuzhiyun static void b43_wireless_exit(struct b43_bus_dev *dev, struct b43_wl *wl)
5548*4882a593Smuzhiyun {
5549*4882a593Smuzhiyun struct ieee80211_hw *hw = wl->hw;
5550*4882a593Smuzhiyun
5551*4882a593Smuzhiyun ssb_set_devtypedata(dev->sdev, NULL);
5552*4882a593Smuzhiyun ieee80211_free_hw(hw);
5553*4882a593Smuzhiyun }
5554*4882a593Smuzhiyun #endif
5555*4882a593Smuzhiyun
b43_wireless_init(struct b43_bus_dev * dev)5556*4882a593Smuzhiyun static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
5557*4882a593Smuzhiyun {
5558*4882a593Smuzhiyun struct ssb_sprom *sprom = dev->bus_sprom;
5559*4882a593Smuzhiyun struct ieee80211_hw *hw;
5560*4882a593Smuzhiyun struct b43_wl *wl;
5561*4882a593Smuzhiyun char chip_name[6];
5562*4882a593Smuzhiyun int queue_num;
5563*4882a593Smuzhiyun
5564*4882a593Smuzhiyun hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
5565*4882a593Smuzhiyun if (!hw) {
5566*4882a593Smuzhiyun b43err(NULL, "Could not allocate ieee80211 device\n");
5567*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
5568*4882a593Smuzhiyun }
5569*4882a593Smuzhiyun wl = hw_to_b43_wl(hw);
5570*4882a593Smuzhiyun
5571*4882a593Smuzhiyun /* fill hw info */
5572*4882a593Smuzhiyun ieee80211_hw_set(hw, RX_INCLUDES_FCS);
5573*4882a593Smuzhiyun ieee80211_hw_set(hw, SIGNAL_DBM);
5574*4882a593Smuzhiyun ieee80211_hw_set(hw, MFP_CAPABLE);
5575*4882a593Smuzhiyun hw->wiphy->interface_modes =
5576*4882a593Smuzhiyun BIT(NL80211_IFTYPE_AP) |
5577*4882a593Smuzhiyun BIT(NL80211_IFTYPE_MESH_POINT) |
5578*4882a593Smuzhiyun BIT(NL80211_IFTYPE_STATION) |
5579*4882a593Smuzhiyun #ifdef CONFIG_WIRELESS_WDS
5580*4882a593Smuzhiyun BIT(NL80211_IFTYPE_WDS) |
5581*4882a593Smuzhiyun #endif
5582*4882a593Smuzhiyun BIT(NL80211_IFTYPE_ADHOC);
5583*4882a593Smuzhiyun
5584*4882a593Smuzhiyun hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
5585*4882a593Smuzhiyun
5586*4882a593Smuzhiyun wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
5587*4882a593Smuzhiyun
5588*4882a593Smuzhiyun wl->hw_registered = false;
5589*4882a593Smuzhiyun hw->max_rates = 2;
5590*4882a593Smuzhiyun SET_IEEE80211_DEV(hw, dev->dev);
5591*4882a593Smuzhiyun if (is_valid_ether_addr(sprom->et1mac))
5592*4882a593Smuzhiyun SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
5593*4882a593Smuzhiyun else
5594*4882a593Smuzhiyun SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
5595*4882a593Smuzhiyun
5596*4882a593Smuzhiyun /* Initialize struct b43_wl */
5597*4882a593Smuzhiyun wl->hw = hw;
5598*4882a593Smuzhiyun mutex_init(&wl->mutex);
5599*4882a593Smuzhiyun spin_lock_init(&wl->hardirq_lock);
5600*4882a593Smuzhiyun spin_lock_init(&wl->beacon_lock);
5601*4882a593Smuzhiyun INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
5602*4882a593Smuzhiyun INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
5603*4882a593Smuzhiyun INIT_WORK(&wl->tx_work, b43_tx_work);
5604*4882a593Smuzhiyun
5605*4882a593Smuzhiyun /* Initialize queues and flags. */
5606*4882a593Smuzhiyun for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) {
5607*4882a593Smuzhiyun skb_queue_head_init(&wl->tx_queue[queue_num]);
5608*4882a593Smuzhiyun wl->tx_queue_stopped[queue_num] = false;
5609*4882a593Smuzhiyun }
5610*4882a593Smuzhiyun
5611*4882a593Smuzhiyun snprintf(chip_name, ARRAY_SIZE(chip_name),
5612*4882a593Smuzhiyun (dev->chip_id > 0x9999) ? "%d" : "%04X", dev->chip_id);
5613*4882a593Smuzhiyun b43info(wl, "Broadcom %s WLAN found (core revision %u)\n", chip_name,
5614*4882a593Smuzhiyun dev->core_rev);
5615*4882a593Smuzhiyun return wl;
5616*4882a593Smuzhiyun }
5617*4882a593Smuzhiyun
5618*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
b43_bcma_probe(struct bcma_device * core)5619*4882a593Smuzhiyun static int b43_bcma_probe(struct bcma_device *core)
5620*4882a593Smuzhiyun {
5621*4882a593Smuzhiyun struct b43_bus_dev *dev;
5622*4882a593Smuzhiyun struct b43_wl *wl;
5623*4882a593Smuzhiyun int err;
5624*4882a593Smuzhiyun
5625*4882a593Smuzhiyun if (!modparam_allhwsupport &&
5626*4882a593Smuzhiyun (core->id.rev == 0x17 || core->id.rev == 0x18)) {
5627*4882a593Smuzhiyun pr_err("Support for cores revisions 0x17 and 0x18 disabled by module param allhwsupport=0. Try b43.allhwsupport=1\n");
5628*4882a593Smuzhiyun return -ENOTSUPP;
5629*4882a593Smuzhiyun }
5630*4882a593Smuzhiyun
5631*4882a593Smuzhiyun dev = b43_bus_dev_bcma_init(core);
5632*4882a593Smuzhiyun if (!dev)
5633*4882a593Smuzhiyun return -ENODEV;
5634*4882a593Smuzhiyun
5635*4882a593Smuzhiyun wl = b43_wireless_init(dev);
5636*4882a593Smuzhiyun if (IS_ERR(wl)) {
5637*4882a593Smuzhiyun err = PTR_ERR(wl);
5638*4882a593Smuzhiyun goto bcma_out;
5639*4882a593Smuzhiyun }
5640*4882a593Smuzhiyun
5641*4882a593Smuzhiyun err = b43_one_core_attach(dev, wl);
5642*4882a593Smuzhiyun if (err)
5643*4882a593Smuzhiyun goto bcma_err_wireless_exit;
5644*4882a593Smuzhiyun
5645*4882a593Smuzhiyun /* setup and start work to load firmware */
5646*4882a593Smuzhiyun INIT_WORK(&wl->firmware_load, b43_request_firmware);
5647*4882a593Smuzhiyun schedule_work(&wl->firmware_load);
5648*4882a593Smuzhiyun
5649*4882a593Smuzhiyun return err;
5650*4882a593Smuzhiyun
5651*4882a593Smuzhiyun bcma_err_wireless_exit:
5652*4882a593Smuzhiyun ieee80211_free_hw(wl->hw);
5653*4882a593Smuzhiyun bcma_out:
5654*4882a593Smuzhiyun kfree(dev);
5655*4882a593Smuzhiyun return err;
5656*4882a593Smuzhiyun }
5657*4882a593Smuzhiyun
b43_bcma_remove(struct bcma_device * core)5658*4882a593Smuzhiyun static void b43_bcma_remove(struct bcma_device *core)
5659*4882a593Smuzhiyun {
5660*4882a593Smuzhiyun struct b43_wldev *wldev = bcma_get_drvdata(core);
5661*4882a593Smuzhiyun struct b43_wl *wl = wldev->wl;
5662*4882a593Smuzhiyun
5663*4882a593Smuzhiyun /* We must cancel any work here before unregistering from ieee80211,
5664*4882a593Smuzhiyun * as the ieee80211 unreg will destroy the workqueue. */
5665*4882a593Smuzhiyun cancel_work_sync(&wldev->restart_work);
5666*4882a593Smuzhiyun cancel_work_sync(&wl->firmware_load);
5667*4882a593Smuzhiyun
5668*4882a593Smuzhiyun B43_WARN_ON(!wl);
5669*4882a593Smuzhiyun if (!wldev->fw.ucode.data)
5670*4882a593Smuzhiyun return; /* NULL if firmware never loaded */
5671*4882a593Smuzhiyun if (wl->current_dev == wldev && wl->hw_registered) {
5672*4882a593Smuzhiyun b43_leds_stop(wldev);
5673*4882a593Smuzhiyun ieee80211_unregister_hw(wl->hw);
5674*4882a593Smuzhiyun }
5675*4882a593Smuzhiyun
5676*4882a593Smuzhiyun b43_one_core_detach(wldev->dev);
5677*4882a593Smuzhiyun
5678*4882a593Smuzhiyun /* Unregister HW RNG driver */
5679*4882a593Smuzhiyun b43_rng_exit(wl);
5680*4882a593Smuzhiyun
5681*4882a593Smuzhiyun b43_leds_unregister(wl);
5682*4882a593Smuzhiyun ieee80211_free_hw(wl->hw);
5683*4882a593Smuzhiyun kfree(wldev->dev);
5684*4882a593Smuzhiyun }
5685*4882a593Smuzhiyun
5686*4882a593Smuzhiyun static struct bcma_driver b43_bcma_driver = {
5687*4882a593Smuzhiyun .name = KBUILD_MODNAME,
5688*4882a593Smuzhiyun .id_table = b43_bcma_tbl,
5689*4882a593Smuzhiyun .probe = b43_bcma_probe,
5690*4882a593Smuzhiyun .remove = b43_bcma_remove,
5691*4882a593Smuzhiyun };
5692*4882a593Smuzhiyun #endif
5693*4882a593Smuzhiyun
5694*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
5695*4882a593Smuzhiyun static
b43_ssb_probe(struct ssb_device * sdev,const struct ssb_device_id * id)5696*4882a593Smuzhiyun int b43_ssb_probe(struct ssb_device *sdev, const struct ssb_device_id *id)
5697*4882a593Smuzhiyun {
5698*4882a593Smuzhiyun struct b43_bus_dev *dev;
5699*4882a593Smuzhiyun struct b43_wl *wl;
5700*4882a593Smuzhiyun int err;
5701*4882a593Smuzhiyun
5702*4882a593Smuzhiyun dev = b43_bus_dev_ssb_init(sdev);
5703*4882a593Smuzhiyun if (!dev)
5704*4882a593Smuzhiyun return -ENOMEM;
5705*4882a593Smuzhiyun
5706*4882a593Smuzhiyun wl = ssb_get_devtypedata(sdev);
5707*4882a593Smuzhiyun if (wl) {
5708*4882a593Smuzhiyun b43err(NULL, "Dual-core devices are not supported\n");
5709*4882a593Smuzhiyun err = -ENOTSUPP;
5710*4882a593Smuzhiyun goto err_ssb_kfree_dev;
5711*4882a593Smuzhiyun }
5712*4882a593Smuzhiyun
5713*4882a593Smuzhiyun b43_sprom_fixup(sdev->bus);
5714*4882a593Smuzhiyun
5715*4882a593Smuzhiyun wl = b43_wireless_init(dev);
5716*4882a593Smuzhiyun if (IS_ERR(wl)) {
5717*4882a593Smuzhiyun err = PTR_ERR(wl);
5718*4882a593Smuzhiyun goto err_ssb_kfree_dev;
5719*4882a593Smuzhiyun }
5720*4882a593Smuzhiyun ssb_set_devtypedata(sdev, wl);
5721*4882a593Smuzhiyun B43_WARN_ON(ssb_get_devtypedata(sdev) != wl);
5722*4882a593Smuzhiyun
5723*4882a593Smuzhiyun err = b43_one_core_attach(dev, wl);
5724*4882a593Smuzhiyun if (err)
5725*4882a593Smuzhiyun goto err_ssb_wireless_exit;
5726*4882a593Smuzhiyun
5727*4882a593Smuzhiyun /* setup and start work to load firmware */
5728*4882a593Smuzhiyun INIT_WORK(&wl->firmware_load, b43_request_firmware);
5729*4882a593Smuzhiyun schedule_work(&wl->firmware_load);
5730*4882a593Smuzhiyun
5731*4882a593Smuzhiyun return err;
5732*4882a593Smuzhiyun
5733*4882a593Smuzhiyun err_ssb_wireless_exit:
5734*4882a593Smuzhiyun b43_wireless_exit(dev, wl);
5735*4882a593Smuzhiyun err_ssb_kfree_dev:
5736*4882a593Smuzhiyun kfree(dev);
5737*4882a593Smuzhiyun return err;
5738*4882a593Smuzhiyun }
5739*4882a593Smuzhiyun
b43_ssb_remove(struct ssb_device * sdev)5740*4882a593Smuzhiyun static void b43_ssb_remove(struct ssb_device *sdev)
5741*4882a593Smuzhiyun {
5742*4882a593Smuzhiyun struct b43_wl *wl = ssb_get_devtypedata(sdev);
5743*4882a593Smuzhiyun struct b43_wldev *wldev = ssb_get_drvdata(sdev);
5744*4882a593Smuzhiyun struct b43_bus_dev *dev = wldev->dev;
5745*4882a593Smuzhiyun
5746*4882a593Smuzhiyun /* We must cancel any work here before unregistering from ieee80211,
5747*4882a593Smuzhiyun * as the ieee80211 unreg will destroy the workqueue. */
5748*4882a593Smuzhiyun cancel_work_sync(&wldev->restart_work);
5749*4882a593Smuzhiyun cancel_work_sync(&wl->firmware_load);
5750*4882a593Smuzhiyun
5751*4882a593Smuzhiyun B43_WARN_ON(!wl);
5752*4882a593Smuzhiyun if (!wldev->fw.ucode.data)
5753*4882a593Smuzhiyun return; /* NULL if firmware never loaded */
5754*4882a593Smuzhiyun if (wl->current_dev == wldev && wl->hw_registered) {
5755*4882a593Smuzhiyun b43_leds_stop(wldev);
5756*4882a593Smuzhiyun ieee80211_unregister_hw(wl->hw);
5757*4882a593Smuzhiyun }
5758*4882a593Smuzhiyun
5759*4882a593Smuzhiyun b43_one_core_detach(dev);
5760*4882a593Smuzhiyun
5761*4882a593Smuzhiyun /* Unregister HW RNG driver */
5762*4882a593Smuzhiyun b43_rng_exit(wl);
5763*4882a593Smuzhiyun
5764*4882a593Smuzhiyun b43_leds_unregister(wl);
5765*4882a593Smuzhiyun b43_wireless_exit(dev, wl);
5766*4882a593Smuzhiyun kfree(dev);
5767*4882a593Smuzhiyun }
5768*4882a593Smuzhiyun
5769*4882a593Smuzhiyun static struct ssb_driver b43_ssb_driver = {
5770*4882a593Smuzhiyun .name = KBUILD_MODNAME,
5771*4882a593Smuzhiyun .id_table = b43_ssb_tbl,
5772*4882a593Smuzhiyun .probe = b43_ssb_probe,
5773*4882a593Smuzhiyun .remove = b43_ssb_remove,
5774*4882a593Smuzhiyun };
5775*4882a593Smuzhiyun #endif /* CONFIG_B43_SSB */
5776*4882a593Smuzhiyun
5777*4882a593Smuzhiyun /* Perform a hardware reset. This can be called from any context. */
b43_controller_restart(struct b43_wldev * dev,const char * reason)5778*4882a593Smuzhiyun void b43_controller_restart(struct b43_wldev *dev, const char *reason)
5779*4882a593Smuzhiyun {
5780*4882a593Smuzhiyun /* Must avoid requeueing, if we are in shutdown. */
5781*4882a593Smuzhiyun if (b43_status(dev) < B43_STAT_INITIALIZED)
5782*4882a593Smuzhiyun return;
5783*4882a593Smuzhiyun b43info(dev->wl, "Controller RESET (%s) ...\n", reason);
5784*4882a593Smuzhiyun ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
5785*4882a593Smuzhiyun }
5786*4882a593Smuzhiyun
b43_print_driverinfo(void)5787*4882a593Smuzhiyun static void b43_print_driverinfo(void)
5788*4882a593Smuzhiyun {
5789*4882a593Smuzhiyun const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
5790*4882a593Smuzhiyun *feat_leds = "", *feat_sdio = "";
5791*4882a593Smuzhiyun
5792*4882a593Smuzhiyun #ifdef CONFIG_B43_PCI_AUTOSELECT
5793*4882a593Smuzhiyun feat_pci = "P";
5794*4882a593Smuzhiyun #endif
5795*4882a593Smuzhiyun #ifdef CONFIG_B43_PCMCIA
5796*4882a593Smuzhiyun feat_pcmcia = "M";
5797*4882a593Smuzhiyun #endif
5798*4882a593Smuzhiyun #ifdef CONFIG_B43_PHY_N
5799*4882a593Smuzhiyun feat_nphy = "N";
5800*4882a593Smuzhiyun #endif
5801*4882a593Smuzhiyun #ifdef CONFIG_B43_LEDS
5802*4882a593Smuzhiyun feat_leds = "L";
5803*4882a593Smuzhiyun #endif
5804*4882a593Smuzhiyun #ifdef CONFIG_B43_SDIO
5805*4882a593Smuzhiyun feat_sdio = "S";
5806*4882a593Smuzhiyun #endif
5807*4882a593Smuzhiyun printk(KERN_INFO "Broadcom 43xx driver loaded "
5808*4882a593Smuzhiyun "[ Features: %s%s%s%s%s ]\n",
5809*4882a593Smuzhiyun feat_pci, feat_pcmcia, feat_nphy,
5810*4882a593Smuzhiyun feat_leds, feat_sdio);
5811*4882a593Smuzhiyun }
5812*4882a593Smuzhiyun
b43_init(void)5813*4882a593Smuzhiyun static int __init b43_init(void)
5814*4882a593Smuzhiyun {
5815*4882a593Smuzhiyun int err;
5816*4882a593Smuzhiyun
5817*4882a593Smuzhiyun b43_debugfs_init();
5818*4882a593Smuzhiyun err = b43_sdio_init();
5819*4882a593Smuzhiyun if (err)
5820*4882a593Smuzhiyun goto err_dfs_exit;
5821*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
5822*4882a593Smuzhiyun err = bcma_driver_register(&b43_bcma_driver);
5823*4882a593Smuzhiyun if (err)
5824*4882a593Smuzhiyun goto err_sdio_exit;
5825*4882a593Smuzhiyun #endif
5826*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
5827*4882a593Smuzhiyun err = ssb_driver_register(&b43_ssb_driver);
5828*4882a593Smuzhiyun if (err)
5829*4882a593Smuzhiyun goto err_bcma_driver_exit;
5830*4882a593Smuzhiyun #endif
5831*4882a593Smuzhiyun b43_print_driverinfo();
5832*4882a593Smuzhiyun
5833*4882a593Smuzhiyun return err;
5834*4882a593Smuzhiyun
5835*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
5836*4882a593Smuzhiyun err_bcma_driver_exit:
5837*4882a593Smuzhiyun #endif
5838*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
5839*4882a593Smuzhiyun bcma_driver_unregister(&b43_bcma_driver);
5840*4882a593Smuzhiyun err_sdio_exit:
5841*4882a593Smuzhiyun #endif
5842*4882a593Smuzhiyun b43_sdio_exit();
5843*4882a593Smuzhiyun err_dfs_exit:
5844*4882a593Smuzhiyun b43_debugfs_exit();
5845*4882a593Smuzhiyun return err;
5846*4882a593Smuzhiyun }
5847*4882a593Smuzhiyun
b43_exit(void)5848*4882a593Smuzhiyun static void __exit b43_exit(void)
5849*4882a593Smuzhiyun {
5850*4882a593Smuzhiyun #ifdef CONFIG_B43_SSB
5851*4882a593Smuzhiyun ssb_driver_unregister(&b43_ssb_driver);
5852*4882a593Smuzhiyun #endif
5853*4882a593Smuzhiyun #ifdef CONFIG_B43_BCMA
5854*4882a593Smuzhiyun bcma_driver_unregister(&b43_bcma_driver);
5855*4882a593Smuzhiyun #endif
5856*4882a593Smuzhiyun b43_sdio_exit();
5857*4882a593Smuzhiyun b43_debugfs_exit();
5858*4882a593Smuzhiyun }
5859*4882a593Smuzhiyun
5860*4882a593Smuzhiyun module_init(b43_init)
5861*4882a593Smuzhiyun module_exit(b43_exit)
5862