blob: fff14adb273f446499821d2c01ae28e33c3ec99f [file] [log] [blame]
Michael Buesche4d6b792007-09-18 15:39:42 -04001/*
2
3 Broadcom B43 wireless driver
4
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
Stefano Brivio1f21ad22007-11-06 22:49:20 +01006 Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
Michael Buesch060210f2009-01-25 15:49:59 +01007 Copyright (c) 2005-2009 Michael Buesch <mb@bu3sch.de>
Michael Buesche4d6b792007-09-18 15:39:42 -04008 Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
9 Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10
Albert Herranz3dbba8e2009-09-10 19:34:49 +020011 SDIO support
12 Copyright (c) 2009 Albert Herranz <albert_herranz@yahoo.es>
13
Michael Buesche4d6b792007-09-18 15:39:42 -040014 Some parts of the code in this file are derived from the ipw2200
15 driver Copyright(c) 2003 - 2004 Intel Corporation.
16
17 This program is free software; you can redistribute it and/or modify
18 it under the terms of the GNU General Public License as published by
19 the Free Software Foundation; either version 2 of the License, or
20 (at your option) any later version.
21
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
26
27 You should have received a copy of the GNU General Public License
28 along with this program; see the file COPYING. If not, write to
29 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
30 Boston, MA 02110-1301, USA.
31
32*/
33
34#include <linux/delay.h>
35#include <linux/init.h>
36#include <linux/moduleparam.h>
37#include <linux/if_arp.h>
38#include <linux/etherdevice.h>
Michael Buesche4d6b792007-09-18 15:39:42 -040039#include <linux/firmware.h>
40#include <linux/wireless.h>
41#include <linux/workqueue.h>
42#include <linux/skbuff.h>
Andrew Morton96cf49a2008-02-04 22:27:19 -080043#include <linux/io.h>
Michael Buesche4d6b792007-09-18 15:39:42 -040044#include <linux/dma-mapping.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090045#include <linux/slab.h>
Michael Buesche4d6b792007-09-18 15:39:42 -040046#include <asm/unaligned.h>
47
48#include "b43.h"
49#include "main.h"
50#include "debugfs.h"
Michael Bueschef1a6282008-08-27 18:53:02 +020051#include "phy_common.h"
52#include "phy_g.h"
Michael Buesch3d0da752008-08-30 02:27:19 +020053#include "phy_n.h"
Michael Buesche4d6b792007-09-18 15:39:42 -040054#include "dma.h"
Michael Buesch5100d5a2008-03-29 21:01:16 +010055#include "pio.h"
Michael Buesche4d6b792007-09-18 15:39:42 -040056#include "sysfs.h"
57#include "xmit.h"
Michael Buesche4d6b792007-09-18 15:39:42 -040058#include "lo.h"
59#include "pcmcia.h"
Albert Herranz3dbba8e2009-09-10 19:34:49 +020060#include "sdio.h"
61#include <linux/mmc/sdio_func.h>
Michael Buesche4d6b792007-09-18 15:39:42 -040062
63MODULE_DESCRIPTION("Broadcom B43 wireless driver");
64MODULE_AUTHOR("Martin Langer");
65MODULE_AUTHOR("Stefano Brivio");
66MODULE_AUTHOR("Michael Buesch");
Gábor Stefanik0136e512009-08-28 22:32:17 +020067MODULE_AUTHOR("Gábor Stefanik");
Michael Buesche4d6b792007-09-18 15:39:42 -040068MODULE_LICENSE("GPL");
69
Michael Buesch9c7d99d2008-02-09 10:23:49 +010070MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
Tim Gardner6021e082010-01-07 11:10:38 -070071MODULE_FIRMWARE("b43/ucode11.fw");
72MODULE_FIRMWARE("b43/ucode13.fw");
73MODULE_FIRMWARE("b43/ucode14.fw");
74MODULE_FIRMWARE("b43/ucode15.fw");
75MODULE_FIRMWARE("b43/ucode5.fw");
76MODULE_FIRMWARE("b43/ucode9.fw");
Michael Buesche4d6b792007-09-18 15:39:42 -040077
78static int modparam_bad_frames_preempt;
79module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
80MODULE_PARM_DESC(bad_frames_preempt,
81 "enable(1) / disable(0) Bad Frames Preemption");
82
Michael Buesche4d6b792007-09-18 15:39:42 -040083static char modparam_fwpostfix[16];
84module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
85MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
86
Michael Buesche4d6b792007-09-18 15:39:42 -040087static int modparam_hwpctl;
88module_param_named(hwpctl, modparam_hwpctl, int, 0444);
89MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)");
90
91static int modparam_nohwcrypt;
92module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
93MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
94
gregor kowski035d0242009-08-19 22:35:45 +020095static int modparam_hwtkip;
96module_param_named(hwtkip, modparam_hwtkip, int, 0444);
97MODULE_PARM_DESC(hwtkip, "Enable hardware tkip.");
98
Michael Buesch403a3a12009-06-08 21:04:57 +020099static int modparam_qos = 1;
100module_param_named(qos, modparam_qos, int, 0444);
Michael Buesche6f5b932008-03-05 21:18:49 +0100101MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
102
Michael Buesch1855ba72008-04-18 20:51:41 +0200103static int modparam_btcoex = 1;
104module_param_named(btcoex, modparam_btcoex, int, 0444);
Gábor Stefanikc71dbd32009-08-28 22:34:21 +0200105MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistence (default on)");
Michael Buesch1855ba72008-04-18 20:51:41 +0200106
Michael Buesch060210f2009-01-25 15:49:59 +0100107int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
108module_param_named(verbose, b43_modparam_verbose, int, 0644);
109MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
110
John W. Linville41950bd2010-07-21 11:37:19 -0400111static int b43_modparam_pio = B43_PIO_DEFAULT;
Linus Torvalds9e3bd912010-02-26 10:34:27 -0800112module_param_named(pio, b43_modparam_pio, int, 0644);
113MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");
Michael Buesche6f5b932008-03-05 21:18:49 +0100114
Michael Buesche4d6b792007-09-18 15:39:42 -0400115static const struct ssb_device_id b43_ssb_tbl[] = {
116 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
117 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
118 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
119 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
120 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
Michael Bueschd5c71e42008-01-04 17:06:29 +0100121 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
Rafał Miłecki003d6d22010-01-15 12:10:53 +0100122 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 12),
Larry Finger013978b2007-11-26 10:29:47 -0600123 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
Michael Buesch6b1c7c62008-12-25 00:39:28 +0100124 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15),
Johannes Berg92d61282008-12-24 12:44:09 +0100125 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16),
Michael Buesche4d6b792007-09-18 15:39:42 -0400126 SSB_DEVTABLE_END
127};
128
129MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
130
131/* Channel and ratetables are shared for all devices.
132 * They can't be const, because ieee80211 puts some precalculated
133 * data in there. This data is the same for all devices, so we don't
134 * get concurrency issues */
135#define RATETAB_ENT(_rateid, _flags) \
Johannes Berg8318d782008-01-24 19:38:38 +0100136 { \
137 .bitrate = B43_RATE_TO_BASE100KBPS(_rateid), \
138 .hw_value = (_rateid), \
139 .flags = (_flags), \
Michael Buesche4d6b792007-09-18 15:39:42 -0400140 }
Johannes Berg8318d782008-01-24 19:38:38 +0100141
142/*
143 * NOTE: When changing this, sync with xmit.c's
144 * b43_plcp_get_bitrate_idx_* functions!
145 */
Michael Buesche4d6b792007-09-18 15:39:42 -0400146static struct ieee80211_rate __b43_ratetable[] = {
Johannes Berg8318d782008-01-24 19:38:38 +0100147 RATETAB_ENT(B43_CCK_RATE_1MB, 0),
148 RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
149 RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
150 RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
151 RATETAB_ENT(B43_OFDM_RATE_6MB, 0),
152 RATETAB_ENT(B43_OFDM_RATE_9MB, 0),
153 RATETAB_ENT(B43_OFDM_RATE_12MB, 0),
154 RATETAB_ENT(B43_OFDM_RATE_18MB, 0),
155 RATETAB_ENT(B43_OFDM_RATE_24MB, 0),
156 RATETAB_ENT(B43_OFDM_RATE_36MB, 0),
157 RATETAB_ENT(B43_OFDM_RATE_48MB, 0),
158 RATETAB_ENT(B43_OFDM_RATE_54MB, 0),
Michael Buesche4d6b792007-09-18 15:39:42 -0400159};
160
161#define b43_a_ratetable (__b43_ratetable + 4)
162#define b43_a_ratetable_size 8
163#define b43_b_ratetable (__b43_ratetable + 0)
164#define b43_b_ratetable_size 4
165#define b43_g_ratetable (__b43_ratetable + 0)
166#define b43_g_ratetable_size 12
167
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100168#define CHAN4G(_channel, _freq, _flags) { \
169 .band = IEEE80211_BAND_2GHZ, \
170 .center_freq = (_freq), \
171 .hw_value = (_channel), \
172 .flags = (_flags), \
173 .max_antenna_gain = 0, \
174 .max_power = 30, \
175}
Michael Buesch96c755a2008-01-06 00:09:46 +0100176static struct ieee80211_channel b43_2ghz_chantable[] = {
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100177 CHAN4G(1, 2412, 0),
178 CHAN4G(2, 2417, 0),
179 CHAN4G(3, 2422, 0),
180 CHAN4G(4, 2427, 0),
181 CHAN4G(5, 2432, 0),
182 CHAN4G(6, 2437, 0),
183 CHAN4G(7, 2442, 0),
184 CHAN4G(8, 2447, 0),
185 CHAN4G(9, 2452, 0),
186 CHAN4G(10, 2457, 0),
187 CHAN4G(11, 2462, 0),
188 CHAN4G(12, 2467, 0),
189 CHAN4G(13, 2472, 0),
190 CHAN4G(14, 2484, 0),
191};
192#undef CHAN4G
193
194#define CHAN5G(_channel, _flags) { \
195 .band = IEEE80211_BAND_5GHZ, \
196 .center_freq = 5000 + (5 * (_channel)), \
197 .hw_value = (_channel), \
198 .flags = (_flags), \
199 .max_antenna_gain = 0, \
200 .max_power = 30, \
201}
202static struct ieee80211_channel b43_5ghz_nphy_chantable[] = {
203 CHAN5G(32, 0), CHAN5G(34, 0),
204 CHAN5G(36, 0), CHAN5G(38, 0),
205 CHAN5G(40, 0), CHAN5G(42, 0),
206 CHAN5G(44, 0), CHAN5G(46, 0),
207 CHAN5G(48, 0), CHAN5G(50, 0),
208 CHAN5G(52, 0), CHAN5G(54, 0),
209 CHAN5G(56, 0), CHAN5G(58, 0),
210 CHAN5G(60, 0), CHAN5G(62, 0),
211 CHAN5G(64, 0), CHAN5G(66, 0),
212 CHAN5G(68, 0), CHAN5G(70, 0),
213 CHAN5G(72, 0), CHAN5G(74, 0),
214 CHAN5G(76, 0), CHAN5G(78, 0),
215 CHAN5G(80, 0), CHAN5G(82, 0),
216 CHAN5G(84, 0), CHAN5G(86, 0),
217 CHAN5G(88, 0), CHAN5G(90, 0),
218 CHAN5G(92, 0), CHAN5G(94, 0),
219 CHAN5G(96, 0), CHAN5G(98, 0),
220 CHAN5G(100, 0), CHAN5G(102, 0),
221 CHAN5G(104, 0), CHAN5G(106, 0),
222 CHAN5G(108, 0), CHAN5G(110, 0),
223 CHAN5G(112, 0), CHAN5G(114, 0),
224 CHAN5G(116, 0), CHAN5G(118, 0),
225 CHAN5G(120, 0), CHAN5G(122, 0),
226 CHAN5G(124, 0), CHAN5G(126, 0),
227 CHAN5G(128, 0), CHAN5G(130, 0),
228 CHAN5G(132, 0), CHAN5G(134, 0),
229 CHAN5G(136, 0), CHAN5G(138, 0),
230 CHAN5G(140, 0), CHAN5G(142, 0),
231 CHAN5G(144, 0), CHAN5G(145, 0),
232 CHAN5G(146, 0), CHAN5G(147, 0),
233 CHAN5G(148, 0), CHAN5G(149, 0),
234 CHAN5G(150, 0), CHAN5G(151, 0),
235 CHAN5G(152, 0), CHAN5G(153, 0),
236 CHAN5G(154, 0), CHAN5G(155, 0),
237 CHAN5G(156, 0), CHAN5G(157, 0),
238 CHAN5G(158, 0), CHAN5G(159, 0),
239 CHAN5G(160, 0), CHAN5G(161, 0),
240 CHAN5G(162, 0), CHAN5G(163, 0),
241 CHAN5G(164, 0), CHAN5G(165, 0),
242 CHAN5G(166, 0), CHAN5G(168, 0),
243 CHAN5G(170, 0), CHAN5G(172, 0),
244 CHAN5G(174, 0), CHAN5G(176, 0),
245 CHAN5G(178, 0), CHAN5G(180, 0),
246 CHAN5G(182, 0), CHAN5G(184, 0),
247 CHAN5G(186, 0), CHAN5G(188, 0),
248 CHAN5G(190, 0), CHAN5G(192, 0),
249 CHAN5G(194, 0), CHAN5G(196, 0),
250 CHAN5G(198, 0), CHAN5G(200, 0),
251 CHAN5G(202, 0), CHAN5G(204, 0),
252 CHAN5G(206, 0), CHAN5G(208, 0),
253 CHAN5G(210, 0), CHAN5G(212, 0),
254 CHAN5G(214, 0), CHAN5G(216, 0),
255 CHAN5G(218, 0), CHAN5G(220, 0),
256 CHAN5G(222, 0), CHAN5G(224, 0),
257 CHAN5G(226, 0), CHAN5G(228, 0),
Michael Buesche4d6b792007-09-18 15:39:42 -0400258};
259
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100260static struct ieee80211_channel b43_5ghz_aphy_chantable[] = {
261 CHAN5G(34, 0), CHAN5G(36, 0),
262 CHAN5G(38, 0), CHAN5G(40, 0),
263 CHAN5G(42, 0), CHAN5G(44, 0),
264 CHAN5G(46, 0), CHAN5G(48, 0),
265 CHAN5G(52, 0), CHAN5G(56, 0),
266 CHAN5G(60, 0), CHAN5G(64, 0),
267 CHAN5G(100, 0), CHAN5G(104, 0),
268 CHAN5G(108, 0), CHAN5G(112, 0),
269 CHAN5G(116, 0), CHAN5G(120, 0),
270 CHAN5G(124, 0), CHAN5G(128, 0),
271 CHAN5G(132, 0), CHAN5G(136, 0),
272 CHAN5G(140, 0), CHAN5G(149, 0),
273 CHAN5G(153, 0), CHAN5G(157, 0),
274 CHAN5G(161, 0), CHAN5G(165, 0),
275 CHAN5G(184, 0), CHAN5G(188, 0),
276 CHAN5G(192, 0), CHAN5G(196, 0),
277 CHAN5G(200, 0), CHAN5G(204, 0),
278 CHAN5G(208, 0), CHAN5G(212, 0),
279 CHAN5G(216, 0),
280};
281#undef CHAN5G
282
283static struct ieee80211_supported_band b43_band_5GHz_nphy = {
284 .band = IEEE80211_BAND_5GHZ,
285 .channels = b43_5ghz_nphy_chantable,
286 .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable),
287 .bitrates = b43_a_ratetable,
288 .n_bitrates = b43_a_ratetable_size,
Michael Buesche4d6b792007-09-18 15:39:42 -0400289};
Johannes Berg8318d782008-01-24 19:38:38 +0100290
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100291static struct ieee80211_supported_band b43_band_5GHz_aphy = {
292 .band = IEEE80211_BAND_5GHZ,
293 .channels = b43_5ghz_aphy_chantable,
294 .n_channels = ARRAY_SIZE(b43_5ghz_aphy_chantable),
295 .bitrates = b43_a_ratetable,
296 .n_bitrates = b43_a_ratetable_size,
Johannes Berg8318d782008-01-24 19:38:38 +0100297};
Michael Buesche4d6b792007-09-18 15:39:42 -0400298
Johannes Berg8318d782008-01-24 19:38:38 +0100299static struct ieee80211_supported_band b43_band_2GHz = {
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100300 .band = IEEE80211_BAND_2GHZ,
301 .channels = b43_2ghz_chantable,
302 .n_channels = ARRAY_SIZE(b43_2ghz_chantable),
303 .bitrates = b43_g_ratetable,
304 .n_bitrates = b43_g_ratetable_size,
Johannes Berg8318d782008-01-24 19:38:38 +0100305};
306
Michael Buesche4d6b792007-09-18 15:39:42 -0400307static void b43_wireless_core_exit(struct b43_wldev *dev);
308static int b43_wireless_core_init(struct b43_wldev *dev);
Michael Buesch36dbd952009-09-04 22:51:29 +0200309static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev);
Michael Buesche4d6b792007-09-18 15:39:42 -0400310static int b43_wireless_core_start(struct b43_wldev *dev);
311
312static int b43_ratelimit(struct b43_wl *wl)
313{
314 if (!wl || !wl->current_dev)
315 return 1;
316 if (b43_status(wl->current_dev) < B43_STAT_STARTED)
317 return 1;
318 /* We are up and running.
319 * Ratelimit the messages to avoid DoS over the net. */
320 return net_ratelimit();
321}
322
323void b43info(struct b43_wl *wl, const char *fmt, ...)
324{
Joe Perches5b736d42010-11-09 16:35:18 -0800325 struct va_format vaf;
Michael Buesche4d6b792007-09-18 15:39:42 -0400326 va_list args;
327
Michael Buesch060210f2009-01-25 15:49:59 +0100328 if (b43_modparam_verbose < B43_VERBOSITY_INFO)
329 return;
Michael Buesche4d6b792007-09-18 15:39:42 -0400330 if (!b43_ratelimit(wl))
331 return;
Joe Perches5b736d42010-11-09 16:35:18 -0800332
Michael Buesche4d6b792007-09-18 15:39:42 -0400333 va_start(args, fmt);
Joe Perches5b736d42010-11-09 16:35:18 -0800334
335 vaf.fmt = fmt;
336 vaf.va = &args;
337
338 printk(KERN_INFO "b43-%s: %pV",
339 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
340
Michael Buesche4d6b792007-09-18 15:39:42 -0400341 va_end(args);
342}
343
344void b43err(struct b43_wl *wl, const char *fmt, ...)
345{
Joe Perches5b736d42010-11-09 16:35:18 -0800346 struct va_format vaf;
Michael Buesche4d6b792007-09-18 15:39:42 -0400347 va_list args;
348
Michael Buesch060210f2009-01-25 15:49:59 +0100349 if (b43_modparam_verbose < B43_VERBOSITY_ERROR)
350 return;
Michael Buesche4d6b792007-09-18 15:39:42 -0400351 if (!b43_ratelimit(wl))
352 return;
Joe Perches5b736d42010-11-09 16:35:18 -0800353
Michael Buesche4d6b792007-09-18 15:39:42 -0400354 va_start(args, fmt);
Joe Perches5b736d42010-11-09 16:35:18 -0800355
356 vaf.fmt = fmt;
357 vaf.va = &args;
358
359 printk(KERN_ERR "b43-%s ERROR: %pV",
360 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
361
Michael Buesche4d6b792007-09-18 15:39:42 -0400362 va_end(args);
363}
364
365void b43warn(struct b43_wl *wl, const char *fmt, ...)
366{
Joe Perches5b736d42010-11-09 16:35:18 -0800367 struct va_format vaf;
Michael Buesche4d6b792007-09-18 15:39:42 -0400368 va_list args;
369
Michael Buesch060210f2009-01-25 15:49:59 +0100370 if (b43_modparam_verbose < B43_VERBOSITY_WARN)
371 return;
Michael Buesche4d6b792007-09-18 15:39:42 -0400372 if (!b43_ratelimit(wl))
373 return;
Joe Perches5b736d42010-11-09 16:35:18 -0800374
Michael Buesche4d6b792007-09-18 15:39:42 -0400375 va_start(args, fmt);
Joe Perches5b736d42010-11-09 16:35:18 -0800376
377 vaf.fmt = fmt;
378 vaf.va = &args;
379
380 printk(KERN_WARNING "b43-%s warning: %pV",
381 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
382
Michael Buesche4d6b792007-09-18 15:39:42 -0400383 va_end(args);
384}
385
Michael Buesche4d6b792007-09-18 15:39:42 -0400386void b43dbg(struct b43_wl *wl, const char *fmt, ...)
387{
Joe Perches5b736d42010-11-09 16:35:18 -0800388 struct va_format vaf;
Michael Buesche4d6b792007-09-18 15:39:42 -0400389 va_list args;
390
Michael Buesch060210f2009-01-25 15:49:59 +0100391 if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
392 return;
Joe Perches5b736d42010-11-09 16:35:18 -0800393
Michael Buesche4d6b792007-09-18 15:39:42 -0400394 va_start(args, fmt);
Joe Perches5b736d42010-11-09 16:35:18 -0800395
396 vaf.fmt = fmt;
397 vaf.va = &args;
398
399 printk(KERN_DEBUG "b43-%s debug: %pV",
400 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
401
Michael Buesche4d6b792007-09-18 15:39:42 -0400402 va_end(args);
403}
Michael Buesche4d6b792007-09-18 15:39:42 -0400404
405static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
406{
407 u32 macctl;
408
409 B43_WARN_ON(offset % 4 != 0);
410
411 macctl = b43_read32(dev, B43_MMIO_MACCTL);
412 if (macctl & B43_MACCTL_BE)
413 val = swab32(val);
414
415 b43_write32(dev, B43_MMIO_RAM_CONTROL, offset);
416 mmiowb();
417 b43_write32(dev, B43_MMIO_RAM_DATA, val);
418}
419
Michael Buesch280d0e12007-12-26 18:26:17 +0100420static inline void b43_shm_control_word(struct b43_wldev *dev,
421 u16 routing, u16 offset)
Michael Buesche4d6b792007-09-18 15:39:42 -0400422{
423 u32 control;
424
425 /* "offset" is the WORD offset. */
Michael Buesche4d6b792007-09-18 15:39:42 -0400426 control = routing;
427 control <<= 16;
428 control |= offset;
429 b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
430}
431
Michael Buesch69eddc82009-09-04 22:57:26 +0200432u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
Michael Buesche4d6b792007-09-18 15:39:42 -0400433{
434 u32 ret;
435
436 if (routing == B43_SHM_SHARED) {
437 B43_WARN_ON(offset & 0x0001);
438 if (offset & 0x0003) {
439 /* Unaligned access */
440 b43_shm_control_word(dev, routing, offset >> 2);
441 ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
Michael Buesche4d6b792007-09-18 15:39:42 -0400442 b43_shm_control_word(dev, routing, (offset >> 2) + 1);
Michael Bueschf62ae6c2009-07-31 20:51:41 +0200443 ret |= ((u32)b43_read16(dev, B43_MMIO_SHM_DATA)) << 16;
Michael Buesche4d6b792007-09-18 15:39:42 -0400444
Michael Buesch280d0e12007-12-26 18:26:17 +0100445 goto out;
Michael Buesche4d6b792007-09-18 15:39:42 -0400446 }
447 offset >>= 2;
448 }
449 b43_shm_control_word(dev, routing, offset);
450 ret = b43_read32(dev, B43_MMIO_SHM_DATA);
Michael Buesch280d0e12007-12-26 18:26:17 +0100451out:
Michael Buesch6bbc3212008-06-19 19:33:51 +0200452 return ret;
453}
454
Michael Buesch69eddc82009-09-04 22:57:26 +0200455u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
Michael Buesche4d6b792007-09-18 15:39:42 -0400456{
457 u16 ret;
458
459 if (routing == B43_SHM_SHARED) {
460 B43_WARN_ON(offset & 0x0001);
461 if (offset & 0x0003) {
462 /* Unaligned access */
463 b43_shm_control_word(dev, routing, offset >> 2);
464 ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
465
Michael Buesch280d0e12007-12-26 18:26:17 +0100466 goto out;
Michael Buesche4d6b792007-09-18 15:39:42 -0400467 }
468 offset >>= 2;
469 }
470 b43_shm_control_word(dev, routing, offset);
471 ret = b43_read16(dev, B43_MMIO_SHM_DATA);
Michael Buesch280d0e12007-12-26 18:26:17 +0100472out:
Michael Buesch6bbc3212008-06-19 19:33:51 +0200473 return ret;
474}
475
Michael Buesch69eddc82009-09-04 22:57:26 +0200476void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
Michael Buesche4d6b792007-09-18 15:39:42 -0400477{
478 if (routing == B43_SHM_SHARED) {
479 B43_WARN_ON(offset & 0x0001);
480 if (offset & 0x0003) {
481 /* Unaligned access */
482 b43_shm_control_word(dev, routing, offset >> 2);
Michael Buesche4d6b792007-09-18 15:39:42 -0400483 b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
Michael Bueschf62ae6c2009-07-31 20:51:41 +0200484 value & 0xFFFF);
Michael Buesche4d6b792007-09-18 15:39:42 -0400485 b43_shm_control_word(dev, routing, (offset >> 2) + 1);
Michael Bueschf62ae6c2009-07-31 20:51:41 +0200486 b43_write16(dev, B43_MMIO_SHM_DATA,
487 (value >> 16) & 0xFFFF);
Michael Buesch6bbc3212008-06-19 19:33:51 +0200488 return;
Michael Buesche4d6b792007-09-18 15:39:42 -0400489 }
490 offset >>= 2;
491 }
492 b43_shm_control_word(dev, routing, offset);
Michael Buesche4d6b792007-09-18 15:39:42 -0400493 b43_write32(dev, B43_MMIO_SHM_DATA, value);
Michael Buesch6bbc3212008-06-19 19:33:51 +0200494}
495
Michael Buesch69eddc82009-09-04 22:57:26 +0200496void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
Michael Buesch6bbc3212008-06-19 19:33:51 +0200497{
498 if (routing == B43_SHM_SHARED) {
499 B43_WARN_ON(offset & 0x0001);
500 if (offset & 0x0003) {
501 /* Unaligned access */
502 b43_shm_control_word(dev, routing, offset >> 2);
503 b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
504 return;
505 }
506 offset >>= 2;
507 }
508 b43_shm_control_word(dev, routing, offset);
509 b43_write16(dev, B43_MMIO_SHM_DATA, value);
510}
511
Michael Buesche4d6b792007-09-18 15:39:42 -0400512/* Read HostFlags */
John Daiker99da1852009-02-24 02:16:42 -0800513u64 b43_hf_read(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -0400514{
Michael Buesch35f0d352008-02-13 14:31:08 +0100515 u64 ret;
Michael Buesche4d6b792007-09-18 15:39:42 -0400516
517 ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
518 ret <<= 16;
Michael Buesch35f0d352008-02-13 14:31:08 +0100519 ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI);
520 ret <<= 16;
Michael Buesche4d6b792007-09-18 15:39:42 -0400521 ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);
522
523 return ret;
524}
525
526/* Write HostFlags */
Michael Buesch35f0d352008-02-13 14:31:08 +0100527void b43_hf_write(struct b43_wldev *dev, u64 value)
Michael Buesche4d6b792007-09-18 15:39:42 -0400528{
Michael Buesch35f0d352008-02-13 14:31:08 +0100529 u16 lo, mi, hi;
530
531 lo = (value & 0x00000000FFFFULL);
532 mi = (value & 0x0000FFFF0000ULL) >> 16;
533 hi = (value & 0xFFFF00000000ULL) >> 32;
534 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO, lo);
535 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI, mi);
536 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi);
Michael Buesche4d6b792007-09-18 15:39:42 -0400537}
538
Michael Buesch403a3a12009-06-08 21:04:57 +0200539/* Read the firmware capabilities bitmask (Opensource firmware only) */
540static u16 b43_fwcapa_read(struct b43_wldev *dev)
541{
542 B43_WARN_ON(!dev->fw.opensource);
543 return b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_FWCAPA);
544}
545
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100546void b43_tsf_read(struct b43_wldev *dev, u64 *tsf)
Michael Buesche4d6b792007-09-18 15:39:42 -0400547{
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100548 u32 low, high;
Michael Buesche4d6b792007-09-18 15:39:42 -0400549
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +0200550 B43_WARN_ON(dev->sdev->id.revision < 3);
Michael Buesche4d6b792007-09-18 15:39:42 -0400551
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100552 /* The hardware guarantees us an atomic read, if we
553 * read the low register first. */
554 low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW);
555 high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);
Michael Buesche4d6b792007-09-18 15:39:42 -0400556
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100557 *tsf = high;
558 *tsf <<= 32;
559 *tsf |= low;
Michael Buesche4d6b792007-09-18 15:39:42 -0400560}
561
562static void b43_time_lock(struct b43_wldev *dev)
563{
564 u32 macctl;
565
566 macctl = b43_read32(dev, B43_MMIO_MACCTL);
567 macctl |= B43_MACCTL_TBTTHOLD;
568 b43_write32(dev, B43_MMIO_MACCTL, macctl);
569 /* Commit the write */
570 b43_read32(dev, B43_MMIO_MACCTL);
571}
572
573static void b43_time_unlock(struct b43_wldev *dev)
574{
575 u32 macctl;
576
577 macctl = b43_read32(dev, B43_MMIO_MACCTL);
578 macctl &= ~B43_MACCTL_TBTTHOLD;
579 b43_write32(dev, B43_MMIO_MACCTL, macctl);
580 /* Commit the write */
581 b43_read32(dev, B43_MMIO_MACCTL);
582}
583
584static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
585{
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100586 u32 low, high;
Michael Buesche4d6b792007-09-18 15:39:42 -0400587
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +0200588 B43_WARN_ON(dev->sdev->id.revision < 3);
Michael Buesche4d6b792007-09-18 15:39:42 -0400589
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100590 low = tsf;
591 high = (tsf >> 32);
592 /* The hardware guarantees us an atomic write, if we
593 * write the low register first. */
594 b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, low);
595 mmiowb();
596 b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, high);
597 mmiowb();
Michael Buesche4d6b792007-09-18 15:39:42 -0400598}
599
600void b43_tsf_write(struct b43_wldev *dev, u64 tsf)
601{
602 b43_time_lock(dev);
603 b43_tsf_write_locked(dev, tsf);
604 b43_time_unlock(dev);
605}
606
607static
John Daiker99da1852009-02-24 02:16:42 -0800608void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 *mac)
Michael Buesche4d6b792007-09-18 15:39:42 -0400609{
610 static const u8 zero_addr[ETH_ALEN] = { 0 };
611 u16 data;
612
613 if (!mac)
614 mac = zero_addr;
615
616 offset |= 0x0020;
617 b43_write16(dev, B43_MMIO_MACFILTER_CONTROL, offset);
618
619 data = mac[0];
620 data |= mac[1] << 8;
621 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
622 data = mac[2];
623 data |= mac[3] << 8;
624 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
625 data = mac[4];
626 data |= mac[5] << 8;
627 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
628}
629
630static void b43_write_mac_bssid_templates(struct b43_wldev *dev)
631{
632 const u8 *mac;
633 const u8 *bssid;
634 u8 mac_bssid[ETH_ALEN * 2];
635 int i;
636 u32 tmp;
637
638 bssid = dev->wl->bssid;
639 mac = dev->wl->mac_addr;
640
641 b43_macfilter_set(dev, B43_MACFILTER_BSSID, bssid);
642
643 memcpy(mac_bssid, mac, ETH_ALEN);
644 memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
645
646 /* Write our MAC address and BSSID to template ram */
647 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
648 tmp = (u32) (mac_bssid[i + 0]);
649 tmp |= (u32) (mac_bssid[i + 1]) << 8;
650 tmp |= (u32) (mac_bssid[i + 2]) << 16;
651 tmp |= (u32) (mac_bssid[i + 3]) << 24;
652 b43_ram_write(dev, 0x20 + i, tmp);
653 }
654}
655
Johannes Berg4150c572007-09-17 01:29:23 -0400656static void b43_upload_card_macaddress(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -0400657{
Michael Buesche4d6b792007-09-18 15:39:42 -0400658 b43_write_mac_bssid_templates(dev);
Johannes Berg4150c572007-09-17 01:29:23 -0400659 b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr);
Michael Buesche4d6b792007-09-18 15:39:42 -0400660}
661
662static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
663{
664 /* slot_time is in usec. */
Larry Fingerb6c3f5b2010-02-02 10:08:19 -0600665 /* This test used to exit for all but a G PHY. */
666 if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
Michael Buesche4d6b792007-09-18 15:39:42 -0400667 return;
Larry Fingerb6c3f5b2010-02-02 10:08:19 -0600668 b43_write16(dev, B43_MMIO_IFSSLOT, 510 + slot_time);
669 /* Shared memory location 0x0010 is the slot time and should be
670 * set to slot_time; however, this register is initially 0 and changing
671 * the value adversely affects the transmit rate for BCM4311
672 * devices. Until this behavior is unterstood, delete this step
673 *
674 * b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
675 */
Michael Buesche4d6b792007-09-18 15:39:42 -0400676}
677
678static void b43_short_slot_timing_enable(struct b43_wldev *dev)
679{
680 b43_set_slot_time(dev, 9);
Michael Buesche4d6b792007-09-18 15:39:42 -0400681}
682
683static void b43_short_slot_timing_disable(struct b43_wldev *dev)
684{
685 b43_set_slot_time(dev, 20);
Michael Buesche4d6b792007-09-18 15:39:42 -0400686}
687
Michael Buesche4d6b792007-09-18 15:39:42 -0400688/* DummyTransmission function, as documented on
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200689 * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission
Michael Buesche4d6b792007-09-18 15:39:42 -0400690 */
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200691void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
Michael Buesche4d6b792007-09-18 15:39:42 -0400692{
693 struct b43_phy *phy = &dev->phy;
694 unsigned int i, max_loop;
695 u16 value;
696 u32 buffer[5] = {
697 0x00000000,
698 0x00D40000,
699 0x00000000,
700 0x01000000,
701 0x00000000,
702 };
703
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200704 if (ofdm) {
Michael Buesche4d6b792007-09-18 15:39:42 -0400705 max_loop = 0x1E;
706 buffer[0] = 0x000201CC;
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200707 } else {
Michael Buesche4d6b792007-09-18 15:39:42 -0400708 max_loop = 0xFA;
709 buffer[0] = 0x000B846E;
Michael Buesche4d6b792007-09-18 15:39:42 -0400710 }
711
712 for (i = 0; i < 5; i++)
713 b43_ram_write(dev, i * 4, buffer[i]);
714
Michael Buesche4d6b792007-09-18 15:39:42 -0400715 b43_write16(dev, 0x0568, 0x0000);
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +0200716 if (dev->sdev->id.revision < 11)
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200717 b43_write16(dev, 0x07C0, 0x0000);
718 else
719 b43_write16(dev, 0x07C0, 0x0100);
720 value = (ofdm ? 0x41 : 0x40);
Michael Buesche4d6b792007-09-18 15:39:42 -0400721 b43_write16(dev, 0x050C, value);
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200722 if ((phy->type == B43_PHYTYPE_N) || (phy->type == B43_PHYTYPE_LP))
723 b43_write16(dev, 0x0514, 0x1A02);
Michael Buesche4d6b792007-09-18 15:39:42 -0400724 b43_write16(dev, 0x0508, 0x0000);
725 b43_write16(dev, 0x050A, 0x0000);
726 b43_write16(dev, 0x054C, 0x0000);
727 b43_write16(dev, 0x056A, 0x0014);
728 b43_write16(dev, 0x0568, 0x0826);
729 b43_write16(dev, 0x0500, 0x0000);
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200730 if (!pa_on && (phy->type == B43_PHYTYPE_N)) {
731 //SPEC TODO
732 }
733
734 switch (phy->type) {
735 case B43_PHYTYPE_N:
736 b43_write16(dev, 0x0502, 0x00D0);
737 break;
738 case B43_PHYTYPE_LP:
739 b43_write16(dev, 0x0502, 0x0050);
740 break;
741 default:
742 b43_write16(dev, 0x0502, 0x0030);
743 }
Michael Buesche4d6b792007-09-18 15:39:42 -0400744
745 if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
746 b43_radio_write16(dev, 0x0051, 0x0017);
747 for (i = 0x00; i < max_loop; i++) {
748 value = b43_read16(dev, 0x050E);
749 if (value & 0x0080)
750 break;
751 udelay(10);
752 }
753 for (i = 0x00; i < 0x0A; i++) {
754 value = b43_read16(dev, 0x050E);
755 if (value & 0x0400)
756 break;
757 udelay(10);
758 }
Larry Finger1d280dd2008-09-29 14:19:29 -0500759 for (i = 0x00; i < 0x19; i++) {
Michael Buesche4d6b792007-09-18 15:39:42 -0400760 value = b43_read16(dev, 0x0690);
761 if (!(value & 0x0100))
762 break;
763 udelay(10);
764 }
765 if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
766 b43_radio_write16(dev, 0x0051, 0x0037);
767}
768
769static void key_write(struct b43_wldev *dev,
John Daiker99da1852009-02-24 02:16:42 -0800770 u8 index, u8 algorithm, const u8 *key)
Michael Buesche4d6b792007-09-18 15:39:42 -0400771{
772 unsigned int i;
773 u32 offset;
774 u16 value;
775 u16 kidx;
776
777 /* Key index/algo block */
778 kidx = b43_kidx_to_fw(dev, index);
779 value = ((kidx << 4) | algorithm);
780 b43_shm_write16(dev, B43_SHM_SHARED,
781 B43_SHM_SH_KEYIDXBLOCK + (kidx * 2), value);
782
783 /* Write the key to the Key Table Pointer offset */
784 offset = dev->ktp + (index * B43_SEC_KEYSIZE);
785 for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
786 value = key[i];
787 value |= (u16) (key[i + 1]) << 8;
788 b43_shm_write16(dev, B43_SHM_SHARED, offset + i, value);
789 }
790}
791
John Daiker99da1852009-02-24 02:16:42 -0800792static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
Michael Buesche4d6b792007-09-18 15:39:42 -0400793{
794 u32 addrtmp[2] = { 0, 0, };
Michael Buesch66d2d082009-08-06 10:36:50 +0200795 u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
Michael Buesche4d6b792007-09-18 15:39:42 -0400796
797 if (b43_new_kidx_api(dev))
Michael Buesch66d2d082009-08-06 10:36:50 +0200798 pairwise_keys_start = B43_NR_GROUP_KEYS;
Michael Buesche4d6b792007-09-18 15:39:42 -0400799
Michael Buesch66d2d082009-08-06 10:36:50 +0200800 B43_WARN_ON(index < pairwise_keys_start);
801 /* We have four default TX keys and possibly four default RX keys.
Michael Buesche4d6b792007-09-18 15:39:42 -0400802 * Physical mac 0 is mapped to physical key 4 or 8, depending
803 * on the firmware version.
804 * So we must adjust the index here.
805 */
Michael Buesch66d2d082009-08-06 10:36:50 +0200806 index -= pairwise_keys_start;
807 B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);
Michael Buesche4d6b792007-09-18 15:39:42 -0400808
809 if (addr) {
810 addrtmp[0] = addr[0];
811 addrtmp[0] |= ((u32) (addr[1]) << 8);
812 addrtmp[0] |= ((u32) (addr[2]) << 16);
813 addrtmp[0] |= ((u32) (addr[3]) << 24);
814 addrtmp[1] = addr[4];
815 addrtmp[1] |= ((u32) (addr[5]) << 8);
816 }
817
Michael Buesch66d2d082009-08-06 10:36:50 +0200818 /* Receive match transmitter address (RCMTA) mechanism */
819 b43_shm_write32(dev, B43_SHM_RCMTA,
820 (index * 2) + 0, addrtmp[0]);
821 b43_shm_write16(dev, B43_SHM_RCMTA,
822 (index * 2) + 1, addrtmp[1]);
Michael Buesche4d6b792007-09-18 15:39:42 -0400823}
824
gregor kowski035d0242009-08-19 22:35:45 +0200825/* The ucode will use phase1 key with TEK key to decrypt rx packets.
826 * When a packet is received, the iv32 is checked.
827 * - if it doesn't the packet is returned without modification (and software
828 * decryption can be done). That's what happen when iv16 wrap.
829 * - if it does, the rc4 key is computed, and decryption is tried.
830 * Either it will success and B43_RX_MAC_DEC is returned,
831 * either it fails and B43_RX_MAC_DEC|B43_RX_MAC_DECERR is returned
832 * and the packet is not usable (it got modified by the ucode).
833 * So in order to never have B43_RX_MAC_DECERR, we should provide
834 * a iv32 and phase1key that match. Because we drop packets in case of
835 * B43_RX_MAC_DECERR, if we have a correct iv32 but a wrong phase1key, all
836 * packets will be lost without higher layer knowing (ie no resync possible
837 * until next wrap).
838 *
839 * NOTE : this should support 50 key like RCMTA because
840 * (B43_SHM_SH_KEYIDXBLOCK - B43_SHM_SH_TKIPTSCTTAK)/14 = 50
841 */
842static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32,
843 u16 *phase1key)
844{
845 unsigned int i;
846 u32 offset;
847 u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
848
849 if (!modparam_hwtkip)
850 return;
851
852 if (b43_new_kidx_api(dev))
853 pairwise_keys_start = B43_NR_GROUP_KEYS;
854
855 B43_WARN_ON(index < pairwise_keys_start);
856 /* We have four default TX keys and possibly four default RX keys.
857 * Physical mac 0 is mapped to physical key 4 or 8, depending
858 * on the firmware version.
859 * So we must adjust the index here.
860 */
861 index -= pairwise_keys_start;
862 B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);
863
864 if (b43_debug(dev, B43_DBG_KEYS)) {
865 b43dbg(dev->wl, "rx_tkip_phase1_write : idx 0x%x, iv32 0x%x\n",
866 index, iv32);
867 }
868 /* Write the key to the RX tkip shared mem */
869 offset = B43_SHM_SH_TKIPTSCTTAK + index * (10 + 4);
870 for (i = 0; i < 10; i += 2) {
871 b43_shm_write16(dev, B43_SHM_SHARED, offset + i,
872 phase1key ? phase1key[i / 2] : 0);
873 }
874 b43_shm_write16(dev, B43_SHM_SHARED, offset + i, iv32);
875 b43_shm_write16(dev, B43_SHM_SHARED, offset + i + 2, iv32 >> 16);
876}
877
878static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
Johannes Bergb3fbdcf2010-01-21 11:40:47 +0100879 struct ieee80211_vif *vif,
880 struct ieee80211_key_conf *keyconf,
881 struct ieee80211_sta *sta,
882 u32 iv32, u16 *phase1key)
gregor kowski035d0242009-08-19 22:35:45 +0200883{
884 struct b43_wl *wl = hw_to_b43_wl(hw);
885 struct b43_wldev *dev;
886 int index = keyconf->hw_key_idx;
887
888 if (B43_WARN_ON(!modparam_hwtkip))
889 return;
890
Michael Buesch96869a32010-01-24 13:13:32 +0100891 /* This is only called from the RX path through mac80211, where
892 * our mutex is already locked. */
893 B43_WARN_ON(!mutex_is_locked(&wl->mutex));
gregor kowski035d0242009-08-19 22:35:45 +0200894 dev = wl->current_dev;
Michael Buesch96869a32010-01-24 13:13:32 +0100895 B43_WARN_ON(!dev || b43_status(dev) < B43_STAT_INITIALIZED);
gregor kowski035d0242009-08-19 22:35:45 +0200896
897 keymac_write(dev, index, NULL); /* First zero out mac to avoid race */
898
899 rx_tkip_phase1_write(dev, index, iv32, phase1key);
Johannes Bergb3fbdcf2010-01-21 11:40:47 +0100900 /* only pairwise TKIP keys are supported right now */
901 if (WARN_ON(!sta))
Michael Buesch96869a32010-01-24 13:13:32 +0100902 return;
Johannes Bergb3fbdcf2010-01-21 11:40:47 +0100903 keymac_write(dev, index, sta->addr);
gregor kowski035d0242009-08-19 22:35:45 +0200904}
905
Michael Buesche4d6b792007-09-18 15:39:42 -0400906static void do_key_write(struct b43_wldev *dev,
907 u8 index, u8 algorithm,
John Daiker99da1852009-02-24 02:16:42 -0800908 const u8 *key, size_t key_len, const u8 *mac_addr)
Michael Buesche4d6b792007-09-18 15:39:42 -0400909{
910 u8 buf[B43_SEC_KEYSIZE] = { 0, };
Michael Buesch66d2d082009-08-06 10:36:50 +0200911 u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
Michael Buesche4d6b792007-09-18 15:39:42 -0400912
913 if (b43_new_kidx_api(dev))
Michael Buesch66d2d082009-08-06 10:36:50 +0200914 pairwise_keys_start = B43_NR_GROUP_KEYS;
Michael Buesche4d6b792007-09-18 15:39:42 -0400915
Michael Buesch66d2d082009-08-06 10:36:50 +0200916 B43_WARN_ON(index >= ARRAY_SIZE(dev->key));
Michael Buesche4d6b792007-09-18 15:39:42 -0400917 B43_WARN_ON(key_len > B43_SEC_KEYSIZE);
918
Michael Buesch66d2d082009-08-06 10:36:50 +0200919 if (index >= pairwise_keys_start)
Michael Buesche4d6b792007-09-18 15:39:42 -0400920 keymac_write(dev, index, NULL); /* First zero out mac. */
gregor kowski035d0242009-08-19 22:35:45 +0200921 if (algorithm == B43_SEC_ALGO_TKIP) {
922 /*
923 * We should provide an initial iv32, phase1key pair.
924 * We could start with iv32=0 and compute the corresponding
925 * phase1key, but this means calling ieee80211_get_tkip_key
926 * with a fake skb (or export other tkip function).
927 * Because we are lazy we hope iv32 won't start with
928 * 0xffffffff and let's b43_op_update_tkip_key provide a
929 * correct pair.
930 */
931 rx_tkip_phase1_write(dev, index, 0xffffffff, (u16*)buf);
932 } else if (index >= pairwise_keys_start) /* clear it */
933 rx_tkip_phase1_write(dev, index, 0, NULL);
Michael Buesche4d6b792007-09-18 15:39:42 -0400934 if (key)
935 memcpy(buf, key, key_len);
936 key_write(dev, index, algorithm, buf);
Michael Buesch66d2d082009-08-06 10:36:50 +0200937 if (index >= pairwise_keys_start)
Michael Buesche4d6b792007-09-18 15:39:42 -0400938 keymac_write(dev, index, mac_addr);
939
940 dev->key[index].algorithm = algorithm;
941}
942
943static int b43_key_write(struct b43_wldev *dev,
944 int index, u8 algorithm,
John Daiker99da1852009-02-24 02:16:42 -0800945 const u8 *key, size_t key_len,
946 const u8 *mac_addr,
Michael Buesche4d6b792007-09-18 15:39:42 -0400947 struct ieee80211_key_conf *keyconf)
948{
949 int i;
Michael Buesch66d2d082009-08-06 10:36:50 +0200950 int pairwise_keys_start;
Michael Buesche4d6b792007-09-18 15:39:42 -0400951
gregor kowski035d0242009-08-19 22:35:45 +0200952 /* For ALG_TKIP the key is encoded as a 256-bit (32 byte) data block:
953 * - Temporal Encryption Key (128 bits)
954 * - Temporal Authenticator Tx MIC Key (64 bits)
955 * - Temporal Authenticator Rx MIC Key (64 bits)
956 *
957 * Hardware only store TEK
958 */
959 if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32)
960 key_len = 16;
Michael Buesche4d6b792007-09-18 15:39:42 -0400961 if (key_len > B43_SEC_KEYSIZE)
962 return -EINVAL;
Michael Buesch66d2d082009-08-06 10:36:50 +0200963 for (i = 0; i < ARRAY_SIZE(dev->key); i++) {
Michael Buesche4d6b792007-09-18 15:39:42 -0400964 /* Check that we don't already have this key. */
965 B43_WARN_ON(dev->key[i].keyconf == keyconf);
966 }
967 if (index < 0) {
Michael Buesche808e582008-12-19 21:30:52 +0100968 /* Pairwise key. Get an empty slot for the key. */
Michael Buesche4d6b792007-09-18 15:39:42 -0400969 if (b43_new_kidx_api(dev))
Michael Buesch66d2d082009-08-06 10:36:50 +0200970 pairwise_keys_start = B43_NR_GROUP_KEYS;
Michael Buesche4d6b792007-09-18 15:39:42 -0400971 else
Michael Buesch66d2d082009-08-06 10:36:50 +0200972 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
973 for (i = pairwise_keys_start;
974 i < pairwise_keys_start + B43_NR_PAIRWISE_KEYS;
975 i++) {
976 B43_WARN_ON(i >= ARRAY_SIZE(dev->key));
Michael Buesche4d6b792007-09-18 15:39:42 -0400977 if (!dev->key[i].keyconf) {
978 /* found empty */
979 index = i;
980 break;
981 }
982 }
983 if (index < 0) {
Michael Buesche808e582008-12-19 21:30:52 +0100984 b43warn(dev->wl, "Out of hardware key memory\n");
Michael Buesche4d6b792007-09-18 15:39:42 -0400985 return -ENOSPC;
986 }
987 } else
988 B43_WARN_ON(index > 3);
989
990 do_key_write(dev, index, algorithm, key, key_len, mac_addr);
991 if ((index <= 3) && !b43_new_kidx_api(dev)) {
992 /* Default RX key */
993 B43_WARN_ON(mac_addr);
994 do_key_write(dev, index + 4, algorithm, key, key_len, NULL);
995 }
996 keyconf->hw_key_idx = index;
997 dev->key[index].keyconf = keyconf;
998
999 return 0;
1000}
1001
1002static int b43_key_clear(struct b43_wldev *dev, int index)
1003{
Michael Buesch66d2d082009-08-06 10:36:50 +02001004 if (B43_WARN_ON((index < 0) || (index >= ARRAY_SIZE(dev->key))))
Michael Buesche4d6b792007-09-18 15:39:42 -04001005 return -EINVAL;
1006 do_key_write(dev, index, B43_SEC_ALGO_NONE,
1007 NULL, B43_SEC_KEYSIZE, NULL);
1008 if ((index <= 3) && !b43_new_kidx_api(dev)) {
1009 do_key_write(dev, index + 4, B43_SEC_ALGO_NONE,
1010 NULL, B43_SEC_KEYSIZE, NULL);
1011 }
1012 dev->key[index].keyconf = NULL;
1013
1014 return 0;
1015}
1016
1017static void b43_clear_keys(struct b43_wldev *dev)
1018{
Michael Buesch66d2d082009-08-06 10:36:50 +02001019 int i, count;
Michael Buesche4d6b792007-09-18 15:39:42 -04001020
Michael Buesch66d2d082009-08-06 10:36:50 +02001021 if (b43_new_kidx_api(dev))
1022 count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
1023 else
1024 count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
1025 for (i = 0; i < count; i++)
Michael Buesche4d6b792007-09-18 15:39:42 -04001026 b43_key_clear(dev, i);
1027}
1028
Michael Buesch9cf7f242008-12-19 20:24:30 +01001029static void b43_dump_keymemory(struct b43_wldev *dev)
1030{
Michael Buesch66d2d082009-08-06 10:36:50 +02001031 unsigned int i, index, count, offset, pairwise_keys_start;
Michael Buesch9cf7f242008-12-19 20:24:30 +01001032 u8 mac[ETH_ALEN];
1033 u16 algo;
1034 u32 rcmta0;
1035 u16 rcmta1;
1036 u64 hf;
1037 struct b43_key *key;
1038
1039 if (!b43_debug(dev, B43_DBG_KEYS))
1040 return;
1041
1042 hf = b43_hf_read(dev);
1043 b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n",
1044 !!(hf & B43_HF_USEDEFKEYS));
Michael Buesch66d2d082009-08-06 10:36:50 +02001045 if (b43_new_kidx_api(dev)) {
1046 pairwise_keys_start = B43_NR_GROUP_KEYS;
1047 count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
1048 } else {
1049 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
1050 count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
1051 }
1052 for (index = 0; index < count; index++) {
Michael Buesch9cf7f242008-12-19 20:24:30 +01001053 key = &(dev->key[index]);
1054 printk(KERN_DEBUG "Key slot %02u: %s",
1055 index, (key->keyconf == NULL) ? " " : "*");
1056 offset = dev->ktp + (index * B43_SEC_KEYSIZE);
1057 for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
1058 u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
1059 printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
1060 }
1061
1062 algo = b43_shm_read16(dev, B43_SHM_SHARED,
1063 B43_SHM_SH_KEYIDXBLOCK + (index * 2));
1064 printk(" Algo: %04X/%02X", algo, key->algorithm);
1065
Michael Buesch66d2d082009-08-06 10:36:50 +02001066 if (index >= pairwise_keys_start) {
gregor kowski035d0242009-08-19 22:35:45 +02001067 if (key->algorithm == B43_SEC_ALGO_TKIP) {
1068 printk(" TKIP: ");
1069 offset = B43_SHM_SH_TKIPTSCTTAK + (index - 4) * (10 + 4);
1070 for (i = 0; i < 14; i += 2) {
1071 u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
1072 printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
1073 }
1074 }
Michael Buesch9cf7f242008-12-19 20:24:30 +01001075 rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
Michael Buesch66d2d082009-08-06 10:36:50 +02001076 ((index - pairwise_keys_start) * 2) + 0);
Michael Buesch9cf7f242008-12-19 20:24:30 +01001077 rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
Michael Buesch66d2d082009-08-06 10:36:50 +02001078 ((index - pairwise_keys_start) * 2) + 1);
Michael Buesch9cf7f242008-12-19 20:24:30 +01001079 *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
1080 *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
Johannes Berge91d8332009-07-15 17:21:41 +02001081 printk(" MAC: %pM", mac);
Michael Buesch9cf7f242008-12-19 20:24:30 +01001082 } else
1083 printk(" DEFAULT KEY");
1084 printk("\n");
1085 }
1086}
1087
Michael Buesche4d6b792007-09-18 15:39:42 -04001088void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
1089{
1090 u32 macctl;
1091 u16 ucstat;
1092 bool hwps;
1093 bool awake;
1094 int i;
1095
1096 B43_WARN_ON((ps_flags & B43_PS_ENABLED) &&
1097 (ps_flags & B43_PS_DISABLED));
1098 B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP));
1099
1100 if (ps_flags & B43_PS_ENABLED) {
1101 hwps = 1;
1102 } else if (ps_flags & B43_PS_DISABLED) {
1103 hwps = 0;
1104 } else {
1105 //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
1106 // and thus is not an AP and we are associated, set bit 25
1107 }
1108 if (ps_flags & B43_PS_AWAKE) {
1109 awake = 1;
1110 } else if (ps_flags & B43_PS_ASLEEP) {
1111 awake = 0;
1112 } else {
1113 //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
1114 // or we are associated, or FIXME, or the latest PS-Poll packet sent was
1115 // successful, set bit26
1116 }
1117
1118/* FIXME: For now we force awake-on and hwps-off */
1119 hwps = 0;
1120 awake = 1;
1121
1122 macctl = b43_read32(dev, B43_MMIO_MACCTL);
1123 if (hwps)
1124 macctl |= B43_MACCTL_HWPS;
1125 else
1126 macctl &= ~B43_MACCTL_HWPS;
1127 if (awake)
1128 macctl |= B43_MACCTL_AWAKE;
1129 else
1130 macctl &= ~B43_MACCTL_AWAKE;
1131 b43_write32(dev, B43_MMIO_MACCTL, macctl);
1132 /* Commit write */
1133 b43_read32(dev, B43_MMIO_MACCTL);
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02001134 if (awake && dev->sdev->id.revision >= 5) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001135 /* Wait for the microcode to wake up. */
1136 for (i = 0; i < 100; i++) {
1137 ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
1138 B43_SHM_SH_UCODESTAT);
1139 if (ucstat != B43_SHM_SH_UCODESTAT_SLEEP)
1140 break;
1141 udelay(10);
1142 }
1143 }
1144}
1145
Rafał Miłecki14952982011-05-17 18:57:28 +02001146static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, u32 flags)
Michael Buesche4d6b792007-09-18 15:39:42 -04001147{
1148 u32 tmslow;
Michael Buesche4d6b792007-09-18 15:39:42 -04001149
1150 flags |= B43_TMSLOW_PHYCLKEN;
1151 flags |= B43_TMSLOW_PHYRESET;
Rafał Miłecki42ab1352010-12-09 20:56:01 +01001152 if (dev->phy.type == B43_PHYTYPE_N)
1153 flags |= B43_TMSLOW_PHY_BANDWIDTH_20MHZ; /* Make 20 MHz def */
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02001154 ssb_device_enable(dev->sdev, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -04001155 msleep(2); /* Wait for the PLL to turn on. */
1156
1157 /* Now take the PHY out of Reset again */
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02001158 tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
Michael Buesche4d6b792007-09-18 15:39:42 -04001159 tmslow |= SSB_TMSLOW_FGC;
1160 tmslow &= ~B43_TMSLOW_PHYRESET;
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02001161 ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
1162 ssb_read32(dev->sdev, SSB_TMSLOW); /* flush */
Michael Buesche4d6b792007-09-18 15:39:42 -04001163 msleep(1);
1164 tmslow &= ~SSB_TMSLOW_FGC;
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02001165 ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
1166 ssb_read32(dev->sdev, SSB_TMSLOW); /* flush */
Michael Buesche4d6b792007-09-18 15:39:42 -04001167 msleep(1);
Rafał Miłecki14952982011-05-17 18:57:28 +02001168}
1169
1170void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
1171{
1172 u32 macctl;
1173
1174 b43_ssb_wireless_core_reset(dev, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -04001175
Michael Bueschfb111372008-09-02 13:00:34 +02001176 /* Turn Analog ON, but only if we already know the PHY-type.
1177 * This protects against very early setup where we don't know the
1178 * PHY-type, yet. wireless_core_reset will be called once again later,
1179 * when we know the PHY-type. */
1180 if (dev->phy.ops)
Michael Bueschcb24f572008-09-03 12:12:20 +02001181 dev->phy.ops->switch_analog(dev, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04001182
1183 macctl = b43_read32(dev, B43_MMIO_MACCTL);
1184 macctl &= ~B43_MACCTL_GMODE;
1185 if (flags & B43_TMSLOW_GMODE)
1186 macctl |= B43_MACCTL_GMODE;
1187 macctl |= B43_MACCTL_IHR_ENABLED;
1188 b43_write32(dev, B43_MMIO_MACCTL, macctl);
1189}
1190
1191static void handle_irq_transmit_status(struct b43_wldev *dev)
1192{
1193 u32 v0, v1;
1194 u16 tmp;
1195 struct b43_txstatus stat;
1196
1197 while (1) {
1198 v0 = b43_read32(dev, B43_MMIO_XMITSTAT_0);
1199 if (!(v0 & 0x00000001))
1200 break;
1201 v1 = b43_read32(dev, B43_MMIO_XMITSTAT_1);
1202
1203 stat.cookie = (v0 >> 16);
1204 stat.seq = (v1 & 0x0000FFFF);
1205 stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
1206 tmp = (v0 & 0x0000FFFF);
1207 stat.frame_count = ((tmp & 0xF000) >> 12);
1208 stat.rts_count = ((tmp & 0x0F00) >> 8);
1209 stat.supp_reason = ((tmp & 0x001C) >> 2);
1210 stat.pm_indicated = !!(tmp & 0x0080);
1211 stat.intermediate = !!(tmp & 0x0040);
1212 stat.for_ampdu = !!(tmp & 0x0020);
1213 stat.acked = !!(tmp & 0x0002);
1214
1215 b43_handle_txstatus(dev, &stat);
1216 }
1217}
1218
1219static void drain_txstatus_queue(struct b43_wldev *dev)
1220{
1221 u32 dummy;
1222
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02001223 if (dev->sdev->id.revision < 5)
Michael Buesche4d6b792007-09-18 15:39:42 -04001224 return;
1225 /* Read all entries from the microcode TXstatus FIFO
1226 * and throw them away.
1227 */
1228 while (1) {
1229 dummy = b43_read32(dev, B43_MMIO_XMITSTAT_0);
1230 if (!(dummy & 0x00000001))
1231 break;
1232 dummy = b43_read32(dev, B43_MMIO_XMITSTAT_1);
1233 }
1234}
1235
1236static u32 b43_jssi_read(struct b43_wldev *dev)
1237{
1238 u32 val = 0;
1239
1240 val = b43_shm_read16(dev, B43_SHM_SHARED, 0x08A);
1241 val <<= 16;
1242 val |= b43_shm_read16(dev, B43_SHM_SHARED, 0x088);
1243
1244 return val;
1245}
1246
1247static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
1248{
1249 b43_shm_write16(dev, B43_SHM_SHARED, 0x088, (jssi & 0x0000FFFF));
1250 b43_shm_write16(dev, B43_SHM_SHARED, 0x08A, (jssi & 0xFFFF0000) >> 16);
1251}
1252
1253static void b43_generate_noise_sample(struct b43_wldev *dev)
1254{
1255 b43_jssi_write(dev, 0x7F7F7F7F);
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01001256 b43_write32(dev, B43_MMIO_MACCMD,
1257 b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE);
Michael Buesche4d6b792007-09-18 15:39:42 -04001258}
1259
1260static void b43_calculate_link_quality(struct b43_wldev *dev)
1261{
1262 /* Top half of Link Quality calculation. */
1263
Michael Bueschef1a6282008-08-27 18:53:02 +02001264 if (dev->phy.type != B43_PHYTYPE_G)
1265 return;
Michael Buesche4d6b792007-09-18 15:39:42 -04001266 if (dev->noisecalc.calculation_running)
1267 return;
Michael Buesche4d6b792007-09-18 15:39:42 -04001268 dev->noisecalc.calculation_running = 1;
1269 dev->noisecalc.nr_samples = 0;
1270
1271 b43_generate_noise_sample(dev);
1272}
1273
1274static void handle_irq_noise(struct b43_wldev *dev)
1275{
Michael Bueschef1a6282008-08-27 18:53:02 +02001276 struct b43_phy_g *phy = dev->phy.g;
Michael Buesche4d6b792007-09-18 15:39:42 -04001277 u16 tmp;
1278 u8 noise[4];
1279 u8 i, j;
1280 s32 average;
1281
1282 /* Bottom half of Link Quality calculation. */
1283
Michael Bueschef1a6282008-08-27 18:53:02 +02001284 if (dev->phy.type != B43_PHYTYPE_G)
1285 return;
1286
Michael Buesch98a3b2f2008-06-12 12:36:29 +02001287 /* Possible race condition: It might be possible that the user
1288 * changed to a different channel in the meantime since we
1289 * started the calculation. We ignore that fact, since it's
1290 * not really that much of a problem. The background noise is
1291 * an estimation only anyway. Slightly wrong results will get damped
1292 * by the averaging of the 8 sample rounds. Additionally the
1293 * value is shortlived. So it will be replaced by the next noise
1294 * calculation round soon. */
1295
Michael Buesche4d6b792007-09-18 15:39:42 -04001296 B43_WARN_ON(!dev->noisecalc.calculation_running);
Michael Buesch1a094042007-09-20 11:13:40 -07001297 *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev));
Michael Buesche4d6b792007-09-18 15:39:42 -04001298 if (noise[0] == 0x7F || noise[1] == 0x7F ||
1299 noise[2] == 0x7F || noise[3] == 0x7F)
1300 goto generate_new;
1301
1302 /* Get the noise samples. */
1303 B43_WARN_ON(dev->noisecalc.nr_samples >= 8);
1304 i = dev->noisecalc.nr_samples;
Harvey Harrisoncdbf0842008-05-02 13:47:48 -07001305 noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1306 noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1307 noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1308 noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04001309 dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
1310 dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
1311 dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
1312 dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
1313 dev->noisecalc.nr_samples++;
1314 if (dev->noisecalc.nr_samples == 8) {
1315 /* Calculate the Link Quality by the noise samples. */
1316 average = 0;
1317 for (i = 0; i < 8; i++) {
1318 for (j = 0; j < 4; j++)
1319 average += dev->noisecalc.samples[i][j];
1320 }
1321 average /= (8 * 4);
1322 average *= 125;
1323 average += 64;
1324 average /= 128;
1325 tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x40C);
1326 tmp = (tmp / 128) & 0x1F;
1327 if (tmp >= 8)
1328 average += 2;
1329 else
1330 average -= 25;
1331 if (tmp == 8)
1332 average -= 72;
1333 else
1334 average -= 48;
1335
1336 dev->stats.link_noise = average;
Michael Buesche4d6b792007-09-18 15:39:42 -04001337 dev->noisecalc.calculation_running = 0;
1338 return;
1339 }
Michael Buesch98a3b2f2008-06-12 12:36:29 +02001340generate_new:
Michael Buesche4d6b792007-09-18 15:39:42 -04001341 b43_generate_noise_sample(dev);
1342}
1343
1344static void handle_irq_tbtt_indication(struct b43_wldev *dev)
1345{
Johannes Berg05c914f2008-09-11 00:01:58 +02001346 if (b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001347 ///TODO: PS TBTT
1348 } else {
1349 if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
1350 b43_power_saving_ctl_bits(dev, 0);
1351 }
Johannes Berg05c914f2008-09-11 00:01:58 +02001352 if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01001353 dev->dfq_valid = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04001354}
1355
1356static void handle_irq_atim_end(struct b43_wldev *dev)
1357{
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01001358 if (dev->dfq_valid) {
1359 b43_write32(dev, B43_MMIO_MACCMD,
1360 b43_read32(dev, B43_MMIO_MACCMD)
1361 | B43_MACCMD_DFQ_VALID);
1362 dev->dfq_valid = 0;
1363 }
Michael Buesche4d6b792007-09-18 15:39:42 -04001364}
1365
1366static void handle_irq_pmq(struct b43_wldev *dev)
1367{
1368 u32 tmp;
1369
1370 //TODO: AP mode.
1371
1372 while (1) {
1373 tmp = b43_read32(dev, B43_MMIO_PS_STATUS);
1374 if (!(tmp & 0x00000008))
1375 break;
1376 }
1377 /* 16bit write is odd, but correct. */
1378 b43_write16(dev, B43_MMIO_PS_STATUS, 0x0002);
1379}
1380
1381static void b43_write_template_common(struct b43_wldev *dev,
John Daiker99da1852009-02-24 02:16:42 -08001382 const u8 *data, u16 size,
Michael Buesche4d6b792007-09-18 15:39:42 -04001383 u16 ram_offset,
1384 u16 shm_size_offset, u8 rate)
1385{
1386 u32 i, tmp;
1387 struct b43_plcp_hdr4 plcp;
1388
1389 plcp.data = 0;
1390 b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
1391 b43_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
1392 ram_offset += sizeof(u32);
1393 /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
1394 * So leave the first two bytes of the next write blank.
1395 */
1396 tmp = (u32) (data[0]) << 16;
1397 tmp |= (u32) (data[1]) << 24;
1398 b43_ram_write(dev, ram_offset, tmp);
1399 ram_offset += sizeof(u32);
1400 for (i = 2; i < size; i += sizeof(u32)) {
1401 tmp = (u32) (data[i + 0]);
1402 if (i + 1 < size)
1403 tmp |= (u32) (data[i + 1]) << 8;
1404 if (i + 2 < size)
1405 tmp |= (u32) (data[i + 2]) << 16;
1406 if (i + 3 < size)
1407 tmp |= (u32) (data[i + 3]) << 24;
1408 b43_ram_write(dev, ram_offset + i - 2, tmp);
1409 }
1410 b43_shm_write16(dev, B43_SHM_SHARED, shm_size_offset,
1411 size + sizeof(struct b43_plcp_hdr6));
1412}
1413
Michael Buesch5042c502008-04-05 15:05:00 +02001414/* Check if the use of the antenna that ieee80211 told us to
1415 * use is possible. This will fall back to DEFAULT.
1416 * "antenna_nr" is the antenna identifier we got from ieee80211. */
1417u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
1418 u8 antenna_nr)
1419{
1420 u8 antenna_mask;
1421
1422 if (antenna_nr == 0) {
1423 /* Zero means "use default antenna". That's always OK. */
1424 return 0;
1425 }
1426
1427 /* Get the mask of available antennas. */
1428 if (dev->phy.gmode)
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02001429 antenna_mask = dev->sdev->bus->sprom.ant_available_bg;
Michael Buesch5042c502008-04-05 15:05:00 +02001430 else
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02001431 antenna_mask = dev->sdev->bus->sprom.ant_available_a;
Michael Buesch5042c502008-04-05 15:05:00 +02001432
1433 if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
1434 /* This antenna is not available. Fall back to default. */
1435 return 0;
1436 }
1437
1438 return antenna_nr;
1439}
1440
Michael Buesch5042c502008-04-05 15:05:00 +02001441/* Convert a b43 antenna number value to the PHY TX control value. */
1442static u16 b43_antenna_to_phyctl(int antenna)
1443{
1444 switch (antenna) {
1445 case B43_ANTENNA0:
1446 return B43_TXH_PHY_ANT0;
1447 case B43_ANTENNA1:
1448 return B43_TXH_PHY_ANT1;
1449 case B43_ANTENNA2:
1450 return B43_TXH_PHY_ANT2;
1451 case B43_ANTENNA3:
1452 return B43_TXH_PHY_ANT3;
Gábor Stefanik64e368b2009-08-27 22:49:49 +02001453 case B43_ANTENNA_AUTO0:
1454 case B43_ANTENNA_AUTO1:
Michael Buesch5042c502008-04-05 15:05:00 +02001455 return B43_TXH_PHY_ANT01AUTO;
1456 }
1457 B43_WARN_ON(1);
1458 return 0;
1459}
1460
Michael Buesche4d6b792007-09-18 15:39:42 -04001461static void b43_write_beacon_template(struct b43_wldev *dev,
1462 u16 ram_offset,
Michael Buesch5042c502008-04-05 15:05:00 +02001463 u16 shm_size_offset)
Michael Buesche4d6b792007-09-18 15:39:42 -04001464{
Michael Buesch47f76ca2007-12-27 22:15:11 +01001465 unsigned int i, len, variable_len;
Michael Buesche66fee62007-12-26 17:47:10 +01001466 const struct ieee80211_mgmt *bcn;
1467 const u8 *ie;
1468 bool tim_found = 0;
Michael Buesch5042c502008-04-05 15:05:00 +02001469 unsigned int rate;
1470 u16 ctl;
1471 int antenna;
Johannes Berge039fa42008-05-15 12:55:29 +02001472 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
Michael Buesche4d6b792007-09-18 15:39:42 -04001473
Michael Buesche66fee62007-12-26 17:47:10 +01001474 bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
1475 len = min((size_t) dev->wl->current_beacon->len,
Michael Buesche4d6b792007-09-18 15:39:42 -04001476 0x200 - sizeof(struct b43_plcp_hdr6));
Johannes Berge039fa42008-05-15 12:55:29 +02001477 rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
Michael Buesche66fee62007-12-26 17:47:10 +01001478
1479 b43_write_template_common(dev, (const u8 *)bcn,
Michael Buesche4d6b792007-09-18 15:39:42 -04001480 len, ram_offset, shm_size_offset, rate);
Michael Buesche66fee62007-12-26 17:47:10 +01001481
Michael Buesch5042c502008-04-05 15:05:00 +02001482 /* Write the PHY TX control parameters. */
Johannes Berg0f4ac382008-10-09 12:18:04 +02001483 antenna = B43_ANTENNA_DEFAULT;
Michael Buesch5042c502008-04-05 15:05:00 +02001484 antenna = b43_antenna_to_phyctl(antenna);
1485 ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
1486 /* We can't send beacons with short preamble. Would get PHY errors. */
1487 ctl &= ~B43_TXH_PHY_SHORTPRMBL;
1488 ctl &= ~B43_TXH_PHY_ANT;
1489 ctl &= ~B43_TXH_PHY_ENC;
1490 ctl |= antenna;
1491 if (b43_is_cck_rate(rate))
1492 ctl |= B43_TXH_PHY_ENC_CCK;
1493 else
1494 ctl |= B43_TXH_PHY_ENC_OFDM;
1495 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);
1496
Michael Buesche66fee62007-12-26 17:47:10 +01001497 /* Find the position of the TIM and the DTIM_period value
1498 * and write them to SHM. */
1499 ie = bcn->u.beacon.variable;
Michael Buesch47f76ca2007-12-27 22:15:11 +01001500 variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
1501 for (i = 0; i < variable_len - 2; ) {
Michael Buesche66fee62007-12-26 17:47:10 +01001502 uint8_t ie_id, ie_len;
1503
1504 ie_id = ie[i];
1505 ie_len = ie[i + 1];
1506 if (ie_id == 5) {
1507 u16 tim_position;
1508 u16 dtim_period;
1509 /* This is the TIM Information Element */
1510
1511 /* Check whether the ie_len is in the beacon data range. */
Michael Buesch47f76ca2007-12-27 22:15:11 +01001512 if (variable_len < ie_len + 2 + i)
Michael Buesche66fee62007-12-26 17:47:10 +01001513 break;
1514 /* A valid TIM is at least 4 bytes long. */
1515 if (ie_len < 4)
1516 break;
1517 tim_found = 1;
1518
1519 tim_position = sizeof(struct b43_plcp_hdr6);
1520 tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable);
1521 tim_position += i;
1522
1523 dtim_period = ie[i + 3];
1524
1525 b43_shm_write16(dev, B43_SHM_SHARED,
1526 B43_SHM_SH_TIMBPOS, tim_position);
1527 b43_shm_write16(dev, B43_SHM_SHARED,
1528 B43_SHM_SH_DTIMPER, dtim_period);
1529 break;
1530 }
1531 i += ie_len + 2;
1532 }
1533 if (!tim_found) {
Johannes Berg04dea132008-05-20 12:10:49 +02001534 /*
1535 * If ucode wants to modify TIM do it behind the beacon, this
1536 * will happen, for example, when doing mesh networking.
1537 */
1538 b43_shm_write16(dev, B43_SHM_SHARED,
1539 B43_SHM_SH_TIMBPOS,
1540 len + sizeof(struct b43_plcp_hdr6));
1541 b43_shm_write16(dev, B43_SHM_SHARED,
1542 B43_SHM_SH_DTIMPER, 0);
1543 }
1544 b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
Michael Buesche4d6b792007-09-18 15:39:42 -04001545}
1546
Michael Buesch6b4bec02008-05-20 12:16:28 +02001547static void b43_upload_beacon0(struct b43_wldev *dev)
1548{
1549 struct b43_wl *wl = dev->wl;
1550
1551 if (wl->beacon0_uploaded)
1552 return;
1553 b43_write_beacon_template(dev, 0x68, 0x18);
Michael Buesch6b4bec02008-05-20 12:16:28 +02001554 wl->beacon0_uploaded = 1;
1555}
1556
1557static void b43_upload_beacon1(struct b43_wldev *dev)
1558{
1559 struct b43_wl *wl = dev->wl;
1560
1561 if (wl->beacon1_uploaded)
1562 return;
1563 b43_write_beacon_template(dev, 0x468, 0x1A);
1564 wl->beacon1_uploaded = 1;
1565}
1566
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001567static void handle_irq_beacon(struct b43_wldev *dev)
1568{
1569 struct b43_wl *wl = dev->wl;
1570 u32 cmd, beacon0_valid, beacon1_valid;
1571
Johannes Berg05c914f2008-09-11 00:01:58 +02001572 if (!b43_is_mode(wl, NL80211_IFTYPE_AP) &&
1573 !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001574 return;
1575
1576 /* This is the bottom half of the asynchronous beacon update. */
1577
1578 /* Ignore interrupt in the future. */
Michael Buesch13790722009-04-08 21:26:27 +02001579 dev->irq_mask &= ~B43_IRQ_BEACON;
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001580
1581 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1582 beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID);
1583 beacon1_valid = (cmd & B43_MACCMD_BEACON1_VALID);
1584
1585 /* Schedule interrupt manually, if busy. */
1586 if (beacon0_valid && beacon1_valid) {
1587 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
Michael Buesch13790722009-04-08 21:26:27 +02001588 dev->irq_mask |= B43_IRQ_BEACON;
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001589 return;
1590 }
1591
Michael Buesch6b4bec02008-05-20 12:16:28 +02001592 if (unlikely(wl->beacon_templates_virgin)) {
1593 /* We never uploaded a beacon before.
1594 * Upload both templates now, but only mark one valid. */
1595 wl->beacon_templates_virgin = 0;
1596 b43_upload_beacon0(dev);
1597 b43_upload_beacon1(dev);
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001598 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1599 cmd |= B43_MACCMD_BEACON0_VALID;
1600 b43_write32(dev, B43_MMIO_MACCMD, cmd);
Michael Buesch6b4bec02008-05-20 12:16:28 +02001601 } else {
1602 if (!beacon0_valid) {
1603 b43_upload_beacon0(dev);
1604 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1605 cmd |= B43_MACCMD_BEACON0_VALID;
1606 b43_write32(dev, B43_MMIO_MACCMD, cmd);
1607 } else if (!beacon1_valid) {
1608 b43_upload_beacon1(dev);
1609 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1610 cmd |= B43_MACCMD_BEACON1_VALID;
1611 b43_write32(dev, B43_MMIO_MACCMD, cmd);
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001612 }
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001613 }
1614}
1615
Michael Buesch36dbd952009-09-04 22:51:29 +02001616static void b43_do_beacon_update_trigger_work(struct b43_wldev *dev)
1617{
1618 u32 old_irq_mask = dev->irq_mask;
1619
1620 /* update beacon right away or defer to irq */
1621 handle_irq_beacon(dev);
1622 if (old_irq_mask != dev->irq_mask) {
1623 /* The handler updated the IRQ mask. */
1624 B43_WARN_ON(!dev->irq_mask);
1625 if (b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)) {
1626 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
1627 } else {
1628 /* Device interrupts are currently disabled. That means
1629 * we just ran the hardirq handler and scheduled the
1630 * IRQ thread. The thread will write the IRQ mask when
1631 * it finished, so there's nothing to do here. Writing
1632 * the mask _here_ would incorrectly re-enable IRQs. */
1633 }
1634 }
1635}
1636
Michael Buescha82d9922008-04-04 21:40:06 +02001637static void b43_beacon_update_trigger_work(struct work_struct *work)
1638{
1639 struct b43_wl *wl = container_of(work, struct b43_wl,
1640 beacon_update_trigger);
1641 struct b43_wldev *dev;
1642
1643 mutex_lock(&wl->mutex);
1644 dev = wl->current_dev;
1645 if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02001646 if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
Michael Buesch36dbd952009-09-04 22:51:29 +02001647 /* wl->mutex is enough. */
1648 b43_do_beacon_update_trigger_work(dev);
1649 mmiowb();
1650 } else {
1651 spin_lock_irq(&wl->hardirq_lock);
1652 b43_do_beacon_update_trigger_work(dev);
1653 mmiowb();
1654 spin_unlock_irq(&wl->hardirq_lock);
1655 }
Michael Buescha82d9922008-04-04 21:40:06 +02001656 }
1657 mutex_unlock(&wl->mutex);
1658}
1659
Michael Bueschd4df6f12007-12-26 18:04:14 +01001660/* Asynchronously update the packet templates in template RAM.
Michael Buesch36dbd952009-09-04 22:51:29 +02001661 * Locking: Requires wl->mutex to be locked. */
Johannes Berg9d139c82008-07-09 14:40:37 +02001662static void b43_update_templates(struct b43_wl *wl)
Michael Buesche4d6b792007-09-18 15:39:42 -04001663{
Johannes Berg9d139c82008-07-09 14:40:37 +02001664 struct sk_buff *beacon;
1665
Michael Buesche66fee62007-12-26 17:47:10 +01001666 /* This is the top half of the ansynchronous beacon update.
1667 * The bottom half is the beacon IRQ.
1668 * Beacon update must be asynchronous to avoid sending an
1669 * invalid beacon. This can happen for example, if the firmware
1670 * transmits a beacon while we are updating it. */
Michael Buesche4d6b792007-09-18 15:39:42 -04001671
Johannes Berg9d139c82008-07-09 14:40:37 +02001672 /* We could modify the existing beacon and set the aid bit in
1673 * the TIM field, but that would probably require resizing and
1674 * moving of data within the beacon template.
1675 * Simply request a new beacon and let mac80211 do the hard work. */
1676 beacon = ieee80211_beacon_get(wl->hw, wl->vif);
1677 if (unlikely(!beacon))
1678 return;
1679
Michael Buesche66fee62007-12-26 17:47:10 +01001680 if (wl->current_beacon)
1681 dev_kfree_skb_any(wl->current_beacon);
1682 wl->current_beacon = beacon;
1683 wl->beacon0_uploaded = 0;
1684 wl->beacon1_uploaded = 0;
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04001685 ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
Michael Buesche4d6b792007-09-18 15:39:42 -04001686}
1687
Michael Buesche4d6b792007-09-18 15:39:42 -04001688static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
1689{
1690 b43_time_lock(dev);
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02001691 if (dev->sdev->id.revision >= 3) {
Michael Buescha82d9922008-04-04 21:40:06 +02001692 b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16));
1693 b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));
Michael Buesche4d6b792007-09-18 15:39:42 -04001694 } else {
1695 b43_write16(dev, 0x606, (beacon_int >> 6));
1696 b43_write16(dev, 0x610, beacon_int);
1697 }
1698 b43_time_unlock(dev);
Michael Buescha82d9922008-04-04 21:40:06 +02001699 b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
Michael Buesche4d6b792007-09-18 15:39:42 -04001700}
1701
Michael Bueschafa83e22008-05-19 23:51:37 +02001702static void b43_handle_firmware_panic(struct b43_wldev *dev)
1703{
1704 u16 reason;
1705
1706 /* Read the register that contains the reason code for the panic. */
1707 reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG);
1708 b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason);
1709
1710 switch (reason) {
1711 default:
1712 b43dbg(dev->wl, "The panic reason is unknown.\n");
1713 /* fallthrough */
1714 case B43_FWPANIC_DIE:
1715 /* Do not restart the controller or firmware.
1716 * The device is nonfunctional from now on.
1717 * Restarting would result in this panic to trigger again,
1718 * so we avoid that recursion. */
1719 break;
1720 case B43_FWPANIC_RESTART:
1721 b43_controller_restart(dev, "Microcode panic");
1722 break;
1723 }
1724}
1725
Michael Buesche4d6b792007-09-18 15:39:42 -04001726static void handle_irq_ucode_debug(struct b43_wldev *dev)
1727{
Michael Buesche48b0ee2008-05-17 22:44:35 +02001728 unsigned int i, cnt;
Michael Buesch53c06852008-05-20 00:24:36 +02001729 u16 reason, marker_id, marker_line;
Michael Buesche48b0ee2008-05-17 22:44:35 +02001730 __le16 *buf;
1731
1732 /* The proprietary firmware doesn't have this IRQ. */
1733 if (!dev->fw.opensource)
1734 return;
1735
Michael Bueschafa83e22008-05-19 23:51:37 +02001736 /* Read the register that contains the reason code for this IRQ. */
1737 reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG);
1738
Michael Buesche48b0ee2008-05-17 22:44:35 +02001739 switch (reason) {
1740 case B43_DEBUGIRQ_PANIC:
Michael Bueschafa83e22008-05-19 23:51:37 +02001741 b43_handle_firmware_panic(dev);
Michael Buesche48b0ee2008-05-17 22:44:35 +02001742 break;
1743 case B43_DEBUGIRQ_DUMP_SHM:
1744 if (!B43_DEBUG)
1745 break; /* Only with driver debugging enabled. */
1746 buf = kmalloc(4096, GFP_ATOMIC);
1747 if (!buf) {
1748 b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n");
1749 goto out;
1750 }
1751 for (i = 0; i < 4096; i += 2) {
1752 u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i);
1753 buf[i / 2] = cpu_to_le16(tmp);
1754 }
1755 b43info(dev->wl, "Shared memory dump:\n");
1756 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET,
1757 16, 2, buf, 4096, 1);
1758 kfree(buf);
1759 break;
1760 case B43_DEBUGIRQ_DUMP_REGS:
1761 if (!B43_DEBUG)
1762 break; /* Only with driver debugging enabled. */
1763 b43info(dev->wl, "Microcode register dump:\n");
1764 for (i = 0, cnt = 0; i < 64; i++) {
1765 u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i);
1766 if (cnt == 0)
1767 printk(KERN_INFO);
1768 printk("r%02u: 0x%04X ", i, tmp);
1769 cnt++;
1770 if (cnt == 6) {
1771 printk("\n");
1772 cnt = 0;
1773 }
1774 }
1775 printk("\n");
1776 break;
Michael Buesch53c06852008-05-20 00:24:36 +02001777 case B43_DEBUGIRQ_MARKER:
1778 if (!B43_DEBUG)
1779 break; /* Only with driver debugging enabled. */
1780 marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH,
1781 B43_MARKER_ID_REG);
1782 marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH,
1783 B43_MARKER_LINE_REG);
1784 b43info(dev->wl, "The firmware just executed the MARKER(%u) "
1785 "at line number %u\n",
1786 marker_id, marker_line);
1787 break;
Michael Buesche48b0ee2008-05-17 22:44:35 +02001788 default:
1789 b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n",
1790 reason);
1791 }
1792out:
Michael Bueschafa83e22008-05-19 23:51:37 +02001793 /* Acknowledge the debug-IRQ, so the firmware can continue. */
1794 b43_shm_write16(dev, B43_SHM_SCRATCH,
1795 B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK);
Michael Buesche4d6b792007-09-18 15:39:42 -04001796}
1797
Michael Buesch36dbd952009-09-04 22:51:29 +02001798static void b43_do_interrupt_thread(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04001799{
1800 u32 reason;
1801 u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
1802 u32 merged_dma_reason = 0;
Michael Buesch21954c32007-09-27 15:31:40 +02001803 int i;
Michael Buesche4d6b792007-09-18 15:39:42 -04001804
Michael Buesch36dbd952009-09-04 22:51:29 +02001805 if (unlikely(b43_status(dev) != B43_STAT_STARTED))
1806 return;
Michael Buesche4d6b792007-09-18 15:39:42 -04001807
1808 reason = dev->irq_reason;
1809 for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
1810 dma_reason[i] = dev->dma_reason[i];
1811 merged_dma_reason |= dma_reason[i];
1812 }
1813
1814 if (unlikely(reason & B43_IRQ_MAC_TXERR))
1815 b43err(dev->wl, "MAC transmission error\n");
1816
Stefano Brivio00e0b8c2007-11-25 11:10:33 +01001817 if (unlikely(reason & B43_IRQ_PHY_TXERR)) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001818 b43err(dev->wl, "PHY transmission error\n");
Stefano Brivio00e0b8c2007-11-25 11:10:33 +01001819 rmb();
1820 if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) {
1821 atomic_set(&dev->phy.txerr_cnt,
1822 B43_PHY_TX_BADNESS_LIMIT);
1823 b43err(dev->wl, "Too many PHY TX errors, "
1824 "restarting the controller\n");
1825 b43_controller_restart(dev, "PHY TX errors");
1826 }
1827 }
Michael Buesche4d6b792007-09-18 15:39:42 -04001828
1829 if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
1830 B43_DMAIRQ_NONFATALMASK))) {
1831 if (merged_dma_reason & B43_DMAIRQ_FATALMASK) {
1832 b43err(dev->wl, "Fatal DMA error: "
1833 "0x%08X, 0x%08X, 0x%08X, "
1834 "0x%08X, 0x%08X, 0x%08X\n",
1835 dma_reason[0], dma_reason[1],
1836 dma_reason[2], dma_reason[3],
1837 dma_reason[4], dma_reason[5]);
Larry Finger214ac9a2009-12-09 13:25:56 -06001838 b43err(dev->wl, "This device does not support DMA "
Larry Fingerbb64d952010-06-19 08:29:08 -05001839 "on your system. It will now be switched to PIO.\n");
Linus Torvalds9e3bd912010-02-26 10:34:27 -08001840 /* Fall back to PIO transfers if we get fatal DMA errors! */
1841 dev->use_pio = 1;
1842 b43_controller_restart(dev, "DMA error");
Michael Buesche4d6b792007-09-18 15:39:42 -04001843 return;
1844 }
1845 if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
1846 b43err(dev->wl, "DMA error: "
1847 "0x%08X, 0x%08X, 0x%08X, "
1848 "0x%08X, 0x%08X, 0x%08X\n",
1849 dma_reason[0], dma_reason[1],
1850 dma_reason[2], dma_reason[3],
1851 dma_reason[4], dma_reason[5]);
1852 }
1853 }
1854
1855 if (unlikely(reason & B43_IRQ_UCODE_DEBUG))
1856 handle_irq_ucode_debug(dev);
1857 if (reason & B43_IRQ_TBTT_INDI)
1858 handle_irq_tbtt_indication(dev);
1859 if (reason & B43_IRQ_ATIM_END)
1860 handle_irq_atim_end(dev);
1861 if (reason & B43_IRQ_BEACON)
1862 handle_irq_beacon(dev);
1863 if (reason & B43_IRQ_PMQ)
1864 handle_irq_pmq(dev);
Michael Buesch21954c32007-09-27 15:31:40 +02001865 if (reason & B43_IRQ_TXFIFO_FLUSH_OK)
1866 ;/* TODO */
1867 if (reason & B43_IRQ_NOISESAMPLE_OK)
Michael Buesche4d6b792007-09-18 15:39:42 -04001868 handle_irq_noise(dev);
1869
1870 /* Check the DMA reason registers for received data. */
Michael Buesch5100d5a2008-03-29 21:01:16 +01001871 if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
1872 if (b43_using_pio_transfers(dev))
1873 b43_pio_rx(dev->pio.rx_queue);
1874 else
1875 b43_dma_rx(dev->dma.rx_ring);
1876 }
Michael Buesche4d6b792007-09-18 15:39:42 -04001877 B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
1878 B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
Michael Bueschb27faf82008-03-06 16:32:46 +01001879 B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE);
Michael Buesche4d6b792007-09-18 15:39:42 -04001880 B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
1881 B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
1882
Michael Buesch21954c32007-09-27 15:31:40 +02001883 if (reason & B43_IRQ_TX_OK)
Michael Buesche4d6b792007-09-18 15:39:42 -04001884 handle_irq_transmit_status(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04001885
Michael Buesch36dbd952009-09-04 22:51:29 +02001886 /* Re-enable interrupts on the device by restoring the current interrupt mask. */
Michael Buesch13790722009-04-08 21:26:27 +02001887 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
Michael Buesch990b86f2009-09-12 00:48:03 +02001888
1889#if B43_DEBUG
1890 if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
1891 dev->irq_count++;
1892 for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
1893 if (reason & (1 << i))
1894 dev->irq_bit_count[i]++;
1895 }
1896 }
1897#endif
Michael Buesche4d6b792007-09-18 15:39:42 -04001898}
1899
Michael Buesch36dbd952009-09-04 22:51:29 +02001900/* Interrupt thread handler. Handles device interrupts in thread context. */
1901static irqreturn_t b43_interrupt_thread_handler(int irq, void *dev_id)
Michael Buesche4d6b792007-09-18 15:39:42 -04001902{
Michael Buesche4d6b792007-09-18 15:39:42 -04001903 struct b43_wldev *dev = dev_id;
Michael Buesch36dbd952009-09-04 22:51:29 +02001904
1905 mutex_lock(&dev->wl->mutex);
1906 b43_do_interrupt_thread(dev);
1907 mmiowb();
1908 mutex_unlock(&dev->wl->mutex);
1909
1910 return IRQ_HANDLED;
1911}
1912
1913static irqreturn_t b43_do_interrupt(struct b43_wldev *dev)
1914{
Michael Buesche4d6b792007-09-18 15:39:42 -04001915 u32 reason;
1916
Michael Buesch36dbd952009-09-04 22:51:29 +02001917 /* This code runs under wl->hardirq_lock, but _only_ on non-SDIO busses.
1918 * On SDIO, this runs under wl->mutex. */
Michael Buesche4d6b792007-09-18 15:39:42 -04001919
Michael Buesche4d6b792007-09-18 15:39:42 -04001920 reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
1921 if (reason == 0xffffffff) /* shared IRQ */
Michael Buesch36dbd952009-09-04 22:51:29 +02001922 return IRQ_NONE;
Michael Buesch13790722009-04-08 21:26:27 +02001923 reason &= dev->irq_mask;
Michael Buesche4d6b792007-09-18 15:39:42 -04001924 if (!reason)
Michael Buesch36dbd952009-09-04 22:51:29 +02001925 return IRQ_HANDLED;
Michael Buesche4d6b792007-09-18 15:39:42 -04001926
1927 dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
1928 & 0x0001DC00;
1929 dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON)
1930 & 0x0000DC00;
1931 dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON)
1932 & 0x0000DC00;
1933 dev->dma_reason[3] = b43_read32(dev, B43_MMIO_DMA3_REASON)
1934 & 0x0001DC00;
1935 dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON)
1936 & 0x0000DC00;
Michael Buesch13790722009-04-08 21:26:27 +02001937/* Unused ring
Michael Buesche4d6b792007-09-18 15:39:42 -04001938 dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON)
1939 & 0x0000DC00;
Michael Buesch13790722009-04-08 21:26:27 +02001940*/
Michael Buesche4d6b792007-09-18 15:39:42 -04001941
Michael Buesch36dbd952009-09-04 22:51:29 +02001942 /* ACK the interrupt. */
1943 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
1944 b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
1945 b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]);
1946 b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
1947 b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
1948 b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
1949/* Unused ring
1950 b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
1951*/
1952
1953 /* Disable IRQs on the device. The IRQ thread handler will re-enable them. */
Michael Buesch13790722009-04-08 21:26:27 +02001954 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
Michael Buesch36dbd952009-09-04 22:51:29 +02001955 /* Save the reason bitmasks for the IRQ thread handler. */
Michael Buesche4d6b792007-09-18 15:39:42 -04001956 dev->irq_reason = reason;
Michael Buesch36dbd952009-09-04 22:51:29 +02001957
1958 return IRQ_WAKE_THREAD;
1959}
1960
1961/* Interrupt handler top-half. This runs with interrupts disabled. */
1962static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
1963{
1964 struct b43_wldev *dev = dev_id;
1965 irqreturn_t ret;
1966
1967 if (unlikely(b43_status(dev) < B43_STAT_STARTED))
1968 return IRQ_NONE;
1969
1970 spin_lock(&dev->wl->hardirq_lock);
1971 ret = b43_do_interrupt(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04001972 mmiowb();
Michael Buesch36dbd952009-09-04 22:51:29 +02001973 spin_unlock(&dev->wl->hardirq_lock);
Michael Buesche4d6b792007-09-18 15:39:42 -04001974
1975 return ret;
1976}
1977
Albert Herranz3dbba8e2009-09-10 19:34:49 +02001978/* SDIO interrupt handler. This runs in process context. */
1979static void b43_sdio_interrupt_handler(struct b43_wldev *dev)
1980{
1981 struct b43_wl *wl = dev->wl;
Albert Herranz3dbba8e2009-09-10 19:34:49 +02001982 irqreturn_t ret;
1983
Albert Herranz3dbba8e2009-09-10 19:34:49 +02001984 mutex_lock(&wl->mutex);
Albert Herranz3dbba8e2009-09-10 19:34:49 +02001985
1986 ret = b43_do_interrupt(dev);
1987 if (ret == IRQ_WAKE_THREAD)
1988 b43_do_interrupt_thread(dev);
1989
Albert Herranz3dbba8e2009-09-10 19:34:49 +02001990 mutex_unlock(&wl->mutex);
1991}
1992
Michael Buesch1a9f5092009-01-23 21:21:51 +01001993void b43_do_release_fw(struct b43_firmware_file *fw)
Michael Buesch61cb5dd2008-01-21 19:55:09 +01001994{
1995 release_firmware(fw->data);
1996 fw->data = NULL;
1997 fw->filename = NULL;
1998}
1999
Michael Buesche4d6b792007-09-18 15:39:42 -04002000static void b43_release_firmware(struct b43_wldev *dev)
2001{
Michael Buesch1a9f5092009-01-23 21:21:51 +01002002 b43_do_release_fw(&dev->fw.ucode);
2003 b43_do_release_fw(&dev->fw.pcm);
2004 b43_do_release_fw(&dev->fw.initvals);
2005 b43_do_release_fw(&dev->fw.initvals_band);
Michael Buesche4d6b792007-09-18 15:39:42 -04002006}
2007
Michael Buescheb189d8b2008-01-28 14:47:41 -08002008static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
Michael Buesche4d6b792007-09-18 15:39:42 -04002009{
Hannes Ederfc68ed42009-02-14 11:50:06 +00002010 const char text[] =
2011 "You must go to " \
2012 "http://wireless.kernel.org/en/users/Drivers/b43#devicefirmware " \
2013 "and download the correct firmware for this driver version. " \
2014 "Please carefully read all instructions on this website.\n";
Michael Buescheb189d8b2008-01-28 14:47:41 -08002015
Michael Buescheb189d8b2008-01-28 14:47:41 -08002016 if (error)
2017 b43err(wl, text);
2018 else
2019 b43warn(wl, text);
Michael Buesche4d6b792007-09-18 15:39:42 -04002020}
2021
Michael Buesch1a9f5092009-01-23 21:21:51 +01002022int b43_do_request_fw(struct b43_request_fw_context *ctx,
2023 const char *name,
2024 struct b43_firmware_file *fw)
Michael Buesche4d6b792007-09-18 15:39:42 -04002025{
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002026 const struct firmware *blob;
Michael Buesche4d6b792007-09-18 15:39:42 -04002027 struct b43_fw_header *hdr;
2028 u32 size;
2029 int err;
2030
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002031 if (!name) {
2032 /* Don't fetch anything. Free possibly cached firmware. */
Michael Buesch1a9f5092009-01-23 21:21:51 +01002033 /* FIXME: We should probably keep it anyway, to save some headache
2034 * on suspend/resume with multiband devices. */
2035 b43_do_release_fw(fw);
Michael Buesche4d6b792007-09-18 15:39:42 -04002036 return 0;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002037 }
2038 if (fw->filename) {
Michael Buesch1a9f5092009-01-23 21:21:51 +01002039 if ((fw->type == ctx->req_type) &&
2040 (strcmp(fw->filename, name) == 0))
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002041 return 0; /* Already have this fw. */
2042 /* Free the cached firmware first. */
Michael Buesch1a9f5092009-01-23 21:21:51 +01002043 /* FIXME: We should probably do this later after we successfully
2044 * got the new fw. This could reduce headache with multiband devices.
2045 * We could also redesign this to cache the firmware for all possible
2046 * bands all the time. */
2047 b43_do_release_fw(fw);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002048 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002049
Michael Buesch1a9f5092009-01-23 21:21:51 +01002050 switch (ctx->req_type) {
2051 case B43_FWTYPE_PROPRIETARY:
2052 snprintf(ctx->fwname, sizeof(ctx->fwname),
2053 "b43%s/%s.fw",
2054 modparam_fwpostfix, name);
2055 break;
2056 case B43_FWTYPE_OPENSOURCE:
2057 snprintf(ctx->fwname, sizeof(ctx->fwname),
2058 "b43-open%s/%s.fw",
2059 modparam_fwpostfix, name);
2060 break;
2061 default:
2062 B43_WARN_ON(1);
2063 return -ENOSYS;
2064 }
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002065 err = request_firmware(&blob, ctx->fwname, ctx->dev->sdev->dev);
Michael Buesch68217832008-05-17 23:43:57 +02002066 if (err == -ENOENT) {
Michael Buesch1a9f5092009-01-23 21:21:51 +01002067 snprintf(ctx->errors[ctx->req_type],
2068 sizeof(ctx->errors[ctx->req_type]),
2069 "Firmware file \"%s\" not found\n", ctx->fwname);
Michael Buesch68217832008-05-17 23:43:57 +02002070 return err;
2071 } else if (err) {
Michael Buesch1a9f5092009-01-23 21:21:51 +01002072 snprintf(ctx->errors[ctx->req_type],
2073 sizeof(ctx->errors[ctx->req_type]),
2074 "Firmware file \"%s\" request failed (err=%d)\n",
2075 ctx->fwname, err);
Michael Buesche4d6b792007-09-18 15:39:42 -04002076 return err;
2077 }
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002078 if (blob->size < sizeof(struct b43_fw_header))
Michael Buesche4d6b792007-09-18 15:39:42 -04002079 goto err_format;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002080 hdr = (struct b43_fw_header *)(blob->data);
Michael Buesche4d6b792007-09-18 15:39:42 -04002081 switch (hdr->type) {
2082 case B43_FW_TYPE_UCODE:
2083 case B43_FW_TYPE_PCM:
2084 size = be32_to_cpu(hdr->size);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002085 if (size != blob->size - sizeof(struct b43_fw_header))
Michael Buesche4d6b792007-09-18 15:39:42 -04002086 goto err_format;
2087 /* fallthrough */
2088 case B43_FW_TYPE_IV:
2089 if (hdr->ver != 1)
2090 goto err_format;
2091 break;
2092 default:
2093 goto err_format;
2094 }
2095
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002096 fw->data = blob;
2097 fw->filename = name;
Michael Buesch1a9f5092009-01-23 21:21:51 +01002098 fw->type = ctx->req_type;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002099
2100 return 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04002101
2102err_format:
Michael Buesch1a9f5092009-01-23 21:21:51 +01002103 snprintf(ctx->errors[ctx->req_type],
2104 sizeof(ctx->errors[ctx->req_type]),
2105 "Firmware file \"%s\" format error.\n", ctx->fwname);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002106 release_firmware(blob);
2107
Michael Buesche4d6b792007-09-18 15:39:42 -04002108 return -EPROTO;
2109}
2110
Michael Buesch1a9f5092009-01-23 21:21:51 +01002111static int b43_try_request_fw(struct b43_request_fw_context *ctx)
Michael Buesche4d6b792007-09-18 15:39:42 -04002112{
Michael Buesch1a9f5092009-01-23 21:21:51 +01002113 struct b43_wldev *dev = ctx->dev;
2114 struct b43_firmware *fw = &ctx->dev->fw;
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002115 const u8 rev = ctx->dev->sdev->id.revision;
Michael Buesche4d6b792007-09-18 15:39:42 -04002116 const char *filename;
2117 u32 tmshigh;
2118 int err;
2119
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002120 /* Get microcode */
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002121 if ((rev >= 5) && (rev <= 10))
2122 filename = "ucode5";
2123 else if ((rev >= 11) && (rev <= 12))
2124 filename = "ucode11";
Gábor Stefanik759b9732009-08-14 14:39:53 +02002125 else if (rev == 13)
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002126 filename = "ucode13";
Gábor Stefanik759b9732009-08-14 14:39:53 +02002127 else if (rev == 14)
2128 filename = "ucode14";
Rafał Miłeckie41596a2010-12-21 11:50:19 +01002129 else if (rev == 15)
Gábor Stefanik759b9732009-08-14 14:39:53 +02002130 filename = "ucode15";
Rafał Miłeckie41596a2010-12-21 11:50:19 +01002131 else if ((rev >= 16) && (rev <= 20))
2132 filename = "ucode16_mimo";
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002133 else
2134 goto err_no_ucode;
Michael Buesch1a9f5092009-01-23 21:21:51 +01002135 err = b43_do_request_fw(ctx, filename, &fw->ucode);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002136 if (err)
2137 goto err_load;
2138
2139 /* Get PCM code */
2140 if ((rev >= 5) && (rev <= 10))
2141 filename = "pcm5";
2142 else if (rev >= 11)
2143 filename = NULL;
2144 else
2145 goto err_no_pcm;
Michael Buesch68217832008-05-17 23:43:57 +02002146 fw->pcm_request_failed = 0;
Michael Buesch1a9f5092009-01-23 21:21:51 +01002147 err = b43_do_request_fw(ctx, filename, &fw->pcm);
Michael Buesch68217832008-05-17 23:43:57 +02002148 if (err == -ENOENT) {
2149 /* We did not find a PCM file? Not fatal, but
2150 * core rev <= 10 must do without hwcrypto then. */
2151 fw->pcm_request_failed = 1;
2152 } else if (err)
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002153 goto err_load;
2154
2155 /* Get initvals */
2156 switch (dev->phy.type) {
2157 case B43_PHYTYPE_A:
2158 if ((rev >= 5) && (rev <= 10)) {
Rafał Miłecki75517322011-05-17 19:19:39 +02002159 tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002160 if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
2161 filename = "a0g1initvals5";
2162 else
2163 filename = "a0g0initvals5";
2164 } else
2165 goto err_no_initvals;
2166 break;
2167 case B43_PHYTYPE_G:
Michael Buesche4d6b792007-09-18 15:39:42 -04002168 if ((rev >= 5) && (rev <= 10))
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002169 filename = "b0g0initvals5";
Michael Buesche4d6b792007-09-18 15:39:42 -04002170 else if (rev >= 13)
Larry.Finger@lwfinger.nete9304882008-05-15 14:07:36 -05002171 filename = "b0g0initvals13";
Michael Buesche4d6b792007-09-18 15:39:42 -04002172 else
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002173 goto err_no_initvals;
2174 break;
2175 case B43_PHYTYPE_N:
Rafał Miłeckie41596a2010-12-21 11:50:19 +01002176 if (rev >= 16)
2177 filename = "n0initvals16";
2178 else if ((rev >= 11) && (rev <= 12))
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002179 filename = "n0initvals11";
2180 else
2181 goto err_no_initvals;
2182 break;
Gábor Stefanik759b9732009-08-14 14:39:53 +02002183 case B43_PHYTYPE_LP:
2184 if (rev == 13)
2185 filename = "lp0initvals13";
2186 else if (rev == 14)
2187 filename = "lp0initvals14";
2188 else if (rev >= 15)
2189 filename = "lp0initvals15";
2190 else
2191 goto err_no_initvals;
2192 break;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002193 default:
2194 goto err_no_initvals;
Michael Buesche4d6b792007-09-18 15:39:42 -04002195 }
Michael Buesch1a9f5092009-01-23 21:21:51 +01002196 err = b43_do_request_fw(ctx, filename, &fw->initvals);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002197 if (err)
2198 goto err_load;
2199
2200 /* Get bandswitch initvals */
2201 switch (dev->phy.type) {
2202 case B43_PHYTYPE_A:
2203 if ((rev >= 5) && (rev <= 10)) {
Rafał Miłecki75517322011-05-17 19:19:39 +02002204 tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002205 if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
2206 filename = "a0g1bsinitvals5";
2207 else
2208 filename = "a0g0bsinitvals5";
2209 } else if (rev >= 11)
2210 filename = NULL;
2211 else
2212 goto err_no_initvals;
2213 break;
2214 case B43_PHYTYPE_G:
Michael Buesche4d6b792007-09-18 15:39:42 -04002215 if ((rev >= 5) && (rev <= 10))
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002216 filename = "b0g0bsinitvals5";
Michael Buesche4d6b792007-09-18 15:39:42 -04002217 else if (rev >= 11)
2218 filename = NULL;
2219 else
Michael Buesche4d6b792007-09-18 15:39:42 -04002220 goto err_no_initvals;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002221 break;
2222 case B43_PHYTYPE_N:
Rafał Miłeckie41596a2010-12-21 11:50:19 +01002223 if (rev >= 16)
2224 filename = "n0bsinitvals16";
2225 else if ((rev >= 11) && (rev <= 12))
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002226 filename = "n0bsinitvals11";
2227 else
Michael Buesche4d6b792007-09-18 15:39:42 -04002228 goto err_no_initvals;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002229 break;
Gábor Stefanik759b9732009-08-14 14:39:53 +02002230 case B43_PHYTYPE_LP:
2231 if (rev == 13)
2232 filename = "lp0bsinitvals13";
2233 else if (rev == 14)
2234 filename = "lp0bsinitvals14";
2235 else if (rev >= 15)
2236 filename = "lp0bsinitvals15";
2237 else
2238 goto err_no_initvals;
2239 break;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002240 default:
2241 goto err_no_initvals;
Michael Buesche4d6b792007-09-18 15:39:42 -04002242 }
Michael Buesch1a9f5092009-01-23 21:21:51 +01002243 err = b43_do_request_fw(ctx, filename, &fw->initvals_band);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002244 if (err)
2245 goto err_load;
Michael Buesche4d6b792007-09-18 15:39:42 -04002246
2247 return 0;
2248
Michael Buesche4d6b792007-09-18 15:39:42 -04002249err_no_ucode:
Michael Buesch1a9f5092009-01-23 21:21:51 +01002250 err = ctx->fatal_failure = -EOPNOTSUPP;
2251 b43err(dev->wl, "The driver does not know which firmware (ucode) "
2252 "is required for your device (wl-core rev %u)\n", rev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002253 goto error;
2254
2255err_no_pcm:
Michael Buesch1a9f5092009-01-23 21:21:51 +01002256 err = ctx->fatal_failure = -EOPNOTSUPP;
2257 b43err(dev->wl, "The driver does not know which firmware (PCM) "
2258 "is required for your device (wl-core rev %u)\n", rev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002259 goto error;
2260
2261err_no_initvals:
Michael Buesch1a9f5092009-01-23 21:21:51 +01002262 err = ctx->fatal_failure = -EOPNOTSUPP;
2263 b43err(dev->wl, "The driver does not know which firmware (initvals) "
2264 "is required for your device (wl-core rev %u)\n", rev);
2265 goto error;
2266
2267err_load:
2268 /* We failed to load this firmware image. The error message
2269 * already is in ctx->errors. Return and let our caller decide
2270 * what to do. */
Michael Buesche4d6b792007-09-18 15:39:42 -04002271 goto error;
2272
2273error:
2274 b43_release_firmware(dev);
2275 return err;
2276}
2277
Michael Buesch1a9f5092009-01-23 21:21:51 +01002278static int b43_request_firmware(struct b43_wldev *dev)
2279{
2280 struct b43_request_fw_context *ctx;
2281 unsigned int i;
2282 int err;
2283 const char *errmsg;
2284
2285 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
2286 if (!ctx)
2287 return -ENOMEM;
2288 ctx->dev = dev;
2289
2290 ctx->req_type = B43_FWTYPE_PROPRIETARY;
2291 err = b43_try_request_fw(ctx);
2292 if (!err)
2293 goto out; /* Successfully loaded it. */
2294 err = ctx->fatal_failure;
2295 if (err)
2296 goto out;
2297
2298 ctx->req_type = B43_FWTYPE_OPENSOURCE;
2299 err = b43_try_request_fw(ctx);
2300 if (!err)
2301 goto out; /* Successfully loaded it. */
2302 err = ctx->fatal_failure;
2303 if (err)
2304 goto out;
2305
2306 /* Could not find a usable firmware. Print the errors. */
2307 for (i = 0; i < B43_NR_FWTYPES; i++) {
2308 errmsg = ctx->errors[i];
2309 if (strlen(errmsg))
2310 b43err(dev->wl, errmsg);
2311 }
2312 b43_print_fw_helptext(dev->wl, 1);
2313 err = -ENOENT;
2314
2315out:
2316 kfree(ctx);
2317 return err;
2318}
2319
Michael Buesche4d6b792007-09-18 15:39:42 -04002320static int b43_upload_microcode(struct b43_wldev *dev)
2321{
John W. Linville652caa52010-07-29 13:27:28 -04002322 struct wiphy *wiphy = dev->wl->hw->wiphy;
Michael Buesche4d6b792007-09-18 15:39:42 -04002323 const size_t hdr_len = sizeof(struct b43_fw_header);
2324 const __be32 *data;
2325 unsigned int i, len;
2326 u16 fwrev, fwpatch, fwdate, fwtime;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002327 u32 tmp, macctl;
Michael Buesche4d6b792007-09-18 15:39:42 -04002328 int err = 0;
2329
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002330 /* Jump the microcode PSM to offset 0 */
2331 macctl = b43_read32(dev, B43_MMIO_MACCTL);
2332 B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN);
2333 macctl |= B43_MACCTL_PSM_JMP0;
2334 b43_write32(dev, B43_MMIO_MACCTL, macctl);
2335 /* Zero out all microcode PSM registers and shared memory. */
2336 for (i = 0; i < 64; i++)
2337 b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0);
2338 for (i = 0; i < 4096; i += 2)
2339 b43_shm_write16(dev, B43_SHM_SHARED, i, 0);
2340
Michael Buesche4d6b792007-09-18 15:39:42 -04002341 /* Upload Microcode. */
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002342 data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
2343 len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
Michael Buesche4d6b792007-09-18 15:39:42 -04002344 b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
2345 for (i = 0; i < len; i++) {
2346 b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
2347 udelay(10);
2348 }
2349
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002350 if (dev->fw.pcm.data) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002351 /* Upload PCM data. */
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002352 data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
2353 len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
Michael Buesche4d6b792007-09-18 15:39:42 -04002354 b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
2355 b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
2356 /* No need for autoinc bit in SHM_HW */
2357 b43_shm_control_word(dev, B43_SHM_HW, 0x01EB);
2358 for (i = 0; i < len; i++) {
2359 b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
2360 udelay(10);
2361 }
2362 }
2363
2364 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002365
2366 /* Start the microcode PSM */
2367 macctl = b43_read32(dev, B43_MMIO_MACCTL);
2368 macctl &= ~B43_MACCTL_PSM_JMP0;
2369 macctl |= B43_MACCTL_PSM_RUN;
2370 b43_write32(dev, B43_MMIO_MACCTL, macctl);
Michael Buesche4d6b792007-09-18 15:39:42 -04002371
2372 /* Wait for the microcode to load and respond */
2373 i = 0;
2374 while (1) {
2375 tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2376 if (tmp == B43_IRQ_MAC_SUSPENDED)
2377 break;
2378 i++;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002379 if (i >= 20) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002380 b43err(dev->wl, "Microcode not responding\n");
Michael Buescheb189d8b2008-01-28 14:47:41 -08002381 b43_print_fw_helptext(dev->wl, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002382 err = -ENODEV;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002383 goto error;
Michael Buesche4d6b792007-09-18 15:39:42 -04002384 }
Michael Buesche175e992009-09-11 18:31:32 +02002385 msleep(50);
Michael Buesche4d6b792007-09-18 15:39:42 -04002386 }
2387 b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */
2388
2389 /* Get and check the revisions. */
2390 fwrev = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEREV);
2391 fwpatch = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEPATCH);
2392 fwdate = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEDATE);
2393 fwtime = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODETIME);
2394
2395 if (fwrev <= 0x128) {
2396 b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
2397 "binary drivers older than version 4.x is unsupported. "
2398 "You must upgrade your firmware files.\n");
Michael Buescheb189d8b2008-01-28 14:47:41 -08002399 b43_print_fw_helptext(dev->wl, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002400 err = -EOPNOTSUPP;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002401 goto error;
Michael Buesche4d6b792007-09-18 15:39:42 -04002402 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002403 dev->fw.rev = fwrev;
2404 dev->fw.patch = fwpatch;
Michael Buesche48b0ee2008-05-17 22:44:35 +02002405 dev->fw.opensource = (fwdate == 0xFFFF);
2406
Michael Buesch403a3a12009-06-08 21:04:57 +02002407 /* Default to use-all-queues. */
2408 dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues;
2409 dev->qos_enabled = !!modparam_qos;
2410 /* Default to firmware/hardware crypto acceleration. */
2411 dev->hwcrypto_enabled = 1;
2412
Michael Buesche48b0ee2008-05-17 22:44:35 +02002413 if (dev->fw.opensource) {
Michael Buesch403a3a12009-06-08 21:04:57 +02002414 u16 fwcapa;
2415
Michael Buesche48b0ee2008-05-17 22:44:35 +02002416 /* Patchlevel info is encoded in the "time" field. */
2417 dev->fw.patch = fwtime;
Michael Buesch403a3a12009-06-08 21:04:57 +02002418 b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n",
2419 dev->fw.rev, dev->fw.patch);
2420
2421 fwcapa = b43_fwcapa_read(dev);
2422 if (!(fwcapa & B43_FWCAPA_HWCRYPTO) || dev->fw.pcm_request_failed) {
2423 b43info(dev->wl, "Hardware crypto acceleration not supported by firmware\n");
2424 /* Disable hardware crypto and fall back to software crypto. */
2425 dev->hwcrypto_enabled = 0;
2426 }
2427 if (!(fwcapa & B43_FWCAPA_QOS)) {
2428 b43info(dev->wl, "QoS not supported by firmware\n");
2429 /* Disable QoS. Tweak hw->queues to 1. It will be restored before
2430 * ieee80211_unregister to make sure the networking core can
2431 * properly free possible resources. */
2432 dev->wl->hw->queues = 1;
2433 dev->qos_enabled = 0;
2434 }
Michael Buesche48b0ee2008-05-17 22:44:35 +02002435 } else {
2436 b43info(dev->wl, "Loading firmware version %u.%u "
2437 "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
2438 fwrev, fwpatch,
2439 (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
2440 (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
Michael Buesch68217832008-05-17 23:43:57 +02002441 if (dev->fw.pcm_request_failed) {
2442 b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. "
2443 "Hardware accelerated cryptography is disabled.\n");
2444 b43_print_fw_helptext(dev->wl, 0);
2445 }
Michael Buesche48b0ee2008-05-17 22:44:35 +02002446 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002447
John W. Linville652caa52010-07-29 13:27:28 -04002448 snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
2449 dev->fw.rev, dev->fw.patch);
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002450 wiphy->hw_version = dev->sdev->id.coreid;
John W. Linville652caa52010-07-29 13:27:28 -04002451
Michael Buescheb189d8b2008-01-28 14:47:41 -08002452 if (b43_is_old_txhdr_format(dev)) {
Michael Bueschc5572892008-12-27 18:26:39 +01002453 /* We're over the deadline, but we keep support for old fw
2454 * until it turns out to be in major conflict with something new. */
Michael Buescheb189d8b2008-01-28 14:47:41 -08002455 b43warn(dev->wl, "You are using an old firmware image. "
Michael Bueschc5572892008-12-27 18:26:39 +01002456 "Support for old firmware will be removed soon "
2457 "(official deadline was July 2008).\n");
Michael Buescheb189d8b2008-01-28 14:47:41 -08002458 b43_print_fw_helptext(dev->wl, 0);
2459 }
2460
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002461 return 0;
2462
2463error:
2464 macctl = b43_read32(dev, B43_MMIO_MACCTL);
2465 macctl &= ~B43_MACCTL_PSM_RUN;
2466 macctl |= B43_MACCTL_PSM_JMP0;
2467 b43_write32(dev, B43_MMIO_MACCTL, macctl);
2468
Michael Buesche4d6b792007-09-18 15:39:42 -04002469 return err;
2470}
2471
2472static int b43_write_initvals(struct b43_wldev *dev,
2473 const struct b43_iv *ivals,
2474 size_t count,
2475 size_t array_size)
2476{
2477 const struct b43_iv *iv;
2478 u16 offset;
2479 size_t i;
2480 bool bit32;
2481
2482 BUILD_BUG_ON(sizeof(struct b43_iv) != 6);
2483 iv = ivals;
2484 for (i = 0; i < count; i++) {
2485 if (array_size < sizeof(iv->offset_size))
2486 goto err_format;
2487 array_size -= sizeof(iv->offset_size);
2488 offset = be16_to_cpu(iv->offset_size);
2489 bit32 = !!(offset & B43_IV_32BIT);
2490 offset &= B43_IV_OFFSET_MASK;
2491 if (offset >= 0x1000)
2492 goto err_format;
2493 if (bit32) {
2494 u32 value;
2495
2496 if (array_size < sizeof(iv->data.d32))
2497 goto err_format;
2498 array_size -= sizeof(iv->data.d32);
2499
Harvey Harrison533dd1b2008-04-29 01:03:36 -07002500 value = get_unaligned_be32(&iv->data.d32);
Michael Buesche4d6b792007-09-18 15:39:42 -04002501 b43_write32(dev, offset, value);
2502
2503 iv = (const struct b43_iv *)((const uint8_t *)iv +
2504 sizeof(__be16) +
2505 sizeof(__be32));
2506 } else {
2507 u16 value;
2508
2509 if (array_size < sizeof(iv->data.d16))
2510 goto err_format;
2511 array_size -= sizeof(iv->data.d16);
2512
2513 value = be16_to_cpu(iv->data.d16);
2514 b43_write16(dev, offset, value);
2515
2516 iv = (const struct b43_iv *)((const uint8_t *)iv +
2517 sizeof(__be16) +
2518 sizeof(__be16));
2519 }
2520 }
2521 if (array_size)
2522 goto err_format;
2523
2524 return 0;
2525
2526err_format:
2527 b43err(dev->wl, "Initial Values Firmware file-format error.\n");
Michael Buescheb189d8b2008-01-28 14:47:41 -08002528 b43_print_fw_helptext(dev->wl, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002529
2530 return -EPROTO;
2531}
2532
2533static int b43_upload_initvals(struct b43_wldev *dev)
2534{
2535 const size_t hdr_len = sizeof(struct b43_fw_header);
2536 const struct b43_fw_header *hdr;
2537 struct b43_firmware *fw = &dev->fw;
2538 const struct b43_iv *ivals;
2539 size_t count;
2540 int err;
2541
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002542 hdr = (const struct b43_fw_header *)(fw->initvals.data->data);
2543 ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002544 count = be32_to_cpu(hdr->size);
2545 err = b43_write_initvals(dev, ivals, count,
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002546 fw->initvals.data->size - hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002547 if (err)
2548 goto out;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002549 if (fw->initvals_band.data) {
2550 hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data);
2551 ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002552 count = be32_to_cpu(hdr->size);
2553 err = b43_write_initvals(dev, ivals, count,
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002554 fw->initvals_band.data->size - hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002555 if (err)
2556 goto out;
2557 }
2558out:
2559
2560 return err;
2561}
2562
2563/* Initialize the GPIOs
2564 * http://bcm-specs.sipsolutions.net/GPIO
2565 */
Rafał Miłeckic4a2a082011-05-17 18:57:27 +02002566static struct ssb_device *b43_ssb_gpio_dev(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04002567{
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002568 struct ssb_bus *bus = dev->sdev->bus;
Rafał Miłeckic4a2a082011-05-17 18:57:27 +02002569
2570#ifdef CONFIG_SSB_DRIVER_PCICORE
2571 return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
2572#else
2573 return bus->chipco.dev;
2574#endif
2575}
2576
2577static int b43_gpio_init(struct b43_wldev *dev)
2578{
2579 struct ssb_device *gpiodev;
Michael Buesche4d6b792007-09-18 15:39:42 -04002580 u32 mask, set;
2581
2582 b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
2583 & ~B43_MACCTL_GPOUTSMSK);
2584
Michael Buesche4d6b792007-09-18 15:39:42 -04002585 b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK)
2586 | 0x000F);
2587
2588 mask = 0x0000001F;
2589 set = 0x0000000F;
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002590 if (dev->sdev->bus->chip_id == 0x4301) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002591 mask |= 0x0060;
2592 set |= 0x0060;
2593 }
2594 if (0 /* FIXME: conditional unknown */ ) {
2595 b43_write16(dev, B43_MMIO_GPIO_MASK,
2596 b43_read16(dev, B43_MMIO_GPIO_MASK)
2597 | 0x0100);
2598 mask |= 0x0180;
2599 set |= 0x0180;
2600 }
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002601 if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002602 b43_write16(dev, B43_MMIO_GPIO_MASK,
2603 b43_read16(dev, B43_MMIO_GPIO_MASK)
2604 | 0x0200);
2605 mask |= 0x0200;
2606 set |= 0x0200;
2607 }
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002608 if (dev->sdev->id.revision >= 2)
Michael Buesche4d6b792007-09-18 15:39:42 -04002609 mask |= 0x0010; /* FIXME: This is redundant. */
2610
Rafał Miłeckic4a2a082011-05-17 18:57:27 +02002611 gpiodev = b43_ssb_gpio_dev(dev);
2612 if (gpiodev)
2613 ssb_write32(gpiodev, B43_GPIO_CONTROL,
2614 (ssb_read32(gpiodev, B43_GPIO_CONTROL)
2615 & mask) | set);
Michael Buesche4d6b792007-09-18 15:39:42 -04002616
2617 return 0;
2618}
2619
2620/* Turn off all GPIO stuff. Call this on module unload, for example. */
2621static void b43_gpio_cleanup(struct b43_wldev *dev)
2622{
Rafał Miłeckic4a2a082011-05-17 18:57:27 +02002623 struct ssb_device *gpiodev;
Michael Buesche4d6b792007-09-18 15:39:42 -04002624
Rafał Miłeckic4a2a082011-05-17 18:57:27 +02002625 gpiodev = b43_ssb_gpio_dev(dev);
2626 if (gpiodev)
2627 ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
Michael Buesche4d6b792007-09-18 15:39:42 -04002628}
2629
2630/* http://bcm-specs.sipsolutions.net/EnableMac */
Michael Bueschf5eda472008-04-20 16:03:32 +02002631void b43_mac_enable(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04002632{
Michael Buesch923fd702008-06-20 18:02:08 +02002633 if (b43_debug(dev, B43_DBG_FIRMWARE)) {
2634 u16 fwstate;
2635
2636 fwstate = b43_shm_read16(dev, B43_SHM_SHARED,
2637 B43_SHM_SH_UCODESTAT);
2638 if ((fwstate != B43_SHM_SH_UCODESTAT_SUSP) &&
2639 (fwstate != B43_SHM_SH_UCODESTAT_SLEEP)) {
2640 b43err(dev->wl, "b43_mac_enable(): The firmware "
2641 "should be suspended, but current state is %u\n",
2642 fwstate);
2643 }
2644 }
2645
Michael Buesche4d6b792007-09-18 15:39:42 -04002646 dev->mac_suspended--;
2647 B43_WARN_ON(dev->mac_suspended < 0);
2648 if (dev->mac_suspended == 0) {
2649 b43_write32(dev, B43_MMIO_MACCTL,
2650 b43_read32(dev, B43_MMIO_MACCTL)
2651 | B43_MACCTL_ENABLED);
2652 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON,
2653 B43_IRQ_MAC_SUSPENDED);
2654 /* Commit writes */
2655 b43_read32(dev, B43_MMIO_MACCTL);
2656 b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2657 b43_power_saving_ctl_bits(dev, 0);
2658 }
2659}
2660
2661/* http://bcm-specs.sipsolutions.net/SuspendMAC */
Michael Bueschf5eda472008-04-20 16:03:32 +02002662void b43_mac_suspend(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04002663{
2664 int i;
2665 u32 tmp;
2666
Michael Buesch05b64b32007-09-28 16:19:03 +02002667 might_sleep();
Michael Buesche4d6b792007-09-18 15:39:42 -04002668 B43_WARN_ON(dev->mac_suspended < 0);
Michael Buesch05b64b32007-09-28 16:19:03 +02002669
Michael Buesche4d6b792007-09-18 15:39:42 -04002670 if (dev->mac_suspended == 0) {
2671 b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
2672 b43_write32(dev, B43_MMIO_MACCTL,
2673 b43_read32(dev, B43_MMIO_MACCTL)
2674 & ~B43_MACCTL_ENABLED);
2675 /* force pci to flush the write */
2676 b43_read32(dev, B43_MMIO_MACCTL);
Michael Bueschba380012008-04-15 21:13:36 +02002677 for (i = 35; i; i--) {
2678 tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2679 if (tmp & B43_IRQ_MAC_SUSPENDED)
2680 goto out;
2681 udelay(10);
2682 }
2683 /* Hm, it seems this will take some time. Use msleep(). */
Michael Buesch05b64b32007-09-28 16:19:03 +02002684 for (i = 40; i; i--) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002685 tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2686 if (tmp & B43_IRQ_MAC_SUSPENDED)
2687 goto out;
Michael Buesch05b64b32007-09-28 16:19:03 +02002688 msleep(1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002689 }
2690 b43err(dev->wl, "MAC suspend failed\n");
2691 }
Michael Buesch05b64b32007-09-28 16:19:03 +02002692out:
Michael Buesche4d6b792007-09-18 15:39:42 -04002693 dev->mac_suspended++;
2694}
2695
Rafał Miłecki858a1652011-05-10 16:05:33 +02002696/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
2697void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on)
2698{
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002699 u32 tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
Rafał Miłecki858a1652011-05-10 16:05:33 +02002700 if (on)
2701 tmslow |= B43_TMSLOW_MACPHYCLKEN;
2702 else
2703 tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002704 ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
Rafał Miłecki858a1652011-05-10 16:05:33 +02002705}
2706
Michael Buesche4d6b792007-09-18 15:39:42 -04002707static void b43_adjust_opmode(struct b43_wldev *dev)
2708{
2709 struct b43_wl *wl = dev->wl;
2710 u32 ctl;
2711 u16 cfp_pretbtt;
2712
2713 ctl = b43_read32(dev, B43_MMIO_MACCTL);
2714 /* Reset status to STA infrastructure mode. */
2715 ctl &= ~B43_MACCTL_AP;
2716 ctl &= ~B43_MACCTL_KEEP_CTL;
2717 ctl &= ~B43_MACCTL_KEEP_BADPLCP;
2718 ctl &= ~B43_MACCTL_KEEP_BAD;
2719 ctl &= ~B43_MACCTL_PROMISC;
Johannes Berg4150c572007-09-17 01:29:23 -04002720 ctl &= ~B43_MACCTL_BEACPROMISC;
Michael Buesche4d6b792007-09-18 15:39:42 -04002721 ctl |= B43_MACCTL_INFRA;
2722
Johannes Berg05c914f2008-09-11 00:01:58 +02002723 if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
2724 b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
Johannes Berg4150c572007-09-17 01:29:23 -04002725 ctl |= B43_MACCTL_AP;
Johannes Berg05c914f2008-09-11 00:01:58 +02002726 else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC))
Johannes Berg4150c572007-09-17 01:29:23 -04002727 ctl &= ~B43_MACCTL_INFRA;
2728
2729 if (wl->filter_flags & FIF_CONTROL)
Michael Buesche4d6b792007-09-18 15:39:42 -04002730 ctl |= B43_MACCTL_KEEP_CTL;
Johannes Berg4150c572007-09-17 01:29:23 -04002731 if (wl->filter_flags & FIF_FCSFAIL)
2732 ctl |= B43_MACCTL_KEEP_BAD;
2733 if (wl->filter_flags & FIF_PLCPFAIL)
2734 ctl |= B43_MACCTL_KEEP_BADPLCP;
2735 if (wl->filter_flags & FIF_PROMISC_IN_BSS)
Michael Buesche4d6b792007-09-18 15:39:42 -04002736 ctl |= B43_MACCTL_PROMISC;
Johannes Berg4150c572007-09-17 01:29:23 -04002737 if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
2738 ctl |= B43_MACCTL_BEACPROMISC;
2739
Michael Buesche4d6b792007-09-18 15:39:42 -04002740 /* Workaround: On old hardware the HW-MAC-address-filter
2741 * doesn't work properly, so always run promisc in filter
2742 * it in software. */
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002743 if (dev->sdev->id.revision <= 4)
Michael Buesche4d6b792007-09-18 15:39:42 -04002744 ctl |= B43_MACCTL_PROMISC;
2745
2746 b43_write32(dev, B43_MMIO_MACCTL, ctl);
2747
2748 cfp_pretbtt = 2;
2749 if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002750 if (dev->sdev->bus->chip_id == 0x4306 &&
2751 dev->sdev->bus->chip_rev == 3)
Michael Buesche4d6b792007-09-18 15:39:42 -04002752 cfp_pretbtt = 100;
2753 else
2754 cfp_pretbtt = 50;
2755 }
2756 b43_write16(dev, 0x612, cfp_pretbtt);
Michael Buesch09ebe2f2009-09-12 00:52:48 +02002757
2758 /* FIXME: We don't currently implement the PMQ mechanism,
2759 * so always disable it. If we want to implement PMQ,
2760 * we need to enable it here (clear DISCPMQ) in AP mode.
2761 */
2762 if (0 /* ctl & B43_MACCTL_AP */) {
2763 b43_write32(dev, B43_MMIO_MACCTL,
2764 b43_read32(dev, B43_MMIO_MACCTL)
2765 & ~B43_MACCTL_DISCPMQ);
2766 } else {
2767 b43_write32(dev, B43_MMIO_MACCTL,
2768 b43_read32(dev, B43_MMIO_MACCTL)
2769 | B43_MACCTL_DISCPMQ);
2770 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002771}
2772
2773static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm)
2774{
2775 u16 offset;
2776
2777 if (is_ofdm) {
2778 offset = 0x480;
2779 offset += (b43_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
2780 } else {
2781 offset = 0x4C0;
2782 offset += (b43_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
2783 }
2784 b43_shm_write16(dev, B43_SHM_SHARED, offset + 0x20,
2785 b43_shm_read16(dev, B43_SHM_SHARED, offset));
2786}
2787
2788static void b43_rate_memory_init(struct b43_wldev *dev)
2789{
2790 switch (dev->phy.type) {
2791 case B43_PHYTYPE_A:
2792 case B43_PHYTYPE_G:
Michael Buesch53a6e232008-01-13 21:23:44 +01002793 case B43_PHYTYPE_N:
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02002794 case B43_PHYTYPE_LP:
Michael Buesche4d6b792007-09-18 15:39:42 -04002795 b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
2796 b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
2797 b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
2798 b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1);
2799 b43_rate_memory_write(dev, B43_OFDM_RATE_36MB, 1);
2800 b43_rate_memory_write(dev, B43_OFDM_RATE_48MB, 1);
2801 b43_rate_memory_write(dev, B43_OFDM_RATE_54MB, 1);
2802 if (dev->phy.type == B43_PHYTYPE_A)
2803 break;
2804 /* fallthrough */
2805 case B43_PHYTYPE_B:
2806 b43_rate_memory_write(dev, B43_CCK_RATE_1MB, 0);
2807 b43_rate_memory_write(dev, B43_CCK_RATE_2MB, 0);
2808 b43_rate_memory_write(dev, B43_CCK_RATE_5MB, 0);
2809 b43_rate_memory_write(dev, B43_CCK_RATE_11MB, 0);
2810 break;
2811 default:
2812 B43_WARN_ON(1);
2813 }
2814}
2815
Michael Buesch5042c502008-04-05 15:05:00 +02002816/* Set the default values for the PHY TX Control Words. */
2817static void b43_set_phytxctl_defaults(struct b43_wldev *dev)
2818{
2819 u16 ctl = 0;
2820
2821 ctl |= B43_TXH_PHY_ENC_CCK;
2822 ctl |= B43_TXH_PHY_ANT01AUTO;
2823 ctl |= B43_TXH_PHY_TXPWR;
2824
2825 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);
2826 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, ctl);
2827 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, ctl);
2828}
2829
Michael Buesche4d6b792007-09-18 15:39:42 -04002830/* Set the TX-Antenna for management frames sent by firmware. */
2831static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
2832{
Michael Buesch5042c502008-04-05 15:05:00 +02002833 u16 ant;
Michael Buesche4d6b792007-09-18 15:39:42 -04002834 u16 tmp;
2835
Michael Buesch5042c502008-04-05 15:05:00 +02002836 ant = b43_antenna_to_phyctl(antenna);
Michael Buesche4d6b792007-09-18 15:39:42 -04002837
Michael Buesche4d6b792007-09-18 15:39:42 -04002838 /* For ACK/CTS */
2839 tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
Michael Buescheb189d8b2008-01-28 14:47:41 -08002840 tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
Michael Buesche4d6b792007-09-18 15:39:42 -04002841 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
2842 /* For Probe Resposes */
2843 tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
Michael Buescheb189d8b2008-01-28 14:47:41 -08002844 tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
Michael Buesche4d6b792007-09-18 15:39:42 -04002845 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
2846}
2847
2848/* This is the opposite of b43_chip_init() */
2849static void b43_chip_exit(struct b43_wldev *dev)
2850{
Michael Bueschfb111372008-09-02 13:00:34 +02002851 b43_phy_exit(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002852 b43_gpio_cleanup(dev);
2853 /* firmware is released later */
2854}
2855
2856/* Initialize the chip
2857 * http://bcm-specs.sipsolutions.net/ChipInit
2858 */
2859static int b43_chip_init(struct b43_wldev *dev)
2860{
2861 struct b43_phy *phy = &dev->phy;
Michael Bueschef1a6282008-08-27 18:53:02 +02002862 int err;
Rafał Miłecki858a1652011-05-10 16:05:33 +02002863 u32 macctl;
Michael Buesche4d6b792007-09-18 15:39:42 -04002864 u16 value16;
2865
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002866 /* Initialize the MAC control */
2867 macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED;
2868 if (dev->phy.gmode)
2869 macctl |= B43_MACCTL_GMODE;
2870 macctl |= B43_MACCTL_INFRA;
2871 b43_write32(dev, B43_MMIO_MACCTL, macctl);
Michael Buesche4d6b792007-09-18 15:39:42 -04002872
2873 err = b43_request_firmware(dev);
2874 if (err)
2875 goto out;
2876 err = b43_upload_microcode(dev);
2877 if (err)
2878 goto out; /* firmware is released later */
2879
2880 err = b43_gpio_init(dev);
2881 if (err)
2882 goto out; /* firmware is released later */
Michael Buesch21954c32007-09-27 15:31:40 +02002883
Michael Buesche4d6b792007-09-18 15:39:42 -04002884 err = b43_upload_initvals(dev);
2885 if (err)
Larry Finger1a8d1222007-12-14 13:59:11 +01002886 goto err_gpio_clean;
Michael Buesche4d6b792007-09-18 15:39:42 -04002887
Michael Buesch0b7dcd92008-09-03 12:31:54 +02002888 /* Turn the Analog on and initialize the PHY. */
2889 phy->ops->switch_analog(dev, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002890 err = b43_phy_init(dev);
2891 if (err)
Michael Bueschef1a6282008-08-27 18:53:02 +02002892 goto err_gpio_clean;
Michael Buesche4d6b792007-09-18 15:39:42 -04002893
Michael Bueschef1a6282008-08-27 18:53:02 +02002894 /* Disable Interference Mitigation. */
2895 if (phy->ops->interf_mitigation)
2896 phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
Michael Buesche4d6b792007-09-18 15:39:42 -04002897
Michael Bueschef1a6282008-08-27 18:53:02 +02002898 /* Select the antennae */
2899 if (phy->ops->set_rx_antenna)
2900 phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
Michael Buesche4d6b792007-09-18 15:39:42 -04002901 b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
2902
2903 if (phy->type == B43_PHYTYPE_B) {
2904 value16 = b43_read16(dev, 0x005E);
2905 value16 |= 0x0004;
2906 b43_write16(dev, 0x005E, value16);
2907 }
2908 b43_write32(dev, 0x0100, 0x01000000);
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002909 if (dev->sdev->id.revision < 5)
Michael Buesche4d6b792007-09-18 15:39:42 -04002910 b43_write32(dev, 0x010C, 0x01000000);
2911
2912 b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
2913 & ~B43_MACCTL_INFRA);
2914 b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
2915 | B43_MACCTL_INFRA);
Michael Buesche4d6b792007-09-18 15:39:42 -04002916
Michael Buesche4d6b792007-09-18 15:39:42 -04002917 /* Probe Response Timeout value */
2918 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2919 b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
2920
2921 /* Initially set the wireless operation mode. */
2922 b43_adjust_opmode(dev);
2923
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002924 if (dev->sdev->id.revision < 3) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002925 b43_write16(dev, 0x060E, 0x0000);
2926 b43_write16(dev, 0x0610, 0x8000);
2927 b43_write16(dev, 0x0604, 0x0000);
2928 b43_write16(dev, 0x0606, 0x0200);
2929 } else {
2930 b43_write32(dev, 0x0188, 0x80000000);
2931 b43_write32(dev, 0x018C, 0x02000000);
2932 }
2933 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, 0x00004000);
2934 b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
2935 b43_write32(dev, B43_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
2936 b43_write32(dev, B43_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2937 b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
2938 b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
2939 b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
2940
Rafał Miłecki858a1652011-05-10 16:05:33 +02002941 b43_mac_phy_clock_set(dev, true);
Michael Buesche4d6b792007-09-18 15:39:42 -04002942
2943 b43_write16(dev, B43_MMIO_POWERUP_DELAY,
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02002944 dev->sdev->bus->chipco.fast_pwrup_delay);
Michael Buesche4d6b792007-09-18 15:39:42 -04002945
2946 err = 0;
2947 b43dbg(dev->wl, "Chip initialized\n");
Michael Buesch21954c32007-09-27 15:31:40 +02002948out:
Michael Buesche4d6b792007-09-18 15:39:42 -04002949 return err;
2950
Larry Finger1a8d1222007-12-14 13:59:11 +01002951err_gpio_clean:
Michael Buesche4d6b792007-09-18 15:39:42 -04002952 b43_gpio_cleanup(dev);
Michael Buesch21954c32007-09-27 15:31:40 +02002953 return err;
Michael Buesche4d6b792007-09-18 15:39:42 -04002954}
2955
Michael Buesche4d6b792007-09-18 15:39:42 -04002956static void b43_periodic_every60sec(struct b43_wldev *dev)
2957{
Michael Bueschef1a6282008-08-27 18:53:02 +02002958 const struct b43_phy_operations *ops = dev->phy.ops;
Michael Buesche4d6b792007-09-18 15:39:42 -04002959
Michael Bueschef1a6282008-08-27 18:53:02 +02002960 if (ops->pwork_60sec)
2961 ops->pwork_60sec(dev);
Michael Buesch18c8ade2008-08-28 19:33:40 +02002962
2963 /* Force check the TX power emission now. */
2964 b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME);
Michael Buesche4d6b792007-09-18 15:39:42 -04002965}
2966
2967static void b43_periodic_every30sec(struct b43_wldev *dev)
2968{
2969 /* Update device statistics. */
2970 b43_calculate_link_quality(dev);
2971}
2972
2973static void b43_periodic_every15sec(struct b43_wldev *dev)
2974{
2975 struct b43_phy *phy = &dev->phy;
Michael Buesch9b839a72008-06-20 17:44:02 +02002976 u16 wdr;
2977
2978 if (dev->fw.opensource) {
2979 /* Check if the firmware is still alive.
2980 * It will reset the watchdog counter to 0 in its idle loop. */
2981 wdr = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_WATCHDOG_REG);
2982 if (unlikely(wdr)) {
2983 b43err(dev->wl, "Firmware watchdog: The firmware died!\n");
2984 b43_controller_restart(dev, "Firmware watchdog");
2985 return;
2986 } else {
2987 b43_shm_write16(dev, B43_SHM_SCRATCH,
2988 B43_WATCHDOG_REG, 1);
2989 }
2990 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002991
Michael Bueschef1a6282008-08-27 18:53:02 +02002992 if (phy->ops->pwork_15sec)
2993 phy->ops->pwork_15sec(dev);
2994
Stefano Brivio00e0b8c2007-11-25 11:10:33 +01002995 atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
2996 wmb();
Michael Buesch990b86f2009-09-12 00:48:03 +02002997
2998#if B43_DEBUG
2999 if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
3000 unsigned int i;
3001
3002 b43dbg(dev->wl, "Stats: %7u IRQs/sec, %7u TX/sec, %7u RX/sec\n",
3003 dev->irq_count / 15,
3004 dev->tx_count / 15,
3005 dev->rx_count / 15);
3006 dev->irq_count = 0;
3007 dev->tx_count = 0;
3008 dev->rx_count = 0;
3009 for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
3010 if (dev->irq_bit_count[i]) {
3011 b43dbg(dev->wl, "Stats: %7u IRQ-%02u/sec (0x%08X)\n",
3012 dev->irq_bit_count[i] / 15, i, (1 << i));
3013 dev->irq_bit_count[i] = 0;
3014 }
3015 }
3016 }
3017#endif
Michael Buesche4d6b792007-09-18 15:39:42 -04003018}
3019
Michael Buesche4d6b792007-09-18 15:39:42 -04003020static void do_periodic_work(struct b43_wldev *dev)
3021{
3022 unsigned int state;
3023
3024 state = dev->periodic_state;
Michael Buesch42bb4cd2007-09-28 14:22:33 +02003025 if (state % 4 == 0)
Michael Buesche4d6b792007-09-18 15:39:42 -04003026 b43_periodic_every60sec(dev);
Michael Buesch42bb4cd2007-09-28 14:22:33 +02003027 if (state % 2 == 0)
Michael Buesche4d6b792007-09-18 15:39:42 -04003028 b43_periodic_every30sec(dev);
Michael Buesch42bb4cd2007-09-28 14:22:33 +02003029 b43_periodic_every15sec(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003030}
3031
Michael Buesch05b64b32007-09-28 16:19:03 +02003032/* Periodic work locking policy:
3033 * The whole periodic work handler is protected by
3034 * wl->mutex. If another lock is needed somewhere in the
Uwe Kleine-König21ae2952009-10-07 15:21:09 +02003035 * pwork callchain, it's acquired in-place, where it's needed.
Michael Buesche4d6b792007-09-18 15:39:42 -04003036 */
Michael Buesche4d6b792007-09-18 15:39:42 -04003037static void b43_periodic_work_handler(struct work_struct *work)
3038{
Michael Buesch05b64b32007-09-28 16:19:03 +02003039 struct b43_wldev *dev = container_of(work, struct b43_wldev,
3040 periodic_work.work);
3041 struct b43_wl *wl = dev->wl;
3042 unsigned long delay;
Michael Buesche4d6b792007-09-18 15:39:42 -04003043
Michael Buesch05b64b32007-09-28 16:19:03 +02003044 mutex_lock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003045
3046 if (unlikely(b43_status(dev) != B43_STAT_STARTED))
3047 goto out;
3048 if (b43_debug(dev, B43_DBG_PWORK_STOP))
3049 goto out_requeue;
3050
Michael Buesch05b64b32007-09-28 16:19:03 +02003051 do_periodic_work(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003052
Michael Buesche4d6b792007-09-18 15:39:42 -04003053 dev->periodic_state++;
Michael Buesch42bb4cd2007-09-28 14:22:33 +02003054out_requeue:
Michael Buesche4d6b792007-09-18 15:39:42 -04003055 if (b43_debug(dev, B43_DBG_PWORK_FAST))
3056 delay = msecs_to_jiffies(50);
3057 else
Anton Blanchard82cd6822007-10-15 00:42:23 -05003058 delay = round_jiffies_relative(HZ * 15);
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04003059 ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay);
Michael Buesch42bb4cd2007-09-28 14:22:33 +02003060out:
Michael Buesch05b64b32007-09-28 16:19:03 +02003061 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003062}
3063
3064static void b43_periodic_tasks_setup(struct b43_wldev *dev)
3065{
3066 struct delayed_work *work = &dev->periodic_work;
3067
3068 dev->periodic_state = 0;
3069 INIT_DELAYED_WORK(work, b43_periodic_work_handler);
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04003070 ieee80211_queue_delayed_work(dev->wl->hw, work, 0);
Michael Buesche4d6b792007-09-18 15:39:42 -04003071}
3072
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01003073/* Check if communication with the device works correctly. */
Michael Buesche4d6b792007-09-18 15:39:42 -04003074static int b43_validate_chipaccess(struct b43_wldev *dev)
3075{
Michael Bueschf62ae6c2009-07-31 20:51:41 +02003076 u32 v, backup0, backup4;
Michael Buesche4d6b792007-09-18 15:39:42 -04003077
Michael Bueschf62ae6c2009-07-31 20:51:41 +02003078 backup0 = b43_shm_read32(dev, B43_SHM_SHARED, 0);
3079 backup4 = b43_shm_read32(dev, B43_SHM_SHARED, 4);
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01003080
3081 /* Check for read/write and endianness problems. */
Michael Buesche4d6b792007-09-18 15:39:42 -04003082 b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
3083 if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55)
3084 goto error;
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01003085 b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
3086 if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
Michael Buesche4d6b792007-09-18 15:39:42 -04003087 goto error;
3088
Michael Bueschf62ae6c2009-07-31 20:51:41 +02003089 /* Check if unaligned 32bit SHM_SHARED access works properly.
3090 * However, don't bail out on failure, because it's noncritical. */
3091 b43_shm_write16(dev, B43_SHM_SHARED, 0, 0x1122);
3092 b43_shm_write16(dev, B43_SHM_SHARED, 2, 0x3344);
3093 b43_shm_write16(dev, B43_SHM_SHARED, 4, 0x5566);
3094 b43_shm_write16(dev, B43_SHM_SHARED, 6, 0x7788);
3095 if (b43_shm_read32(dev, B43_SHM_SHARED, 2) != 0x55663344)
3096 b43warn(dev->wl, "Unaligned 32bit SHM read access is broken\n");
3097 b43_shm_write32(dev, B43_SHM_SHARED, 2, 0xAABBCCDD);
3098 if (b43_shm_read16(dev, B43_SHM_SHARED, 0) != 0x1122 ||
3099 b43_shm_read16(dev, B43_SHM_SHARED, 2) != 0xCCDD ||
3100 b43_shm_read16(dev, B43_SHM_SHARED, 4) != 0xAABB ||
3101 b43_shm_read16(dev, B43_SHM_SHARED, 6) != 0x7788)
3102 b43warn(dev->wl, "Unaligned 32bit SHM write access is broken\n");
3103
3104 b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0);
3105 b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4);
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01003106
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02003107 if ((dev->sdev->id.revision >= 3) && (dev->sdev->id.revision <= 10)) {
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01003108 /* The 32bit register shadows the two 16bit registers
3109 * with update sideeffects. Validate this. */
3110 b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
3111 b43_write32(dev, B43_MMIO_TSF_CFP_START, 0xCCCCBBBB);
3112 if (b43_read16(dev, B43_MMIO_TSF_CFP_START_LOW) != 0xBBBB)
3113 goto error;
3114 if (b43_read16(dev, B43_MMIO_TSF_CFP_START_HIGH) != 0xCCCC)
3115 goto error;
3116 }
3117 b43_write32(dev, B43_MMIO_TSF_CFP_START, 0);
3118
3119 v = b43_read32(dev, B43_MMIO_MACCTL);
3120 v |= B43_MACCTL_GMODE;
3121 if (v != (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
Michael Buesche4d6b792007-09-18 15:39:42 -04003122 goto error;
3123
3124 return 0;
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01003125error:
Michael Buesche4d6b792007-09-18 15:39:42 -04003126 b43err(dev->wl, "Failed to validate the chipaccess\n");
3127 return -ENODEV;
3128}
3129
3130static void b43_security_init(struct b43_wldev *dev)
3131{
Michael Buesche4d6b792007-09-18 15:39:42 -04003132 dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP);
3133 /* KTP is a word address, but we address SHM bytewise.
3134 * So multiply by two.
3135 */
3136 dev->ktp *= 2;
Michael Buesch66d2d082009-08-06 10:36:50 +02003137 /* Number of RCMTA address slots */
3138 b43_write16(dev, B43_MMIO_RCMTA_COUNT, B43_NR_PAIRWISE_KEYS);
3139 /* Clear the key memory. */
Michael Buesche4d6b792007-09-18 15:39:42 -04003140 b43_clear_keys(dev);
3141}
3142
Michael Buesch616de352009-03-29 13:19:31 +02003143#ifdef CONFIG_B43_HWRNG
John Daiker99da1852009-02-24 02:16:42 -08003144static int b43_rng_read(struct hwrng *rng, u32 *data)
Michael Buesche4d6b792007-09-18 15:39:42 -04003145{
3146 struct b43_wl *wl = (struct b43_wl *)rng->priv;
Michael Buescha78b3bb2009-09-11 21:44:05 +02003147 struct b43_wldev *dev;
3148 int count = -ENODEV;
Michael Buesche4d6b792007-09-18 15:39:42 -04003149
Michael Buescha78b3bb2009-09-11 21:44:05 +02003150 mutex_lock(&wl->mutex);
3151 dev = wl->current_dev;
3152 if (likely(dev && b43_status(dev) >= B43_STAT_INITIALIZED)) {
3153 *data = b43_read16(dev, B43_MMIO_RNG);
3154 count = sizeof(u16);
3155 }
3156 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003157
Michael Buescha78b3bb2009-09-11 21:44:05 +02003158 return count;
Michael Buesche4d6b792007-09-18 15:39:42 -04003159}
Michael Buesch616de352009-03-29 13:19:31 +02003160#endif /* CONFIG_B43_HWRNG */
Michael Buesche4d6b792007-09-18 15:39:42 -04003161
Rafael J. Wysockib844eba2008-03-23 20:28:24 +01003162static void b43_rng_exit(struct b43_wl *wl)
Michael Buesche4d6b792007-09-18 15:39:42 -04003163{
Michael Buesch616de352009-03-29 13:19:31 +02003164#ifdef CONFIG_B43_HWRNG
Michael Buesche4d6b792007-09-18 15:39:42 -04003165 if (wl->rng_initialized)
Rafael J. Wysockib844eba2008-03-23 20:28:24 +01003166 hwrng_unregister(&wl->rng);
Michael Buesch616de352009-03-29 13:19:31 +02003167#endif /* CONFIG_B43_HWRNG */
Michael Buesche4d6b792007-09-18 15:39:42 -04003168}
3169
3170static int b43_rng_init(struct b43_wl *wl)
3171{
Michael Buesch616de352009-03-29 13:19:31 +02003172 int err = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04003173
Michael Buesch616de352009-03-29 13:19:31 +02003174#ifdef CONFIG_B43_HWRNG
Michael Buesche4d6b792007-09-18 15:39:42 -04003175 snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
3176 "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
3177 wl->rng.name = wl->rng_name;
3178 wl->rng.data_read = b43_rng_read;
3179 wl->rng.priv = (unsigned long)wl;
3180 wl->rng_initialized = 1;
3181 err = hwrng_register(&wl->rng);
3182 if (err) {
3183 wl->rng_initialized = 0;
3184 b43err(wl, "Failed to register the random "
3185 "number generator (%d)\n", err);
3186 }
Michael Buesch616de352009-03-29 13:19:31 +02003187#endif /* CONFIG_B43_HWRNG */
Michael Buesche4d6b792007-09-18 15:39:42 -04003188
3189 return err;
3190}
3191
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003192static void b43_tx_work(struct work_struct *work)
Michael Buesche4d6b792007-09-18 15:39:42 -04003193{
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003194 struct b43_wl *wl = container_of(work, struct b43_wl, tx_work);
3195 struct b43_wldev *dev;
3196 struct sk_buff *skb;
3197 int err = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04003198
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003199 mutex_lock(&wl->mutex);
3200 dev = wl->current_dev;
3201 if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED)) {
3202 mutex_unlock(&wl->mutex);
3203 return;
Michael Buesch5100d5a2008-03-29 21:01:16 +01003204 }
Michael Buesch21a75d72008-04-25 19:29:08 +02003205
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003206 while (skb_queue_len(&wl->tx_queue)) {
3207 skb = skb_dequeue(&wl->tx_queue);
Michael Buesch21a75d72008-04-25 19:29:08 +02003208
Michael Buesch21a75d72008-04-25 19:29:08 +02003209 if (b43_using_pio_transfers(dev))
Johannes Berge039fa42008-05-15 12:55:29 +02003210 err = b43_pio_tx(dev, skb);
Michael Buesch21a75d72008-04-25 19:29:08 +02003211 else
Johannes Berge039fa42008-05-15 12:55:29 +02003212 err = b43_dma_tx(dev, skb);
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003213 if (unlikely(err))
3214 dev_kfree_skb(skb); /* Drop it */
Michael Buesch21a75d72008-04-25 19:29:08 +02003215 }
3216
Michael Buesch990b86f2009-09-12 00:48:03 +02003217#if B43_DEBUG
3218 dev->tx_count++;
3219#endif
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003220 mutex_unlock(&wl->mutex);
3221}
Michael Buesch21a75d72008-04-25 19:29:08 +02003222
Johannes Berg7bb45682011-02-24 14:42:06 +01003223static void b43_op_tx(struct ieee80211_hw *hw,
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003224 struct sk_buff *skb)
3225{
3226 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Bueschc9e8eae2008-06-15 15:17:29 +02003227
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003228 if (unlikely(skb->len < 2 + 2 + 6)) {
3229 /* Too short, this can't be a valid frame. */
3230 dev_kfree_skb_any(skb);
Johannes Berg7bb45682011-02-24 14:42:06 +01003231 return;
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003232 }
3233 B43_WARN_ON(skb_shinfo(skb)->nr_frags);
3234
3235 skb_queue_tail(&wl->tx_queue, skb);
3236 ieee80211_queue_work(wl->hw, &wl->tx_work);
Michael Buesche4d6b792007-09-18 15:39:42 -04003237}
3238
Michael Buesche6f5b932008-03-05 21:18:49 +01003239static void b43_qos_params_upload(struct b43_wldev *dev,
3240 const struct ieee80211_tx_queue_params *p,
3241 u16 shm_offset)
3242{
3243 u16 params[B43_NR_QOSPARAMS];
Johannes Berg0b576642008-07-15 02:08:24 -07003244 int bslots, tmp;
Michael Buesche6f5b932008-03-05 21:18:49 +01003245 unsigned int i;
3246
Michael Bueschb0544eb2009-09-06 15:42:45 +02003247 if (!dev->qos_enabled)
3248 return;
3249
Johannes Berg0b576642008-07-15 02:08:24 -07003250 bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min;
Michael Buesche6f5b932008-03-05 21:18:49 +01003251
3252 memset(&params, 0, sizeof(params));
3253
3254 params[B43_QOSPARAM_TXOP] = p->txop * 32;
Johannes Berg0b576642008-07-15 02:08:24 -07003255 params[B43_QOSPARAM_CWMIN] = p->cw_min;
3256 params[B43_QOSPARAM_CWMAX] = p->cw_max;
3257 params[B43_QOSPARAM_CWCUR] = p->cw_min;
3258 params[B43_QOSPARAM_AIFS] = p->aifs;
Michael Buesche6f5b932008-03-05 21:18:49 +01003259 params[B43_QOSPARAM_BSLOTS] = bslots;
Johannes Berg0b576642008-07-15 02:08:24 -07003260 params[B43_QOSPARAM_REGGAP] = bslots + p->aifs;
Michael Buesche6f5b932008-03-05 21:18:49 +01003261
3262 for (i = 0; i < ARRAY_SIZE(params); i++) {
3263 if (i == B43_QOSPARAM_STATUS) {
3264 tmp = b43_shm_read16(dev, B43_SHM_SHARED,
3265 shm_offset + (i * 2));
3266 /* Mark the parameters as updated. */
3267 tmp |= 0x100;
3268 b43_shm_write16(dev, B43_SHM_SHARED,
3269 shm_offset + (i * 2),
3270 tmp);
3271 } else {
3272 b43_shm_write16(dev, B43_SHM_SHARED,
3273 shm_offset + (i * 2),
3274 params[i]);
3275 }
3276 }
3277}
3278
Michael Bueschc40c1122008-09-06 16:21:47 +02003279/* Mapping of mac80211 queue numbers to b43 QoS SHM offsets. */
3280static const u16 b43_qos_shm_offsets[] = {
3281 /* [mac80211-queue-nr] = SHM_OFFSET, */
3282 [0] = B43_QOS_VOICE,
3283 [1] = B43_QOS_VIDEO,
3284 [2] = B43_QOS_BESTEFFORT,
3285 [3] = B43_QOS_BACKGROUND,
3286};
3287
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003288/* Update all QOS parameters in hardware. */
3289static void b43_qos_upload_all(struct b43_wldev *dev)
Michael Buesche6f5b932008-03-05 21:18:49 +01003290{
3291 struct b43_wl *wl = dev->wl;
3292 struct b43_qos_params *params;
Michael Buesche6f5b932008-03-05 21:18:49 +01003293 unsigned int i;
3294
Michael Bueschb0544eb2009-09-06 15:42:45 +02003295 if (!dev->qos_enabled)
3296 return;
3297
Michael Bueschc40c1122008-09-06 16:21:47 +02003298 BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
3299 ARRAY_SIZE(wl->qos_params));
Michael Buesche6f5b932008-03-05 21:18:49 +01003300
3301 b43_mac_suspend(dev);
Michael Buesche6f5b932008-03-05 21:18:49 +01003302 for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
3303 params = &(wl->qos_params[i]);
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003304 b43_qos_params_upload(dev, &(params->p),
3305 b43_qos_shm_offsets[i]);
Michael Buesche6f5b932008-03-05 21:18:49 +01003306 }
Michael Buesche6f5b932008-03-05 21:18:49 +01003307 b43_mac_enable(dev);
3308}
3309
3310static void b43_qos_clear(struct b43_wl *wl)
3311{
3312 struct b43_qos_params *params;
3313 unsigned int i;
3314
Michael Bueschc40c1122008-09-06 16:21:47 +02003315 /* Initialize QoS parameters to sane defaults. */
3316
3317 BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
3318 ARRAY_SIZE(wl->qos_params));
3319
Michael Buesche6f5b932008-03-05 21:18:49 +01003320 for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
3321 params = &(wl->qos_params[i]);
3322
Michael Bueschc40c1122008-09-06 16:21:47 +02003323 switch (b43_qos_shm_offsets[i]) {
3324 case B43_QOS_VOICE:
3325 params->p.txop = 0;
3326 params->p.aifs = 2;
3327 params->p.cw_min = 0x0001;
3328 params->p.cw_max = 0x0001;
3329 break;
3330 case B43_QOS_VIDEO:
3331 params->p.txop = 0;
3332 params->p.aifs = 2;
3333 params->p.cw_min = 0x0001;
3334 params->p.cw_max = 0x0001;
3335 break;
3336 case B43_QOS_BESTEFFORT:
3337 params->p.txop = 0;
3338 params->p.aifs = 3;
3339 params->p.cw_min = 0x0001;
3340 params->p.cw_max = 0x03FF;
3341 break;
3342 case B43_QOS_BACKGROUND:
3343 params->p.txop = 0;
3344 params->p.aifs = 7;
3345 params->p.cw_min = 0x0001;
3346 params->p.cw_max = 0x03FF;
3347 break;
3348 default:
3349 B43_WARN_ON(1);
3350 }
Michael Buesche6f5b932008-03-05 21:18:49 +01003351 }
3352}
3353
3354/* Initialize the core's QOS capabilities */
3355static void b43_qos_init(struct b43_wldev *dev)
3356{
Michael Bueschb0544eb2009-09-06 15:42:45 +02003357 if (!dev->qos_enabled) {
3358 /* Disable QOS support. */
3359 b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_EDCF);
3360 b43_write16(dev, B43_MMIO_IFSCTL,
3361 b43_read16(dev, B43_MMIO_IFSCTL)
3362 & ~B43_MMIO_IFSCTL_USE_EDCF);
3363 b43dbg(dev->wl, "QoS disabled\n");
3364 return;
3365 }
3366
Michael Buesche6f5b932008-03-05 21:18:49 +01003367 /* Upload the current QOS parameters. */
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003368 b43_qos_upload_all(dev);
Michael Buesche6f5b932008-03-05 21:18:49 +01003369
3370 /* Enable QOS support. */
3371 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
3372 b43_write16(dev, B43_MMIO_IFSCTL,
3373 b43_read16(dev, B43_MMIO_IFSCTL)
3374 | B43_MMIO_IFSCTL_USE_EDCF);
Michael Bueschb0544eb2009-09-06 15:42:45 +02003375 b43dbg(dev->wl, "QoS enabled\n");
Michael Buesche6f5b932008-03-05 21:18:49 +01003376}
3377
Johannes Berge100bb62008-04-30 18:51:21 +02003378static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue,
Michael Buesch40faacc2007-10-28 16:29:32 +01003379 const struct ieee80211_tx_queue_params *params)
Michael Buesche4d6b792007-09-18 15:39:42 -04003380{
Michael Buesche6f5b932008-03-05 21:18:49 +01003381 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003382 struct b43_wldev *dev;
Michael Buesche6f5b932008-03-05 21:18:49 +01003383 unsigned int queue = (unsigned int)_queue;
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003384 int err = -ENODEV;
Michael Buesche6f5b932008-03-05 21:18:49 +01003385
3386 if (queue >= ARRAY_SIZE(wl->qos_params)) {
3387 /* Queue not available or don't support setting
3388 * params on this queue. Return success to not
3389 * confuse mac80211. */
3390 return 0;
3391 }
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003392 BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
3393 ARRAY_SIZE(wl->qos_params));
Michael Buesche6f5b932008-03-05 21:18:49 +01003394
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003395 mutex_lock(&wl->mutex);
3396 dev = wl->current_dev;
3397 if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED)))
3398 goto out_unlock;
Michael Buesche6f5b932008-03-05 21:18:49 +01003399
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003400 memcpy(&(wl->qos_params[queue].p), params, sizeof(*params));
3401 b43_mac_suspend(dev);
3402 b43_qos_params_upload(dev, &(wl->qos_params[queue].p),
3403 b43_qos_shm_offsets[queue]);
3404 b43_mac_enable(dev);
3405 err = 0;
Michael Buesche6f5b932008-03-05 21:18:49 +01003406
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003407out_unlock:
3408 mutex_unlock(&wl->mutex);
3409
3410 return err;
Michael Buesche4d6b792007-09-18 15:39:42 -04003411}
3412
Michael Buesch40faacc2007-10-28 16:29:32 +01003413static int b43_op_get_stats(struct ieee80211_hw *hw,
3414 struct ieee80211_low_level_stats *stats)
Michael Buesche4d6b792007-09-18 15:39:42 -04003415{
3416 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Buesche4d6b792007-09-18 15:39:42 -04003417
Michael Buesch36dbd952009-09-04 22:51:29 +02003418 mutex_lock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003419 memcpy(stats, &wl->ieee_stats, sizeof(*stats));
Michael Buesch36dbd952009-09-04 22:51:29 +02003420 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003421
3422 return 0;
3423}
3424
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01003425static u64 b43_op_get_tsf(struct ieee80211_hw *hw)
3426{
3427 struct b43_wl *wl = hw_to_b43_wl(hw);
3428 struct b43_wldev *dev;
3429 u64 tsf;
3430
3431 mutex_lock(&wl->mutex);
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01003432 dev = wl->current_dev;
3433
3434 if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED))
3435 b43_tsf_read(dev, &tsf);
3436 else
3437 tsf = 0;
3438
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01003439 mutex_unlock(&wl->mutex);
3440
3441 return tsf;
3442}
3443
3444static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
3445{
3446 struct b43_wl *wl = hw_to_b43_wl(hw);
3447 struct b43_wldev *dev;
3448
3449 mutex_lock(&wl->mutex);
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01003450 dev = wl->current_dev;
3451
3452 if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED))
3453 b43_tsf_write(dev, tsf);
3454
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01003455 mutex_unlock(&wl->mutex);
3456}
3457
Michael Buesche4d6b792007-09-18 15:39:42 -04003458static void b43_put_phy_into_reset(struct b43_wldev *dev)
3459{
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02003460 struct ssb_device *sdev = dev->sdev;
Michael Buesche4d6b792007-09-18 15:39:42 -04003461 u32 tmslow;
3462
3463 tmslow = ssb_read32(sdev, SSB_TMSLOW);
3464 tmslow &= ~B43_TMSLOW_GMODE;
3465 tmslow |= B43_TMSLOW_PHYRESET;
3466 tmslow |= SSB_TMSLOW_FGC;
3467 ssb_write32(sdev, SSB_TMSLOW, tmslow);
3468 msleep(1);
3469
3470 tmslow = ssb_read32(sdev, SSB_TMSLOW);
3471 tmslow &= ~SSB_TMSLOW_FGC;
3472 tmslow |= B43_TMSLOW_PHYRESET;
3473 ssb_write32(sdev, SSB_TMSLOW, tmslow);
3474 msleep(1);
3475}
3476
John Daiker99da1852009-02-24 02:16:42 -08003477static const char *band_to_string(enum ieee80211_band band)
Michael Buesche4d6b792007-09-18 15:39:42 -04003478{
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003479 switch (band) {
3480 case IEEE80211_BAND_5GHZ:
3481 return "5";
3482 case IEEE80211_BAND_2GHZ:
3483 return "2.4";
3484 default:
3485 break;
3486 }
3487 B43_WARN_ON(1);
3488 return "";
3489}
3490
3491/* Expects wl->mutex locked */
3492static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan)
3493{
3494 struct b43_wldev *up_dev = NULL;
Michael Buesche4d6b792007-09-18 15:39:42 -04003495 struct b43_wldev *down_dev;
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003496 struct b43_wldev *d;
Michael Buesche4d6b792007-09-18 15:39:42 -04003497 int err;
John W. Linville922d8a02009-01-12 14:40:20 -05003498 bool uninitialized_var(gmode);
Michael Buesche4d6b792007-09-18 15:39:42 -04003499 int prev_status;
3500
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003501 /* Find a device and PHY which supports the band. */
3502 list_for_each_entry(d, &wl->devlist, list) {
3503 switch (chan->band) {
3504 case IEEE80211_BAND_5GHZ:
3505 if (d->phy.supports_5ghz) {
3506 up_dev = d;
3507 gmode = 0;
3508 }
3509 break;
3510 case IEEE80211_BAND_2GHZ:
3511 if (d->phy.supports_2ghz) {
3512 up_dev = d;
3513 gmode = 1;
3514 }
3515 break;
3516 default:
3517 B43_WARN_ON(1);
3518 return -EINVAL;
3519 }
3520 if (up_dev)
3521 break;
3522 }
3523 if (!up_dev) {
3524 b43err(wl, "Could not find a device for %s-GHz band operation\n",
3525 band_to_string(chan->band));
3526 return -ENODEV;
Michael Buesche4d6b792007-09-18 15:39:42 -04003527 }
3528 if ((up_dev == wl->current_dev) &&
3529 (!!wl->current_dev->phy.gmode == !!gmode)) {
3530 /* This device is already running. */
3531 return 0;
3532 }
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003533 b43dbg(wl, "Switching to %s-GHz band\n",
3534 band_to_string(chan->band));
Michael Buesche4d6b792007-09-18 15:39:42 -04003535 down_dev = wl->current_dev;
3536
3537 prev_status = b43_status(down_dev);
3538 /* Shutdown the currently running core. */
3539 if (prev_status >= B43_STAT_STARTED)
Michael Buesch36dbd952009-09-04 22:51:29 +02003540 down_dev = b43_wireless_core_stop(down_dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003541 if (prev_status >= B43_STAT_INITIALIZED)
3542 b43_wireless_core_exit(down_dev);
3543
3544 if (down_dev != up_dev) {
3545 /* We switch to a different core, so we put PHY into
3546 * RESET on the old core. */
3547 b43_put_phy_into_reset(down_dev);
3548 }
3549
3550 /* Now start the new core. */
3551 up_dev->phy.gmode = gmode;
3552 if (prev_status >= B43_STAT_INITIALIZED) {
3553 err = b43_wireless_core_init(up_dev);
3554 if (err) {
3555 b43err(wl, "Fatal: Could not initialize device for "
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003556 "selected %s-GHz band\n",
3557 band_to_string(chan->band));
Michael Buesche4d6b792007-09-18 15:39:42 -04003558 goto init_failure;
3559 }
3560 }
3561 if (prev_status >= B43_STAT_STARTED) {
3562 err = b43_wireless_core_start(up_dev);
3563 if (err) {
3564 b43err(wl, "Fatal: Coult not start device for "
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003565 "selected %s-GHz band\n",
3566 band_to_string(chan->band));
Michael Buesche4d6b792007-09-18 15:39:42 -04003567 b43_wireless_core_exit(up_dev);
3568 goto init_failure;
3569 }
3570 }
3571 B43_WARN_ON(b43_status(up_dev) != prev_status);
3572
3573 wl->current_dev = up_dev;
3574
3575 return 0;
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003576init_failure:
Michael Buesche4d6b792007-09-18 15:39:42 -04003577 /* Whoops, failed to init the new core. No core is operating now. */
3578 wl->current_dev = NULL;
3579 return err;
3580}
3581
Johannes Berg9124b072008-10-14 19:17:54 +02003582/* Write the short and long frame retry limit values. */
3583static void b43_set_retry_limits(struct b43_wldev *dev,
3584 unsigned int short_retry,
3585 unsigned int long_retry)
3586{
3587 /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
3588 * the chip-internal counter. */
3589 short_retry = min(short_retry, (unsigned int)0xF);
3590 long_retry = min(long_retry, (unsigned int)0xF);
3591
3592 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
3593 short_retry);
3594 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
3595 long_retry);
3596}
3597
Johannes Berge8975582008-10-09 12:18:51 +02003598static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
Michael Buesche4d6b792007-09-18 15:39:42 -04003599{
3600 struct b43_wl *wl = hw_to_b43_wl(hw);
3601 struct b43_wldev *dev;
3602 struct b43_phy *phy;
Johannes Berge8975582008-10-09 12:18:51 +02003603 struct ieee80211_conf *conf = &hw->conf;
Michael Buesch9db1f6d2007-12-22 21:54:20 +01003604 int antenna;
Michael Buesche4d6b792007-09-18 15:39:42 -04003605 int err = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04003606
Michael Buesche4d6b792007-09-18 15:39:42 -04003607 mutex_lock(&wl->mutex);
3608
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003609 /* Switch the band (if necessary). This might change the active core. */
3610 err = b43_switch_band(wl, conf->channel);
Michael Buesche4d6b792007-09-18 15:39:42 -04003611 if (err)
3612 goto out_unlock_mutex;
3613 dev = wl->current_dev;
3614 phy = &dev->phy;
3615
Rafał Miłeckiaa4c7b22010-01-22 01:53:12 +01003616 if (conf_is_ht(conf))
3617 phy->is_40mhz =
3618 (conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf));
3619 else
3620 phy->is_40mhz = false;
3621
Michael Bueschd10d0e52008-12-18 22:13:39 +01003622 b43_mac_suspend(dev);
3623
Johannes Berg9124b072008-10-14 19:17:54 +02003624 if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
3625 b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
3626 conf->long_frame_max_tx_count);
3627 changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
3628 if (!changed)
Michael Bueschd10d0e52008-12-18 22:13:39 +01003629 goto out_mac_enable;
Michael Buesche4d6b792007-09-18 15:39:42 -04003630
3631 /* Switch to the requested channel.
3632 * The firmware takes care of races with the TX handler. */
Johannes Berg8318d782008-01-24 19:38:38 +01003633 if (conf->channel->hw_value != phy->channel)
Michael Bueschef1a6282008-08-27 18:53:02 +02003634 b43_switch_channel(dev, conf->channel->hw_value);
Michael Buesche4d6b792007-09-18 15:39:42 -04003635
Johannes Berg0869aea2009-10-28 10:03:35 +01003636 dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR);
Johannes Bergd42ce842007-11-23 14:50:51 +01003637
Michael Buesche4d6b792007-09-18 15:39:42 -04003638 /* Adjust the desired TX power level. */
3639 if (conf->power_level != 0) {
Michael Buesch18c8ade2008-08-28 19:33:40 +02003640 if (conf->power_level != phy->desired_txpower) {
3641 phy->desired_txpower = conf->power_level;
3642 b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME |
3643 B43_TXPWR_IGNORE_TSSI);
Michael Buesche4d6b792007-09-18 15:39:42 -04003644 }
3645 }
3646
3647 /* Antennas for RX and management frame TX. */
Johannes Berg0f4ac382008-10-09 12:18:04 +02003648 antenna = B43_ANTENNA_DEFAULT;
Michael Buesch9db1f6d2007-12-22 21:54:20 +01003649 b43_mgmtframe_txantenna(dev, antenna);
Johannes Berg0f4ac382008-10-09 12:18:04 +02003650 antenna = B43_ANTENNA_DEFAULT;
Michael Bueschef1a6282008-08-27 18:53:02 +02003651 if (phy->ops->set_rx_antenna)
3652 phy->ops->set_rx_antenna(dev, antenna);
Michael Buesche4d6b792007-09-18 15:39:42 -04003653
Larry Fingerfd4973c2009-06-20 12:58:11 -05003654 if (wl->radio_enabled != phy->radio_on) {
3655 if (wl->radio_enabled) {
Johannes Berg19d337d2009-06-02 13:01:37 +02003656 b43_software_rfkill(dev, false);
Michael Bueschfda9abc2007-09-20 22:14:18 +02003657 b43info(dev->wl, "Radio turned on by software\n");
3658 if (!dev->radio_hw_enable) {
3659 b43info(dev->wl, "The hardware RF-kill button "
3660 "still turns the radio physically off. "
3661 "Press the button to turn it on.\n");
3662 }
3663 } else {
Johannes Berg19d337d2009-06-02 13:01:37 +02003664 b43_software_rfkill(dev, true);
Michael Bueschfda9abc2007-09-20 22:14:18 +02003665 b43info(dev->wl, "Radio turned off by software\n");
3666 }
3667 }
3668
Michael Bueschd10d0e52008-12-18 22:13:39 +01003669out_mac_enable:
3670 b43_mac_enable(dev);
3671out_unlock_mutex:
Michael Buesche4d6b792007-09-18 15:39:42 -04003672 mutex_unlock(&wl->mutex);
3673
3674 return err;
3675}
3676
Johannes Berg881d9482009-01-21 15:13:48 +01003677static void b43_update_basic_rates(struct b43_wldev *dev, u32 brates)
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003678{
3679 struct ieee80211_supported_band *sband =
3680 dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)];
3681 struct ieee80211_rate *rate;
3682 int i;
3683 u16 basic, direct, offset, basic_offset, rateptr;
3684
3685 for (i = 0; i < sband->n_bitrates; i++) {
3686 rate = &sband->bitrates[i];
3687
3688 if (b43_is_cck_rate(rate->hw_value)) {
3689 direct = B43_SHM_SH_CCKDIRECT;
3690 basic = B43_SHM_SH_CCKBASIC;
3691 offset = b43_plcp_get_ratecode_cck(rate->hw_value);
3692 offset &= 0xF;
3693 } else {
3694 direct = B43_SHM_SH_OFDMDIRECT;
3695 basic = B43_SHM_SH_OFDMBASIC;
3696 offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
3697 offset &= 0xF;
3698 }
3699
3700 rate = ieee80211_get_response_rate(sband, brates, rate->bitrate);
3701
3702 if (b43_is_cck_rate(rate->hw_value)) {
3703 basic_offset = b43_plcp_get_ratecode_cck(rate->hw_value);
3704 basic_offset &= 0xF;
3705 } else {
3706 basic_offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
3707 basic_offset &= 0xF;
3708 }
3709
3710 /*
3711 * Get the pointer that we need to point to
3712 * from the direct map
3713 */
3714 rateptr = b43_shm_read16(dev, B43_SHM_SHARED,
3715 direct + 2 * basic_offset);
3716 /* and write it to the basic map */
3717 b43_shm_write16(dev, B43_SHM_SHARED, basic + 2 * offset,
3718 rateptr);
3719 }
3720}
3721
3722static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
3723 struct ieee80211_vif *vif,
3724 struct ieee80211_bss_conf *conf,
3725 u32 changed)
3726{
3727 struct b43_wl *wl = hw_to_b43_wl(hw);
3728 struct b43_wldev *dev;
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003729
3730 mutex_lock(&wl->mutex);
3731
3732 dev = wl->current_dev;
Michael Bueschd10d0e52008-12-18 22:13:39 +01003733 if (!dev || b43_status(dev) < B43_STAT_STARTED)
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003734 goto out_unlock_mutex;
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003735
3736 B43_WARN_ON(wl->vif != vif);
3737
3738 if (changed & BSS_CHANGED_BSSID) {
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003739 if (conf->bssid)
3740 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
3741 else
3742 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003743 }
3744
Johannes Berg3f0d8432009-05-18 10:53:18 +02003745 if (b43_status(dev) >= B43_STAT_INITIALIZED) {
3746 if (changed & BSS_CHANGED_BEACON &&
3747 (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
3748 b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) ||
3749 b43_is_mode(wl, NL80211_IFTYPE_ADHOC)))
3750 b43_update_templates(wl);
3751
3752 if (changed & BSS_CHANGED_BSSID)
3753 b43_write_mac_bssid_templates(dev);
3754 }
Johannes Berg3f0d8432009-05-18 10:53:18 +02003755
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003756 b43_mac_suspend(dev);
3757
Johannes Berg57c4d7b2009-04-23 16:10:04 +02003758 /* Update templates for AP/mesh mode. */
3759 if (changed & BSS_CHANGED_BEACON_INT &&
3760 (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
3761 b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) ||
3762 b43_is_mode(wl, NL80211_IFTYPE_ADHOC)))
3763 b43_set_beacon_int(dev, conf->beacon_int);
3764
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003765 if (changed & BSS_CHANGED_BASIC_RATES)
3766 b43_update_basic_rates(dev, conf->basic_rates);
3767
3768 if (changed & BSS_CHANGED_ERP_SLOT) {
3769 if (conf->use_short_slot)
3770 b43_short_slot_timing_enable(dev);
3771 else
3772 b43_short_slot_timing_disable(dev);
3773 }
3774
3775 b43_mac_enable(dev);
Michael Bueschd10d0e52008-12-18 22:13:39 +01003776out_unlock_mutex:
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003777 mutex_unlock(&wl->mutex);
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003778}
3779
Michael Buesch40faacc2007-10-28 16:29:32 +01003780static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
Johannes Bergdc822b52008-12-29 12:55:09 +01003781 struct ieee80211_vif *vif, struct ieee80211_sta *sta,
3782 struct ieee80211_key_conf *key)
Michael Buesche4d6b792007-09-18 15:39:42 -04003783{
3784 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003785 struct b43_wldev *dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04003786 u8 algorithm;
3787 u8 index;
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003788 int err;
Michael Buesch060210f2009-01-25 15:49:59 +01003789 static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
Michael Buesche4d6b792007-09-18 15:39:42 -04003790
3791 if (modparam_nohwcrypt)
3792 return -ENOSPC; /* User disabled HW-crypto */
3793
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003794 mutex_lock(&wl->mutex);
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003795
3796 dev = wl->current_dev;
3797 err = -ENODEV;
3798 if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
3799 goto out_unlock;
3800
Michael Buesch403a3a12009-06-08 21:04:57 +02003801 if (dev->fw.pcm_request_failed || !dev->hwcrypto_enabled) {
Michael Buesch68217832008-05-17 23:43:57 +02003802 /* We don't have firmware for the crypto engine.
3803 * Must use software-crypto. */
3804 err = -EOPNOTSUPP;
3805 goto out_unlock;
3806 }
3807
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003808 err = -EINVAL;
Johannes Berg97359d12010-08-10 09:46:38 +02003809 switch (key->cipher) {
3810 case WLAN_CIPHER_SUITE_WEP40:
3811 algorithm = B43_SEC_ALGO_WEP40;
Michael Buesche4d6b792007-09-18 15:39:42 -04003812 break;
Johannes Berg97359d12010-08-10 09:46:38 +02003813 case WLAN_CIPHER_SUITE_WEP104:
3814 algorithm = B43_SEC_ALGO_WEP104;
3815 break;
3816 case WLAN_CIPHER_SUITE_TKIP:
Michael Buesche4d6b792007-09-18 15:39:42 -04003817 algorithm = B43_SEC_ALGO_TKIP;
3818 break;
Johannes Berg97359d12010-08-10 09:46:38 +02003819 case WLAN_CIPHER_SUITE_CCMP:
Michael Buesche4d6b792007-09-18 15:39:42 -04003820 algorithm = B43_SEC_ALGO_AES;
3821 break;
3822 default:
3823 B43_WARN_ON(1);
Michael Buesche4d6b792007-09-18 15:39:42 -04003824 goto out_unlock;
3825 }
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003826 index = (u8) (key->keyidx);
3827 if (index > 3)
3828 goto out_unlock;
Michael Buesche4d6b792007-09-18 15:39:42 -04003829
3830 switch (cmd) {
3831 case SET_KEY:
gregor kowski035d0242009-08-19 22:35:45 +02003832 if (algorithm == B43_SEC_ALGO_TKIP &&
3833 (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
3834 !modparam_hwtkip)) {
3835 /* We support only pairwise key */
Michael Buesche4d6b792007-09-18 15:39:42 -04003836 err = -EOPNOTSUPP;
3837 goto out_unlock;
3838 }
3839
Michael Buesche808e582008-12-19 21:30:52 +01003840 if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
Johannes Bergdc822b52008-12-29 12:55:09 +01003841 if (WARN_ON(!sta)) {
3842 err = -EOPNOTSUPP;
3843 goto out_unlock;
3844 }
Michael Buesche808e582008-12-19 21:30:52 +01003845 /* Pairwise key with an assigned MAC address. */
Michael Buesche4d6b792007-09-18 15:39:42 -04003846 err = b43_key_write(dev, -1, algorithm,
Johannes Bergdc822b52008-12-29 12:55:09 +01003847 key->key, key->keylen,
3848 sta->addr, key);
Michael Buesche808e582008-12-19 21:30:52 +01003849 } else {
3850 /* Group key */
3851 err = b43_key_write(dev, index, algorithm,
3852 key->key, key->keylen, NULL, key);
Michael Buesche4d6b792007-09-18 15:39:42 -04003853 }
3854 if (err)
3855 goto out_unlock;
3856
3857 if (algorithm == B43_SEC_ALGO_WEP40 ||
3858 algorithm == B43_SEC_ALGO_WEP104) {
3859 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_USEDEFKEYS);
3860 } else {
3861 b43_hf_write(dev,
3862 b43_hf_read(dev) & ~B43_HF_USEDEFKEYS);
3863 }
3864 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
gregor kowski035d0242009-08-19 22:35:45 +02003865 if (algorithm == B43_SEC_ALGO_TKIP)
3866 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
Michael Buesche4d6b792007-09-18 15:39:42 -04003867 break;
3868 case DISABLE_KEY: {
3869 err = b43_key_clear(dev, key->hw_key_idx);
3870 if (err)
3871 goto out_unlock;
3872 break;
3873 }
3874 default:
3875 B43_WARN_ON(1);
3876 }
Michael Buesch9cf7f242008-12-19 20:24:30 +01003877
Michael Buesche4d6b792007-09-18 15:39:42 -04003878out_unlock:
Michael Buesche4d6b792007-09-18 15:39:42 -04003879 if (!err) {
3880 b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
Johannes Berge1749612008-10-27 15:59:26 -07003881 "mac: %pM\n",
Michael Buesche4d6b792007-09-18 15:39:42 -04003882 cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
Larry Fingera1d882102009-01-14 11:15:25 -06003883 sta ? sta->addr : bcast_addr);
Michael Buesch9cf7f242008-12-19 20:24:30 +01003884 b43_dump_keymemory(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003885 }
Michael Buesch9cf7f242008-12-19 20:24:30 +01003886 mutex_unlock(&wl->mutex);
3887
Michael Buesche4d6b792007-09-18 15:39:42 -04003888 return err;
3889}
3890
Michael Buesch40faacc2007-10-28 16:29:32 +01003891static void b43_op_configure_filter(struct ieee80211_hw *hw,
3892 unsigned int changed, unsigned int *fflags,
Johannes Berg3ac64be2009-08-17 16:16:53 +02003893 u64 multicast)
Michael Buesche4d6b792007-09-18 15:39:42 -04003894{
3895 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Buesch36dbd952009-09-04 22:51:29 +02003896 struct b43_wldev *dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04003897
Michael Buesch36dbd952009-09-04 22:51:29 +02003898 mutex_lock(&wl->mutex);
3899 dev = wl->current_dev;
Johannes Berg4150c572007-09-17 01:29:23 -04003900 if (!dev) {
3901 *fflags = 0;
Michael Buesch36dbd952009-09-04 22:51:29 +02003902 goto out_unlock;
Michael Buesche4d6b792007-09-18 15:39:42 -04003903 }
Johannes Berg4150c572007-09-17 01:29:23 -04003904
Johannes Berg4150c572007-09-17 01:29:23 -04003905 *fflags &= FIF_PROMISC_IN_BSS |
3906 FIF_ALLMULTI |
3907 FIF_FCSFAIL |
3908 FIF_PLCPFAIL |
3909 FIF_CONTROL |
3910 FIF_OTHER_BSS |
3911 FIF_BCN_PRBRESP_PROMISC;
3912
3913 changed &= FIF_PROMISC_IN_BSS |
3914 FIF_ALLMULTI |
3915 FIF_FCSFAIL |
3916 FIF_PLCPFAIL |
3917 FIF_CONTROL |
3918 FIF_OTHER_BSS |
3919 FIF_BCN_PRBRESP_PROMISC;
3920
3921 wl->filter_flags = *fflags;
3922
3923 if (changed && b43_status(dev) >= B43_STAT_INITIALIZED)
3924 b43_adjust_opmode(dev);
Michael Buesch36dbd952009-09-04 22:51:29 +02003925
3926out_unlock:
3927 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003928}
3929
Michael Buesch36dbd952009-09-04 22:51:29 +02003930/* Locking: wl->mutex
3931 * Returns the current dev. This might be different from the passed in dev,
3932 * because the core might be gone away while we unlocked the mutex. */
3933static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04003934{
3935 struct b43_wl *wl = dev->wl;
Michael Buesch36dbd952009-09-04 22:51:29 +02003936 struct b43_wldev *orig_dev;
Michael Buesch49d965c2009-10-03 00:57:58 +02003937 u32 mask;
Michael Buesche4d6b792007-09-18 15:39:42 -04003938
Michael Buesch36dbd952009-09-04 22:51:29 +02003939redo:
3940 if (!dev || b43_status(dev) < B43_STAT_STARTED)
3941 return dev;
Stefano Brivioa19d12d2007-11-07 18:16:11 +01003942
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003943 /* Cancel work. Unlock to avoid deadlocks. */
Michael Buesche4d6b792007-09-18 15:39:42 -04003944 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003945 cancel_delayed_work_sync(&dev->periodic_work);
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003946 cancel_work_sync(&wl->tx_work);
Michael Buesche4d6b792007-09-18 15:39:42 -04003947 mutex_lock(&wl->mutex);
Michael Buesch36dbd952009-09-04 22:51:29 +02003948 dev = wl->current_dev;
3949 if (!dev || b43_status(dev) < B43_STAT_STARTED) {
3950 /* Whoops, aliens ate up the device while we were unlocked. */
3951 return dev;
3952 }
Michael Buesche4d6b792007-09-18 15:39:42 -04003953
Michael Buesch36dbd952009-09-04 22:51:29 +02003954 /* Disable interrupts on the device. */
3955 b43_set_status(dev, B43_STAT_INITIALIZED);
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02003956 if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
Michael Buesch36dbd952009-09-04 22:51:29 +02003957 /* wl->mutex is locked. That is enough. */
3958 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
3959 b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
3960 } else {
3961 spin_lock_irq(&wl->hardirq_lock);
3962 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
3963 b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
3964 spin_unlock_irq(&wl->hardirq_lock);
3965 }
Michael Buesch176e9f62009-09-11 23:04:04 +02003966 /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
Michael Buesch36dbd952009-09-04 22:51:29 +02003967 orig_dev = dev;
3968 mutex_unlock(&wl->mutex);
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02003969 if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
Michael Buesch176e9f62009-09-11 23:04:04 +02003970 b43_sdio_free_irq(dev);
3971 } else {
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02003972 synchronize_irq(dev->sdev->irq);
3973 free_irq(dev->sdev->irq, dev);
Michael Buesch176e9f62009-09-11 23:04:04 +02003974 }
Michael Buesch36dbd952009-09-04 22:51:29 +02003975 mutex_lock(&wl->mutex);
3976 dev = wl->current_dev;
3977 if (!dev)
3978 return dev;
3979 if (dev != orig_dev) {
3980 if (b43_status(dev) >= B43_STAT_STARTED)
3981 goto redo;
3982 return dev;
3983 }
Michael Buesch49d965c2009-10-03 00:57:58 +02003984 mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
3985 B43_WARN_ON(mask != 0xFFFFFFFF && mask);
Michael Buesch36dbd952009-09-04 22:51:29 +02003986
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003987 /* Drain the TX queue */
3988 while (skb_queue_len(&wl->tx_queue))
3989 dev_kfree_skb(skb_dequeue(&wl->tx_queue));
3990
Michael Buesche4d6b792007-09-18 15:39:42 -04003991 b43_mac_suspend(dev);
Michael Buescha78b3bb2009-09-11 21:44:05 +02003992 b43_leds_exit(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003993 b43dbg(wl, "Wireless interface stopped\n");
Michael Buesch36dbd952009-09-04 22:51:29 +02003994
3995 return dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04003996}
3997
3998/* Locking: wl->mutex */
3999static int b43_wireless_core_start(struct b43_wldev *dev)
4000{
4001 int err;
4002
4003 B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
4004
4005 drain_txstatus_queue(dev);
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004006 if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
Albert Herranz3dbba8e2009-09-10 19:34:49 +02004007 err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler);
4008 if (err) {
4009 b43err(dev->wl, "Cannot request SDIO IRQ\n");
4010 goto out;
4011 }
4012 } else {
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004013 err = request_threaded_irq(dev->sdev->irq, b43_interrupt_handler,
Albert Herranz3dbba8e2009-09-10 19:34:49 +02004014 b43_interrupt_thread_handler,
4015 IRQF_SHARED, KBUILD_MODNAME, dev);
4016 if (err) {
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004017 b43err(dev->wl, "Cannot request IRQ-%d\n",
4018 dev->sdev->irq);
Albert Herranz3dbba8e2009-09-10 19:34:49 +02004019 goto out;
4020 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004021 }
4022
4023 /* We are ready to run. */
Larry Finger0866b032010-02-03 13:33:44 -06004024 ieee80211_wake_queues(dev->wl->hw);
Michael Buesche4d6b792007-09-18 15:39:42 -04004025 b43_set_status(dev, B43_STAT_STARTED);
4026
4027 /* Start data flow (TX/RX). */
4028 b43_mac_enable(dev);
Michael Buesch13790722009-04-08 21:26:27 +02004029 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
Michael Buesche4d6b792007-09-18 15:39:42 -04004030
4031 /* Start maintainance work */
4032 b43_periodic_tasks_setup(dev);
4033
Michael Buescha78b3bb2009-09-11 21:44:05 +02004034 b43_leds_init(dev);
4035
Michael Buesche4d6b792007-09-18 15:39:42 -04004036 b43dbg(dev->wl, "Wireless interface started\n");
Michael Buescha78b3bb2009-09-11 21:44:05 +02004037out:
Michael Buesche4d6b792007-09-18 15:39:42 -04004038 return err;
4039}
4040
4041/* Get PHY and RADIO versioning numbers */
4042static int b43_phy_versioning(struct b43_wldev *dev)
4043{
4044 struct b43_phy *phy = &dev->phy;
4045 u32 tmp;
4046 u8 analog_type;
4047 u8 phy_type;
4048 u8 phy_rev;
4049 u16 radio_manuf;
4050 u16 radio_ver;
4051 u16 radio_rev;
4052 int unsupported = 0;
4053
4054 /* Get PHY versioning */
4055 tmp = b43_read16(dev, B43_MMIO_PHY_VER);
4056 analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT;
4057 phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT;
4058 phy_rev = (tmp & B43_PHYVER_VERSION);
4059 switch (phy_type) {
4060 case B43_PHYTYPE_A:
4061 if (phy_rev >= 4)
4062 unsupported = 1;
4063 break;
4064 case B43_PHYTYPE_B:
4065 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6
4066 && phy_rev != 7)
4067 unsupported = 1;
4068 break;
4069 case B43_PHYTYPE_G:
Larry Finger013978b2007-11-26 10:29:47 -06004070 if (phy_rev > 9)
Michael Buesche4d6b792007-09-18 15:39:42 -04004071 unsupported = 1;
4072 break;
Rafał Miłecki692d2c02010-12-07 21:56:00 +01004073#ifdef CONFIG_B43_PHY_N
Michael Bueschd5c71e42008-01-04 17:06:29 +01004074 case B43_PHYTYPE_N:
Rafał Miłeckiab72efd2010-12-21 21:29:44 +01004075 if (phy_rev > 9)
Michael Bueschd5c71e42008-01-04 17:06:29 +01004076 unsupported = 1;
4077 break;
4078#endif
Michael Buesch6b1c7c62008-12-25 00:39:28 +01004079#ifdef CONFIG_B43_PHY_LP
4080 case B43_PHYTYPE_LP:
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02004081 if (phy_rev > 2)
Michael Buesch6b1c7c62008-12-25 00:39:28 +01004082 unsupported = 1;
4083 break;
4084#endif
Michael Buesche4d6b792007-09-18 15:39:42 -04004085 default:
4086 unsupported = 1;
4087 };
4088 if (unsupported) {
4089 b43err(dev->wl, "FOUND UNSUPPORTED PHY "
4090 "(Analog %u, Type %u, Revision %u)\n",
4091 analog_type, phy_type, phy_rev);
4092 return -EOPNOTSUPP;
4093 }
4094 b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
4095 analog_type, phy_type, phy_rev);
4096
4097 /* Get RADIO versioning */
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004098 if (dev->sdev->bus->chip_id == 0x4317) {
4099 if (dev->sdev->bus->chip_rev == 0)
Michael Buesche4d6b792007-09-18 15:39:42 -04004100 tmp = 0x3205017F;
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004101 else if (dev->sdev->bus->chip_rev == 1)
Michael Buesche4d6b792007-09-18 15:39:42 -04004102 tmp = 0x4205017F;
4103 else
4104 tmp = 0x5205017F;
4105 } else {
4106 b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
Michael Buesch243dcfc2008-01-13 14:12:44 +01004107 tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
Michael Buesche4d6b792007-09-18 15:39:42 -04004108 b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
Michael Buesch243dcfc2008-01-13 14:12:44 +01004109 tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
Michael Buesche4d6b792007-09-18 15:39:42 -04004110 }
4111 radio_manuf = (tmp & 0x00000FFF);
4112 radio_ver = (tmp & 0x0FFFF000) >> 12;
4113 radio_rev = (tmp & 0xF0000000) >> 28;
Michael Buesch96c755a2008-01-06 00:09:46 +01004114 if (radio_manuf != 0x17F /* Broadcom */)
4115 unsupported = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004116 switch (phy_type) {
4117 case B43_PHYTYPE_A:
4118 if (radio_ver != 0x2060)
4119 unsupported = 1;
4120 if (radio_rev != 1)
4121 unsupported = 1;
4122 if (radio_manuf != 0x17F)
4123 unsupported = 1;
4124 break;
4125 case B43_PHYTYPE_B:
4126 if ((radio_ver & 0xFFF0) != 0x2050)
4127 unsupported = 1;
4128 break;
4129 case B43_PHYTYPE_G:
4130 if (radio_ver != 0x2050)
4131 unsupported = 1;
4132 break;
Michael Buesch96c755a2008-01-06 00:09:46 +01004133 case B43_PHYTYPE_N:
Johannes Bergbb519be2008-12-24 15:26:40 +01004134 if (radio_ver != 0x2055 && radio_ver != 0x2056)
Michael Buesch96c755a2008-01-06 00:09:46 +01004135 unsupported = 1;
4136 break;
Michael Buesch6b1c7c62008-12-25 00:39:28 +01004137 case B43_PHYTYPE_LP:
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02004138 if (radio_ver != 0x2062 && radio_ver != 0x2063)
Michael Buesch6b1c7c62008-12-25 00:39:28 +01004139 unsupported = 1;
4140 break;
Michael Buesche4d6b792007-09-18 15:39:42 -04004141 default:
4142 B43_WARN_ON(1);
4143 }
4144 if (unsupported) {
4145 b43err(dev->wl, "FOUND UNSUPPORTED RADIO "
4146 "(Manuf 0x%X, Version 0x%X, Revision %u)\n",
4147 radio_manuf, radio_ver, radio_rev);
4148 return -EOPNOTSUPP;
4149 }
4150 b43dbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X, Revision %u\n",
4151 radio_manuf, radio_ver, radio_rev);
4152
4153 phy->radio_manuf = radio_manuf;
4154 phy->radio_ver = radio_ver;
4155 phy->radio_rev = radio_rev;
4156
4157 phy->analog = analog_type;
4158 phy->type = phy_type;
4159 phy->rev = phy_rev;
4160
4161 return 0;
4162}
4163
4164static void setup_struct_phy_for_init(struct b43_wldev *dev,
4165 struct b43_phy *phy)
4166{
Michael Buesche4d6b792007-09-18 15:39:42 -04004167 phy->hardware_power_control = !!modparam_hwpctl;
Michael Buesch18c8ade2008-08-28 19:33:40 +02004168 phy->next_txpwr_check_time = jiffies;
Michael Buesch8ed7fc42007-12-09 22:34:59 +01004169 /* PHY TX errors counter. */
4170 atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
Michael Buesch591f3dc2009-03-31 12:27:32 +02004171
4172#if B43_DEBUG
4173 phy->phy_locked = 0;
4174 phy->radio_locked = 0;
4175#endif
Michael Buesche4d6b792007-09-18 15:39:42 -04004176}
4177
4178static void setup_struct_wldev_for_init(struct b43_wldev *dev)
4179{
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01004180 dev->dfq_valid = 0;
4181
Michael Buesch6a724d62007-09-20 22:12:58 +02004182 /* Assume the radio is enabled. If it's not enabled, the state will
4183 * immediately get fixed on the first periodic work run. */
4184 dev->radio_hw_enable = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004185
4186 /* Stats */
4187 memset(&dev->stats, 0, sizeof(dev->stats));
4188
4189 setup_struct_phy_for_init(dev, &dev->phy);
4190
4191 /* IRQ related flags */
4192 dev->irq_reason = 0;
4193 memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
Michael Buesch13790722009-04-08 21:26:27 +02004194 dev->irq_mask = B43_IRQ_MASKTEMPLATE;
Michael Buesch3e3ccb32009-03-19 19:27:21 +01004195 if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
Michael Buesch13790722009-04-08 21:26:27 +02004196 dev->irq_mask &= ~B43_IRQ_PHY_TXERR;
Michael Buesche4d6b792007-09-18 15:39:42 -04004197
4198 dev->mac_suspended = 1;
4199
4200 /* Noise calculation context */
4201 memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
4202}
4203
4204static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
4205{
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004206 struct ssb_sprom *sprom = &dev->sdev->bus->sprom;
Michael Buescha259d6a2008-04-18 21:06:37 +02004207 u64 hf;
Michael Buesche4d6b792007-09-18 15:39:42 -04004208
Michael Buesch1855ba72008-04-18 20:51:41 +02004209 if (!modparam_btcoex)
4210 return;
Larry Finger95de2842007-11-09 16:57:18 -06004211 if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST))
Michael Buesche4d6b792007-09-18 15:39:42 -04004212 return;
4213 if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
4214 return;
4215
4216 hf = b43_hf_read(dev);
Larry Finger95de2842007-11-09 16:57:18 -06004217 if (sprom->boardflags_lo & B43_BFL_BTCMOD)
Michael Buesche4d6b792007-09-18 15:39:42 -04004218 hf |= B43_HF_BTCOEXALT;
4219 else
4220 hf |= B43_HF_BTCOEX;
4221 b43_hf_write(dev, hf);
Michael Buesche4d6b792007-09-18 15:39:42 -04004222}
4223
4224static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
Michael Buesch1855ba72008-04-18 20:51:41 +02004225{
4226 if (!modparam_btcoex)
4227 return;
4228 //TODO
Michael Buesche4d6b792007-09-18 15:39:42 -04004229}
4230
4231static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
4232{
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004233 struct ssb_bus *bus = dev->sdev->bus;
Rafał Miłecki0fd82ea2011-05-11 02:10:59 +02004234 u32 tmp;
4235
4236 if ((bus->chip_id == 0x4311 && bus->chip_rev == 2) ||
4237 (bus->chip_id == 0x4312)) {
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004238 tmp = ssb_read32(dev->sdev, SSB_IMCFGLO);
Rafał Miłecki0fd82ea2011-05-11 02:10:59 +02004239 tmp &= ~SSB_IMCFGLO_REQTO;
4240 tmp &= ~SSB_IMCFGLO_SERTO;
4241 tmp |= 0x3;
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004242 ssb_write32(dev->sdev, SSB_IMCFGLO, tmp);
Rafał Miłecki0fd82ea2011-05-11 02:10:59 +02004243 ssb_commit_settings(bus);
4244 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004245}
4246
Michael Bueschd59f7202008-04-03 18:56:19 +02004247static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
4248{
4249 u16 pu_delay;
4250
4251 /* The time value is in microseconds. */
4252 if (dev->phy.type == B43_PHYTYPE_A)
4253 pu_delay = 3700;
4254 else
4255 pu_delay = 1050;
Johannes Berg05c914f2008-09-11 00:01:58 +02004256 if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle)
Michael Bueschd59f7202008-04-03 18:56:19 +02004257 pu_delay = 500;
4258 if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
4259 pu_delay = max(pu_delay, (u16)2400);
4260
4261 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SPUWKUP, pu_delay);
4262}
4263
4264/* Set the TSF CFP pre-TargetBeaconTransmissionTime. */
4265static void b43_set_pretbtt(struct b43_wldev *dev)
4266{
4267 u16 pretbtt;
4268
4269 /* The time value is in microseconds. */
Johannes Berg05c914f2008-09-11 00:01:58 +02004270 if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) {
Michael Bueschd59f7202008-04-03 18:56:19 +02004271 pretbtt = 2;
4272 } else {
4273 if (dev->phy.type == B43_PHYTYPE_A)
4274 pretbtt = 120;
4275 else
4276 pretbtt = 250;
4277 }
4278 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRETBTT, pretbtt);
4279 b43_write16(dev, B43_MMIO_TSF_CFP_PRETBTT, pretbtt);
4280}
4281
Michael Buesche4d6b792007-09-18 15:39:42 -04004282/* Shutdown a wireless core */
4283/* Locking: wl->mutex */
4284static void b43_wireless_core_exit(struct b43_wldev *dev)
4285{
Michael Buesch1f7d87b2008-01-22 20:23:34 +01004286 u32 macctl;
Michael Buesche4d6b792007-09-18 15:39:42 -04004287
Michael Buesch36dbd952009-09-04 22:51:29 +02004288 B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED);
4289 if (!dev || b43_status(dev) != B43_STAT_INITIALIZED)
Michael Buesche4d6b792007-09-18 15:39:42 -04004290 return;
John W. Linville84c164a2010-08-06 15:31:45 -04004291
4292 /* Unregister HW RNG driver */
4293 b43_rng_exit(dev->wl);
4294
Michael Buesche4d6b792007-09-18 15:39:42 -04004295 b43_set_status(dev, B43_STAT_UNINIT);
4296
Michael Buesch1f7d87b2008-01-22 20:23:34 +01004297 /* Stop the microcode PSM. */
4298 macctl = b43_read32(dev, B43_MMIO_MACCTL);
4299 macctl &= ~B43_MACCTL_PSM_RUN;
4300 macctl |= B43_MACCTL_PSM_JMP0;
4301 b43_write32(dev, B43_MMIO_MACCTL, macctl);
4302
Michael Buesche4d6b792007-09-18 15:39:42 -04004303 b43_dma_free(dev);
Michael Buesch5100d5a2008-03-29 21:01:16 +01004304 b43_pio_free(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004305 b43_chip_exit(dev);
Michael Bueschcb24f572008-09-03 12:12:20 +02004306 dev->phy.ops->switch_analog(dev, 0);
Michael Buesche66fee62007-12-26 17:47:10 +01004307 if (dev->wl->current_beacon) {
4308 dev_kfree_skb_any(dev->wl->current_beacon);
4309 dev->wl->current_beacon = NULL;
4310 }
4311
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004312 ssb_device_disable(dev->sdev, 0);
4313 ssb_bus_may_powerdown(dev->sdev->bus);
Michael Buesche4d6b792007-09-18 15:39:42 -04004314}
4315
4316/* Initialize a wireless core */
4317static int b43_wireless_core_init(struct b43_wldev *dev)
4318{
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004319 struct ssb_bus *bus = dev->sdev->bus;
Michael Buesche4d6b792007-09-18 15:39:42 -04004320 struct ssb_sprom *sprom = &bus->sprom;
4321 struct b43_phy *phy = &dev->phy;
4322 int err;
Michael Buescha259d6a2008-04-18 21:06:37 +02004323 u64 hf;
4324 u32 tmp;
Michael Buesche4d6b792007-09-18 15:39:42 -04004325
4326 B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
4327
4328 err = ssb_bus_powerup(bus, 0);
4329 if (err)
4330 goto out;
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004331 if (!ssb_device_is_enabled(dev->sdev)) {
Michael Buesche4d6b792007-09-18 15:39:42 -04004332 tmp = phy->gmode ? B43_TMSLOW_GMODE : 0;
4333 b43_wireless_core_reset(dev, tmp);
4334 }
4335
Michael Bueschfb111372008-09-02 13:00:34 +02004336 /* Reset all data structures. */
Michael Buesche4d6b792007-09-18 15:39:42 -04004337 setup_struct_wldev_for_init(dev);
Michael Bueschfb111372008-09-02 13:00:34 +02004338 phy->ops->prepare_structs(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004339
4340 /* Enable IRQ routing to this device. */
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004341 ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->sdev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004342
4343 b43_imcfglo_timeouts_workaround(dev);
4344 b43_bluetooth_coext_disable(dev);
Michael Bueschfb111372008-09-02 13:00:34 +02004345 if (phy->ops->prepare_hardware) {
4346 err = phy->ops->prepare_hardware(dev);
Michael Bueschef1a6282008-08-27 18:53:02 +02004347 if (err)
Michael Bueschfb111372008-09-02 13:00:34 +02004348 goto err_busdown;
Michael Bueschef1a6282008-08-27 18:53:02 +02004349 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004350 err = b43_chip_init(dev);
4351 if (err)
Michael Bueschfb111372008-09-02 13:00:34 +02004352 goto err_busdown;
Michael Buesche4d6b792007-09-18 15:39:42 -04004353 b43_shm_write16(dev, B43_SHM_SHARED,
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004354 B43_SHM_SH_WLCOREREV, dev->sdev->id.revision);
Michael Buesche4d6b792007-09-18 15:39:42 -04004355 hf = b43_hf_read(dev);
4356 if (phy->type == B43_PHYTYPE_G) {
4357 hf |= B43_HF_SYMW;
4358 if (phy->rev == 1)
4359 hf |= B43_HF_GDCW;
Larry Finger95de2842007-11-09 16:57:18 -06004360 if (sprom->boardflags_lo & B43_BFL_PACTRL)
Michael Buesche4d6b792007-09-18 15:39:42 -04004361 hf |= B43_HF_OFDMPABOOST;
Michael Buesch969d15c2009-02-20 14:27:15 +01004362 }
4363 if (phy->radio_ver == 0x2050) {
4364 if (phy->radio_rev == 6)
4365 hf |= B43_HF_4318TSSI;
4366 if (phy->radio_rev < 6)
4367 hf |= B43_HF_VCORECALC;
Michael Buesche4d6b792007-09-18 15:39:42 -04004368 }
Michael Buesch1cc8f472009-02-20 14:47:56 +01004369 if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
4370 hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
Michael Buesch1a777332009-03-04 16:41:10 +01004371#ifdef CONFIG_SSB_DRIVER_PCICORE
Michael Buesch88219052009-02-20 14:58:59 +01004372 if ((bus->bustype == SSB_BUSTYPE_PCI) &&
4373 (bus->pcicore.dev->id.revision <= 10))
4374 hf |= B43_HF_PCISCW; /* PCI slow clock workaround. */
Michael Buesch1a777332009-03-04 16:41:10 +01004375#endif
Michael Buesch25d3ef52009-02-20 15:39:21 +01004376 hf &= ~B43_HF_SKCFPUP;
Michael Buesche4d6b792007-09-18 15:39:42 -04004377 b43_hf_write(dev, hf);
4378
Michael Buesch74cfdba2007-10-28 16:19:44 +01004379 b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
4380 B43_DEFAULT_LONG_RETRY_LIMIT);
Michael Buesche4d6b792007-09-18 15:39:42 -04004381 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
4382 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2);
4383
4384 /* Disable sending probe responses from firmware.
4385 * Setting the MaxTime to one usec will always trigger
4386 * a timeout, so we never send any probe resp.
4387 * A timeout of zero is infinite. */
4388 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1);
4389
4390 b43_rate_memory_init(dev);
Michael Buesch5042c502008-04-05 15:05:00 +02004391 b43_set_phytxctl_defaults(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004392
4393 /* Minimum Contention Window */
Daniel Nguc5a079f2010-03-23 00:52:44 +13004394 if (phy->type == B43_PHYTYPE_B)
Michael Buesche4d6b792007-09-18 15:39:42 -04004395 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F);
Daniel Nguc5a079f2010-03-23 00:52:44 +13004396 else
Michael Buesche4d6b792007-09-18 15:39:42 -04004397 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF);
Michael Buesche4d6b792007-09-18 15:39:42 -04004398 /* Maximum Contention Window */
4399 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
4400
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004401 if ((dev->sdev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
4402 (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) ||
Linus Torvalds9e3bd912010-02-26 10:34:27 -08004403 dev->use_pio) {
Michael Buesch5100d5a2008-03-29 21:01:16 +01004404 dev->__using_pio_transfers = 1;
4405 err = b43_pio_init(dev);
4406 } else {
4407 dev->__using_pio_transfers = 0;
4408 err = b43_dma_init(dev);
4409 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004410 if (err)
4411 goto err_chip_exit;
Michael Buesch03b29772007-12-26 14:41:30 +01004412 b43_qos_init(dev);
Michael Bueschd59f7202008-04-03 18:56:19 +02004413 b43_set_synth_pu_delay(dev, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04004414 b43_bluetooth_coext_enable(dev);
4415
Michael Buesch1cc8f472009-02-20 14:47:56 +01004416 ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
Johannes Berg4150c572007-09-17 01:29:23 -04004417 b43_upload_card_macaddress(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004418 b43_security_init(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004419
Michael Buesch5ab95492009-09-10 20:31:46 +02004420 ieee80211_wake_queues(dev->wl->hw);
Michael Buesche4d6b792007-09-18 15:39:42 -04004421
4422 b43_set_status(dev, B43_STAT_INITIALIZED);
4423
John W. Linville84c164a2010-08-06 15:31:45 -04004424 /* Register HW RNG driver */
4425 b43_rng_init(dev->wl);
4426
Larry Finger1a8d1222007-12-14 13:59:11 +01004427out:
Michael Buesche4d6b792007-09-18 15:39:42 -04004428 return err;
4429
Michael Bueschef1a6282008-08-27 18:53:02 +02004430err_chip_exit:
Michael Buesche4d6b792007-09-18 15:39:42 -04004431 b43_chip_exit(dev);
Michael Bueschef1a6282008-08-27 18:53:02 +02004432err_busdown:
Michael Buesche4d6b792007-09-18 15:39:42 -04004433 ssb_bus_may_powerdown(bus);
4434 B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
4435 return err;
4436}
4437
Michael Buesch40faacc2007-10-28 16:29:32 +01004438static int b43_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01004439 struct ieee80211_vif *vif)
Michael Buesche4d6b792007-09-18 15:39:42 -04004440{
4441 struct b43_wl *wl = hw_to_b43_wl(hw);
4442 struct b43_wldev *dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04004443 int err = -EOPNOTSUPP;
Johannes Berg4150c572007-09-17 01:29:23 -04004444
4445 /* TODO: allow WDS/AP devices to coexist */
4446
Johannes Berg1ed32e42009-12-23 13:15:45 +01004447 if (vif->type != NL80211_IFTYPE_AP &&
4448 vif->type != NL80211_IFTYPE_MESH_POINT &&
4449 vif->type != NL80211_IFTYPE_STATION &&
4450 vif->type != NL80211_IFTYPE_WDS &&
4451 vif->type != NL80211_IFTYPE_ADHOC)
Johannes Berg4150c572007-09-17 01:29:23 -04004452 return -EOPNOTSUPP;
Michael Buesche4d6b792007-09-18 15:39:42 -04004453
4454 mutex_lock(&wl->mutex);
Johannes Berg4150c572007-09-17 01:29:23 -04004455 if (wl->operating)
Michael Buesche4d6b792007-09-18 15:39:42 -04004456 goto out_mutex_unlock;
4457
Johannes Berg1ed32e42009-12-23 13:15:45 +01004458 b43dbg(wl, "Adding Interface type %d\n", vif->type);
Michael Buesche4d6b792007-09-18 15:39:42 -04004459
4460 dev = wl->current_dev;
Johannes Berg4150c572007-09-17 01:29:23 -04004461 wl->operating = 1;
Johannes Berg1ed32e42009-12-23 13:15:45 +01004462 wl->vif = vif;
4463 wl->if_type = vif->type;
4464 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Michael Buesche4d6b792007-09-18 15:39:42 -04004465
Michael Buesche4d6b792007-09-18 15:39:42 -04004466 b43_adjust_opmode(dev);
Michael Bueschd59f7202008-04-03 18:56:19 +02004467 b43_set_pretbtt(dev);
4468 b43_set_synth_pu_delay(dev, 0);
Johannes Berg4150c572007-09-17 01:29:23 -04004469 b43_upload_card_macaddress(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004470
4471 err = 0;
Johannes Berg4150c572007-09-17 01:29:23 -04004472 out_mutex_unlock:
Michael Buesche4d6b792007-09-18 15:39:42 -04004473 mutex_unlock(&wl->mutex);
4474
4475 return err;
4476}
4477
Michael Buesch40faacc2007-10-28 16:29:32 +01004478static void b43_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01004479 struct ieee80211_vif *vif)
Michael Buesche4d6b792007-09-18 15:39:42 -04004480{
4481 struct b43_wl *wl = hw_to_b43_wl(hw);
Johannes Berg4150c572007-09-17 01:29:23 -04004482 struct b43_wldev *dev = wl->current_dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04004483
Johannes Berg1ed32e42009-12-23 13:15:45 +01004484 b43dbg(wl, "Removing Interface type %d\n", vif->type);
Michael Buesche4d6b792007-09-18 15:39:42 -04004485
4486 mutex_lock(&wl->mutex);
Johannes Berg4150c572007-09-17 01:29:23 -04004487
4488 B43_WARN_ON(!wl->operating);
Johannes Berg1ed32e42009-12-23 13:15:45 +01004489 B43_WARN_ON(wl->vif != vif);
Johannes Berg32bfd352007-12-19 01:31:26 +01004490 wl->vif = NULL;
Johannes Berg4150c572007-09-17 01:29:23 -04004491
4492 wl->operating = 0;
4493
Johannes Berg4150c572007-09-17 01:29:23 -04004494 b43_adjust_opmode(dev);
4495 memset(wl->mac_addr, 0, ETH_ALEN);
4496 b43_upload_card_macaddress(dev);
Johannes Berg4150c572007-09-17 01:29:23 -04004497
4498 mutex_unlock(&wl->mutex);
4499}
4500
Michael Buesch40faacc2007-10-28 16:29:32 +01004501static int b43_op_start(struct ieee80211_hw *hw)
Johannes Berg4150c572007-09-17 01:29:23 -04004502{
4503 struct b43_wl *wl = hw_to_b43_wl(hw);
4504 struct b43_wldev *dev = wl->current_dev;
4505 int did_init = 0;
WANG Cong923403b2007-10-16 14:29:38 -07004506 int err = 0;
Johannes Berg4150c572007-09-17 01:29:23 -04004507
Michael Buesch7be1bb62008-01-23 21:10:56 +01004508 /* Kill all old instance specific information to make sure
4509 * the card won't use it in the short timeframe between start
4510 * and mac80211 reconfiguring it. */
4511 memset(wl->bssid, 0, ETH_ALEN);
4512 memset(wl->mac_addr, 0, ETH_ALEN);
4513 wl->filter_flags = 0;
4514 wl->radiotap_enabled = 0;
Michael Buesche6f5b932008-03-05 21:18:49 +01004515 b43_qos_clear(wl);
Michael Buesch6b4bec02008-05-20 12:16:28 +02004516 wl->beacon0_uploaded = 0;
4517 wl->beacon1_uploaded = 0;
4518 wl->beacon_templates_virgin = 1;
Larry Fingerfd4973c2009-06-20 12:58:11 -05004519 wl->radio_enabled = 1;
Michael Buesch7be1bb62008-01-23 21:10:56 +01004520
Johannes Berg4150c572007-09-17 01:29:23 -04004521 mutex_lock(&wl->mutex);
4522
4523 if (b43_status(dev) < B43_STAT_INITIALIZED) {
4524 err = b43_wireless_core_init(dev);
Johannes Bergf41f3f32009-06-07 12:30:34 -05004525 if (err)
Johannes Berg4150c572007-09-17 01:29:23 -04004526 goto out_mutex_unlock;
4527 did_init = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004528 }
4529
Johannes Berg4150c572007-09-17 01:29:23 -04004530 if (b43_status(dev) < B43_STAT_STARTED) {
4531 err = b43_wireless_core_start(dev);
4532 if (err) {
4533 if (did_init)
4534 b43_wireless_core_exit(dev);
4535 goto out_mutex_unlock;
4536 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004537 }
Johannes Berg4150c572007-09-17 01:29:23 -04004538
Johannes Bergf41f3f32009-06-07 12:30:34 -05004539 /* XXX: only do if device doesn't support rfkill irq */
4540 wiphy_rfkill_start_polling(hw->wiphy);
4541
Johannes Berg4150c572007-09-17 01:29:23 -04004542 out_mutex_unlock:
4543 mutex_unlock(&wl->mutex);
4544
4545 return err;
4546}
4547
Michael Buesch40faacc2007-10-28 16:29:32 +01004548static void b43_op_stop(struct ieee80211_hw *hw)
Johannes Berg4150c572007-09-17 01:29:23 -04004549{
4550 struct b43_wl *wl = hw_to_b43_wl(hw);
4551 struct b43_wldev *dev = wl->current_dev;
4552
Michael Buescha82d9922008-04-04 21:40:06 +02004553 cancel_work_sync(&(wl->beacon_update_trigger));
Larry Finger1a8d1222007-12-14 13:59:11 +01004554
Johannes Berg4150c572007-09-17 01:29:23 -04004555 mutex_lock(&wl->mutex);
Michael Buesch36dbd952009-09-04 22:51:29 +02004556 if (b43_status(dev) >= B43_STAT_STARTED) {
4557 dev = b43_wireless_core_stop(dev);
4558 if (!dev)
4559 goto out_unlock;
4560 }
Johannes Berg4150c572007-09-17 01:29:23 -04004561 b43_wireless_core_exit(dev);
Larry Fingerfd4973c2009-06-20 12:58:11 -05004562 wl->radio_enabled = 0;
Michael Buesch36dbd952009-09-04 22:51:29 +02004563
4564out_unlock:
Michael Buesche4d6b792007-09-18 15:39:42 -04004565 mutex_unlock(&wl->mutex);
Michael Buesch18c8ade2008-08-28 19:33:40 +02004566
4567 cancel_work_sync(&(wl->txpower_adjust_work));
Michael Buesche4d6b792007-09-18 15:39:42 -04004568}
4569
Johannes Berg17741cd2008-09-11 00:02:02 +02004570static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
4571 struct ieee80211_sta *sta, bool set)
Michael Buesche66fee62007-12-26 17:47:10 +01004572{
4573 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Buesche66fee62007-12-26 17:47:10 +01004574
Felix Fietkau8f611282009-11-07 18:37:37 +01004575 /* FIXME: add locking */
Johannes Berg9d139c82008-07-09 14:40:37 +02004576 b43_update_templates(wl);
Michael Buesche66fee62007-12-26 17:47:10 +01004577
4578 return 0;
4579}
4580
Johannes Berg38968d02008-02-25 16:27:50 +01004581static void b43_op_sta_notify(struct ieee80211_hw *hw,
4582 struct ieee80211_vif *vif,
4583 enum sta_notify_cmd notify_cmd,
Johannes Berg17741cd2008-09-11 00:02:02 +02004584 struct ieee80211_sta *sta)
Johannes Berg38968d02008-02-25 16:27:50 +01004585{
4586 struct b43_wl *wl = hw_to_b43_wl(hw);
4587
4588 B43_WARN_ON(!vif || wl->vif != vif);
4589}
4590
Michael Buesch25d3ef52009-02-20 15:39:21 +01004591static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw)
4592{
4593 struct b43_wl *wl = hw_to_b43_wl(hw);
4594 struct b43_wldev *dev;
4595
4596 mutex_lock(&wl->mutex);
4597 dev = wl->current_dev;
4598 if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) {
4599 /* Disable CFP update during scan on other channels. */
4600 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_SKCFPUP);
4601 }
4602 mutex_unlock(&wl->mutex);
4603}
4604
4605static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw)
4606{
4607 struct b43_wl *wl = hw_to_b43_wl(hw);
4608 struct b43_wldev *dev;
4609
4610 mutex_lock(&wl->mutex);
4611 dev = wl->current_dev;
4612 if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) {
4613 /* Re-enable CFP update. */
4614 b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_SKCFPUP);
4615 }
4616 mutex_unlock(&wl->mutex);
4617}
4618
John W. Linville354b4f02010-04-29 15:56:06 -04004619static int b43_op_get_survey(struct ieee80211_hw *hw, int idx,
4620 struct survey_info *survey)
4621{
4622 struct b43_wl *wl = hw_to_b43_wl(hw);
4623 struct b43_wldev *dev = wl->current_dev;
4624 struct ieee80211_conf *conf = &hw->conf;
4625
4626 if (idx != 0)
4627 return -ENOENT;
4628
4629 survey->channel = conf->channel;
4630 survey->filled = SURVEY_INFO_NOISE_DBM;
4631 survey->noise = dev->stats.link_noise;
4632
4633 return 0;
4634}
4635
Michael Buesche4d6b792007-09-18 15:39:42 -04004636static const struct ieee80211_ops b43_hw_ops = {
Michael Buesch40faacc2007-10-28 16:29:32 +01004637 .tx = b43_op_tx,
4638 .conf_tx = b43_op_conf_tx,
4639 .add_interface = b43_op_add_interface,
4640 .remove_interface = b43_op_remove_interface,
4641 .config = b43_op_config,
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01004642 .bss_info_changed = b43_op_bss_info_changed,
Michael Buesch40faacc2007-10-28 16:29:32 +01004643 .configure_filter = b43_op_configure_filter,
4644 .set_key = b43_op_set_key,
gregor kowski035d0242009-08-19 22:35:45 +02004645 .update_tkip_key = b43_op_update_tkip_key,
Michael Buesch40faacc2007-10-28 16:29:32 +01004646 .get_stats = b43_op_get_stats,
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01004647 .get_tsf = b43_op_get_tsf,
4648 .set_tsf = b43_op_set_tsf,
Michael Buesch40faacc2007-10-28 16:29:32 +01004649 .start = b43_op_start,
4650 .stop = b43_op_stop,
Michael Buesche66fee62007-12-26 17:47:10 +01004651 .set_tim = b43_op_beacon_set_tim,
Johannes Berg38968d02008-02-25 16:27:50 +01004652 .sta_notify = b43_op_sta_notify,
Michael Buesch25d3ef52009-02-20 15:39:21 +01004653 .sw_scan_start = b43_op_sw_scan_start_notifier,
4654 .sw_scan_complete = b43_op_sw_scan_complete_notifier,
John W. Linville354b4f02010-04-29 15:56:06 -04004655 .get_survey = b43_op_get_survey,
Johannes Bergf41f3f32009-06-07 12:30:34 -05004656 .rfkill_poll = b43_rfkill_poll,
Michael Buesche4d6b792007-09-18 15:39:42 -04004657};
4658
4659/* Hard-reset the chip. Do not call this directly.
4660 * Use b43_controller_restart()
4661 */
4662static void b43_chip_reset(struct work_struct *work)
4663{
4664 struct b43_wldev *dev =
4665 container_of(work, struct b43_wldev, restart_work);
4666 struct b43_wl *wl = dev->wl;
4667 int err = 0;
4668 int prev_status;
4669
4670 mutex_lock(&wl->mutex);
4671
4672 prev_status = b43_status(dev);
4673 /* Bring the device down... */
Michael Buesch36dbd952009-09-04 22:51:29 +02004674 if (prev_status >= B43_STAT_STARTED) {
4675 dev = b43_wireless_core_stop(dev);
4676 if (!dev) {
4677 err = -ENODEV;
4678 goto out;
4679 }
4680 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004681 if (prev_status >= B43_STAT_INITIALIZED)
4682 b43_wireless_core_exit(dev);
4683
4684 /* ...and up again. */
4685 if (prev_status >= B43_STAT_INITIALIZED) {
4686 err = b43_wireless_core_init(dev);
4687 if (err)
4688 goto out;
4689 }
4690 if (prev_status >= B43_STAT_STARTED) {
4691 err = b43_wireless_core_start(dev);
4692 if (err) {
4693 b43_wireless_core_exit(dev);
4694 goto out;
4695 }
4696 }
Michael Buesch3bf0a322008-05-22 16:32:16 +02004697out:
4698 if (err)
4699 wl->current_dev = NULL; /* Failed to init the dev. */
Michael Buesche4d6b792007-09-18 15:39:42 -04004700 mutex_unlock(&wl->mutex);
4701 if (err)
4702 b43err(wl, "Controller restart FAILED\n");
4703 else
4704 b43info(wl, "Controller restarted\n");
4705}
4706
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004707static int b43_setup_bands(struct b43_wldev *dev,
Michael Buesch96c755a2008-01-06 00:09:46 +01004708 bool have_2ghz_phy, bool have_5ghz_phy)
Michael Buesche4d6b792007-09-18 15:39:42 -04004709{
4710 struct ieee80211_hw *hw = dev->wl->hw;
Michael Buesche4d6b792007-09-18 15:39:42 -04004711
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004712 if (have_2ghz_phy)
4713 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz;
4714 if (dev->phy.type == B43_PHYTYPE_N) {
4715 if (have_5ghz_phy)
4716 hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_nphy;
4717 } else {
4718 if (have_5ghz_phy)
4719 hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_aphy;
4720 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004721
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004722 dev->phy.supports_2ghz = have_2ghz_phy;
4723 dev->phy.supports_5ghz = have_5ghz_phy;
Michael Buesche4d6b792007-09-18 15:39:42 -04004724
4725 return 0;
4726}
4727
4728static void b43_wireless_core_detach(struct b43_wldev *dev)
4729{
4730 /* We release firmware that late to not be required to re-request
4731 * is all the time when we reinit the core. */
4732 b43_release_firmware(dev);
Michael Bueschfb111372008-09-02 13:00:34 +02004733 b43_phy_free(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004734}
4735
4736static int b43_wireless_core_attach(struct b43_wldev *dev)
4737{
4738 struct b43_wl *wl = dev->wl;
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004739 struct ssb_bus *bus = dev->sdev->bus;
Michael Buesch899110f2009-10-09 20:30:10 +02004740 struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
Michael Buesche4d6b792007-09-18 15:39:42 -04004741 int err;
Michael Buesch96c755a2008-01-06 00:09:46 +01004742 bool have_2ghz_phy = 0, have_5ghz_phy = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04004743 u32 tmp;
4744
4745 /* Do NOT do any device initialization here.
4746 * Do it in wireless_core_init() instead.
4747 * This function is for gathering basic information about the HW, only.
4748 * Also some structs may be set up here. But most likely you want to have
4749 * that in core_init(), too.
4750 */
4751
4752 err = ssb_bus_powerup(bus, 0);
4753 if (err) {
4754 b43err(wl, "Bus powerup failed\n");
4755 goto out;
4756 }
4757 /* Get the PHY type. */
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004758 if (dev->sdev->id.revision >= 5) {
Michael Buesche4d6b792007-09-18 15:39:42 -04004759 u32 tmshigh;
4760
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004761 tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
Michael Buesch96c755a2008-01-06 00:09:46 +01004762 have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
4763 have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
Michael Buesche4d6b792007-09-18 15:39:42 -04004764 } else
Michael Buesch96c755a2008-01-06 00:09:46 +01004765 B43_WARN_ON(1);
Michael Buesche4d6b792007-09-18 15:39:42 -04004766
Michael Buesch96c755a2008-01-06 00:09:46 +01004767 dev->phy.gmode = have_2ghz_phy;
Larry Fingerfd4973c2009-06-20 12:58:11 -05004768 dev->phy.radio_on = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004769 tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
4770 b43_wireless_core_reset(dev, tmp);
4771
4772 err = b43_phy_versioning(dev);
4773 if (err)
Michael Buesch21954c32007-09-27 15:31:40 +02004774 goto err_powerdown;
Michael Buesche4d6b792007-09-18 15:39:42 -04004775 /* Check if this device supports multiband. */
4776 if (!pdev ||
4777 (pdev->device != 0x4312 &&
4778 pdev->device != 0x4319 && pdev->device != 0x4324)) {
4779 /* No multiband support. */
Michael Buesch96c755a2008-01-06 00:09:46 +01004780 have_2ghz_phy = 0;
4781 have_5ghz_phy = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04004782 switch (dev->phy.type) {
4783 case B43_PHYTYPE_A:
Michael Buesch96c755a2008-01-06 00:09:46 +01004784 have_5ghz_phy = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004785 break;
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02004786 case B43_PHYTYPE_LP: //FIXME not always!
Gábor Stefanik86b28922009-08-16 20:22:41 +02004787#if 0 //FIXME enabling 5GHz causes a NULL pointer dereference
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02004788 have_5ghz_phy = 1;
Gábor Stefanik86b28922009-08-16 20:22:41 +02004789#endif
Michael Buesche4d6b792007-09-18 15:39:42 -04004790 case B43_PHYTYPE_G:
Michael Buesch96c755a2008-01-06 00:09:46 +01004791 case B43_PHYTYPE_N:
4792 have_2ghz_phy = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004793 break;
4794 default:
4795 B43_WARN_ON(1);
4796 }
4797 }
Michael Buesch96c755a2008-01-06 00:09:46 +01004798 if (dev->phy.type == B43_PHYTYPE_A) {
4799 /* FIXME */
4800 b43err(wl, "IEEE 802.11a devices are unsupported\n");
4801 err = -EOPNOTSUPP;
4802 goto err_powerdown;
4803 }
Michael Buesch2e35af12008-04-27 19:06:18 +02004804 if (1 /* disable A-PHY */) {
4805 /* FIXME: For now we disable the A-PHY on multi-PHY devices. */
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02004806 if (dev->phy.type != B43_PHYTYPE_N &&
4807 dev->phy.type != B43_PHYTYPE_LP) {
Michael Buesch2e35af12008-04-27 19:06:18 +02004808 have_2ghz_phy = 1;
4809 have_5ghz_phy = 0;
4810 }
4811 }
4812
Michael Bueschfb111372008-09-02 13:00:34 +02004813 err = b43_phy_allocate(dev);
4814 if (err)
4815 goto err_powerdown;
4816
Michael Buesch96c755a2008-01-06 00:09:46 +01004817 dev->phy.gmode = have_2ghz_phy;
Michael Buesche4d6b792007-09-18 15:39:42 -04004818 tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
4819 b43_wireless_core_reset(dev, tmp);
4820
4821 err = b43_validate_chipaccess(dev);
4822 if (err)
Michael Bueschfb111372008-09-02 13:00:34 +02004823 goto err_phy_free;
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004824 err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy);
Michael Buesche4d6b792007-09-18 15:39:42 -04004825 if (err)
Michael Bueschfb111372008-09-02 13:00:34 +02004826 goto err_phy_free;
Michael Buesche4d6b792007-09-18 15:39:42 -04004827
4828 /* Now set some default "current_dev" */
4829 if (!wl->current_dev)
4830 wl->current_dev = dev;
4831 INIT_WORK(&dev->restart_work, b43_chip_reset);
4832
Michael Bueschcb24f572008-09-03 12:12:20 +02004833 dev->phy.ops->switch_analog(dev, 0);
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004834 ssb_device_disable(dev->sdev, 0);
Michael Buesche4d6b792007-09-18 15:39:42 -04004835 ssb_bus_may_powerdown(bus);
4836
4837out:
4838 return err;
4839
Michael Bueschfb111372008-09-02 13:00:34 +02004840err_phy_free:
4841 b43_phy_free(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004842err_powerdown:
4843 ssb_bus_may_powerdown(bus);
4844 return err;
4845}
4846
4847static void b43_one_core_detach(struct ssb_device *dev)
4848{
4849 struct b43_wldev *wldev;
4850 struct b43_wl *wl;
4851
Michael Buesch3bf0a322008-05-22 16:32:16 +02004852 /* Do not cancel ieee80211-workqueue based work here.
4853 * See comment in b43_remove(). */
4854
Michael Buesche4d6b792007-09-18 15:39:42 -04004855 wldev = ssb_get_drvdata(dev);
4856 wl = wldev->wl;
Michael Buesche4d6b792007-09-18 15:39:42 -04004857 b43_debugfs_remove_device(wldev);
4858 b43_wireless_core_detach(wldev);
4859 list_del(&wldev->list);
4860 wl->nr_devs--;
4861 ssb_set_drvdata(dev, NULL);
4862 kfree(wldev);
4863}
4864
4865static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
4866{
4867 struct b43_wldev *wldev;
Michael Buesche4d6b792007-09-18 15:39:42 -04004868 int err = -ENOMEM;
4869
Michael Buesche4d6b792007-09-18 15:39:42 -04004870 wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
4871 if (!wldev)
4872 goto out;
4873
Linus Torvalds9e3bd912010-02-26 10:34:27 -08004874 wldev->use_pio = b43_modparam_pio;
Rafał Miłeckidedb1eb2011-05-14 00:04:38 +02004875 wldev->sdev = dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04004876 wldev->wl = wl;
4877 b43_set_status(wldev, B43_STAT_UNINIT);
4878 wldev->bad_frames_preempt = modparam_bad_frames_preempt;
Michael Buesche4d6b792007-09-18 15:39:42 -04004879 INIT_LIST_HEAD(&wldev->list);
4880
4881 err = b43_wireless_core_attach(wldev);
4882 if (err)
4883 goto err_kfree_wldev;
4884
4885 list_add(&wldev->list, &wl->devlist);
4886 wl->nr_devs++;
4887 ssb_set_drvdata(dev, wldev);
4888 b43_debugfs_add_device(wldev);
4889
4890 out:
4891 return err;
4892
4893 err_kfree_wldev:
4894 kfree(wldev);
4895 return err;
4896}
4897
Michael Buesch9fc38452008-04-19 16:53:00 +02004898#define IS_PDEV(pdev, _vendor, _device, _subvendor, _subdevice) ( \
4899 (pdev->vendor == PCI_VENDOR_ID_##_vendor) && \
4900 (pdev->device == _device) && \
4901 (pdev->subsystem_vendor == PCI_VENDOR_ID_##_subvendor) && \
4902 (pdev->subsystem_device == _subdevice) )
4903
Michael Buesche4d6b792007-09-18 15:39:42 -04004904static void b43_sprom_fixup(struct ssb_bus *bus)
4905{
Michael Buesch1855ba72008-04-18 20:51:41 +02004906 struct pci_dev *pdev;
4907
Michael Buesche4d6b792007-09-18 15:39:42 -04004908 /* boardflags workarounds */
4909 if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
4910 bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
Larry Finger95de2842007-11-09 16:57:18 -06004911 bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST;
Michael Buesche4d6b792007-09-18 15:39:42 -04004912 if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
4913 bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
Larry Finger95de2842007-11-09 16:57:18 -06004914 bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
Michael Buesch1855ba72008-04-18 20:51:41 +02004915 if (bus->bustype == SSB_BUSTYPE_PCI) {
4916 pdev = bus->host_pci;
Michael Buesch9fc38452008-04-19 16:53:00 +02004917 if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) ||
Larry Finger430cd472008-08-14 18:57:11 -05004918 IS_PDEV(pdev, BROADCOM, 0x4320, DELL, 0x0003) ||
Larry Finger570bdfb2008-09-26 08:23:00 -05004919 IS_PDEV(pdev, BROADCOM, 0x4320, HP, 0x12f8) ||
Michael Buesch9fc38452008-04-19 16:53:00 +02004920 IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) ||
Larry Fingera58d4522008-08-10 10:19:33 -05004921 IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0014) ||
Larry Finger3bb91bf2008-09-19 14:47:38 -05004922 IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013) ||
4923 IS_PDEV(pdev, BROADCOM, 0x4320, MOTOROLA, 0x7010))
Michael Buesch1855ba72008-04-18 20:51:41 +02004924 bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST;
4925 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004926}
4927
4928static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
4929{
4930 struct ieee80211_hw *hw = wl->hw;
4931
4932 ssb_set_devtypedata(dev, NULL);
4933 ieee80211_free_hw(hw);
4934}
4935
Rafał Miłecki0355a342011-05-17 14:00:01 +02004936static struct b43_wl *b43_wireless_init(struct ssb_device *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04004937{
4938 struct ssb_sprom *sprom = &dev->bus->sprom;
4939 struct ieee80211_hw *hw;
4940 struct b43_wl *wl;
Michael Buesche4d6b792007-09-18 15:39:42 -04004941
4942 hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
4943 if (!hw) {
4944 b43err(NULL, "Could not allocate ieee80211 device\n");
Rafał Miłecki0355a342011-05-17 14:00:01 +02004945 return ERR_PTR(-ENOMEM);
Michael Buesche4d6b792007-09-18 15:39:42 -04004946 }
Michael Buesch403a3a12009-06-08 21:04:57 +02004947 wl = hw_to_b43_wl(hw);
Michael Buesche4d6b792007-09-18 15:39:42 -04004948
4949 /* fill hw info */
Johannes Berg605a0bd2008-07-15 10:10:01 +02004950 hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
John W. Linvillef5c044e2010-04-30 15:37:00 -04004951 IEEE80211_HW_SIGNAL_DBM;
Bruno Randolf566bfe52008-05-08 19:15:40 +02004952
Luis R. Rodriguezf59ac042008-08-29 16:26:43 -07004953 hw->wiphy->interface_modes =
4954 BIT(NL80211_IFTYPE_AP) |
4955 BIT(NL80211_IFTYPE_MESH_POINT) |
4956 BIT(NL80211_IFTYPE_STATION) |
4957 BIT(NL80211_IFTYPE_WDS) |
4958 BIT(NL80211_IFTYPE_ADHOC);
4959
Michael Buesch403a3a12009-06-08 21:04:57 +02004960 hw->queues = modparam_qos ? 4 : 1;
4961 wl->mac80211_initially_registered_queues = hw->queues;
Johannes Berge6a98542008-10-21 12:40:02 +02004962 hw->max_rates = 2;
Michael Buesche4d6b792007-09-18 15:39:42 -04004963 SET_IEEE80211_DEV(hw, dev->dev);
Larry Finger95de2842007-11-09 16:57:18 -06004964 if (is_valid_ether_addr(sprom->et1mac))
4965 SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
Michael Buesche4d6b792007-09-18 15:39:42 -04004966 else
Larry Finger95de2842007-11-09 16:57:18 -06004967 SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
Michael Buesche4d6b792007-09-18 15:39:42 -04004968
Michael Buesch403a3a12009-06-08 21:04:57 +02004969 /* Initialize struct b43_wl */
Michael Buesche4d6b792007-09-18 15:39:42 -04004970 wl->hw = hw;
Michael Buesche4d6b792007-09-18 15:39:42 -04004971 mutex_init(&wl->mutex);
Michael Buesch36dbd952009-09-04 22:51:29 +02004972 spin_lock_init(&wl->hardirq_lock);
Michael Buesche4d6b792007-09-18 15:39:42 -04004973 INIT_LIST_HEAD(&wl->devlist);
Michael Buescha82d9922008-04-04 21:40:06 +02004974 INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
Michael Buesch18c8ade2008-08-28 19:33:40 +02004975 INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
Michael Bueschf5d40ee2009-09-04 22:53:18 +02004976 INIT_WORK(&wl->tx_work, b43_tx_work);
4977 skb_queue_head_init(&wl->tx_queue);
Michael Buesche4d6b792007-09-18 15:39:42 -04004978
Michael Buesch060210f2009-01-25 15:49:59 +01004979 b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n",
4980 dev->bus->chip_id, dev->id.revision);
Rafał Miłecki0355a342011-05-17 14:00:01 +02004981 return wl;
Michael Buesche4d6b792007-09-18 15:39:42 -04004982}
4983
Rafał Miłecki5ee9c6a2011-05-09 00:21:18 +02004984static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id)
Michael Buesche4d6b792007-09-18 15:39:42 -04004985{
4986 struct b43_wl *wl;
4987 int err;
4988 int first = 0;
4989
4990 wl = ssb_get_devtypedata(dev);
4991 if (!wl) {
4992 /* Probing the first core. Must setup common struct b43_wl */
4993 first = 1;
Rafał Miłecki0355a342011-05-17 14:00:01 +02004994 b43_sprom_fixup(dev->bus);
4995 wl = b43_wireless_init(dev);
4996 if (IS_ERR(wl)) {
4997 err = PTR_ERR(wl);
Michael Buesche4d6b792007-09-18 15:39:42 -04004998 goto out;
Rafał Miłecki0355a342011-05-17 14:00:01 +02004999 }
5000 ssb_set_devtypedata(dev, wl);
5001 B43_WARN_ON(ssb_get_devtypedata(dev) != wl);
Michael Buesche4d6b792007-09-18 15:39:42 -04005002 }
5003 err = b43_one_core_attach(dev, wl);
5004 if (err)
5005 goto err_wireless_exit;
5006
5007 if (first) {
5008 err = ieee80211_register_hw(wl->hw);
5009 if (err)
5010 goto err_one_core_detach;
Michael Buescha78b3bb2009-09-11 21:44:05 +02005011 b43_leds_register(wl->current_dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04005012 }
5013
5014 out:
5015 return err;
5016
5017 err_one_core_detach:
5018 b43_one_core_detach(dev);
5019 err_wireless_exit:
5020 if (first)
5021 b43_wireless_exit(dev, wl);
5022 return err;
5023}
5024
Rafał Miłecki5ee9c6a2011-05-09 00:21:18 +02005025static void b43_ssb_remove(struct ssb_device *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04005026{
5027 struct b43_wl *wl = ssb_get_devtypedata(dev);
5028 struct b43_wldev *wldev = ssb_get_drvdata(dev);
5029
Michael Buesch3bf0a322008-05-22 16:32:16 +02005030 /* We must cancel any work here before unregistering from ieee80211,
5031 * as the ieee80211 unreg will destroy the workqueue. */
5032 cancel_work_sync(&wldev->restart_work);
5033
Michael Buesche4d6b792007-09-18 15:39:42 -04005034 B43_WARN_ON(!wl);
Michael Buesch403a3a12009-06-08 21:04:57 +02005035 if (wl->current_dev == wldev) {
5036 /* Restore the queues count before unregistering, because firmware detect
5037 * might have modified it. Restoring is important, so the networking
5038 * stack can properly free resources. */
5039 wl->hw->queues = wl->mac80211_initially_registered_queues;
Albert Herranz82905ac2009-09-16 00:26:19 +02005040 b43_leds_stop(wldev);
Michael Buesche4d6b792007-09-18 15:39:42 -04005041 ieee80211_unregister_hw(wl->hw);
Michael Buesch403a3a12009-06-08 21:04:57 +02005042 }
Michael Buesche4d6b792007-09-18 15:39:42 -04005043
5044 b43_one_core_detach(dev);
5045
5046 if (list_empty(&wl->devlist)) {
Michael Buesch727c9882009-10-01 15:54:32 +02005047 b43_leds_unregister(wl);
Michael Buesche4d6b792007-09-18 15:39:42 -04005048 /* Last core on the chip unregistered.
5049 * We can destroy common struct b43_wl.
5050 */
5051 b43_wireless_exit(dev, wl);
5052 }
5053}
5054
5055/* Perform a hardware reset. This can be called from any context. */
5056void b43_controller_restart(struct b43_wldev *dev, const char *reason)
5057{
5058 /* Must avoid requeueing, if we are in shutdown. */
5059 if (b43_status(dev) < B43_STAT_INITIALIZED)
5060 return;
5061 b43info(dev->wl, "Controller RESET (%s) ...\n", reason);
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04005062 ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
Michael Buesche4d6b792007-09-18 15:39:42 -04005063}
5064
Michael Buesche4d6b792007-09-18 15:39:42 -04005065static struct ssb_driver b43_ssb_driver = {
5066 .name = KBUILD_MODNAME,
5067 .id_table = b43_ssb_tbl,
Rafał Miłecki5ee9c6a2011-05-09 00:21:18 +02005068 .probe = b43_ssb_probe,
5069 .remove = b43_ssb_remove,
Michael Buesche4d6b792007-09-18 15:39:42 -04005070};
5071
Michael Buesch26bc7832008-02-09 00:18:35 +01005072static void b43_print_driverinfo(void)
5073{
5074 const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005075 *feat_leds = "", *feat_sdio = "";
Michael Buesch26bc7832008-02-09 00:18:35 +01005076
5077#ifdef CONFIG_B43_PCI_AUTOSELECT
5078 feat_pci = "P";
5079#endif
5080#ifdef CONFIG_B43_PCMCIA
5081 feat_pcmcia = "M";
5082#endif
Rafał Miłecki692d2c02010-12-07 21:56:00 +01005083#ifdef CONFIG_B43_PHY_N
Michael Buesch26bc7832008-02-09 00:18:35 +01005084 feat_nphy = "N";
5085#endif
5086#ifdef CONFIG_B43_LEDS
5087 feat_leds = "L";
5088#endif
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005089#ifdef CONFIG_B43_SDIO
5090 feat_sdio = "S";
5091#endif
Michael Buesch26bc7832008-02-09 00:18:35 +01005092 printk(KERN_INFO "Broadcom 43xx driver loaded "
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005093 "[ Features: %s%s%s%s%s, Firmware-ID: "
Michael Buesch26bc7832008-02-09 00:18:35 +01005094 B43_SUPPORTED_FIRMWARE_ID " ]\n",
5095 feat_pci, feat_pcmcia, feat_nphy,
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005096 feat_leds, feat_sdio);
Michael Buesch26bc7832008-02-09 00:18:35 +01005097}
5098
Michael Buesche4d6b792007-09-18 15:39:42 -04005099static int __init b43_init(void)
5100{
5101 int err;
5102
5103 b43_debugfs_init();
5104 err = b43_pcmcia_init();
5105 if (err)
5106 goto err_dfs_exit;
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005107 err = b43_sdio_init();
Michael Buesche4d6b792007-09-18 15:39:42 -04005108 if (err)
5109 goto err_pcmcia_exit;
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005110 err = ssb_driver_register(&b43_ssb_driver);
5111 if (err)
5112 goto err_sdio_exit;
Michael Buesch26bc7832008-02-09 00:18:35 +01005113 b43_print_driverinfo();
Michael Buesche4d6b792007-09-18 15:39:42 -04005114
5115 return err;
5116
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005117err_sdio_exit:
5118 b43_sdio_exit();
Michael Buesche4d6b792007-09-18 15:39:42 -04005119err_pcmcia_exit:
5120 b43_pcmcia_exit();
5121err_dfs_exit:
5122 b43_debugfs_exit();
5123 return err;
5124}
5125
5126static void __exit b43_exit(void)
5127{
5128 ssb_driver_unregister(&b43_ssb_driver);
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005129 b43_sdio_exit();
Michael Buesche4d6b792007-09-18 15:39:42 -04005130 b43_pcmcia_exit();
5131 b43_debugfs_exit();
5132}
5133
5134module_init(b43_init)
5135module_exit(b43_exit)