blob: 881afff86bd363b824c751c92f20fcbf12269b2b [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>
45#include <asm/unaligned.h>
46
47#include "b43.h"
48#include "main.h"
49#include "debugfs.h"
Michael Bueschef1a6282008-08-27 18:53:02 +020050#include "phy_common.h"
51#include "phy_g.h"
Michael Buesch3d0da752008-08-30 02:27:19 +020052#include "phy_n.h"
Michael Buesche4d6b792007-09-18 15:39:42 -040053#include "dma.h"
Michael Buesch5100d5a2008-03-29 21:01:16 +010054#include "pio.h"
Michael Buesche4d6b792007-09-18 15:39:42 -040055#include "sysfs.h"
56#include "xmit.h"
Michael Buesche4d6b792007-09-18 15:39:42 -040057#include "lo.h"
58#include "pcmcia.h"
Albert Herranz3dbba8e2009-09-10 19:34:49 +020059#include "sdio.h"
60#include <linux/mmc/sdio_func.h>
Michael Buesche4d6b792007-09-18 15:39:42 -040061
62MODULE_DESCRIPTION("Broadcom B43 wireless driver");
63MODULE_AUTHOR("Martin Langer");
64MODULE_AUTHOR("Stefano Brivio");
65MODULE_AUTHOR("Michael Buesch");
Gábor Stefanik0136e512009-08-28 22:32:17 +020066MODULE_AUTHOR("Gábor Stefanik");
Michael Buesche4d6b792007-09-18 15:39:42 -040067MODULE_LICENSE("GPL");
68
Michael Buesch9c7d99d2008-02-09 10:23:49 +010069MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
Tim Gardner6021e082010-01-07 11:10:38 -070070MODULE_FIRMWARE("b43/ucode11.fw");
71MODULE_FIRMWARE("b43/ucode13.fw");
72MODULE_FIRMWARE("b43/ucode14.fw");
73MODULE_FIRMWARE("b43/ucode15.fw");
74MODULE_FIRMWARE("b43/ucode5.fw");
75MODULE_FIRMWARE("b43/ucode9.fw");
Michael Buesche4d6b792007-09-18 15:39:42 -040076
77static int modparam_bad_frames_preempt;
78module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
79MODULE_PARM_DESC(bad_frames_preempt,
80 "enable(1) / disable(0) Bad Frames Preemption");
81
Michael Buesche4d6b792007-09-18 15:39:42 -040082static char modparam_fwpostfix[16];
83module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
84MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
85
Michael Buesche4d6b792007-09-18 15:39:42 -040086static int modparam_hwpctl;
87module_param_named(hwpctl, modparam_hwpctl, int, 0444);
88MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)");
89
90static int modparam_nohwcrypt;
91module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
92MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
93
gregor kowski035d0242009-08-19 22:35:45 +020094static int modparam_hwtkip;
95module_param_named(hwtkip, modparam_hwtkip, int, 0444);
96MODULE_PARM_DESC(hwtkip, "Enable hardware tkip.");
97
Michael Buesch403a3a12009-06-08 21:04:57 +020098static int modparam_qos = 1;
99module_param_named(qos, modparam_qos, int, 0444);
Michael Buesche6f5b932008-03-05 21:18:49 +0100100MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
101
Michael Buesch1855ba72008-04-18 20:51:41 +0200102static int modparam_btcoex = 1;
103module_param_named(btcoex, modparam_btcoex, int, 0444);
Gábor Stefanikc71dbd32009-08-28 22:34:21 +0200104MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistence (default on)");
Michael Buesch1855ba72008-04-18 20:51:41 +0200105
Michael Buesch060210f2009-01-25 15:49:59 +0100106int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
107module_param_named(verbose, b43_modparam_verbose, int, 0644);
108MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
109
Larry Fingerb02914a2009-12-10 17:35:01 -0600110static int modparam_pio;
111module_param_named(pio, modparam_pio, int, 0444);
112MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
Michael Buesche6f5b932008-03-05 21:18:49 +0100113
Michael Buesche4d6b792007-09-18 15:39:42 -0400114static const struct ssb_device_id b43_ssb_tbl[] = {
115 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
116 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
117 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
118 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
119 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
Michael Bueschd5c71e42008-01-04 17:06:29 +0100120 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
Larry Finger013978b2007-11-26 10:29:47 -0600121 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
Michael Buesch6b1c7c62008-12-25 00:39:28 +0100122 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15),
Johannes Berg92d61282008-12-24 12:44:09 +0100123 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16),
Michael Buesche4d6b792007-09-18 15:39:42 -0400124 SSB_DEVTABLE_END
125};
126
127MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
128
129/* Channel and ratetables are shared for all devices.
130 * They can't be const, because ieee80211 puts some precalculated
131 * data in there. This data is the same for all devices, so we don't
132 * get concurrency issues */
133#define RATETAB_ENT(_rateid, _flags) \
Johannes Berg8318d782008-01-24 19:38:38 +0100134 { \
135 .bitrate = B43_RATE_TO_BASE100KBPS(_rateid), \
136 .hw_value = (_rateid), \
137 .flags = (_flags), \
Michael Buesche4d6b792007-09-18 15:39:42 -0400138 }
Johannes Berg8318d782008-01-24 19:38:38 +0100139
140/*
141 * NOTE: When changing this, sync with xmit.c's
142 * b43_plcp_get_bitrate_idx_* functions!
143 */
Michael Buesche4d6b792007-09-18 15:39:42 -0400144static struct ieee80211_rate __b43_ratetable[] = {
Johannes Berg8318d782008-01-24 19:38:38 +0100145 RATETAB_ENT(B43_CCK_RATE_1MB, 0),
146 RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
147 RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
148 RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
149 RATETAB_ENT(B43_OFDM_RATE_6MB, 0),
150 RATETAB_ENT(B43_OFDM_RATE_9MB, 0),
151 RATETAB_ENT(B43_OFDM_RATE_12MB, 0),
152 RATETAB_ENT(B43_OFDM_RATE_18MB, 0),
153 RATETAB_ENT(B43_OFDM_RATE_24MB, 0),
154 RATETAB_ENT(B43_OFDM_RATE_36MB, 0),
155 RATETAB_ENT(B43_OFDM_RATE_48MB, 0),
156 RATETAB_ENT(B43_OFDM_RATE_54MB, 0),
Michael Buesche4d6b792007-09-18 15:39:42 -0400157};
158
159#define b43_a_ratetable (__b43_ratetable + 4)
160#define b43_a_ratetable_size 8
161#define b43_b_ratetable (__b43_ratetable + 0)
162#define b43_b_ratetable_size 4
163#define b43_g_ratetable (__b43_ratetable + 0)
164#define b43_g_ratetable_size 12
165
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100166#define CHAN4G(_channel, _freq, _flags) { \
167 .band = IEEE80211_BAND_2GHZ, \
168 .center_freq = (_freq), \
169 .hw_value = (_channel), \
170 .flags = (_flags), \
171 .max_antenna_gain = 0, \
172 .max_power = 30, \
173}
Michael Buesch96c755a2008-01-06 00:09:46 +0100174static struct ieee80211_channel b43_2ghz_chantable[] = {
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100175 CHAN4G(1, 2412, 0),
176 CHAN4G(2, 2417, 0),
177 CHAN4G(3, 2422, 0),
178 CHAN4G(4, 2427, 0),
179 CHAN4G(5, 2432, 0),
180 CHAN4G(6, 2437, 0),
181 CHAN4G(7, 2442, 0),
182 CHAN4G(8, 2447, 0),
183 CHAN4G(9, 2452, 0),
184 CHAN4G(10, 2457, 0),
185 CHAN4G(11, 2462, 0),
186 CHAN4G(12, 2467, 0),
187 CHAN4G(13, 2472, 0),
188 CHAN4G(14, 2484, 0),
189};
190#undef CHAN4G
191
192#define CHAN5G(_channel, _flags) { \
193 .band = IEEE80211_BAND_5GHZ, \
194 .center_freq = 5000 + (5 * (_channel)), \
195 .hw_value = (_channel), \
196 .flags = (_flags), \
197 .max_antenna_gain = 0, \
198 .max_power = 30, \
199}
200static struct ieee80211_channel b43_5ghz_nphy_chantable[] = {
201 CHAN5G(32, 0), CHAN5G(34, 0),
202 CHAN5G(36, 0), CHAN5G(38, 0),
203 CHAN5G(40, 0), CHAN5G(42, 0),
204 CHAN5G(44, 0), CHAN5G(46, 0),
205 CHAN5G(48, 0), CHAN5G(50, 0),
206 CHAN5G(52, 0), CHAN5G(54, 0),
207 CHAN5G(56, 0), CHAN5G(58, 0),
208 CHAN5G(60, 0), CHAN5G(62, 0),
209 CHAN5G(64, 0), CHAN5G(66, 0),
210 CHAN5G(68, 0), CHAN5G(70, 0),
211 CHAN5G(72, 0), CHAN5G(74, 0),
212 CHAN5G(76, 0), CHAN5G(78, 0),
213 CHAN5G(80, 0), CHAN5G(82, 0),
214 CHAN5G(84, 0), CHAN5G(86, 0),
215 CHAN5G(88, 0), CHAN5G(90, 0),
216 CHAN5G(92, 0), CHAN5G(94, 0),
217 CHAN5G(96, 0), CHAN5G(98, 0),
218 CHAN5G(100, 0), CHAN5G(102, 0),
219 CHAN5G(104, 0), CHAN5G(106, 0),
220 CHAN5G(108, 0), CHAN5G(110, 0),
221 CHAN5G(112, 0), CHAN5G(114, 0),
222 CHAN5G(116, 0), CHAN5G(118, 0),
223 CHAN5G(120, 0), CHAN5G(122, 0),
224 CHAN5G(124, 0), CHAN5G(126, 0),
225 CHAN5G(128, 0), CHAN5G(130, 0),
226 CHAN5G(132, 0), CHAN5G(134, 0),
227 CHAN5G(136, 0), CHAN5G(138, 0),
228 CHAN5G(140, 0), CHAN5G(142, 0),
229 CHAN5G(144, 0), CHAN5G(145, 0),
230 CHAN5G(146, 0), CHAN5G(147, 0),
231 CHAN5G(148, 0), CHAN5G(149, 0),
232 CHAN5G(150, 0), CHAN5G(151, 0),
233 CHAN5G(152, 0), CHAN5G(153, 0),
234 CHAN5G(154, 0), CHAN5G(155, 0),
235 CHAN5G(156, 0), CHAN5G(157, 0),
236 CHAN5G(158, 0), CHAN5G(159, 0),
237 CHAN5G(160, 0), CHAN5G(161, 0),
238 CHAN5G(162, 0), CHAN5G(163, 0),
239 CHAN5G(164, 0), CHAN5G(165, 0),
240 CHAN5G(166, 0), CHAN5G(168, 0),
241 CHAN5G(170, 0), CHAN5G(172, 0),
242 CHAN5G(174, 0), CHAN5G(176, 0),
243 CHAN5G(178, 0), CHAN5G(180, 0),
244 CHAN5G(182, 0), CHAN5G(184, 0),
245 CHAN5G(186, 0), CHAN5G(188, 0),
246 CHAN5G(190, 0), CHAN5G(192, 0),
247 CHAN5G(194, 0), CHAN5G(196, 0),
248 CHAN5G(198, 0), CHAN5G(200, 0),
249 CHAN5G(202, 0), CHAN5G(204, 0),
250 CHAN5G(206, 0), CHAN5G(208, 0),
251 CHAN5G(210, 0), CHAN5G(212, 0),
252 CHAN5G(214, 0), CHAN5G(216, 0),
253 CHAN5G(218, 0), CHAN5G(220, 0),
254 CHAN5G(222, 0), CHAN5G(224, 0),
255 CHAN5G(226, 0), CHAN5G(228, 0),
Michael Buesche4d6b792007-09-18 15:39:42 -0400256};
257
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100258static struct ieee80211_channel b43_5ghz_aphy_chantable[] = {
259 CHAN5G(34, 0), CHAN5G(36, 0),
260 CHAN5G(38, 0), CHAN5G(40, 0),
261 CHAN5G(42, 0), CHAN5G(44, 0),
262 CHAN5G(46, 0), CHAN5G(48, 0),
263 CHAN5G(52, 0), CHAN5G(56, 0),
264 CHAN5G(60, 0), CHAN5G(64, 0),
265 CHAN5G(100, 0), CHAN5G(104, 0),
266 CHAN5G(108, 0), CHAN5G(112, 0),
267 CHAN5G(116, 0), CHAN5G(120, 0),
268 CHAN5G(124, 0), CHAN5G(128, 0),
269 CHAN5G(132, 0), CHAN5G(136, 0),
270 CHAN5G(140, 0), CHAN5G(149, 0),
271 CHAN5G(153, 0), CHAN5G(157, 0),
272 CHAN5G(161, 0), CHAN5G(165, 0),
273 CHAN5G(184, 0), CHAN5G(188, 0),
274 CHAN5G(192, 0), CHAN5G(196, 0),
275 CHAN5G(200, 0), CHAN5G(204, 0),
276 CHAN5G(208, 0), CHAN5G(212, 0),
277 CHAN5G(216, 0),
278};
279#undef CHAN5G
280
281static struct ieee80211_supported_band b43_band_5GHz_nphy = {
282 .band = IEEE80211_BAND_5GHZ,
283 .channels = b43_5ghz_nphy_chantable,
284 .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable),
285 .bitrates = b43_a_ratetable,
286 .n_bitrates = b43_a_ratetable_size,
Michael Buesche4d6b792007-09-18 15:39:42 -0400287};
Johannes Berg8318d782008-01-24 19:38:38 +0100288
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100289static struct ieee80211_supported_band b43_band_5GHz_aphy = {
290 .band = IEEE80211_BAND_5GHZ,
291 .channels = b43_5ghz_aphy_chantable,
292 .n_channels = ARRAY_SIZE(b43_5ghz_aphy_chantable),
293 .bitrates = b43_a_ratetable,
294 .n_bitrates = b43_a_ratetable_size,
Johannes Berg8318d782008-01-24 19:38:38 +0100295};
Michael Buesche4d6b792007-09-18 15:39:42 -0400296
Johannes Berg8318d782008-01-24 19:38:38 +0100297static struct ieee80211_supported_band b43_band_2GHz = {
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100298 .band = IEEE80211_BAND_2GHZ,
299 .channels = b43_2ghz_chantable,
300 .n_channels = ARRAY_SIZE(b43_2ghz_chantable),
301 .bitrates = b43_g_ratetable,
302 .n_bitrates = b43_g_ratetable_size,
Johannes Berg8318d782008-01-24 19:38:38 +0100303};
304
Michael Buesche4d6b792007-09-18 15:39:42 -0400305static void b43_wireless_core_exit(struct b43_wldev *dev);
306static int b43_wireless_core_init(struct b43_wldev *dev);
Michael Buesch36dbd952009-09-04 22:51:29 +0200307static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev);
Michael Buesche4d6b792007-09-18 15:39:42 -0400308static int b43_wireless_core_start(struct b43_wldev *dev);
309
310static int b43_ratelimit(struct b43_wl *wl)
311{
312 if (!wl || !wl->current_dev)
313 return 1;
314 if (b43_status(wl->current_dev) < B43_STAT_STARTED)
315 return 1;
316 /* We are up and running.
317 * Ratelimit the messages to avoid DoS over the net. */
318 return net_ratelimit();
319}
320
321void b43info(struct b43_wl *wl, const char *fmt, ...)
322{
323 va_list args;
324
Michael Buesch060210f2009-01-25 15:49:59 +0100325 if (b43_modparam_verbose < B43_VERBOSITY_INFO)
326 return;
Michael Buesche4d6b792007-09-18 15:39:42 -0400327 if (!b43_ratelimit(wl))
328 return;
329 va_start(args, fmt);
330 printk(KERN_INFO "b43-%s: ",
331 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
332 vprintk(fmt, args);
333 va_end(args);
334}
335
336void b43err(struct b43_wl *wl, const char *fmt, ...)
337{
338 va_list args;
339
Michael Buesch060210f2009-01-25 15:49:59 +0100340 if (b43_modparam_verbose < B43_VERBOSITY_ERROR)
341 return;
Michael Buesche4d6b792007-09-18 15:39:42 -0400342 if (!b43_ratelimit(wl))
343 return;
344 va_start(args, fmt);
345 printk(KERN_ERR "b43-%s ERROR: ",
346 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
347 vprintk(fmt, args);
348 va_end(args);
349}
350
351void b43warn(struct b43_wl *wl, const char *fmt, ...)
352{
353 va_list args;
354
Michael Buesch060210f2009-01-25 15:49:59 +0100355 if (b43_modparam_verbose < B43_VERBOSITY_WARN)
356 return;
Michael Buesche4d6b792007-09-18 15:39:42 -0400357 if (!b43_ratelimit(wl))
358 return;
359 va_start(args, fmt);
360 printk(KERN_WARNING "b43-%s warning: ",
361 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
362 vprintk(fmt, args);
363 va_end(args);
364}
365
Michael Buesche4d6b792007-09-18 15:39:42 -0400366void b43dbg(struct b43_wl *wl, const char *fmt, ...)
367{
368 va_list args;
369
Michael Buesch060210f2009-01-25 15:49:59 +0100370 if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
371 return;
Michael Buesche4d6b792007-09-18 15:39:42 -0400372 va_start(args, fmt);
373 printk(KERN_DEBUG "b43-%s debug: ",
374 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
375 vprintk(fmt, args);
376 va_end(args);
377}
Michael Buesche4d6b792007-09-18 15:39:42 -0400378
379static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
380{
381 u32 macctl;
382
383 B43_WARN_ON(offset % 4 != 0);
384
385 macctl = b43_read32(dev, B43_MMIO_MACCTL);
386 if (macctl & B43_MACCTL_BE)
387 val = swab32(val);
388
389 b43_write32(dev, B43_MMIO_RAM_CONTROL, offset);
390 mmiowb();
391 b43_write32(dev, B43_MMIO_RAM_DATA, val);
392}
393
Michael Buesch280d0e12007-12-26 18:26:17 +0100394static inline void b43_shm_control_word(struct b43_wldev *dev,
395 u16 routing, u16 offset)
Michael Buesche4d6b792007-09-18 15:39:42 -0400396{
397 u32 control;
398
399 /* "offset" is the WORD offset. */
Michael Buesche4d6b792007-09-18 15:39:42 -0400400 control = routing;
401 control <<= 16;
402 control |= offset;
403 b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
404}
405
Michael Buesch69eddc82009-09-04 22:57:26 +0200406u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
Michael Buesche4d6b792007-09-18 15:39:42 -0400407{
408 u32 ret;
409
410 if (routing == B43_SHM_SHARED) {
411 B43_WARN_ON(offset & 0x0001);
412 if (offset & 0x0003) {
413 /* Unaligned access */
414 b43_shm_control_word(dev, routing, offset >> 2);
415 ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
Michael Buesche4d6b792007-09-18 15:39:42 -0400416 b43_shm_control_word(dev, routing, (offset >> 2) + 1);
Michael Bueschf62ae6c2009-07-31 20:51:41 +0200417 ret |= ((u32)b43_read16(dev, B43_MMIO_SHM_DATA)) << 16;
Michael Buesche4d6b792007-09-18 15:39:42 -0400418
Michael Buesch280d0e12007-12-26 18:26:17 +0100419 goto out;
Michael Buesche4d6b792007-09-18 15:39:42 -0400420 }
421 offset >>= 2;
422 }
423 b43_shm_control_word(dev, routing, offset);
424 ret = b43_read32(dev, B43_MMIO_SHM_DATA);
Michael Buesch280d0e12007-12-26 18:26:17 +0100425out:
Michael Buesch6bbc3212008-06-19 19:33:51 +0200426 return ret;
427}
428
Michael Buesch69eddc82009-09-04 22:57:26 +0200429u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
Michael Buesche4d6b792007-09-18 15:39:42 -0400430{
431 u16 ret;
432
433 if (routing == B43_SHM_SHARED) {
434 B43_WARN_ON(offset & 0x0001);
435 if (offset & 0x0003) {
436 /* Unaligned access */
437 b43_shm_control_word(dev, routing, offset >> 2);
438 ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
439
Michael Buesch280d0e12007-12-26 18:26:17 +0100440 goto out;
Michael Buesche4d6b792007-09-18 15:39:42 -0400441 }
442 offset >>= 2;
443 }
444 b43_shm_control_word(dev, routing, offset);
445 ret = b43_read16(dev, B43_MMIO_SHM_DATA);
Michael Buesch280d0e12007-12-26 18:26:17 +0100446out:
Michael Buesch6bbc3212008-06-19 19:33:51 +0200447 return ret;
448}
449
Michael Buesch69eddc82009-09-04 22:57:26 +0200450void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
Michael Buesche4d6b792007-09-18 15:39:42 -0400451{
452 if (routing == B43_SHM_SHARED) {
453 B43_WARN_ON(offset & 0x0001);
454 if (offset & 0x0003) {
455 /* Unaligned access */
456 b43_shm_control_word(dev, routing, offset >> 2);
Michael Buesche4d6b792007-09-18 15:39:42 -0400457 b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
Michael Bueschf62ae6c2009-07-31 20:51:41 +0200458 value & 0xFFFF);
Michael Buesche4d6b792007-09-18 15:39:42 -0400459 b43_shm_control_word(dev, routing, (offset >> 2) + 1);
Michael Bueschf62ae6c2009-07-31 20:51:41 +0200460 b43_write16(dev, B43_MMIO_SHM_DATA,
461 (value >> 16) & 0xFFFF);
Michael Buesch6bbc3212008-06-19 19:33:51 +0200462 return;
Michael Buesche4d6b792007-09-18 15:39:42 -0400463 }
464 offset >>= 2;
465 }
466 b43_shm_control_word(dev, routing, offset);
Michael Buesche4d6b792007-09-18 15:39:42 -0400467 b43_write32(dev, B43_MMIO_SHM_DATA, value);
Michael Buesch6bbc3212008-06-19 19:33:51 +0200468}
469
Michael Buesch69eddc82009-09-04 22:57:26 +0200470void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
Michael Buesch6bbc3212008-06-19 19:33:51 +0200471{
472 if (routing == B43_SHM_SHARED) {
473 B43_WARN_ON(offset & 0x0001);
474 if (offset & 0x0003) {
475 /* Unaligned access */
476 b43_shm_control_word(dev, routing, offset >> 2);
477 b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
478 return;
479 }
480 offset >>= 2;
481 }
482 b43_shm_control_word(dev, routing, offset);
483 b43_write16(dev, B43_MMIO_SHM_DATA, value);
484}
485
Michael Buesche4d6b792007-09-18 15:39:42 -0400486/* Read HostFlags */
John Daiker99da1852009-02-24 02:16:42 -0800487u64 b43_hf_read(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -0400488{
Michael Buesch35f0d352008-02-13 14:31:08 +0100489 u64 ret;
Michael Buesche4d6b792007-09-18 15:39:42 -0400490
491 ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
492 ret <<= 16;
Michael Buesch35f0d352008-02-13 14:31:08 +0100493 ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI);
494 ret <<= 16;
Michael Buesche4d6b792007-09-18 15:39:42 -0400495 ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);
496
497 return ret;
498}
499
500/* Write HostFlags */
Michael Buesch35f0d352008-02-13 14:31:08 +0100501void b43_hf_write(struct b43_wldev *dev, u64 value)
Michael Buesche4d6b792007-09-18 15:39:42 -0400502{
Michael Buesch35f0d352008-02-13 14:31:08 +0100503 u16 lo, mi, hi;
504
505 lo = (value & 0x00000000FFFFULL);
506 mi = (value & 0x0000FFFF0000ULL) >> 16;
507 hi = (value & 0xFFFF00000000ULL) >> 32;
508 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO, lo);
509 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI, mi);
510 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi);
Michael Buesche4d6b792007-09-18 15:39:42 -0400511}
512
Michael Buesch403a3a12009-06-08 21:04:57 +0200513/* Read the firmware capabilities bitmask (Opensource firmware only) */
514static u16 b43_fwcapa_read(struct b43_wldev *dev)
515{
516 B43_WARN_ON(!dev->fw.opensource);
517 return b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_FWCAPA);
518}
519
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100520void b43_tsf_read(struct b43_wldev *dev, u64 *tsf)
Michael Buesche4d6b792007-09-18 15:39:42 -0400521{
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100522 u32 low, high;
Michael Buesche4d6b792007-09-18 15:39:42 -0400523
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100524 B43_WARN_ON(dev->dev->id.revision < 3);
Michael Buesche4d6b792007-09-18 15:39:42 -0400525
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100526 /* The hardware guarantees us an atomic read, if we
527 * read the low register first. */
528 low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW);
529 high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);
Michael Buesche4d6b792007-09-18 15:39:42 -0400530
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100531 *tsf = high;
532 *tsf <<= 32;
533 *tsf |= low;
Michael Buesche4d6b792007-09-18 15:39:42 -0400534}
535
536static void b43_time_lock(struct b43_wldev *dev)
537{
538 u32 macctl;
539
540 macctl = b43_read32(dev, B43_MMIO_MACCTL);
541 macctl |= B43_MACCTL_TBTTHOLD;
542 b43_write32(dev, B43_MMIO_MACCTL, macctl);
543 /* Commit the write */
544 b43_read32(dev, B43_MMIO_MACCTL);
545}
546
547static void b43_time_unlock(struct b43_wldev *dev)
548{
549 u32 macctl;
550
551 macctl = b43_read32(dev, B43_MMIO_MACCTL);
552 macctl &= ~B43_MACCTL_TBTTHOLD;
553 b43_write32(dev, B43_MMIO_MACCTL, macctl);
554 /* Commit the write */
555 b43_read32(dev, B43_MMIO_MACCTL);
556}
557
558static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
559{
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100560 u32 low, high;
Michael Buesche4d6b792007-09-18 15:39:42 -0400561
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100562 B43_WARN_ON(dev->dev->id.revision < 3);
Michael Buesche4d6b792007-09-18 15:39:42 -0400563
Michael Buesch3ebbbb52008-12-19 22:51:57 +0100564 low = tsf;
565 high = (tsf >> 32);
566 /* The hardware guarantees us an atomic write, if we
567 * write the low register first. */
568 b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, low);
569 mmiowb();
570 b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, high);
571 mmiowb();
Michael Buesche4d6b792007-09-18 15:39:42 -0400572}
573
574void b43_tsf_write(struct b43_wldev *dev, u64 tsf)
575{
576 b43_time_lock(dev);
577 b43_tsf_write_locked(dev, tsf);
578 b43_time_unlock(dev);
579}
580
581static
John Daiker99da1852009-02-24 02:16:42 -0800582void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 *mac)
Michael Buesche4d6b792007-09-18 15:39:42 -0400583{
584 static const u8 zero_addr[ETH_ALEN] = { 0 };
585 u16 data;
586
587 if (!mac)
588 mac = zero_addr;
589
590 offset |= 0x0020;
591 b43_write16(dev, B43_MMIO_MACFILTER_CONTROL, offset);
592
593 data = mac[0];
594 data |= mac[1] << 8;
595 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
596 data = mac[2];
597 data |= mac[3] << 8;
598 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
599 data = mac[4];
600 data |= mac[5] << 8;
601 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
602}
603
604static void b43_write_mac_bssid_templates(struct b43_wldev *dev)
605{
606 const u8 *mac;
607 const u8 *bssid;
608 u8 mac_bssid[ETH_ALEN * 2];
609 int i;
610 u32 tmp;
611
612 bssid = dev->wl->bssid;
613 mac = dev->wl->mac_addr;
614
615 b43_macfilter_set(dev, B43_MACFILTER_BSSID, bssid);
616
617 memcpy(mac_bssid, mac, ETH_ALEN);
618 memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
619
620 /* Write our MAC address and BSSID to template ram */
621 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
622 tmp = (u32) (mac_bssid[i + 0]);
623 tmp |= (u32) (mac_bssid[i + 1]) << 8;
624 tmp |= (u32) (mac_bssid[i + 2]) << 16;
625 tmp |= (u32) (mac_bssid[i + 3]) << 24;
626 b43_ram_write(dev, 0x20 + i, tmp);
627 }
628}
629
Johannes Berg4150c572007-09-17 01:29:23 -0400630static void b43_upload_card_macaddress(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -0400631{
Michael Buesche4d6b792007-09-18 15:39:42 -0400632 b43_write_mac_bssid_templates(dev);
Johannes Berg4150c572007-09-17 01:29:23 -0400633 b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr);
Michael Buesche4d6b792007-09-18 15:39:42 -0400634}
635
636static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
637{
638 /* slot_time is in usec. */
639 if (dev->phy.type != B43_PHYTYPE_G)
640 return;
641 b43_write16(dev, 0x684, 510 + slot_time);
642 b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
643}
644
645static void b43_short_slot_timing_enable(struct b43_wldev *dev)
646{
647 b43_set_slot_time(dev, 9);
Michael Buesche4d6b792007-09-18 15:39:42 -0400648}
649
650static void b43_short_slot_timing_disable(struct b43_wldev *dev)
651{
652 b43_set_slot_time(dev, 20);
Michael Buesche4d6b792007-09-18 15:39:42 -0400653}
654
Michael Buesche4d6b792007-09-18 15:39:42 -0400655/* DummyTransmission function, as documented on
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200656 * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission
Michael Buesche4d6b792007-09-18 15:39:42 -0400657 */
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200658void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
Michael Buesche4d6b792007-09-18 15:39:42 -0400659{
660 struct b43_phy *phy = &dev->phy;
661 unsigned int i, max_loop;
662 u16 value;
663 u32 buffer[5] = {
664 0x00000000,
665 0x00D40000,
666 0x00000000,
667 0x01000000,
668 0x00000000,
669 };
670
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200671 if (ofdm) {
Michael Buesche4d6b792007-09-18 15:39:42 -0400672 max_loop = 0x1E;
673 buffer[0] = 0x000201CC;
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200674 } else {
Michael Buesche4d6b792007-09-18 15:39:42 -0400675 max_loop = 0xFA;
676 buffer[0] = 0x000B846E;
Michael Buesche4d6b792007-09-18 15:39:42 -0400677 }
678
679 for (i = 0; i < 5; i++)
680 b43_ram_write(dev, i * 4, buffer[i]);
681
Michael Buesche4d6b792007-09-18 15:39:42 -0400682 b43_write16(dev, 0x0568, 0x0000);
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200683 if (dev->dev->id.revision < 11)
684 b43_write16(dev, 0x07C0, 0x0000);
685 else
686 b43_write16(dev, 0x07C0, 0x0100);
687 value = (ofdm ? 0x41 : 0x40);
Michael Buesche4d6b792007-09-18 15:39:42 -0400688 b43_write16(dev, 0x050C, value);
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200689 if ((phy->type == B43_PHYTYPE_N) || (phy->type == B43_PHYTYPE_LP))
690 b43_write16(dev, 0x0514, 0x1A02);
Michael Buesche4d6b792007-09-18 15:39:42 -0400691 b43_write16(dev, 0x0508, 0x0000);
692 b43_write16(dev, 0x050A, 0x0000);
693 b43_write16(dev, 0x054C, 0x0000);
694 b43_write16(dev, 0x056A, 0x0014);
695 b43_write16(dev, 0x0568, 0x0826);
696 b43_write16(dev, 0x0500, 0x0000);
Gábor Stefanik2f19c282009-08-13 16:51:51 +0200697 if (!pa_on && (phy->type == B43_PHYTYPE_N)) {
698 //SPEC TODO
699 }
700
701 switch (phy->type) {
702 case B43_PHYTYPE_N:
703 b43_write16(dev, 0x0502, 0x00D0);
704 break;
705 case B43_PHYTYPE_LP:
706 b43_write16(dev, 0x0502, 0x0050);
707 break;
708 default:
709 b43_write16(dev, 0x0502, 0x0030);
710 }
Michael Buesche4d6b792007-09-18 15:39:42 -0400711
712 if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
713 b43_radio_write16(dev, 0x0051, 0x0017);
714 for (i = 0x00; i < max_loop; i++) {
715 value = b43_read16(dev, 0x050E);
716 if (value & 0x0080)
717 break;
718 udelay(10);
719 }
720 for (i = 0x00; i < 0x0A; i++) {
721 value = b43_read16(dev, 0x050E);
722 if (value & 0x0400)
723 break;
724 udelay(10);
725 }
Larry Finger1d280dd2008-09-29 14:19:29 -0500726 for (i = 0x00; i < 0x19; i++) {
Michael Buesche4d6b792007-09-18 15:39:42 -0400727 value = b43_read16(dev, 0x0690);
728 if (!(value & 0x0100))
729 break;
730 udelay(10);
731 }
732 if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
733 b43_radio_write16(dev, 0x0051, 0x0037);
734}
735
736static void key_write(struct b43_wldev *dev,
John Daiker99da1852009-02-24 02:16:42 -0800737 u8 index, u8 algorithm, const u8 *key)
Michael Buesche4d6b792007-09-18 15:39:42 -0400738{
739 unsigned int i;
740 u32 offset;
741 u16 value;
742 u16 kidx;
743
744 /* Key index/algo block */
745 kidx = b43_kidx_to_fw(dev, index);
746 value = ((kidx << 4) | algorithm);
747 b43_shm_write16(dev, B43_SHM_SHARED,
748 B43_SHM_SH_KEYIDXBLOCK + (kidx * 2), value);
749
750 /* Write the key to the Key Table Pointer offset */
751 offset = dev->ktp + (index * B43_SEC_KEYSIZE);
752 for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
753 value = key[i];
754 value |= (u16) (key[i + 1]) << 8;
755 b43_shm_write16(dev, B43_SHM_SHARED, offset + i, value);
756 }
757}
758
John Daiker99da1852009-02-24 02:16:42 -0800759static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
Michael Buesche4d6b792007-09-18 15:39:42 -0400760{
761 u32 addrtmp[2] = { 0, 0, };
Michael Buesch66d2d082009-08-06 10:36:50 +0200762 u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
Michael Buesche4d6b792007-09-18 15:39:42 -0400763
764 if (b43_new_kidx_api(dev))
Michael Buesch66d2d082009-08-06 10:36:50 +0200765 pairwise_keys_start = B43_NR_GROUP_KEYS;
Michael Buesche4d6b792007-09-18 15:39:42 -0400766
Michael Buesch66d2d082009-08-06 10:36:50 +0200767 B43_WARN_ON(index < pairwise_keys_start);
768 /* We have four default TX keys and possibly four default RX keys.
Michael Buesche4d6b792007-09-18 15:39:42 -0400769 * Physical mac 0 is mapped to physical key 4 or 8, depending
770 * on the firmware version.
771 * So we must adjust the index here.
772 */
Michael Buesch66d2d082009-08-06 10:36:50 +0200773 index -= pairwise_keys_start;
774 B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);
Michael Buesche4d6b792007-09-18 15:39:42 -0400775
776 if (addr) {
777 addrtmp[0] = addr[0];
778 addrtmp[0] |= ((u32) (addr[1]) << 8);
779 addrtmp[0] |= ((u32) (addr[2]) << 16);
780 addrtmp[0] |= ((u32) (addr[3]) << 24);
781 addrtmp[1] = addr[4];
782 addrtmp[1] |= ((u32) (addr[5]) << 8);
783 }
784
Michael Buesch66d2d082009-08-06 10:36:50 +0200785 /* Receive match transmitter address (RCMTA) mechanism */
786 b43_shm_write32(dev, B43_SHM_RCMTA,
787 (index * 2) + 0, addrtmp[0]);
788 b43_shm_write16(dev, B43_SHM_RCMTA,
789 (index * 2) + 1, addrtmp[1]);
Michael Buesche4d6b792007-09-18 15:39:42 -0400790}
791
gregor kowski035d0242009-08-19 22:35:45 +0200792/* The ucode will use phase1 key with TEK key to decrypt rx packets.
793 * When a packet is received, the iv32 is checked.
794 * - if it doesn't the packet is returned without modification (and software
795 * decryption can be done). That's what happen when iv16 wrap.
796 * - if it does, the rc4 key is computed, and decryption is tried.
797 * Either it will success and B43_RX_MAC_DEC is returned,
798 * either it fails and B43_RX_MAC_DEC|B43_RX_MAC_DECERR is returned
799 * and the packet is not usable (it got modified by the ucode).
800 * So in order to never have B43_RX_MAC_DECERR, we should provide
801 * a iv32 and phase1key that match. Because we drop packets in case of
802 * B43_RX_MAC_DECERR, if we have a correct iv32 but a wrong phase1key, all
803 * packets will be lost without higher layer knowing (ie no resync possible
804 * until next wrap).
805 *
806 * NOTE : this should support 50 key like RCMTA because
807 * (B43_SHM_SH_KEYIDXBLOCK - B43_SHM_SH_TKIPTSCTTAK)/14 = 50
808 */
809static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32,
810 u16 *phase1key)
811{
812 unsigned int i;
813 u32 offset;
814 u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
815
816 if (!modparam_hwtkip)
817 return;
818
819 if (b43_new_kidx_api(dev))
820 pairwise_keys_start = B43_NR_GROUP_KEYS;
821
822 B43_WARN_ON(index < pairwise_keys_start);
823 /* We have four default TX keys and possibly four default RX keys.
824 * Physical mac 0 is mapped to physical key 4 or 8, depending
825 * on the firmware version.
826 * So we must adjust the index here.
827 */
828 index -= pairwise_keys_start;
829 B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);
830
831 if (b43_debug(dev, B43_DBG_KEYS)) {
832 b43dbg(dev->wl, "rx_tkip_phase1_write : idx 0x%x, iv32 0x%x\n",
833 index, iv32);
834 }
835 /* Write the key to the RX tkip shared mem */
836 offset = B43_SHM_SH_TKIPTSCTTAK + index * (10 + 4);
837 for (i = 0; i < 10; i += 2) {
838 b43_shm_write16(dev, B43_SHM_SHARED, offset + i,
839 phase1key ? phase1key[i / 2] : 0);
840 }
841 b43_shm_write16(dev, B43_SHM_SHARED, offset + i, iv32);
842 b43_shm_write16(dev, B43_SHM_SHARED, offset + i + 2, iv32 >> 16);
843}
844
845static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
846 struct ieee80211_key_conf *keyconf, const u8 *addr,
847 u32 iv32, u16 *phase1key)
848{
849 struct b43_wl *wl = hw_to_b43_wl(hw);
850 struct b43_wldev *dev;
851 int index = keyconf->hw_key_idx;
852
853 if (B43_WARN_ON(!modparam_hwtkip))
854 return;
855
856 mutex_lock(&wl->mutex);
857
858 dev = wl->current_dev;
859 if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
860 goto out_unlock;
861
862 keymac_write(dev, index, NULL); /* First zero out mac to avoid race */
863
864 rx_tkip_phase1_write(dev, index, iv32, phase1key);
865 keymac_write(dev, index, addr);
866
867out_unlock:
868 mutex_unlock(&wl->mutex);
869}
870
Michael Buesche4d6b792007-09-18 15:39:42 -0400871static void do_key_write(struct b43_wldev *dev,
872 u8 index, u8 algorithm,
John Daiker99da1852009-02-24 02:16:42 -0800873 const u8 *key, size_t key_len, const u8 *mac_addr)
Michael Buesche4d6b792007-09-18 15:39:42 -0400874{
875 u8 buf[B43_SEC_KEYSIZE] = { 0, };
Michael Buesch66d2d082009-08-06 10:36:50 +0200876 u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
Michael Buesche4d6b792007-09-18 15:39:42 -0400877
878 if (b43_new_kidx_api(dev))
Michael Buesch66d2d082009-08-06 10:36:50 +0200879 pairwise_keys_start = B43_NR_GROUP_KEYS;
Michael Buesche4d6b792007-09-18 15:39:42 -0400880
Michael Buesch66d2d082009-08-06 10:36:50 +0200881 B43_WARN_ON(index >= ARRAY_SIZE(dev->key));
Michael Buesche4d6b792007-09-18 15:39:42 -0400882 B43_WARN_ON(key_len > B43_SEC_KEYSIZE);
883
Michael Buesch66d2d082009-08-06 10:36:50 +0200884 if (index >= pairwise_keys_start)
Michael Buesche4d6b792007-09-18 15:39:42 -0400885 keymac_write(dev, index, NULL); /* First zero out mac. */
gregor kowski035d0242009-08-19 22:35:45 +0200886 if (algorithm == B43_SEC_ALGO_TKIP) {
887 /*
888 * We should provide an initial iv32, phase1key pair.
889 * We could start with iv32=0 and compute the corresponding
890 * phase1key, but this means calling ieee80211_get_tkip_key
891 * with a fake skb (or export other tkip function).
892 * Because we are lazy we hope iv32 won't start with
893 * 0xffffffff and let's b43_op_update_tkip_key provide a
894 * correct pair.
895 */
896 rx_tkip_phase1_write(dev, index, 0xffffffff, (u16*)buf);
897 } else if (index >= pairwise_keys_start) /* clear it */
898 rx_tkip_phase1_write(dev, index, 0, NULL);
Michael Buesche4d6b792007-09-18 15:39:42 -0400899 if (key)
900 memcpy(buf, key, key_len);
901 key_write(dev, index, algorithm, buf);
Michael Buesch66d2d082009-08-06 10:36:50 +0200902 if (index >= pairwise_keys_start)
Michael Buesche4d6b792007-09-18 15:39:42 -0400903 keymac_write(dev, index, mac_addr);
904
905 dev->key[index].algorithm = algorithm;
906}
907
908static int b43_key_write(struct b43_wldev *dev,
909 int index, u8 algorithm,
John Daiker99da1852009-02-24 02:16:42 -0800910 const u8 *key, size_t key_len,
911 const u8 *mac_addr,
Michael Buesche4d6b792007-09-18 15:39:42 -0400912 struct ieee80211_key_conf *keyconf)
913{
914 int i;
Michael Buesch66d2d082009-08-06 10:36:50 +0200915 int pairwise_keys_start;
Michael Buesche4d6b792007-09-18 15:39:42 -0400916
gregor kowski035d0242009-08-19 22:35:45 +0200917 /* For ALG_TKIP the key is encoded as a 256-bit (32 byte) data block:
918 * - Temporal Encryption Key (128 bits)
919 * - Temporal Authenticator Tx MIC Key (64 bits)
920 * - Temporal Authenticator Rx MIC Key (64 bits)
921 *
922 * Hardware only store TEK
923 */
924 if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32)
925 key_len = 16;
Michael Buesche4d6b792007-09-18 15:39:42 -0400926 if (key_len > B43_SEC_KEYSIZE)
927 return -EINVAL;
Michael Buesch66d2d082009-08-06 10:36:50 +0200928 for (i = 0; i < ARRAY_SIZE(dev->key); i++) {
Michael Buesche4d6b792007-09-18 15:39:42 -0400929 /* Check that we don't already have this key. */
930 B43_WARN_ON(dev->key[i].keyconf == keyconf);
931 }
932 if (index < 0) {
Michael Buesche808e582008-12-19 21:30:52 +0100933 /* Pairwise key. Get an empty slot for the key. */
Michael Buesche4d6b792007-09-18 15:39:42 -0400934 if (b43_new_kidx_api(dev))
Michael Buesch66d2d082009-08-06 10:36:50 +0200935 pairwise_keys_start = B43_NR_GROUP_KEYS;
Michael Buesche4d6b792007-09-18 15:39:42 -0400936 else
Michael Buesch66d2d082009-08-06 10:36:50 +0200937 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
938 for (i = pairwise_keys_start;
939 i < pairwise_keys_start + B43_NR_PAIRWISE_KEYS;
940 i++) {
941 B43_WARN_ON(i >= ARRAY_SIZE(dev->key));
Michael Buesche4d6b792007-09-18 15:39:42 -0400942 if (!dev->key[i].keyconf) {
943 /* found empty */
944 index = i;
945 break;
946 }
947 }
948 if (index < 0) {
Michael Buesche808e582008-12-19 21:30:52 +0100949 b43warn(dev->wl, "Out of hardware key memory\n");
Michael Buesche4d6b792007-09-18 15:39:42 -0400950 return -ENOSPC;
951 }
952 } else
953 B43_WARN_ON(index > 3);
954
955 do_key_write(dev, index, algorithm, key, key_len, mac_addr);
956 if ((index <= 3) && !b43_new_kidx_api(dev)) {
957 /* Default RX key */
958 B43_WARN_ON(mac_addr);
959 do_key_write(dev, index + 4, algorithm, key, key_len, NULL);
960 }
961 keyconf->hw_key_idx = index;
962 dev->key[index].keyconf = keyconf;
963
964 return 0;
965}
966
967static int b43_key_clear(struct b43_wldev *dev, int index)
968{
Michael Buesch66d2d082009-08-06 10:36:50 +0200969 if (B43_WARN_ON((index < 0) || (index >= ARRAY_SIZE(dev->key))))
Michael Buesche4d6b792007-09-18 15:39:42 -0400970 return -EINVAL;
971 do_key_write(dev, index, B43_SEC_ALGO_NONE,
972 NULL, B43_SEC_KEYSIZE, NULL);
973 if ((index <= 3) && !b43_new_kidx_api(dev)) {
974 do_key_write(dev, index + 4, B43_SEC_ALGO_NONE,
975 NULL, B43_SEC_KEYSIZE, NULL);
976 }
977 dev->key[index].keyconf = NULL;
978
979 return 0;
980}
981
982static void b43_clear_keys(struct b43_wldev *dev)
983{
Michael Buesch66d2d082009-08-06 10:36:50 +0200984 int i, count;
Michael Buesche4d6b792007-09-18 15:39:42 -0400985
Michael Buesch66d2d082009-08-06 10:36:50 +0200986 if (b43_new_kidx_api(dev))
987 count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
988 else
989 count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
990 for (i = 0; i < count; i++)
Michael Buesche4d6b792007-09-18 15:39:42 -0400991 b43_key_clear(dev, i);
992}
993
Michael Buesch9cf7f242008-12-19 20:24:30 +0100994static void b43_dump_keymemory(struct b43_wldev *dev)
995{
Michael Buesch66d2d082009-08-06 10:36:50 +0200996 unsigned int i, index, count, offset, pairwise_keys_start;
Michael Buesch9cf7f242008-12-19 20:24:30 +0100997 u8 mac[ETH_ALEN];
998 u16 algo;
999 u32 rcmta0;
1000 u16 rcmta1;
1001 u64 hf;
1002 struct b43_key *key;
1003
1004 if (!b43_debug(dev, B43_DBG_KEYS))
1005 return;
1006
1007 hf = b43_hf_read(dev);
1008 b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n",
1009 !!(hf & B43_HF_USEDEFKEYS));
Michael Buesch66d2d082009-08-06 10:36:50 +02001010 if (b43_new_kidx_api(dev)) {
1011 pairwise_keys_start = B43_NR_GROUP_KEYS;
1012 count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
1013 } else {
1014 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
1015 count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
1016 }
1017 for (index = 0; index < count; index++) {
Michael Buesch9cf7f242008-12-19 20:24:30 +01001018 key = &(dev->key[index]);
1019 printk(KERN_DEBUG "Key slot %02u: %s",
1020 index, (key->keyconf == NULL) ? " " : "*");
1021 offset = dev->ktp + (index * B43_SEC_KEYSIZE);
1022 for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
1023 u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
1024 printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
1025 }
1026
1027 algo = b43_shm_read16(dev, B43_SHM_SHARED,
1028 B43_SHM_SH_KEYIDXBLOCK + (index * 2));
1029 printk(" Algo: %04X/%02X", algo, key->algorithm);
1030
Michael Buesch66d2d082009-08-06 10:36:50 +02001031 if (index >= pairwise_keys_start) {
gregor kowski035d0242009-08-19 22:35:45 +02001032 if (key->algorithm == B43_SEC_ALGO_TKIP) {
1033 printk(" TKIP: ");
1034 offset = B43_SHM_SH_TKIPTSCTTAK + (index - 4) * (10 + 4);
1035 for (i = 0; i < 14; i += 2) {
1036 u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
1037 printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
1038 }
1039 }
Michael Buesch9cf7f242008-12-19 20:24:30 +01001040 rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
Michael Buesch66d2d082009-08-06 10:36:50 +02001041 ((index - pairwise_keys_start) * 2) + 0);
Michael Buesch9cf7f242008-12-19 20:24:30 +01001042 rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
Michael Buesch66d2d082009-08-06 10:36:50 +02001043 ((index - pairwise_keys_start) * 2) + 1);
Michael Buesch9cf7f242008-12-19 20:24:30 +01001044 *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
1045 *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
Johannes Berge91d8332009-07-15 17:21:41 +02001046 printk(" MAC: %pM", mac);
Michael Buesch9cf7f242008-12-19 20:24:30 +01001047 } else
1048 printk(" DEFAULT KEY");
1049 printk("\n");
1050 }
1051}
1052
Michael Buesche4d6b792007-09-18 15:39:42 -04001053void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
1054{
1055 u32 macctl;
1056 u16 ucstat;
1057 bool hwps;
1058 bool awake;
1059 int i;
1060
1061 B43_WARN_ON((ps_flags & B43_PS_ENABLED) &&
1062 (ps_flags & B43_PS_DISABLED));
1063 B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP));
1064
1065 if (ps_flags & B43_PS_ENABLED) {
1066 hwps = 1;
1067 } else if (ps_flags & B43_PS_DISABLED) {
1068 hwps = 0;
1069 } else {
1070 //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
1071 // and thus is not an AP and we are associated, set bit 25
1072 }
1073 if (ps_flags & B43_PS_AWAKE) {
1074 awake = 1;
1075 } else if (ps_flags & B43_PS_ASLEEP) {
1076 awake = 0;
1077 } else {
1078 //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
1079 // or we are associated, or FIXME, or the latest PS-Poll packet sent was
1080 // successful, set bit26
1081 }
1082
1083/* FIXME: For now we force awake-on and hwps-off */
1084 hwps = 0;
1085 awake = 1;
1086
1087 macctl = b43_read32(dev, B43_MMIO_MACCTL);
1088 if (hwps)
1089 macctl |= B43_MACCTL_HWPS;
1090 else
1091 macctl &= ~B43_MACCTL_HWPS;
1092 if (awake)
1093 macctl |= B43_MACCTL_AWAKE;
1094 else
1095 macctl &= ~B43_MACCTL_AWAKE;
1096 b43_write32(dev, B43_MMIO_MACCTL, macctl);
1097 /* Commit write */
1098 b43_read32(dev, B43_MMIO_MACCTL);
1099 if (awake && dev->dev->id.revision >= 5) {
1100 /* Wait for the microcode to wake up. */
1101 for (i = 0; i < 100; i++) {
1102 ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
1103 B43_SHM_SH_UCODESTAT);
1104 if (ucstat != B43_SHM_SH_UCODESTAT_SLEEP)
1105 break;
1106 udelay(10);
1107 }
1108 }
1109}
1110
Michael Buesche4d6b792007-09-18 15:39:42 -04001111void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
1112{
1113 u32 tmslow;
1114 u32 macctl;
1115
1116 flags |= B43_TMSLOW_PHYCLKEN;
1117 flags |= B43_TMSLOW_PHYRESET;
1118 ssb_device_enable(dev->dev, flags);
1119 msleep(2); /* Wait for the PLL to turn on. */
1120
1121 /* Now take the PHY out of Reset again */
1122 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
1123 tmslow |= SSB_TMSLOW_FGC;
1124 tmslow &= ~B43_TMSLOW_PHYRESET;
1125 ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
1126 ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
1127 msleep(1);
1128 tmslow &= ~SSB_TMSLOW_FGC;
1129 ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
1130 ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
1131 msleep(1);
1132
Michael Bueschfb111372008-09-02 13:00:34 +02001133 /* Turn Analog ON, but only if we already know the PHY-type.
1134 * This protects against very early setup where we don't know the
1135 * PHY-type, yet. wireless_core_reset will be called once again later,
1136 * when we know the PHY-type. */
1137 if (dev->phy.ops)
Michael Bueschcb24f572008-09-03 12:12:20 +02001138 dev->phy.ops->switch_analog(dev, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04001139
1140 macctl = b43_read32(dev, B43_MMIO_MACCTL);
1141 macctl &= ~B43_MACCTL_GMODE;
1142 if (flags & B43_TMSLOW_GMODE)
1143 macctl |= B43_MACCTL_GMODE;
1144 macctl |= B43_MACCTL_IHR_ENABLED;
1145 b43_write32(dev, B43_MMIO_MACCTL, macctl);
1146}
1147
1148static void handle_irq_transmit_status(struct b43_wldev *dev)
1149{
1150 u32 v0, v1;
1151 u16 tmp;
1152 struct b43_txstatus stat;
1153
1154 while (1) {
1155 v0 = b43_read32(dev, B43_MMIO_XMITSTAT_0);
1156 if (!(v0 & 0x00000001))
1157 break;
1158 v1 = b43_read32(dev, B43_MMIO_XMITSTAT_1);
1159
1160 stat.cookie = (v0 >> 16);
1161 stat.seq = (v1 & 0x0000FFFF);
1162 stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
1163 tmp = (v0 & 0x0000FFFF);
1164 stat.frame_count = ((tmp & 0xF000) >> 12);
1165 stat.rts_count = ((tmp & 0x0F00) >> 8);
1166 stat.supp_reason = ((tmp & 0x001C) >> 2);
1167 stat.pm_indicated = !!(tmp & 0x0080);
1168 stat.intermediate = !!(tmp & 0x0040);
1169 stat.for_ampdu = !!(tmp & 0x0020);
1170 stat.acked = !!(tmp & 0x0002);
1171
1172 b43_handle_txstatus(dev, &stat);
1173 }
1174}
1175
1176static void drain_txstatus_queue(struct b43_wldev *dev)
1177{
1178 u32 dummy;
1179
1180 if (dev->dev->id.revision < 5)
1181 return;
1182 /* Read all entries from the microcode TXstatus FIFO
1183 * and throw them away.
1184 */
1185 while (1) {
1186 dummy = b43_read32(dev, B43_MMIO_XMITSTAT_0);
1187 if (!(dummy & 0x00000001))
1188 break;
1189 dummy = b43_read32(dev, B43_MMIO_XMITSTAT_1);
1190 }
1191}
1192
1193static u32 b43_jssi_read(struct b43_wldev *dev)
1194{
1195 u32 val = 0;
1196
1197 val = b43_shm_read16(dev, B43_SHM_SHARED, 0x08A);
1198 val <<= 16;
1199 val |= b43_shm_read16(dev, B43_SHM_SHARED, 0x088);
1200
1201 return val;
1202}
1203
1204static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
1205{
1206 b43_shm_write16(dev, B43_SHM_SHARED, 0x088, (jssi & 0x0000FFFF));
1207 b43_shm_write16(dev, B43_SHM_SHARED, 0x08A, (jssi & 0xFFFF0000) >> 16);
1208}
1209
1210static void b43_generate_noise_sample(struct b43_wldev *dev)
1211{
1212 b43_jssi_write(dev, 0x7F7F7F7F);
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01001213 b43_write32(dev, B43_MMIO_MACCMD,
1214 b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE);
Michael Buesche4d6b792007-09-18 15:39:42 -04001215}
1216
1217static void b43_calculate_link_quality(struct b43_wldev *dev)
1218{
1219 /* Top half of Link Quality calculation. */
1220
Michael Bueschef1a6282008-08-27 18:53:02 +02001221 if (dev->phy.type != B43_PHYTYPE_G)
1222 return;
Michael Buesche4d6b792007-09-18 15:39:42 -04001223 if (dev->noisecalc.calculation_running)
1224 return;
Michael Buesche4d6b792007-09-18 15:39:42 -04001225 dev->noisecalc.calculation_running = 1;
1226 dev->noisecalc.nr_samples = 0;
1227
1228 b43_generate_noise_sample(dev);
1229}
1230
1231static void handle_irq_noise(struct b43_wldev *dev)
1232{
Michael Bueschef1a6282008-08-27 18:53:02 +02001233 struct b43_phy_g *phy = dev->phy.g;
Michael Buesche4d6b792007-09-18 15:39:42 -04001234 u16 tmp;
1235 u8 noise[4];
1236 u8 i, j;
1237 s32 average;
1238
1239 /* Bottom half of Link Quality calculation. */
1240
Michael Bueschef1a6282008-08-27 18:53:02 +02001241 if (dev->phy.type != B43_PHYTYPE_G)
1242 return;
1243
Michael Buesch98a3b2f2008-06-12 12:36:29 +02001244 /* Possible race condition: It might be possible that the user
1245 * changed to a different channel in the meantime since we
1246 * started the calculation. We ignore that fact, since it's
1247 * not really that much of a problem. The background noise is
1248 * an estimation only anyway. Slightly wrong results will get damped
1249 * by the averaging of the 8 sample rounds. Additionally the
1250 * value is shortlived. So it will be replaced by the next noise
1251 * calculation round soon. */
1252
Michael Buesche4d6b792007-09-18 15:39:42 -04001253 B43_WARN_ON(!dev->noisecalc.calculation_running);
Michael Buesch1a094042007-09-20 11:13:40 -07001254 *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev));
Michael Buesche4d6b792007-09-18 15:39:42 -04001255 if (noise[0] == 0x7F || noise[1] == 0x7F ||
1256 noise[2] == 0x7F || noise[3] == 0x7F)
1257 goto generate_new;
1258
1259 /* Get the noise samples. */
1260 B43_WARN_ON(dev->noisecalc.nr_samples >= 8);
1261 i = dev->noisecalc.nr_samples;
Harvey Harrisoncdbf0842008-05-02 13:47:48 -07001262 noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1263 noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1264 noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1265 noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04001266 dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
1267 dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
1268 dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
1269 dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
1270 dev->noisecalc.nr_samples++;
1271 if (dev->noisecalc.nr_samples == 8) {
1272 /* Calculate the Link Quality by the noise samples. */
1273 average = 0;
1274 for (i = 0; i < 8; i++) {
1275 for (j = 0; j < 4; j++)
1276 average += dev->noisecalc.samples[i][j];
1277 }
1278 average /= (8 * 4);
1279 average *= 125;
1280 average += 64;
1281 average /= 128;
1282 tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x40C);
1283 tmp = (tmp / 128) & 0x1F;
1284 if (tmp >= 8)
1285 average += 2;
1286 else
1287 average -= 25;
1288 if (tmp == 8)
1289 average -= 72;
1290 else
1291 average -= 48;
1292
1293 dev->stats.link_noise = average;
Michael Buesche4d6b792007-09-18 15:39:42 -04001294 dev->noisecalc.calculation_running = 0;
1295 return;
1296 }
Michael Buesch98a3b2f2008-06-12 12:36:29 +02001297generate_new:
Michael Buesche4d6b792007-09-18 15:39:42 -04001298 b43_generate_noise_sample(dev);
1299}
1300
1301static void handle_irq_tbtt_indication(struct b43_wldev *dev)
1302{
Johannes Berg05c914f2008-09-11 00:01:58 +02001303 if (b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001304 ///TODO: PS TBTT
1305 } else {
1306 if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
1307 b43_power_saving_ctl_bits(dev, 0);
1308 }
Johannes Berg05c914f2008-09-11 00:01:58 +02001309 if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01001310 dev->dfq_valid = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04001311}
1312
1313static void handle_irq_atim_end(struct b43_wldev *dev)
1314{
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01001315 if (dev->dfq_valid) {
1316 b43_write32(dev, B43_MMIO_MACCMD,
1317 b43_read32(dev, B43_MMIO_MACCMD)
1318 | B43_MACCMD_DFQ_VALID);
1319 dev->dfq_valid = 0;
1320 }
Michael Buesche4d6b792007-09-18 15:39:42 -04001321}
1322
1323static void handle_irq_pmq(struct b43_wldev *dev)
1324{
1325 u32 tmp;
1326
1327 //TODO: AP mode.
1328
1329 while (1) {
1330 tmp = b43_read32(dev, B43_MMIO_PS_STATUS);
1331 if (!(tmp & 0x00000008))
1332 break;
1333 }
1334 /* 16bit write is odd, but correct. */
1335 b43_write16(dev, B43_MMIO_PS_STATUS, 0x0002);
1336}
1337
1338static void b43_write_template_common(struct b43_wldev *dev,
John Daiker99da1852009-02-24 02:16:42 -08001339 const u8 *data, u16 size,
Michael Buesche4d6b792007-09-18 15:39:42 -04001340 u16 ram_offset,
1341 u16 shm_size_offset, u8 rate)
1342{
1343 u32 i, tmp;
1344 struct b43_plcp_hdr4 plcp;
1345
1346 plcp.data = 0;
1347 b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
1348 b43_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
1349 ram_offset += sizeof(u32);
1350 /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
1351 * So leave the first two bytes of the next write blank.
1352 */
1353 tmp = (u32) (data[0]) << 16;
1354 tmp |= (u32) (data[1]) << 24;
1355 b43_ram_write(dev, ram_offset, tmp);
1356 ram_offset += sizeof(u32);
1357 for (i = 2; i < size; i += sizeof(u32)) {
1358 tmp = (u32) (data[i + 0]);
1359 if (i + 1 < size)
1360 tmp |= (u32) (data[i + 1]) << 8;
1361 if (i + 2 < size)
1362 tmp |= (u32) (data[i + 2]) << 16;
1363 if (i + 3 < size)
1364 tmp |= (u32) (data[i + 3]) << 24;
1365 b43_ram_write(dev, ram_offset + i - 2, tmp);
1366 }
1367 b43_shm_write16(dev, B43_SHM_SHARED, shm_size_offset,
1368 size + sizeof(struct b43_plcp_hdr6));
1369}
1370
Michael Buesch5042c502008-04-05 15:05:00 +02001371/* Check if the use of the antenna that ieee80211 told us to
1372 * use is possible. This will fall back to DEFAULT.
1373 * "antenna_nr" is the antenna identifier we got from ieee80211. */
1374u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
1375 u8 antenna_nr)
1376{
1377 u8 antenna_mask;
1378
1379 if (antenna_nr == 0) {
1380 /* Zero means "use default antenna". That's always OK. */
1381 return 0;
1382 }
1383
1384 /* Get the mask of available antennas. */
1385 if (dev->phy.gmode)
1386 antenna_mask = dev->dev->bus->sprom.ant_available_bg;
1387 else
1388 antenna_mask = dev->dev->bus->sprom.ant_available_a;
1389
1390 if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
1391 /* This antenna is not available. Fall back to default. */
1392 return 0;
1393 }
1394
1395 return antenna_nr;
1396}
1397
Michael Buesch5042c502008-04-05 15:05:00 +02001398/* Convert a b43 antenna number value to the PHY TX control value. */
1399static u16 b43_antenna_to_phyctl(int antenna)
1400{
1401 switch (antenna) {
1402 case B43_ANTENNA0:
1403 return B43_TXH_PHY_ANT0;
1404 case B43_ANTENNA1:
1405 return B43_TXH_PHY_ANT1;
1406 case B43_ANTENNA2:
1407 return B43_TXH_PHY_ANT2;
1408 case B43_ANTENNA3:
1409 return B43_TXH_PHY_ANT3;
Gábor Stefanik64e368b2009-08-27 22:49:49 +02001410 case B43_ANTENNA_AUTO0:
1411 case B43_ANTENNA_AUTO1:
Michael Buesch5042c502008-04-05 15:05:00 +02001412 return B43_TXH_PHY_ANT01AUTO;
1413 }
1414 B43_WARN_ON(1);
1415 return 0;
1416}
1417
Michael Buesche4d6b792007-09-18 15:39:42 -04001418static void b43_write_beacon_template(struct b43_wldev *dev,
1419 u16 ram_offset,
Michael Buesch5042c502008-04-05 15:05:00 +02001420 u16 shm_size_offset)
Michael Buesche4d6b792007-09-18 15:39:42 -04001421{
Michael Buesch47f76ca2007-12-27 22:15:11 +01001422 unsigned int i, len, variable_len;
Michael Buesche66fee62007-12-26 17:47:10 +01001423 const struct ieee80211_mgmt *bcn;
1424 const u8 *ie;
1425 bool tim_found = 0;
Michael Buesch5042c502008-04-05 15:05:00 +02001426 unsigned int rate;
1427 u16 ctl;
1428 int antenna;
Johannes Berge039fa42008-05-15 12:55:29 +02001429 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
Michael Buesche4d6b792007-09-18 15:39:42 -04001430
Michael Buesche66fee62007-12-26 17:47:10 +01001431 bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
1432 len = min((size_t) dev->wl->current_beacon->len,
Michael Buesche4d6b792007-09-18 15:39:42 -04001433 0x200 - sizeof(struct b43_plcp_hdr6));
Johannes Berge039fa42008-05-15 12:55:29 +02001434 rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
Michael Buesche66fee62007-12-26 17:47:10 +01001435
1436 b43_write_template_common(dev, (const u8 *)bcn,
Michael Buesche4d6b792007-09-18 15:39:42 -04001437 len, ram_offset, shm_size_offset, rate);
Michael Buesche66fee62007-12-26 17:47:10 +01001438
Michael Buesch5042c502008-04-05 15:05:00 +02001439 /* Write the PHY TX control parameters. */
Johannes Berg0f4ac382008-10-09 12:18:04 +02001440 antenna = B43_ANTENNA_DEFAULT;
Michael Buesch5042c502008-04-05 15:05:00 +02001441 antenna = b43_antenna_to_phyctl(antenna);
1442 ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
1443 /* We can't send beacons with short preamble. Would get PHY errors. */
1444 ctl &= ~B43_TXH_PHY_SHORTPRMBL;
1445 ctl &= ~B43_TXH_PHY_ANT;
1446 ctl &= ~B43_TXH_PHY_ENC;
1447 ctl |= antenna;
1448 if (b43_is_cck_rate(rate))
1449 ctl |= B43_TXH_PHY_ENC_CCK;
1450 else
1451 ctl |= B43_TXH_PHY_ENC_OFDM;
1452 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);
1453
Michael Buesche66fee62007-12-26 17:47:10 +01001454 /* Find the position of the TIM and the DTIM_period value
1455 * and write them to SHM. */
1456 ie = bcn->u.beacon.variable;
Michael Buesch47f76ca2007-12-27 22:15:11 +01001457 variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
1458 for (i = 0; i < variable_len - 2; ) {
Michael Buesche66fee62007-12-26 17:47:10 +01001459 uint8_t ie_id, ie_len;
1460
1461 ie_id = ie[i];
1462 ie_len = ie[i + 1];
1463 if (ie_id == 5) {
1464 u16 tim_position;
1465 u16 dtim_period;
1466 /* This is the TIM Information Element */
1467
1468 /* Check whether the ie_len is in the beacon data range. */
Michael Buesch47f76ca2007-12-27 22:15:11 +01001469 if (variable_len < ie_len + 2 + i)
Michael Buesche66fee62007-12-26 17:47:10 +01001470 break;
1471 /* A valid TIM is at least 4 bytes long. */
1472 if (ie_len < 4)
1473 break;
1474 tim_found = 1;
1475
1476 tim_position = sizeof(struct b43_plcp_hdr6);
1477 tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable);
1478 tim_position += i;
1479
1480 dtim_period = ie[i + 3];
1481
1482 b43_shm_write16(dev, B43_SHM_SHARED,
1483 B43_SHM_SH_TIMBPOS, tim_position);
1484 b43_shm_write16(dev, B43_SHM_SHARED,
1485 B43_SHM_SH_DTIMPER, dtim_period);
1486 break;
1487 }
1488 i += ie_len + 2;
1489 }
1490 if (!tim_found) {
Johannes Berg04dea132008-05-20 12:10:49 +02001491 /*
1492 * If ucode wants to modify TIM do it behind the beacon, this
1493 * will happen, for example, when doing mesh networking.
1494 */
1495 b43_shm_write16(dev, B43_SHM_SHARED,
1496 B43_SHM_SH_TIMBPOS,
1497 len + sizeof(struct b43_plcp_hdr6));
1498 b43_shm_write16(dev, B43_SHM_SHARED,
1499 B43_SHM_SH_DTIMPER, 0);
1500 }
1501 b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
Michael Buesche4d6b792007-09-18 15:39:42 -04001502}
1503
Michael Buesch6b4bec012008-05-20 12:16:28 +02001504static void b43_upload_beacon0(struct b43_wldev *dev)
1505{
1506 struct b43_wl *wl = dev->wl;
1507
1508 if (wl->beacon0_uploaded)
1509 return;
1510 b43_write_beacon_template(dev, 0x68, 0x18);
Michael Buesch6b4bec012008-05-20 12:16:28 +02001511 wl->beacon0_uploaded = 1;
1512}
1513
1514static void b43_upload_beacon1(struct b43_wldev *dev)
1515{
1516 struct b43_wl *wl = dev->wl;
1517
1518 if (wl->beacon1_uploaded)
1519 return;
1520 b43_write_beacon_template(dev, 0x468, 0x1A);
1521 wl->beacon1_uploaded = 1;
1522}
1523
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001524static void handle_irq_beacon(struct b43_wldev *dev)
1525{
1526 struct b43_wl *wl = dev->wl;
1527 u32 cmd, beacon0_valid, beacon1_valid;
1528
Johannes Berg05c914f2008-09-11 00:01:58 +02001529 if (!b43_is_mode(wl, NL80211_IFTYPE_AP) &&
1530 !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001531 return;
1532
1533 /* This is the bottom half of the asynchronous beacon update. */
1534
1535 /* Ignore interrupt in the future. */
Michael Buesch13790722009-04-08 21:26:27 +02001536 dev->irq_mask &= ~B43_IRQ_BEACON;
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001537
1538 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1539 beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID);
1540 beacon1_valid = (cmd & B43_MACCMD_BEACON1_VALID);
1541
1542 /* Schedule interrupt manually, if busy. */
1543 if (beacon0_valid && beacon1_valid) {
1544 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
Michael Buesch13790722009-04-08 21:26:27 +02001545 dev->irq_mask |= B43_IRQ_BEACON;
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001546 return;
1547 }
1548
Michael Buesch6b4bec012008-05-20 12:16:28 +02001549 if (unlikely(wl->beacon_templates_virgin)) {
1550 /* We never uploaded a beacon before.
1551 * Upload both templates now, but only mark one valid. */
1552 wl->beacon_templates_virgin = 0;
1553 b43_upload_beacon0(dev);
1554 b43_upload_beacon1(dev);
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001555 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1556 cmd |= B43_MACCMD_BEACON0_VALID;
1557 b43_write32(dev, B43_MMIO_MACCMD, cmd);
Michael Buesch6b4bec012008-05-20 12:16:28 +02001558 } else {
1559 if (!beacon0_valid) {
1560 b43_upload_beacon0(dev);
1561 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1562 cmd |= B43_MACCMD_BEACON0_VALID;
1563 b43_write32(dev, B43_MMIO_MACCMD, cmd);
1564 } else if (!beacon1_valid) {
1565 b43_upload_beacon1(dev);
1566 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1567 cmd |= B43_MACCMD_BEACON1_VALID;
1568 b43_write32(dev, B43_MMIO_MACCMD, cmd);
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001569 }
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001570 }
1571}
1572
Michael Buesch36dbd952009-09-04 22:51:29 +02001573static void b43_do_beacon_update_trigger_work(struct b43_wldev *dev)
1574{
1575 u32 old_irq_mask = dev->irq_mask;
1576
1577 /* update beacon right away or defer to irq */
1578 handle_irq_beacon(dev);
1579 if (old_irq_mask != dev->irq_mask) {
1580 /* The handler updated the IRQ mask. */
1581 B43_WARN_ON(!dev->irq_mask);
1582 if (b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)) {
1583 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
1584 } else {
1585 /* Device interrupts are currently disabled. That means
1586 * we just ran the hardirq handler and scheduled the
1587 * IRQ thread. The thread will write the IRQ mask when
1588 * it finished, so there's nothing to do here. Writing
1589 * the mask _here_ would incorrectly re-enable IRQs. */
1590 }
1591 }
1592}
1593
Michael Buescha82d9922008-04-04 21:40:06 +02001594static void b43_beacon_update_trigger_work(struct work_struct *work)
1595{
1596 struct b43_wl *wl = container_of(work, struct b43_wl,
1597 beacon_update_trigger);
1598 struct b43_wldev *dev;
1599
1600 mutex_lock(&wl->mutex);
1601 dev = wl->current_dev;
1602 if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
Albert Herranz3dbba8e2009-09-10 19:34:49 +02001603 if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
Michael Buesch36dbd952009-09-04 22:51:29 +02001604 /* wl->mutex is enough. */
1605 b43_do_beacon_update_trigger_work(dev);
1606 mmiowb();
1607 } else {
1608 spin_lock_irq(&wl->hardirq_lock);
1609 b43_do_beacon_update_trigger_work(dev);
1610 mmiowb();
1611 spin_unlock_irq(&wl->hardirq_lock);
1612 }
Michael Buescha82d9922008-04-04 21:40:06 +02001613 }
1614 mutex_unlock(&wl->mutex);
1615}
1616
Michael Bueschd4df6f12007-12-26 18:04:14 +01001617/* Asynchronously update the packet templates in template RAM.
Michael Buesch36dbd952009-09-04 22:51:29 +02001618 * Locking: Requires wl->mutex to be locked. */
Johannes Berg9d139c82008-07-09 14:40:37 +02001619static void b43_update_templates(struct b43_wl *wl)
Michael Buesche4d6b792007-09-18 15:39:42 -04001620{
Johannes Berg9d139c82008-07-09 14:40:37 +02001621 struct sk_buff *beacon;
1622
Michael Buesche66fee62007-12-26 17:47:10 +01001623 /* This is the top half of the ansynchronous beacon update.
1624 * The bottom half is the beacon IRQ.
1625 * Beacon update must be asynchronous to avoid sending an
1626 * invalid beacon. This can happen for example, if the firmware
1627 * transmits a beacon while we are updating it. */
Michael Buesche4d6b792007-09-18 15:39:42 -04001628
Johannes Berg9d139c82008-07-09 14:40:37 +02001629 /* We could modify the existing beacon and set the aid bit in
1630 * the TIM field, but that would probably require resizing and
1631 * moving of data within the beacon template.
1632 * Simply request a new beacon and let mac80211 do the hard work. */
1633 beacon = ieee80211_beacon_get(wl->hw, wl->vif);
1634 if (unlikely(!beacon))
1635 return;
1636
Michael Buesche66fee62007-12-26 17:47:10 +01001637 if (wl->current_beacon)
1638 dev_kfree_skb_any(wl->current_beacon);
1639 wl->current_beacon = beacon;
1640 wl->beacon0_uploaded = 0;
1641 wl->beacon1_uploaded = 0;
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04001642 ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
Michael Buesche4d6b792007-09-18 15:39:42 -04001643}
1644
Michael Buesche4d6b792007-09-18 15:39:42 -04001645static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
1646{
1647 b43_time_lock(dev);
1648 if (dev->dev->id.revision >= 3) {
Michael Buescha82d9922008-04-04 21:40:06 +02001649 b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16));
1650 b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));
Michael Buesche4d6b792007-09-18 15:39:42 -04001651 } else {
1652 b43_write16(dev, 0x606, (beacon_int >> 6));
1653 b43_write16(dev, 0x610, beacon_int);
1654 }
1655 b43_time_unlock(dev);
Michael Buescha82d9922008-04-04 21:40:06 +02001656 b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
Michael Buesche4d6b792007-09-18 15:39:42 -04001657}
1658
Michael Bueschafa83e22008-05-19 23:51:37 +02001659static void b43_handle_firmware_panic(struct b43_wldev *dev)
1660{
1661 u16 reason;
1662
1663 /* Read the register that contains the reason code for the panic. */
1664 reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG);
1665 b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason);
1666
1667 switch (reason) {
1668 default:
1669 b43dbg(dev->wl, "The panic reason is unknown.\n");
1670 /* fallthrough */
1671 case B43_FWPANIC_DIE:
1672 /* Do not restart the controller or firmware.
1673 * The device is nonfunctional from now on.
1674 * Restarting would result in this panic to trigger again,
1675 * so we avoid that recursion. */
1676 break;
1677 case B43_FWPANIC_RESTART:
1678 b43_controller_restart(dev, "Microcode panic");
1679 break;
1680 }
1681}
1682
Michael Buesche4d6b792007-09-18 15:39:42 -04001683static void handle_irq_ucode_debug(struct b43_wldev *dev)
1684{
Michael Buesche48b0ee2008-05-17 22:44:35 +02001685 unsigned int i, cnt;
Michael Buesch53c06852008-05-20 00:24:36 +02001686 u16 reason, marker_id, marker_line;
Michael Buesche48b0ee2008-05-17 22:44:35 +02001687 __le16 *buf;
1688
1689 /* The proprietary firmware doesn't have this IRQ. */
1690 if (!dev->fw.opensource)
1691 return;
1692
Michael Bueschafa83e22008-05-19 23:51:37 +02001693 /* Read the register that contains the reason code for this IRQ. */
1694 reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG);
1695
Michael Buesche48b0ee2008-05-17 22:44:35 +02001696 switch (reason) {
1697 case B43_DEBUGIRQ_PANIC:
Michael Bueschafa83e22008-05-19 23:51:37 +02001698 b43_handle_firmware_panic(dev);
Michael Buesche48b0ee2008-05-17 22:44:35 +02001699 break;
1700 case B43_DEBUGIRQ_DUMP_SHM:
1701 if (!B43_DEBUG)
1702 break; /* Only with driver debugging enabled. */
1703 buf = kmalloc(4096, GFP_ATOMIC);
1704 if (!buf) {
1705 b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n");
1706 goto out;
1707 }
1708 for (i = 0; i < 4096; i += 2) {
1709 u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i);
1710 buf[i / 2] = cpu_to_le16(tmp);
1711 }
1712 b43info(dev->wl, "Shared memory dump:\n");
1713 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET,
1714 16, 2, buf, 4096, 1);
1715 kfree(buf);
1716 break;
1717 case B43_DEBUGIRQ_DUMP_REGS:
1718 if (!B43_DEBUG)
1719 break; /* Only with driver debugging enabled. */
1720 b43info(dev->wl, "Microcode register dump:\n");
1721 for (i = 0, cnt = 0; i < 64; i++) {
1722 u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i);
1723 if (cnt == 0)
1724 printk(KERN_INFO);
1725 printk("r%02u: 0x%04X ", i, tmp);
1726 cnt++;
1727 if (cnt == 6) {
1728 printk("\n");
1729 cnt = 0;
1730 }
1731 }
1732 printk("\n");
1733 break;
Michael Buesch53c06852008-05-20 00:24:36 +02001734 case B43_DEBUGIRQ_MARKER:
1735 if (!B43_DEBUG)
1736 break; /* Only with driver debugging enabled. */
1737 marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH,
1738 B43_MARKER_ID_REG);
1739 marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH,
1740 B43_MARKER_LINE_REG);
1741 b43info(dev->wl, "The firmware just executed the MARKER(%u) "
1742 "at line number %u\n",
1743 marker_id, marker_line);
1744 break;
Michael Buesche48b0ee2008-05-17 22:44:35 +02001745 default:
1746 b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n",
1747 reason);
1748 }
1749out:
Michael Bueschafa83e22008-05-19 23:51:37 +02001750 /* Acknowledge the debug-IRQ, so the firmware can continue. */
1751 b43_shm_write16(dev, B43_SHM_SCRATCH,
1752 B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK);
Michael Buesche4d6b792007-09-18 15:39:42 -04001753}
1754
Michael Buesch36dbd952009-09-04 22:51:29 +02001755static void b43_do_interrupt_thread(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04001756{
1757 u32 reason;
1758 u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
1759 u32 merged_dma_reason = 0;
Michael Buesch21954c32007-09-27 15:31:40 +02001760 int i;
Michael Buesche4d6b792007-09-18 15:39:42 -04001761
Michael Buesch36dbd952009-09-04 22:51:29 +02001762 if (unlikely(b43_status(dev) != B43_STAT_STARTED))
1763 return;
Michael Buesche4d6b792007-09-18 15:39:42 -04001764
1765 reason = dev->irq_reason;
1766 for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
1767 dma_reason[i] = dev->dma_reason[i];
1768 merged_dma_reason |= dma_reason[i];
1769 }
1770
1771 if (unlikely(reason & B43_IRQ_MAC_TXERR))
1772 b43err(dev->wl, "MAC transmission error\n");
1773
Stefano Brivio00e0b8c2007-11-25 11:10:33 +01001774 if (unlikely(reason & B43_IRQ_PHY_TXERR)) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001775 b43err(dev->wl, "PHY transmission error\n");
Stefano Brivio00e0b8c2007-11-25 11:10:33 +01001776 rmb();
1777 if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) {
1778 atomic_set(&dev->phy.txerr_cnt,
1779 B43_PHY_TX_BADNESS_LIMIT);
1780 b43err(dev->wl, "Too many PHY TX errors, "
1781 "restarting the controller\n");
1782 b43_controller_restart(dev, "PHY TX errors");
1783 }
1784 }
Michael Buesche4d6b792007-09-18 15:39:42 -04001785
1786 if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
1787 B43_DMAIRQ_NONFATALMASK))) {
1788 if (merged_dma_reason & B43_DMAIRQ_FATALMASK) {
1789 b43err(dev->wl, "Fatal DMA error: "
1790 "0x%08X, 0x%08X, 0x%08X, "
1791 "0x%08X, 0x%08X, 0x%08X\n",
1792 dma_reason[0], dma_reason[1],
1793 dma_reason[2], dma_reason[3],
1794 dma_reason[4], dma_reason[5]);
Larry Finger214ac9a2009-12-09 13:25:56 -06001795 b43err(dev->wl, "This device does not support DMA "
1796 "on your system. Please use PIO instead.\n");
Larry Fingerb02914a2009-12-10 17:35:01 -06001797 b43err(dev->wl, "Unload the b43 module and reload "
1798 "with 'pio=1'\n");
Michael Buesche4d6b792007-09-18 15:39:42 -04001799 return;
1800 }
1801 if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
1802 b43err(dev->wl, "DMA error: "
1803 "0x%08X, 0x%08X, 0x%08X, "
1804 "0x%08X, 0x%08X, 0x%08X\n",
1805 dma_reason[0], dma_reason[1],
1806 dma_reason[2], dma_reason[3],
1807 dma_reason[4], dma_reason[5]);
1808 }
1809 }
1810
1811 if (unlikely(reason & B43_IRQ_UCODE_DEBUG))
1812 handle_irq_ucode_debug(dev);
1813 if (reason & B43_IRQ_TBTT_INDI)
1814 handle_irq_tbtt_indication(dev);
1815 if (reason & B43_IRQ_ATIM_END)
1816 handle_irq_atim_end(dev);
1817 if (reason & B43_IRQ_BEACON)
1818 handle_irq_beacon(dev);
1819 if (reason & B43_IRQ_PMQ)
1820 handle_irq_pmq(dev);
Michael Buesch21954c32007-09-27 15:31:40 +02001821 if (reason & B43_IRQ_TXFIFO_FLUSH_OK)
1822 ;/* TODO */
1823 if (reason & B43_IRQ_NOISESAMPLE_OK)
Michael Buesche4d6b792007-09-18 15:39:42 -04001824 handle_irq_noise(dev);
1825
1826 /* Check the DMA reason registers for received data. */
Michael Buesch5100d5a2008-03-29 21:01:16 +01001827 if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
1828 if (b43_using_pio_transfers(dev))
1829 b43_pio_rx(dev->pio.rx_queue);
1830 else
1831 b43_dma_rx(dev->dma.rx_ring);
1832 }
Michael Buesche4d6b792007-09-18 15:39:42 -04001833 B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
1834 B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
Michael Bueschb27faf82008-03-06 16:32:46 +01001835 B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE);
Michael Buesche4d6b792007-09-18 15:39:42 -04001836 B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
1837 B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
1838
Michael Buesch21954c32007-09-27 15:31:40 +02001839 if (reason & B43_IRQ_TX_OK)
Michael Buesche4d6b792007-09-18 15:39:42 -04001840 handle_irq_transmit_status(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04001841
Michael Buesch36dbd952009-09-04 22:51:29 +02001842 /* Re-enable interrupts on the device by restoring the current interrupt mask. */
Michael Buesch13790722009-04-08 21:26:27 +02001843 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
Michael Buesch990b86f2009-09-12 00:48:03 +02001844
1845#if B43_DEBUG
1846 if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
1847 dev->irq_count++;
1848 for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
1849 if (reason & (1 << i))
1850 dev->irq_bit_count[i]++;
1851 }
1852 }
1853#endif
Michael Buesche4d6b792007-09-18 15:39:42 -04001854}
1855
Michael Buesch36dbd952009-09-04 22:51:29 +02001856/* Interrupt thread handler. Handles device interrupts in thread context. */
1857static irqreturn_t b43_interrupt_thread_handler(int irq, void *dev_id)
Michael Buesche4d6b792007-09-18 15:39:42 -04001858{
Michael Buesche4d6b792007-09-18 15:39:42 -04001859 struct b43_wldev *dev = dev_id;
Michael Buesch36dbd952009-09-04 22:51:29 +02001860
1861 mutex_lock(&dev->wl->mutex);
1862 b43_do_interrupt_thread(dev);
1863 mmiowb();
1864 mutex_unlock(&dev->wl->mutex);
1865
1866 return IRQ_HANDLED;
1867}
1868
1869static irqreturn_t b43_do_interrupt(struct b43_wldev *dev)
1870{
Michael Buesche4d6b792007-09-18 15:39:42 -04001871 u32 reason;
1872
Michael Buesch36dbd952009-09-04 22:51:29 +02001873 /* This code runs under wl->hardirq_lock, but _only_ on non-SDIO busses.
1874 * On SDIO, this runs under wl->mutex. */
Michael Buesche4d6b792007-09-18 15:39:42 -04001875
Michael Buesche4d6b792007-09-18 15:39:42 -04001876 reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
1877 if (reason == 0xffffffff) /* shared IRQ */
Michael Buesch36dbd952009-09-04 22:51:29 +02001878 return IRQ_NONE;
Michael Buesch13790722009-04-08 21:26:27 +02001879 reason &= dev->irq_mask;
Michael Buesche4d6b792007-09-18 15:39:42 -04001880 if (!reason)
Michael Buesch36dbd952009-09-04 22:51:29 +02001881 return IRQ_HANDLED;
Michael Buesche4d6b792007-09-18 15:39:42 -04001882
1883 dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
1884 & 0x0001DC00;
1885 dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON)
1886 & 0x0000DC00;
1887 dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON)
1888 & 0x0000DC00;
1889 dev->dma_reason[3] = b43_read32(dev, B43_MMIO_DMA3_REASON)
1890 & 0x0001DC00;
1891 dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON)
1892 & 0x0000DC00;
Michael Buesch13790722009-04-08 21:26:27 +02001893/* Unused ring
Michael Buesche4d6b792007-09-18 15:39:42 -04001894 dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON)
1895 & 0x0000DC00;
Michael Buesch13790722009-04-08 21:26:27 +02001896*/
Michael Buesche4d6b792007-09-18 15:39:42 -04001897
Michael Buesch36dbd952009-09-04 22:51:29 +02001898 /* ACK the interrupt. */
1899 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
1900 b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
1901 b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]);
1902 b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
1903 b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
1904 b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
1905/* Unused ring
1906 b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
1907*/
1908
1909 /* Disable IRQs on the device. The IRQ thread handler will re-enable them. */
Michael Buesch13790722009-04-08 21:26:27 +02001910 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
Michael Buesch36dbd952009-09-04 22:51:29 +02001911 /* Save the reason bitmasks for the IRQ thread handler. */
Michael Buesche4d6b792007-09-18 15:39:42 -04001912 dev->irq_reason = reason;
Michael Buesch36dbd952009-09-04 22:51:29 +02001913
1914 return IRQ_WAKE_THREAD;
1915}
1916
1917/* Interrupt handler top-half. This runs with interrupts disabled. */
1918static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
1919{
1920 struct b43_wldev *dev = dev_id;
1921 irqreturn_t ret;
1922
1923 if (unlikely(b43_status(dev) < B43_STAT_STARTED))
1924 return IRQ_NONE;
1925
1926 spin_lock(&dev->wl->hardirq_lock);
1927 ret = b43_do_interrupt(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04001928 mmiowb();
Michael Buesch36dbd952009-09-04 22:51:29 +02001929 spin_unlock(&dev->wl->hardirq_lock);
Michael Buesche4d6b792007-09-18 15:39:42 -04001930
1931 return ret;
1932}
1933
Albert Herranz3dbba8e2009-09-10 19:34:49 +02001934/* SDIO interrupt handler. This runs in process context. */
1935static void b43_sdio_interrupt_handler(struct b43_wldev *dev)
1936{
1937 struct b43_wl *wl = dev->wl;
Albert Herranz3dbba8e2009-09-10 19:34:49 +02001938 irqreturn_t ret;
1939
Albert Herranz3dbba8e2009-09-10 19:34:49 +02001940 mutex_lock(&wl->mutex);
Albert Herranz3dbba8e2009-09-10 19:34:49 +02001941
1942 ret = b43_do_interrupt(dev);
1943 if (ret == IRQ_WAKE_THREAD)
1944 b43_do_interrupt_thread(dev);
1945
Albert Herranz3dbba8e2009-09-10 19:34:49 +02001946 mutex_unlock(&wl->mutex);
1947}
1948
Michael Buesch1a9f5092009-01-23 21:21:51 +01001949void b43_do_release_fw(struct b43_firmware_file *fw)
Michael Buesch61cb5dd2008-01-21 19:55:09 +01001950{
1951 release_firmware(fw->data);
1952 fw->data = NULL;
1953 fw->filename = NULL;
1954}
1955
Michael Buesche4d6b792007-09-18 15:39:42 -04001956static void b43_release_firmware(struct b43_wldev *dev)
1957{
Michael Buesch1a9f5092009-01-23 21:21:51 +01001958 b43_do_release_fw(&dev->fw.ucode);
1959 b43_do_release_fw(&dev->fw.pcm);
1960 b43_do_release_fw(&dev->fw.initvals);
1961 b43_do_release_fw(&dev->fw.initvals_band);
Michael Buesche4d6b792007-09-18 15:39:42 -04001962}
1963
Michael Buescheb189d8b2008-01-28 14:47:41 -08001964static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
Michael Buesche4d6b792007-09-18 15:39:42 -04001965{
Hannes Ederfc68ed42009-02-14 11:50:06 +00001966 const char text[] =
1967 "You must go to " \
1968 "http://wireless.kernel.org/en/users/Drivers/b43#devicefirmware " \
1969 "and download the correct firmware for this driver version. " \
1970 "Please carefully read all instructions on this website.\n";
Michael Buescheb189d8b2008-01-28 14:47:41 -08001971
Michael Buescheb189d8b2008-01-28 14:47:41 -08001972 if (error)
1973 b43err(wl, text);
1974 else
1975 b43warn(wl, text);
Michael Buesche4d6b792007-09-18 15:39:42 -04001976}
1977
Michael Buesch1a9f5092009-01-23 21:21:51 +01001978int b43_do_request_fw(struct b43_request_fw_context *ctx,
1979 const char *name,
1980 struct b43_firmware_file *fw)
Michael Buesche4d6b792007-09-18 15:39:42 -04001981{
Michael Buesch61cb5dd2008-01-21 19:55:09 +01001982 const struct firmware *blob;
Michael Buesche4d6b792007-09-18 15:39:42 -04001983 struct b43_fw_header *hdr;
1984 u32 size;
1985 int err;
1986
Michael Buesch61cb5dd2008-01-21 19:55:09 +01001987 if (!name) {
1988 /* Don't fetch anything. Free possibly cached firmware. */
Michael Buesch1a9f5092009-01-23 21:21:51 +01001989 /* FIXME: We should probably keep it anyway, to save some headache
1990 * on suspend/resume with multiband devices. */
1991 b43_do_release_fw(fw);
Michael Buesche4d6b792007-09-18 15:39:42 -04001992 return 0;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01001993 }
1994 if (fw->filename) {
Michael Buesch1a9f5092009-01-23 21:21:51 +01001995 if ((fw->type == ctx->req_type) &&
1996 (strcmp(fw->filename, name) == 0))
Michael Buesch61cb5dd2008-01-21 19:55:09 +01001997 return 0; /* Already have this fw. */
1998 /* Free the cached firmware first. */
Michael Buesch1a9f5092009-01-23 21:21:51 +01001999 /* FIXME: We should probably do this later after we successfully
2000 * got the new fw. This could reduce headache with multiband devices.
2001 * We could also redesign this to cache the firmware for all possible
2002 * bands all the time. */
2003 b43_do_release_fw(fw);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002004 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002005
Michael Buesch1a9f5092009-01-23 21:21:51 +01002006 switch (ctx->req_type) {
2007 case B43_FWTYPE_PROPRIETARY:
2008 snprintf(ctx->fwname, sizeof(ctx->fwname),
2009 "b43%s/%s.fw",
2010 modparam_fwpostfix, name);
2011 break;
2012 case B43_FWTYPE_OPENSOURCE:
2013 snprintf(ctx->fwname, sizeof(ctx->fwname),
2014 "b43-open%s/%s.fw",
2015 modparam_fwpostfix, name);
2016 break;
2017 default:
2018 B43_WARN_ON(1);
2019 return -ENOSYS;
2020 }
2021 err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev);
Michael Buesch68217832008-05-17 23:43:57 +02002022 if (err == -ENOENT) {
Michael Buesch1a9f5092009-01-23 21:21:51 +01002023 snprintf(ctx->errors[ctx->req_type],
2024 sizeof(ctx->errors[ctx->req_type]),
2025 "Firmware file \"%s\" not found\n", ctx->fwname);
Michael Buesch68217832008-05-17 23:43:57 +02002026 return err;
2027 } else if (err) {
Michael Buesch1a9f5092009-01-23 21:21:51 +01002028 snprintf(ctx->errors[ctx->req_type],
2029 sizeof(ctx->errors[ctx->req_type]),
2030 "Firmware file \"%s\" request failed (err=%d)\n",
2031 ctx->fwname, err);
Michael Buesche4d6b792007-09-18 15:39:42 -04002032 return err;
2033 }
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002034 if (blob->size < sizeof(struct b43_fw_header))
Michael Buesche4d6b792007-09-18 15:39:42 -04002035 goto err_format;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002036 hdr = (struct b43_fw_header *)(blob->data);
Michael Buesche4d6b792007-09-18 15:39:42 -04002037 switch (hdr->type) {
2038 case B43_FW_TYPE_UCODE:
2039 case B43_FW_TYPE_PCM:
2040 size = be32_to_cpu(hdr->size);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002041 if (size != blob->size - sizeof(struct b43_fw_header))
Michael Buesche4d6b792007-09-18 15:39:42 -04002042 goto err_format;
2043 /* fallthrough */
2044 case B43_FW_TYPE_IV:
2045 if (hdr->ver != 1)
2046 goto err_format;
2047 break;
2048 default:
2049 goto err_format;
2050 }
2051
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002052 fw->data = blob;
2053 fw->filename = name;
Michael Buesch1a9f5092009-01-23 21:21:51 +01002054 fw->type = ctx->req_type;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002055
2056 return 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04002057
2058err_format:
Michael Buesch1a9f5092009-01-23 21:21:51 +01002059 snprintf(ctx->errors[ctx->req_type],
2060 sizeof(ctx->errors[ctx->req_type]),
2061 "Firmware file \"%s\" format error.\n", ctx->fwname);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002062 release_firmware(blob);
2063
Michael Buesche4d6b792007-09-18 15:39:42 -04002064 return -EPROTO;
2065}
2066
Michael Buesch1a9f5092009-01-23 21:21:51 +01002067static int b43_try_request_fw(struct b43_request_fw_context *ctx)
Michael Buesche4d6b792007-09-18 15:39:42 -04002068{
Michael Buesch1a9f5092009-01-23 21:21:51 +01002069 struct b43_wldev *dev = ctx->dev;
2070 struct b43_firmware *fw = &ctx->dev->fw;
2071 const u8 rev = ctx->dev->dev->id.revision;
Michael Buesche4d6b792007-09-18 15:39:42 -04002072 const char *filename;
2073 u32 tmshigh;
2074 int err;
2075
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002076 /* Get microcode */
Michael Buesche4d6b792007-09-18 15:39:42 -04002077 tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002078 if ((rev >= 5) && (rev <= 10))
2079 filename = "ucode5";
2080 else if ((rev >= 11) && (rev <= 12))
2081 filename = "ucode11";
Gábor Stefanik759b9732009-08-14 14:39:53 +02002082 else if (rev == 13)
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002083 filename = "ucode13";
Gábor Stefanik759b9732009-08-14 14:39:53 +02002084 else if (rev == 14)
2085 filename = "ucode14";
2086 else if (rev >= 15)
2087 filename = "ucode15";
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002088 else
2089 goto err_no_ucode;
Michael Buesch1a9f5092009-01-23 21:21:51 +01002090 err = b43_do_request_fw(ctx, filename, &fw->ucode);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002091 if (err)
2092 goto err_load;
2093
2094 /* Get PCM code */
2095 if ((rev >= 5) && (rev <= 10))
2096 filename = "pcm5";
2097 else if (rev >= 11)
2098 filename = NULL;
2099 else
2100 goto err_no_pcm;
Michael Buesch68217832008-05-17 23:43:57 +02002101 fw->pcm_request_failed = 0;
Michael Buesch1a9f5092009-01-23 21:21:51 +01002102 err = b43_do_request_fw(ctx, filename, &fw->pcm);
Michael Buesch68217832008-05-17 23:43:57 +02002103 if (err == -ENOENT) {
2104 /* We did not find a PCM file? Not fatal, but
2105 * core rev <= 10 must do without hwcrypto then. */
2106 fw->pcm_request_failed = 1;
2107 } else if (err)
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002108 goto err_load;
2109
2110 /* Get initvals */
2111 switch (dev->phy.type) {
2112 case B43_PHYTYPE_A:
2113 if ((rev >= 5) && (rev <= 10)) {
2114 if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
2115 filename = "a0g1initvals5";
2116 else
2117 filename = "a0g0initvals5";
2118 } else
2119 goto err_no_initvals;
2120 break;
2121 case B43_PHYTYPE_G:
Michael Buesche4d6b792007-09-18 15:39:42 -04002122 if ((rev >= 5) && (rev <= 10))
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002123 filename = "b0g0initvals5";
Michael Buesche4d6b792007-09-18 15:39:42 -04002124 else if (rev >= 13)
Larry.Finger@lwfinger.nete9304882008-05-15 14:07:36 -05002125 filename = "b0g0initvals13";
Michael Buesche4d6b792007-09-18 15:39:42 -04002126 else
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002127 goto err_no_initvals;
2128 break;
2129 case B43_PHYTYPE_N:
2130 if ((rev >= 11) && (rev <= 12))
2131 filename = "n0initvals11";
2132 else
2133 goto err_no_initvals;
2134 break;
Gábor Stefanik759b9732009-08-14 14:39:53 +02002135 case B43_PHYTYPE_LP:
2136 if (rev == 13)
2137 filename = "lp0initvals13";
2138 else if (rev == 14)
2139 filename = "lp0initvals14";
2140 else if (rev >= 15)
2141 filename = "lp0initvals15";
2142 else
2143 goto err_no_initvals;
2144 break;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002145 default:
2146 goto err_no_initvals;
Michael Buesche4d6b792007-09-18 15:39:42 -04002147 }
Michael Buesch1a9f5092009-01-23 21:21:51 +01002148 err = b43_do_request_fw(ctx, filename, &fw->initvals);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002149 if (err)
2150 goto err_load;
2151
2152 /* Get bandswitch initvals */
2153 switch (dev->phy.type) {
2154 case B43_PHYTYPE_A:
2155 if ((rev >= 5) && (rev <= 10)) {
2156 if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
2157 filename = "a0g1bsinitvals5";
2158 else
2159 filename = "a0g0bsinitvals5";
2160 } else if (rev >= 11)
2161 filename = NULL;
2162 else
2163 goto err_no_initvals;
2164 break;
2165 case B43_PHYTYPE_G:
Michael Buesche4d6b792007-09-18 15:39:42 -04002166 if ((rev >= 5) && (rev <= 10))
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002167 filename = "b0g0bsinitvals5";
Michael Buesche4d6b792007-09-18 15:39:42 -04002168 else if (rev >= 11)
2169 filename = NULL;
2170 else
Michael Buesche4d6b792007-09-18 15:39:42 -04002171 goto err_no_initvals;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002172 break;
2173 case B43_PHYTYPE_N:
2174 if ((rev >= 11) && (rev <= 12))
2175 filename = "n0bsinitvals11";
2176 else
Michael Buesche4d6b792007-09-18 15:39:42 -04002177 goto err_no_initvals;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002178 break;
Gábor Stefanik759b9732009-08-14 14:39:53 +02002179 case B43_PHYTYPE_LP:
2180 if (rev == 13)
2181 filename = "lp0bsinitvals13";
2182 else if (rev == 14)
2183 filename = "lp0bsinitvals14";
2184 else if (rev >= 15)
2185 filename = "lp0bsinitvals15";
2186 else
2187 goto err_no_initvals;
2188 break;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002189 default:
2190 goto err_no_initvals;
Michael Buesche4d6b792007-09-18 15:39:42 -04002191 }
Michael Buesch1a9f5092009-01-23 21:21:51 +01002192 err = b43_do_request_fw(ctx, filename, &fw->initvals_band);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002193 if (err)
2194 goto err_load;
Michael Buesche4d6b792007-09-18 15:39:42 -04002195
2196 return 0;
2197
Michael Buesche4d6b792007-09-18 15:39:42 -04002198err_no_ucode:
Michael Buesch1a9f5092009-01-23 21:21:51 +01002199 err = ctx->fatal_failure = -EOPNOTSUPP;
2200 b43err(dev->wl, "The driver does not know which firmware (ucode) "
2201 "is required for your device (wl-core rev %u)\n", rev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002202 goto error;
2203
2204err_no_pcm:
Michael Buesch1a9f5092009-01-23 21:21:51 +01002205 err = ctx->fatal_failure = -EOPNOTSUPP;
2206 b43err(dev->wl, "The driver does not know which firmware (PCM) "
2207 "is required for your device (wl-core rev %u)\n", rev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002208 goto error;
2209
2210err_no_initvals:
Michael Buesch1a9f5092009-01-23 21:21:51 +01002211 err = ctx->fatal_failure = -EOPNOTSUPP;
2212 b43err(dev->wl, "The driver does not know which firmware (initvals) "
2213 "is required for your device (wl-core rev %u)\n", rev);
2214 goto error;
2215
2216err_load:
2217 /* We failed to load this firmware image. The error message
2218 * already is in ctx->errors. Return and let our caller decide
2219 * what to do. */
Michael Buesche4d6b792007-09-18 15:39:42 -04002220 goto error;
2221
2222error:
2223 b43_release_firmware(dev);
2224 return err;
2225}
2226
Michael Buesch1a9f5092009-01-23 21:21:51 +01002227static int b43_request_firmware(struct b43_wldev *dev)
2228{
2229 struct b43_request_fw_context *ctx;
2230 unsigned int i;
2231 int err;
2232 const char *errmsg;
2233
2234 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
2235 if (!ctx)
2236 return -ENOMEM;
2237 ctx->dev = dev;
2238
2239 ctx->req_type = B43_FWTYPE_PROPRIETARY;
2240 err = b43_try_request_fw(ctx);
2241 if (!err)
2242 goto out; /* Successfully loaded it. */
2243 err = ctx->fatal_failure;
2244 if (err)
2245 goto out;
2246
2247 ctx->req_type = B43_FWTYPE_OPENSOURCE;
2248 err = b43_try_request_fw(ctx);
2249 if (!err)
2250 goto out; /* Successfully loaded it. */
2251 err = ctx->fatal_failure;
2252 if (err)
2253 goto out;
2254
2255 /* Could not find a usable firmware. Print the errors. */
2256 for (i = 0; i < B43_NR_FWTYPES; i++) {
2257 errmsg = ctx->errors[i];
2258 if (strlen(errmsg))
2259 b43err(dev->wl, errmsg);
2260 }
2261 b43_print_fw_helptext(dev->wl, 1);
2262 err = -ENOENT;
2263
2264out:
2265 kfree(ctx);
2266 return err;
2267}
2268
Michael Buesche4d6b792007-09-18 15:39:42 -04002269static int b43_upload_microcode(struct b43_wldev *dev)
2270{
2271 const size_t hdr_len = sizeof(struct b43_fw_header);
2272 const __be32 *data;
2273 unsigned int i, len;
2274 u16 fwrev, fwpatch, fwdate, fwtime;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002275 u32 tmp, macctl;
Michael Buesche4d6b792007-09-18 15:39:42 -04002276 int err = 0;
2277
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002278 /* Jump the microcode PSM to offset 0 */
2279 macctl = b43_read32(dev, B43_MMIO_MACCTL);
2280 B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN);
2281 macctl |= B43_MACCTL_PSM_JMP0;
2282 b43_write32(dev, B43_MMIO_MACCTL, macctl);
2283 /* Zero out all microcode PSM registers and shared memory. */
2284 for (i = 0; i < 64; i++)
2285 b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0);
2286 for (i = 0; i < 4096; i += 2)
2287 b43_shm_write16(dev, B43_SHM_SHARED, i, 0);
2288
Michael Buesche4d6b792007-09-18 15:39:42 -04002289 /* Upload Microcode. */
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002290 data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
2291 len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
Michael Buesche4d6b792007-09-18 15:39:42 -04002292 b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
2293 for (i = 0; i < len; i++) {
2294 b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
2295 udelay(10);
2296 }
2297
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002298 if (dev->fw.pcm.data) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002299 /* Upload PCM data. */
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002300 data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
2301 len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
Michael Buesche4d6b792007-09-18 15:39:42 -04002302 b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
2303 b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
2304 /* No need for autoinc bit in SHM_HW */
2305 b43_shm_control_word(dev, B43_SHM_HW, 0x01EB);
2306 for (i = 0; i < len; i++) {
2307 b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
2308 udelay(10);
2309 }
2310 }
2311
2312 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002313
2314 /* Start the microcode PSM */
2315 macctl = b43_read32(dev, B43_MMIO_MACCTL);
2316 macctl &= ~B43_MACCTL_PSM_JMP0;
2317 macctl |= B43_MACCTL_PSM_RUN;
2318 b43_write32(dev, B43_MMIO_MACCTL, macctl);
Michael Buesche4d6b792007-09-18 15:39:42 -04002319
2320 /* Wait for the microcode to load and respond */
2321 i = 0;
2322 while (1) {
2323 tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2324 if (tmp == B43_IRQ_MAC_SUSPENDED)
2325 break;
2326 i++;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002327 if (i >= 20) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002328 b43err(dev->wl, "Microcode not responding\n");
Michael Buescheb189d8b2008-01-28 14:47:41 -08002329 b43_print_fw_helptext(dev->wl, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002330 err = -ENODEV;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002331 goto error;
Michael Buesche4d6b792007-09-18 15:39:42 -04002332 }
Michael Buesche175e992009-09-11 18:31:32 +02002333 msleep(50);
Michael Buesche4d6b792007-09-18 15:39:42 -04002334 }
2335 b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */
2336
2337 /* Get and check the revisions. */
2338 fwrev = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEREV);
2339 fwpatch = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEPATCH);
2340 fwdate = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEDATE);
2341 fwtime = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODETIME);
2342
2343 if (fwrev <= 0x128) {
2344 b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
2345 "binary drivers older than version 4.x is unsupported. "
2346 "You must upgrade your firmware files.\n");
Michael Buescheb189d8b2008-01-28 14:47:41 -08002347 b43_print_fw_helptext(dev->wl, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002348 err = -EOPNOTSUPP;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002349 goto error;
Michael Buesche4d6b792007-09-18 15:39:42 -04002350 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002351 dev->fw.rev = fwrev;
2352 dev->fw.patch = fwpatch;
Michael Buesche48b0ee2008-05-17 22:44:35 +02002353 dev->fw.opensource = (fwdate == 0xFFFF);
2354
Michael Buesch403a3a12009-06-08 21:04:57 +02002355 /* Default to use-all-queues. */
2356 dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues;
2357 dev->qos_enabled = !!modparam_qos;
2358 /* Default to firmware/hardware crypto acceleration. */
2359 dev->hwcrypto_enabled = 1;
2360
Michael Buesche48b0ee2008-05-17 22:44:35 +02002361 if (dev->fw.opensource) {
Michael Buesch403a3a12009-06-08 21:04:57 +02002362 u16 fwcapa;
2363
Michael Buesche48b0ee2008-05-17 22:44:35 +02002364 /* Patchlevel info is encoded in the "time" field. */
2365 dev->fw.patch = fwtime;
Michael Buesch403a3a12009-06-08 21:04:57 +02002366 b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n",
2367 dev->fw.rev, dev->fw.patch);
2368
2369 fwcapa = b43_fwcapa_read(dev);
2370 if (!(fwcapa & B43_FWCAPA_HWCRYPTO) || dev->fw.pcm_request_failed) {
2371 b43info(dev->wl, "Hardware crypto acceleration not supported by firmware\n");
2372 /* Disable hardware crypto and fall back to software crypto. */
2373 dev->hwcrypto_enabled = 0;
2374 }
2375 if (!(fwcapa & B43_FWCAPA_QOS)) {
2376 b43info(dev->wl, "QoS not supported by firmware\n");
2377 /* Disable QoS. Tweak hw->queues to 1. It will be restored before
2378 * ieee80211_unregister to make sure the networking core can
2379 * properly free possible resources. */
2380 dev->wl->hw->queues = 1;
2381 dev->qos_enabled = 0;
2382 }
Michael Buesche48b0ee2008-05-17 22:44:35 +02002383 } else {
2384 b43info(dev->wl, "Loading firmware version %u.%u "
2385 "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
2386 fwrev, fwpatch,
2387 (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
2388 (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
Michael Buesch68217832008-05-17 23:43:57 +02002389 if (dev->fw.pcm_request_failed) {
2390 b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. "
2391 "Hardware accelerated cryptography is disabled.\n");
2392 b43_print_fw_helptext(dev->wl, 0);
2393 }
Michael Buesche48b0ee2008-05-17 22:44:35 +02002394 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002395
Michael Buescheb189d8b2008-01-28 14:47:41 -08002396 if (b43_is_old_txhdr_format(dev)) {
Michael Bueschc5572892008-12-27 18:26:39 +01002397 /* We're over the deadline, but we keep support for old fw
2398 * until it turns out to be in major conflict with something new. */
Michael Buescheb189d8b2008-01-28 14:47:41 -08002399 b43warn(dev->wl, "You are using an old firmware image. "
Michael Bueschc5572892008-12-27 18:26:39 +01002400 "Support for old firmware will be removed soon "
2401 "(official deadline was July 2008).\n");
Michael Buescheb189d8b2008-01-28 14:47:41 -08002402 b43_print_fw_helptext(dev->wl, 0);
2403 }
2404
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002405 return 0;
2406
2407error:
2408 macctl = b43_read32(dev, B43_MMIO_MACCTL);
2409 macctl &= ~B43_MACCTL_PSM_RUN;
2410 macctl |= B43_MACCTL_PSM_JMP0;
2411 b43_write32(dev, B43_MMIO_MACCTL, macctl);
2412
Michael Buesche4d6b792007-09-18 15:39:42 -04002413 return err;
2414}
2415
2416static int b43_write_initvals(struct b43_wldev *dev,
2417 const struct b43_iv *ivals,
2418 size_t count,
2419 size_t array_size)
2420{
2421 const struct b43_iv *iv;
2422 u16 offset;
2423 size_t i;
2424 bool bit32;
2425
2426 BUILD_BUG_ON(sizeof(struct b43_iv) != 6);
2427 iv = ivals;
2428 for (i = 0; i < count; i++) {
2429 if (array_size < sizeof(iv->offset_size))
2430 goto err_format;
2431 array_size -= sizeof(iv->offset_size);
2432 offset = be16_to_cpu(iv->offset_size);
2433 bit32 = !!(offset & B43_IV_32BIT);
2434 offset &= B43_IV_OFFSET_MASK;
2435 if (offset >= 0x1000)
2436 goto err_format;
2437 if (bit32) {
2438 u32 value;
2439
2440 if (array_size < sizeof(iv->data.d32))
2441 goto err_format;
2442 array_size -= sizeof(iv->data.d32);
2443
Harvey Harrison533dd1b2008-04-29 01:03:36 -07002444 value = get_unaligned_be32(&iv->data.d32);
Michael Buesche4d6b792007-09-18 15:39:42 -04002445 b43_write32(dev, offset, value);
2446
2447 iv = (const struct b43_iv *)((const uint8_t *)iv +
2448 sizeof(__be16) +
2449 sizeof(__be32));
2450 } else {
2451 u16 value;
2452
2453 if (array_size < sizeof(iv->data.d16))
2454 goto err_format;
2455 array_size -= sizeof(iv->data.d16);
2456
2457 value = be16_to_cpu(iv->data.d16);
2458 b43_write16(dev, offset, value);
2459
2460 iv = (const struct b43_iv *)((const uint8_t *)iv +
2461 sizeof(__be16) +
2462 sizeof(__be16));
2463 }
2464 }
2465 if (array_size)
2466 goto err_format;
2467
2468 return 0;
2469
2470err_format:
2471 b43err(dev->wl, "Initial Values Firmware file-format error.\n");
Michael Buescheb189d8b2008-01-28 14:47:41 -08002472 b43_print_fw_helptext(dev->wl, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002473
2474 return -EPROTO;
2475}
2476
2477static int b43_upload_initvals(struct b43_wldev *dev)
2478{
2479 const size_t hdr_len = sizeof(struct b43_fw_header);
2480 const struct b43_fw_header *hdr;
2481 struct b43_firmware *fw = &dev->fw;
2482 const struct b43_iv *ivals;
2483 size_t count;
2484 int err;
2485
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002486 hdr = (const struct b43_fw_header *)(fw->initvals.data->data);
2487 ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002488 count = be32_to_cpu(hdr->size);
2489 err = b43_write_initvals(dev, ivals, count,
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002490 fw->initvals.data->size - hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002491 if (err)
2492 goto out;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002493 if (fw->initvals_band.data) {
2494 hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data);
2495 ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002496 count = be32_to_cpu(hdr->size);
2497 err = b43_write_initvals(dev, ivals, count,
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002498 fw->initvals_band.data->size - hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002499 if (err)
2500 goto out;
2501 }
2502out:
2503
2504 return err;
2505}
2506
2507/* Initialize the GPIOs
2508 * http://bcm-specs.sipsolutions.net/GPIO
2509 */
2510static int b43_gpio_init(struct b43_wldev *dev)
2511{
2512 struct ssb_bus *bus = dev->dev->bus;
2513 struct ssb_device *gpiodev, *pcidev = NULL;
2514 u32 mask, set;
2515
2516 b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
2517 & ~B43_MACCTL_GPOUTSMSK);
2518
Michael Buesche4d6b792007-09-18 15:39:42 -04002519 b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK)
2520 | 0x000F);
2521
2522 mask = 0x0000001F;
2523 set = 0x0000000F;
2524 if (dev->dev->bus->chip_id == 0x4301) {
2525 mask |= 0x0060;
2526 set |= 0x0060;
2527 }
2528 if (0 /* FIXME: conditional unknown */ ) {
2529 b43_write16(dev, B43_MMIO_GPIO_MASK,
2530 b43_read16(dev, B43_MMIO_GPIO_MASK)
2531 | 0x0100);
2532 mask |= 0x0180;
2533 set |= 0x0180;
2534 }
Larry Finger95de2842007-11-09 16:57:18 -06002535 if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002536 b43_write16(dev, B43_MMIO_GPIO_MASK,
2537 b43_read16(dev, B43_MMIO_GPIO_MASK)
2538 | 0x0200);
2539 mask |= 0x0200;
2540 set |= 0x0200;
2541 }
2542 if (dev->dev->id.revision >= 2)
2543 mask |= 0x0010; /* FIXME: This is redundant. */
2544
2545#ifdef CONFIG_SSB_DRIVER_PCICORE
2546 pcidev = bus->pcicore.dev;
2547#endif
2548 gpiodev = bus->chipco.dev ? : pcidev;
2549 if (!gpiodev)
2550 return 0;
2551 ssb_write32(gpiodev, B43_GPIO_CONTROL,
2552 (ssb_read32(gpiodev, B43_GPIO_CONTROL)
2553 & mask) | set);
2554
2555 return 0;
2556}
2557
2558/* Turn off all GPIO stuff. Call this on module unload, for example. */
2559static void b43_gpio_cleanup(struct b43_wldev *dev)
2560{
2561 struct ssb_bus *bus = dev->dev->bus;
2562 struct ssb_device *gpiodev, *pcidev = NULL;
2563
2564#ifdef CONFIG_SSB_DRIVER_PCICORE
2565 pcidev = bus->pcicore.dev;
2566#endif
2567 gpiodev = bus->chipco.dev ? : pcidev;
2568 if (!gpiodev)
2569 return;
2570 ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
2571}
2572
2573/* http://bcm-specs.sipsolutions.net/EnableMac */
Michael Bueschf5eda472008-04-20 16:03:32 +02002574void b43_mac_enable(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04002575{
Michael Buesch923fd702008-06-20 18:02:08 +02002576 if (b43_debug(dev, B43_DBG_FIRMWARE)) {
2577 u16 fwstate;
2578
2579 fwstate = b43_shm_read16(dev, B43_SHM_SHARED,
2580 B43_SHM_SH_UCODESTAT);
2581 if ((fwstate != B43_SHM_SH_UCODESTAT_SUSP) &&
2582 (fwstate != B43_SHM_SH_UCODESTAT_SLEEP)) {
2583 b43err(dev->wl, "b43_mac_enable(): The firmware "
2584 "should be suspended, but current state is %u\n",
2585 fwstate);
2586 }
2587 }
2588
Michael Buesche4d6b792007-09-18 15:39:42 -04002589 dev->mac_suspended--;
2590 B43_WARN_ON(dev->mac_suspended < 0);
2591 if (dev->mac_suspended == 0) {
2592 b43_write32(dev, B43_MMIO_MACCTL,
2593 b43_read32(dev, B43_MMIO_MACCTL)
2594 | B43_MACCTL_ENABLED);
2595 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON,
2596 B43_IRQ_MAC_SUSPENDED);
2597 /* Commit writes */
2598 b43_read32(dev, B43_MMIO_MACCTL);
2599 b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2600 b43_power_saving_ctl_bits(dev, 0);
2601 }
2602}
2603
2604/* http://bcm-specs.sipsolutions.net/SuspendMAC */
Michael Bueschf5eda472008-04-20 16:03:32 +02002605void b43_mac_suspend(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04002606{
2607 int i;
2608 u32 tmp;
2609
Michael Buesch05b64b32007-09-28 16:19:03 +02002610 might_sleep();
Michael Buesche4d6b792007-09-18 15:39:42 -04002611 B43_WARN_ON(dev->mac_suspended < 0);
Michael Buesch05b64b32007-09-28 16:19:03 +02002612
Michael Buesche4d6b792007-09-18 15:39:42 -04002613 if (dev->mac_suspended == 0) {
2614 b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
2615 b43_write32(dev, B43_MMIO_MACCTL,
2616 b43_read32(dev, B43_MMIO_MACCTL)
2617 & ~B43_MACCTL_ENABLED);
2618 /* force pci to flush the write */
2619 b43_read32(dev, B43_MMIO_MACCTL);
Michael Bueschba380012008-04-15 21:13:36 +02002620 for (i = 35; i; i--) {
2621 tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2622 if (tmp & B43_IRQ_MAC_SUSPENDED)
2623 goto out;
2624 udelay(10);
2625 }
2626 /* Hm, it seems this will take some time. Use msleep(). */
Michael Buesch05b64b32007-09-28 16:19:03 +02002627 for (i = 40; i; i--) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002628 tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2629 if (tmp & B43_IRQ_MAC_SUSPENDED)
2630 goto out;
Michael Buesch05b64b32007-09-28 16:19:03 +02002631 msleep(1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002632 }
2633 b43err(dev->wl, "MAC suspend failed\n");
2634 }
Michael Buesch05b64b32007-09-28 16:19:03 +02002635out:
Michael Buesche4d6b792007-09-18 15:39:42 -04002636 dev->mac_suspended++;
2637}
2638
2639static void b43_adjust_opmode(struct b43_wldev *dev)
2640{
2641 struct b43_wl *wl = dev->wl;
2642 u32 ctl;
2643 u16 cfp_pretbtt;
2644
2645 ctl = b43_read32(dev, B43_MMIO_MACCTL);
2646 /* Reset status to STA infrastructure mode. */
2647 ctl &= ~B43_MACCTL_AP;
2648 ctl &= ~B43_MACCTL_KEEP_CTL;
2649 ctl &= ~B43_MACCTL_KEEP_BADPLCP;
2650 ctl &= ~B43_MACCTL_KEEP_BAD;
2651 ctl &= ~B43_MACCTL_PROMISC;
Johannes Berg4150c572007-09-17 01:29:23 -04002652 ctl &= ~B43_MACCTL_BEACPROMISC;
Michael Buesche4d6b792007-09-18 15:39:42 -04002653 ctl |= B43_MACCTL_INFRA;
2654
Johannes Berg05c914f2008-09-11 00:01:58 +02002655 if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
2656 b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
Johannes Berg4150c572007-09-17 01:29:23 -04002657 ctl |= B43_MACCTL_AP;
Johannes Berg05c914f2008-09-11 00:01:58 +02002658 else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC))
Johannes Berg4150c572007-09-17 01:29:23 -04002659 ctl &= ~B43_MACCTL_INFRA;
2660
2661 if (wl->filter_flags & FIF_CONTROL)
Michael Buesche4d6b792007-09-18 15:39:42 -04002662 ctl |= B43_MACCTL_KEEP_CTL;
Johannes Berg4150c572007-09-17 01:29:23 -04002663 if (wl->filter_flags & FIF_FCSFAIL)
2664 ctl |= B43_MACCTL_KEEP_BAD;
2665 if (wl->filter_flags & FIF_PLCPFAIL)
2666 ctl |= B43_MACCTL_KEEP_BADPLCP;
2667 if (wl->filter_flags & FIF_PROMISC_IN_BSS)
Michael Buesche4d6b792007-09-18 15:39:42 -04002668 ctl |= B43_MACCTL_PROMISC;
Johannes Berg4150c572007-09-17 01:29:23 -04002669 if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
2670 ctl |= B43_MACCTL_BEACPROMISC;
2671
Michael Buesche4d6b792007-09-18 15:39:42 -04002672 /* Workaround: On old hardware the HW-MAC-address-filter
2673 * doesn't work properly, so always run promisc in filter
2674 * it in software. */
2675 if (dev->dev->id.revision <= 4)
2676 ctl |= B43_MACCTL_PROMISC;
2677
2678 b43_write32(dev, B43_MMIO_MACCTL, ctl);
2679
2680 cfp_pretbtt = 2;
2681 if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
2682 if (dev->dev->bus->chip_id == 0x4306 &&
2683 dev->dev->bus->chip_rev == 3)
2684 cfp_pretbtt = 100;
2685 else
2686 cfp_pretbtt = 50;
2687 }
2688 b43_write16(dev, 0x612, cfp_pretbtt);
Michael Buesch09ebe2f2009-09-12 00:52:48 +02002689
2690 /* FIXME: We don't currently implement the PMQ mechanism,
2691 * so always disable it. If we want to implement PMQ,
2692 * we need to enable it here (clear DISCPMQ) in AP mode.
2693 */
2694 if (0 /* ctl & B43_MACCTL_AP */) {
2695 b43_write32(dev, B43_MMIO_MACCTL,
2696 b43_read32(dev, B43_MMIO_MACCTL)
2697 & ~B43_MACCTL_DISCPMQ);
2698 } else {
2699 b43_write32(dev, B43_MMIO_MACCTL,
2700 b43_read32(dev, B43_MMIO_MACCTL)
2701 | B43_MACCTL_DISCPMQ);
2702 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002703}
2704
2705static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm)
2706{
2707 u16 offset;
2708
2709 if (is_ofdm) {
2710 offset = 0x480;
2711 offset += (b43_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
2712 } else {
2713 offset = 0x4C0;
2714 offset += (b43_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
2715 }
2716 b43_shm_write16(dev, B43_SHM_SHARED, offset + 0x20,
2717 b43_shm_read16(dev, B43_SHM_SHARED, offset));
2718}
2719
2720static void b43_rate_memory_init(struct b43_wldev *dev)
2721{
2722 switch (dev->phy.type) {
2723 case B43_PHYTYPE_A:
2724 case B43_PHYTYPE_G:
Michael Buesch53a6e232008-01-13 21:23:44 +01002725 case B43_PHYTYPE_N:
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02002726 case B43_PHYTYPE_LP:
Michael Buesche4d6b792007-09-18 15:39:42 -04002727 b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
2728 b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
2729 b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
2730 b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1);
2731 b43_rate_memory_write(dev, B43_OFDM_RATE_36MB, 1);
2732 b43_rate_memory_write(dev, B43_OFDM_RATE_48MB, 1);
2733 b43_rate_memory_write(dev, B43_OFDM_RATE_54MB, 1);
2734 if (dev->phy.type == B43_PHYTYPE_A)
2735 break;
2736 /* fallthrough */
2737 case B43_PHYTYPE_B:
2738 b43_rate_memory_write(dev, B43_CCK_RATE_1MB, 0);
2739 b43_rate_memory_write(dev, B43_CCK_RATE_2MB, 0);
2740 b43_rate_memory_write(dev, B43_CCK_RATE_5MB, 0);
2741 b43_rate_memory_write(dev, B43_CCK_RATE_11MB, 0);
2742 break;
2743 default:
2744 B43_WARN_ON(1);
2745 }
2746}
2747
Michael Buesch5042c502008-04-05 15:05:00 +02002748/* Set the default values for the PHY TX Control Words. */
2749static void b43_set_phytxctl_defaults(struct b43_wldev *dev)
2750{
2751 u16 ctl = 0;
2752
2753 ctl |= B43_TXH_PHY_ENC_CCK;
2754 ctl |= B43_TXH_PHY_ANT01AUTO;
2755 ctl |= B43_TXH_PHY_TXPWR;
2756
2757 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);
2758 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, ctl);
2759 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, ctl);
2760}
2761
Michael Buesche4d6b792007-09-18 15:39:42 -04002762/* Set the TX-Antenna for management frames sent by firmware. */
2763static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
2764{
Michael Buesch5042c502008-04-05 15:05:00 +02002765 u16 ant;
Michael Buesche4d6b792007-09-18 15:39:42 -04002766 u16 tmp;
2767
Michael Buesch5042c502008-04-05 15:05:00 +02002768 ant = b43_antenna_to_phyctl(antenna);
Michael Buesche4d6b792007-09-18 15:39:42 -04002769
Michael Buesche4d6b792007-09-18 15:39:42 -04002770 /* For ACK/CTS */
2771 tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
Michael Buescheb189d8b2008-01-28 14:47:41 -08002772 tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
Michael Buesche4d6b792007-09-18 15:39:42 -04002773 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
2774 /* For Probe Resposes */
2775 tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
Michael Buescheb189d8b2008-01-28 14:47:41 -08002776 tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
Michael Buesche4d6b792007-09-18 15:39:42 -04002777 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
2778}
2779
2780/* This is the opposite of b43_chip_init() */
2781static void b43_chip_exit(struct b43_wldev *dev)
2782{
Michael Bueschfb111372008-09-02 13:00:34 +02002783 b43_phy_exit(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002784 b43_gpio_cleanup(dev);
2785 /* firmware is released later */
2786}
2787
2788/* Initialize the chip
2789 * http://bcm-specs.sipsolutions.net/ChipInit
2790 */
2791static int b43_chip_init(struct b43_wldev *dev)
2792{
2793 struct b43_phy *phy = &dev->phy;
Michael Bueschef1a6282008-08-27 18:53:02 +02002794 int err;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002795 u32 value32, macctl;
Michael Buesche4d6b792007-09-18 15:39:42 -04002796 u16 value16;
2797
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002798 /* Initialize the MAC control */
2799 macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED;
2800 if (dev->phy.gmode)
2801 macctl |= B43_MACCTL_GMODE;
2802 macctl |= B43_MACCTL_INFRA;
2803 b43_write32(dev, B43_MMIO_MACCTL, macctl);
Michael Buesche4d6b792007-09-18 15:39:42 -04002804
2805 err = b43_request_firmware(dev);
2806 if (err)
2807 goto out;
2808 err = b43_upload_microcode(dev);
2809 if (err)
2810 goto out; /* firmware is released later */
2811
2812 err = b43_gpio_init(dev);
2813 if (err)
2814 goto out; /* firmware is released later */
Michael Buesch21954c32007-09-27 15:31:40 +02002815
Michael Buesche4d6b792007-09-18 15:39:42 -04002816 err = b43_upload_initvals(dev);
2817 if (err)
Larry Finger1a8d1222007-12-14 13:59:11 +01002818 goto err_gpio_clean;
Michael Buesche4d6b792007-09-18 15:39:42 -04002819
Michael Buesch0b7dcd92008-09-03 12:31:54 +02002820 /* Turn the Analog on and initialize the PHY. */
2821 phy->ops->switch_analog(dev, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002822 err = b43_phy_init(dev);
2823 if (err)
Michael Bueschef1a6282008-08-27 18:53:02 +02002824 goto err_gpio_clean;
Michael Buesche4d6b792007-09-18 15:39:42 -04002825
Michael Bueschef1a6282008-08-27 18:53:02 +02002826 /* Disable Interference Mitigation. */
2827 if (phy->ops->interf_mitigation)
2828 phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
Michael Buesche4d6b792007-09-18 15:39:42 -04002829
Michael Bueschef1a6282008-08-27 18:53:02 +02002830 /* Select the antennae */
2831 if (phy->ops->set_rx_antenna)
2832 phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
Michael Buesche4d6b792007-09-18 15:39:42 -04002833 b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
2834
2835 if (phy->type == B43_PHYTYPE_B) {
2836 value16 = b43_read16(dev, 0x005E);
2837 value16 |= 0x0004;
2838 b43_write16(dev, 0x005E, value16);
2839 }
2840 b43_write32(dev, 0x0100, 0x01000000);
2841 if (dev->dev->id.revision < 5)
2842 b43_write32(dev, 0x010C, 0x01000000);
2843
2844 b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
2845 & ~B43_MACCTL_INFRA);
2846 b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
2847 | B43_MACCTL_INFRA);
Michael Buesche4d6b792007-09-18 15:39:42 -04002848
Michael Buesche4d6b792007-09-18 15:39:42 -04002849 /* Probe Response Timeout value */
2850 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2851 b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
2852
2853 /* Initially set the wireless operation mode. */
2854 b43_adjust_opmode(dev);
2855
2856 if (dev->dev->id.revision < 3) {
2857 b43_write16(dev, 0x060E, 0x0000);
2858 b43_write16(dev, 0x0610, 0x8000);
2859 b43_write16(dev, 0x0604, 0x0000);
2860 b43_write16(dev, 0x0606, 0x0200);
2861 } else {
2862 b43_write32(dev, 0x0188, 0x80000000);
2863 b43_write32(dev, 0x018C, 0x02000000);
2864 }
2865 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, 0x00004000);
2866 b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
2867 b43_write32(dev, B43_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
2868 b43_write32(dev, B43_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2869 b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
2870 b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
2871 b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
2872
2873 value32 = ssb_read32(dev->dev, SSB_TMSLOW);
2874 value32 |= 0x00100000;
2875 ssb_write32(dev->dev, SSB_TMSLOW, value32);
2876
2877 b43_write16(dev, B43_MMIO_POWERUP_DELAY,
2878 dev->dev->bus->chipco.fast_pwrup_delay);
2879
2880 err = 0;
2881 b43dbg(dev->wl, "Chip initialized\n");
Michael Buesch21954c32007-09-27 15:31:40 +02002882out:
Michael Buesche4d6b792007-09-18 15:39:42 -04002883 return err;
2884
Larry Finger1a8d1222007-12-14 13:59:11 +01002885err_gpio_clean:
Michael Buesche4d6b792007-09-18 15:39:42 -04002886 b43_gpio_cleanup(dev);
Michael Buesch21954c32007-09-27 15:31:40 +02002887 return err;
Michael Buesche4d6b792007-09-18 15:39:42 -04002888}
2889
Michael Buesche4d6b792007-09-18 15:39:42 -04002890static void b43_periodic_every60sec(struct b43_wldev *dev)
2891{
Michael Bueschef1a6282008-08-27 18:53:02 +02002892 const struct b43_phy_operations *ops = dev->phy.ops;
Michael Buesche4d6b792007-09-18 15:39:42 -04002893
Michael Bueschef1a6282008-08-27 18:53:02 +02002894 if (ops->pwork_60sec)
2895 ops->pwork_60sec(dev);
Michael Buesch18c8ade2008-08-28 19:33:40 +02002896
2897 /* Force check the TX power emission now. */
2898 b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME);
Michael Buesche4d6b792007-09-18 15:39:42 -04002899}
2900
2901static void b43_periodic_every30sec(struct b43_wldev *dev)
2902{
2903 /* Update device statistics. */
2904 b43_calculate_link_quality(dev);
2905}
2906
2907static void b43_periodic_every15sec(struct b43_wldev *dev)
2908{
2909 struct b43_phy *phy = &dev->phy;
Michael Buesch9b839a72008-06-20 17:44:02 +02002910 u16 wdr;
2911
2912 if (dev->fw.opensource) {
2913 /* Check if the firmware is still alive.
2914 * It will reset the watchdog counter to 0 in its idle loop. */
2915 wdr = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_WATCHDOG_REG);
2916 if (unlikely(wdr)) {
2917 b43err(dev->wl, "Firmware watchdog: The firmware died!\n");
2918 b43_controller_restart(dev, "Firmware watchdog");
2919 return;
2920 } else {
2921 b43_shm_write16(dev, B43_SHM_SCRATCH,
2922 B43_WATCHDOG_REG, 1);
2923 }
2924 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002925
Michael Bueschef1a6282008-08-27 18:53:02 +02002926 if (phy->ops->pwork_15sec)
2927 phy->ops->pwork_15sec(dev);
2928
Stefano Brivio00e0b8c2007-11-25 11:10:33 +01002929 atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
2930 wmb();
Michael Buesch990b86f2009-09-12 00:48:03 +02002931
2932#if B43_DEBUG
2933 if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
2934 unsigned int i;
2935
2936 b43dbg(dev->wl, "Stats: %7u IRQs/sec, %7u TX/sec, %7u RX/sec\n",
2937 dev->irq_count / 15,
2938 dev->tx_count / 15,
2939 dev->rx_count / 15);
2940 dev->irq_count = 0;
2941 dev->tx_count = 0;
2942 dev->rx_count = 0;
2943 for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
2944 if (dev->irq_bit_count[i]) {
2945 b43dbg(dev->wl, "Stats: %7u IRQ-%02u/sec (0x%08X)\n",
2946 dev->irq_bit_count[i] / 15, i, (1 << i));
2947 dev->irq_bit_count[i] = 0;
2948 }
2949 }
2950 }
2951#endif
Michael Buesche4d6b792007-09-18 15:39:42 -04002952}
2953
Michael Buesche4d6b792007-09-18 15:39:42 -04002954static void do_periodic_work(struct b43_wldev *dev)
2955{
2956 unsigned int state;
2957
2958 state = dev->periodic_state;
Michael Buesch42bb4cd2007-09-28 14:22:33 +02002959 if (state % 4 == 0)
Michael Buesche4d6b792007-09-18 15:39:42 -04002960 b43_periodic_every60sec(dev);
Michael Buesch42bb4cd2007-09-28 14:22:33 +02002961 if (state % 2 == 0)
Michael Buesche4d6b792007-09-18 15:39:42 -04002962 b43_periodic_every30sec(dev);
Michael Buesch42bb4cd2007-09-28 14:22:33 +02002963 b43_periodic_every15sec(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002964}
2965
Michael Buesch05b64b32007-09-28 16:19:03 +02002966/* Periodic work locking policy:
2967 * The whole periodic work handler is protected by
2968 * wl->mutex. If another lock is needed somewhere in the
2969 * pwork callchain, it's aquired in-place, where it's needed.
Michael Buesche4d6b792007-09-18 15:39:42 -04002970 */
Michael Buesche4d6b792007-09-18 15:39:42 -04002971static void b43_periodic_work_handler(struct work_struct *work)
2972{
Michael Buesch05b64b32007-09-28 16:19:03 +02002973 struct b43_wldev *dev = container_of(work, struct b43_wldev,
2974 periodic_work.work);
2975 struct b43_wl *wl = dev->wl;
2976 unsigned long delay;
Michael Buesche4d6b792007-09-18 15:39:42 -04002977
Michael Buesch05b64b32007-09-28 16:19:03 +02002978 mutex_lock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04002979
2980 if (unlikely(b43_status(dev) != B43_STAT_STARTED))
2981 goto out;
2982 if (b43_debug(dev, B43_DBG_PWORK_STOP))
2983 goto out_requeue;
2984
Michael Buesch05b64b32007-09-28 16:19:03 +02002985 do_periodic_work(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002986
Michael Buesche4d6b792007-09-18 15:39:42 -04002987 dev->periodic_state++;
Michael Buesch42bb4cd2007-09-28 14:22:33 +02002988out_requeue:
Michael Buesche4d6b792007-09-18 15:39:42 -04002989 if (b43_debug(dev, B43_DBG_PWORK_FAST))
2990 delay = msecs_to_jiffies(50);
2991 else
Anton Blanchard82cd6822007-10-15 00:42:23 -05002992 delay = round_jiffies_relative(HZ * 15);
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002993 ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay);
Michael Buesch42bb4cd2007-09-28 14:22:33 +02002994out:
Michael Buesch05b64b32007-09-28 16:19:03 +02002995 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04002996}
2997
2998static void b43_periodic_tasks_setup(struct b43_wldev *dev)
2999{
3000 struct delayed_work *work = &dev->periodic_work;
3001
3002 dev->periodic_state = 0;
3003 INIT_DELAYED_WORK(work, b43_periodic_work_handler);
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04003004 ieee80211_queue_delayed_work(dev->wl->hw, work, 0);
Michael Buesche4d6b792007-09-18 15:39:42 -04003005}
3006
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01003007/* Check if communication with the device works correctly. */
Michael Buesche4d6b792007-09-18 15:39:42 -04003008static int b43_validate_chipaccess(struct b43_wldev *dev)
3009{
Michael Bueschf62ae6c2009-07-31 20:51:41 +02003010 u32 v, backup0, backup4;
Michael Buesche4d6b792007-09-18 15:39:42 -04003011
Michael Bueschf62ae6c2009-07-31 20:51:41 +02003012 backup0 = b43_shm_read32(dev, B43_SHM_SHARED, 0);
3013 backup4 = b43_shm_read32(dev, B43_SHM_SHARED, 4);
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01003014
3015 /* Check for read/write and endianness problems. */
Michael Buesche4d6b792007-09-18 15:39:42 -04003016 b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
3017 if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55)
3018 goto error;
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01003019 b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
3020 if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
Michael Buesche4d6b792007-09-18 15:39:42 -04003021 goto error;
3022
Michael Bueschf62ae6c2009-07-31 20:51:41 +02003023 /* Check if unaligned 32bit SHM_SHARED access works properly.
3024 * However, don't bail out on failure, because it's noncritical. */
3025 b43_shm_write16(dev, B43_SHM_SHARED, 0, 0x1122);
3026 b43_shm_write16(dev, B43_SHM_SHARED, 2, 0x3344);
3027 b43_shm_write16(dev, B43_SHM_SHARED, 4, 0x5566);
3028 b43_shm_write16(dev, B43_SHM_SHARED, 6, 0x7788);
3029 if (b43_shm_read32(dev, B43_SHM_SHARED, 2) != 0x55663344)
3030 b43warn(dev->wl, "Unaligned 32bit SHM read access is broken\n");
3031 b43_shm_write32(dev, B43_SHM_SHARED, 2, 0xAABBCCDD);
3032 if (b43_shm_read16(dev, B43_SHM_SHARED, 0) != 0x1122 ||
3033 b43_shm_read16(dev, B43_SHM_SHARED, 2) != 0xCCDD ||
3034 b43_shm_read16(dev, B43_SHM_SHARED, 4) != 0xAABB ||
3035 b43_shm_read16(dev, B43_SHM_SHARED, 6) != 0x7788)
3036 b43warn(dev->wl, "Unaligned 32bit SHM write access is broken\n");
3037
3038 b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0);
3039 b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4);
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01003040
3041 if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) {
3042 /* The 32bit register shadows the two 16bit registers
3043 * with update sideeffects. Validate this. */
3044 b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
3045 b43_write32(dev, B43_MMIO_TSF_CFP_START, 0xCCCCBBBB);
3046 if (b43_read16(dev, B43_MMIO_TSF_CFP_START_LOW) != 0xBBBB)
3047 goto error;
3048 if (b43_read16(dev, B43_MMIO_TSF_CFP_START_HIGH) != 0xCCCC)
3049 goto error;
3050 }
3051 b43_write32(dev, B43_MMIO_TSF_CFP_START, 0);
3052
3053 v = b43_read32(dev, B43_MMIO_MACCTL);
3054 v |= B43_MACCTL_GMODE;
3055 if (v != (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
Michael Buesche4d6b792007-09-18 15:39:42 -04003056 goto error;
3057
3058 return 0;
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01003059error:
Michael Buesche4d6b792007-09-18 15:39:42 -04003060 b43err(dev->wl, "Failed to validate the chipaccess\n");
3061 return -ENODEV;
3062}
3063
3064static void b43_security_init(struct b43_wldev *dev)
3065{
Michael Buesche4d6b792007-09-18 15:39:42 -04003066 dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP);
3067 /* KTP is a word address, but we address SHM bytewise.
3068 * So multiply by two.
3069 */
3070 dev->ktp *= 2;
Michael Buesch66d2d082009-08-06 10:36:50 +02003071 /* Number of RCMTA address slots */
3072 b43_write16(dev, B43_MMIO_RCMTA_COUNT, B43_NR_PAIRWISE_KEYS);
3073 /* Clear the key memory. */
Michael Buesche4d6b792007-09-18 15:39:42 -04003074 b43_clear_keys(dev);
3075}
3076
Michael Buesch616de352009-03-29 13:19:31 +02003077#ifdef CONFIG_B43_HWRNG
John Daiker99da1852009-02-24 02:16:42 -08003078static int b43_rng_read(struct hwrng *rng, u32 *data)
Michael Buesche4d6b792007-09-18 15:39:42 -04003079{
3080 struct b43_wl *wl = (struct b43_wl *)rng->priv;
Michael Buescha78b3bb2009-09-11 21:44:05 +02003081 struct b43_wldev *dev;
3082 int count = -ENODEV;
Michael Buesche4d6b792007-09-18 15:39:42 -04003083
Michael Buescha78b3bb2009-09-11 21:44:05 +02003084 mutex_lock(&wl->mutex);
3085 dev = wl->current_dev;
3086 if (likely(dev && b43_status(dev) >= B43_STAT_INITIALIZED)) {
3087 *data = b43_read16(dev, B43_MMIO_RNG);
3088 count = sizeof(u16);
3089 }
3090 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003091
Michael Buescha78b3bb2009-09-11 21:44:05 +02003092 return count;
Michael Buesche4d6b792007-09-18 15:39:42 -04003093}
Michael Buesch616de352009-03-29 13:19:31 +02003094#endif /* CONFIG_B43_HWRNG */
Michael Buesche4d6b792007-09-18 15:39:42 -04003095
Rafael J. Wysockib844eba2008-03-23 20:28:24 +01003096static void b43_rng_exit(struct b43_wl *wl)
Michael Buesche4d6b792007-09-18 15:39:42 -04003097{
Michael Buesch616de352009-03-29 13:19:31 +02003098#ifdef CONFIG_B43_HWRNG
Michael Buesche4d6b792007-09-18 15:39:42 -04003099 if (wl->rng_initialized)
Rafael J. Wysockib844eba2008-03-23 20:28:24 +01003100 hwrng_unregister(&wl->rng);
Michael Buesch616de352009-03-29 13:19:31 +02003101#endif /* CONFIG_B43_HWRNG */
Michael Buesche4d6b792007-09-18 15:39:42 -04003102}
3103
3104static int b43_rng_init(struct b43_wl *wl)
3105{
Michael Buesch616de352009-03-29 13:19:31 +02003106 int err = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04003107
Michael Buesch616de352009-03-29 13:19:31 +02003108#ifdef CONFIG_B43_HWRNG
Michael Buesche4d6b792007-09-18 15:39:42 -04003109 snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
3110 "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
3111 wl->rng.name = wl->rng_name;
3112 wl->rng.data_read = b43_rng_read;
3113 wl->rng.priv = (unsigned long)wl;
3114 wl->rng_initialized = 1;
3115 err = hwrng_register(&wl->rng);
3116 if (err) {
3117 wl->rng_initialized = 0;
3118 b43err(wl, "Failed to register the random "
3119 "number generator (%d)\n", err);
3120 }
Michael Buesch616de352009-03-29 13:19:31 +02003121#endif /* CONFIG_B43_HWRNG */
Michael Buesche4d6b792007-09-18 15:39:42 -04003122
3123 return err;
3124}
3125
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003126static void b43_tx_work(struct work_struct *work)
Michael Buesche4d6b792007-09-18 15:39:42 -04003127{
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003128 struct b43_wl *wl = container_of(work, struct b43_wl, tx_work);
3129 struct b43_wldev *dev;
3130 struct sk_buff *skb;
3131 int err = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04003132
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003133 mutex_lock(&wl->mutex);
3134 dev = wl->current_dev;
3135 if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED)) {
3136 mutex_unlock(&wl->mutex);
3137 return;
Michael Buesch5100d5a2008-03-29 21:01:16 +01003138 }
Michael Buesch21a75d72008-04-25 19:29:08 +02003139
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003140 while (skb_queue_len(&wl->tx_queue)) {
3141 skb = skb_dequeue(&wl->tx_queue);
Michael Buesch21a75d72008-04-25 19:29:08 +02003142
Michael Buesch21a75d72008-04-25 19:29:08 +02003143 if (b43_using_pio_transfers(dev))
Johannes Berge039fa42008-05-15 12:55:29 +02003144 err = b43_pio_tx(dev, skb);
Michael Buesch21a75d72008-04-25 19:29:08 +02003145 else
Johannes Berge039fa42008-05-15 12:55:29 +02003146 err = b43_dma_tx(dev, skb);
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003147 if (unlikely(err))
3148 dev_kfree_skb(skb); /* Drop it */
Michael Buesch21a75d72008-04-25 19:29:08 +02003149 }
3150
Michael Buesch990b86f2009-09-12 00:48:03 +02003151#if B43_DEBUG
3152 dev->tx_count++;
3153#endif
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003154 mutex_unlock(&wl->mutex);
3155}
Michael Buesch21a75d72008-04-25 19:29:08 +02003156
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003157static int b43_op_tx(struct ieee80211_hw *hw,
3158 struct sk_buff *skb)
3159{
3160 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Bueschc9e8eae2008-06-15 15:17:29 +02003161
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003162 if (unlikely(skb->len < 2 + 2 + 6)) {
3163 /* Too short, this can't be a valid frame. */
3164 dev_kfree_skb_any(skb);
3165 return NETDEV_TX_OK;
3166 }
3167 B43_WARN_ON(skb_shinfo(skb)->nr_frags);
3168
3169 skb_queue_tail(&wl->tx_queue, skb);
3170 ieee80211_queue_work(wl->hw, &wl->tx_work);
3171
Michael Buesche4d6b792007-09-18 15:39:42 -04003172 return NETDEV_TX_OK;
3173}
3174
Michael Buesche6f5b932008-03-05 21:18:49 +01003175static void b43_qos_params_upload(struct b43_wldev *dev,
3176 const struct ieee80211_tx_queue_params *p,
3177 u16 shm_offset)
3178{
3179 u16 params[B43_NR_QOSPARAMS];
Johannes Berg0b576642008-07-15 02:08:24 -07003180 int bslots, tmp;
Michael Buesche6f5b932008-03-05 21:18:49 +01003181 unsigned int i;
3182
Michael Bueschb0544eb2009-09-06 15:42:45 +02003183 if (!dev->qos_enabled)
3184 return;
3185
Johannes Berg0b576642008-07-15 02:08:24 -07003186 bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min;
Michael Buesche6f5b932008-03-05 21:18:49 +01003187
3188 memset(&params, 0, sizeof(params));
3189
3190 params[B43_QOSPARAM_TXOP] = p->txop * 32;
Johannes Berg0b576642008-07-15 02:08:24 -07003191 params[B43_QOSPARAM_CWMIN] = p->cw_min;
3192 params[B43_QOSPARAM_CWMAX] = p->cw_max;
3193 params[B43_QOSPARAM_CWCUR] = p->cw_min;
3194 params[B43_QOSPARAM_AIFS] = p->aifs;
Michael Buesche6f5b932008-03-05 21:18:49 +01003195 params[B43_QOSPARAM_BSLOTS] = bslots;
Johannes Berg0b576642008-07-15 02:08:24 -07003196 params[B43_QOSPARAM_REGGAP] = bslots + p->aifs;
Michael Buesche6f5b932008-03-05 21:18:49 +01003197
3198 for (i = 0; i < ARRAY_SIZE(params); i++) {
3199 if (i == B43_QOSPARAM_STATUS) {
3200 tmp = b43_shm_read16(dev, B43_SHM_SHARED,
3201 shm_offset + (i * 2));
3202 /* Mark the parameters as updated. */
3203 tmp |= 0x100;
3204 b43_shm_write16(dev, B43_SHM_SHARED,
3205 shm_offset + (i * 2),
3206 tmp);
3207 } else {
3208 b43_shm_write16(dev, B43_SHM_SHARED,
3209 shm_offset + (i * 2),
3210 params[i]);
3211 }
3212 }
3213}
3214
Michael Bueschc40c1122008-09-06 16:21:47 +02003215/* Mapping of mac80211 queue numbers to b43 QoS SHM offsets. */
3216static const u16 b43_qos_shm_offsets[] = {
3217 /* [mac80211-queue-nr] = SHM_OFFSET, */
3218 [0] = B43_QOS_VOICE,
3219 [1] = B43_QOS_VIDEO,
3220 [2] = B43_QOS_BESTEFFORT,
3221 [3] = B43_QOS_BACKGROUND,
3222};
3223
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003224/* Update all QOS parameters in hardware. */
3225static void b43_qos_upload_all(struct b43_wldev *dev)
Michael Buesche6f5b932008-03-05 21:18:49 +01003226{
3227 struct b43_wl *wl = dev->wl;
3228 struct b43_qos_params *params;
Michael Buesche6f5b932008-03-05 21:18:49 +01003229 unsigned int i;
3230
Michael Bueschb0544eb2009-09-06 15:42:45 +02003231 if (!dev->qos_enabled)
3232 return;
3233
Michael Bueschc40c1122008-09-06 16:21:47 +02003234 BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
3235 ARRAY_SIZE(wl->qos_params));
Michael Buesche6f5b932008-03-05 21:18:49 +01003236
3237 b43_mac_suspend(dev);
Michael Buesche6f5b932008-03-05 21:18:49 +01003238 for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
3239 params = &(wl->qos_params[i]);
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003240 b43_qos_params_upload(dev, &(params->p),
3241 b43_qos_shm_offsets[i]);
Michael Buesche6f5b932008-03-05 21:18:49 +01003242 }
Michael Buesche6f5b932008-03-05 21:18:49 +01003243 b43_mac_enable(dev);
3244}
3245
3246static void b43_qos_clear(struct b43_wl *wl)
3247{
3248 struct b43_qos_params *params;
3249 unsigned int i;
3250
Michael Bueschc40c1122008-09-06 16:21:47 +02003251 /* Initialize QoS parameters to sane defaults. */
3252
3253 BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
3254 ARRAY_SIZE(wl->qos_params));
3255
Michael Buesche6f5b932008-03-05 21:18:49 +01003256 for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
3257 params = &(wl->qos_params[i]);
3258
Michael Bueschc40c1122008-09-06 16:21:47 +02003259 switch (b43_qos_shm_offsets[i]) {
3260 case B43_QOS_VOICE:
3261 params->p.txop = 0;
3262 params->p.aifs = 2;
3263 params->p.cw_min = 0x0001;
3264 params->p.cw_max = 0x0001;
3265 break;
3266 case B43_QOS_VIDEO:
3267 params->p.txop = 0;
3268 params->p.aifs = 2;
3269 params->p.cw_min = 0x0001;
3270 params->p.cw_max = 0x0001;
3271 break;
3272 case B43_QOS_BESTEFFORT:
3273 params->p.txop = 0;
3274 params->p.aifs = 3;
3275 params->p.cw_min = 0x0001;
3276 params->p.cw_max = 0x03FF;
3277 break;
3278 case B43_QOS_BACKGROUND:
3279 params->p.txop = 0;
3280 params->p.aifs = 7;
3281 params->p.cw_min = 0x0001;
3282 params->p.cw_max = 0x03FF;
3283 break;
3284 default:
3285 B43_WARN_ON(1);
3286 }
Michael Buesche6f5b932008-03-05 21:18:49 +01003287 }
3288}
3289
3290/* Initialize the core's QOS capabilities */
3291static void b43_qos_init(struct b43_wldev *dev)
3292{
Michael Bueschb0544eb2009-09-06 15:42:45 +02003293 if (!dev->qos_enabled) {
3294 /* Disable QOS support. */
3295 b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_EDCF);
3296 b43_write16(dev, B43_MMIO_IFSCTL,
3297 b43_read16(dev, B43_MMIO_IFSCTL)
3298 & ~B43_MMIO_IFSCTL_USE_EDCF);
3299 b43dbg(dev->wl, "QoS disabled\n");
3300 return;
3301 }
3302
Michael Buesche6f5b932008-03-05 21:18:49 +01003303 /* Upload the current QOS parameters. */
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003304 b43_qos_upload_all(dev);
Michael Buesche6f5b932008-03-05 21:18:49 +01003305
3306 /* Enable QOS support. */
3307 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
3308 b43_write16(dev, B43_MMIO_IFSCTL,
3309 b43_read16(dev, B43_MMIO_IFSCTL)
3310 | B43_MMIO_IFSCTL_USE_EDCF);
Michael Bueschb0544eb2009-09-06 15:42:45 +02003311 b43dbg(dev->wl, "QoS enabled\n");
Michael Buesche6f5b932008-03-05 21:18:49 +01003312}
3313
Johannes Berge100bb62008-04-30 18:51:21 +02003314static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue,
Michael Buesch40faacc2007-10-28 16:29:32 +01003315 const struct ieee80211_tx_queue_params *params)
Michael Buesche4d6b792007-09-18 15:39:42 -04003316{
Michael Buesche6f5b932008-03-05 21:18:49 +01003317 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003318 struct b43_wldev *dev;
Michael Buesche6f5b932008-03-05 21:18:49 +01003319 unsigned int queue = (unsigned int)_queue;
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003320 int err = -ENODEV;
Michael Buesche6f5b932008-03-05 21:18:49 +01003321
3322 if (queue >= ARRAY_SIZE(wl->qos_params)) {
3323 /* Queue not available or don't support setting
3324 * params on this queue. Return success to not
3325 * confuse mac80211. */
3326 return 0;
3327 }
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003328 BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
3329 ARRAY_SIZE(wl->qos_params));
Michael Buesche6f5b932008-03-05 21:18:49 +01003330
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003331 mutex_lock(&wl->mutex);
3332 dev = wl->current_dev;
3333 if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED)))
3334 goto out_unlock;
Michael Buesche6f5b932008-03-05 21:18:49 +01003335
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003336 memcpy(&(wl->qos_params[queue].p), params, sizeof(*params));
3337 b43_mac_suspend(dev);
3338 b43_qos_params_upload(dev, &(wl->qos_params[queue].p),
3339 b43_qos_shm_offsets[queue]);
3340 b43_mac_enable(dev);
3341 err = 0;
Michael Buesche6f5b932008-03-05 21:18:49 +01003342
Michael Buesch5a5f3b42008-09-06 20:07:31 +02003343out_unlock:
3344 mutex_unlock(&wl->mutex);
3345
3346 return err;
Michael Buesche4d6b792007-09-18 15:39:42 -04003347}
3348
Michael Buesch40faacc2007-10-28 16:29:32 +01003349static int b43_op_get_tx_stats(struct ieee80211_hw *hw,
3350 struct ieee80211_tx_queue_stats *stats)
Michael Buesche4d6b792007-09-18 15:39:42 -04003351{
3352 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Buesch36dbd952009-09-04 22:51:29 +02003353 struct b43_wldev *dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04003354 int err = -ENODEV;
3355
Michael Buesch36dbd952009-09-04 22:51:29 +02003356 mutex_lock(&wl->mutex);
3357 dev = wl->current_dev;
3358 if (dev && b43_status(dev) >= B43_STAT_STARTED) {
Michael Buesch5100d5a2008-03-29 21:01:16 +01003359 if (b43_using_pio_transfers(dev))
3360 b43_pio_get_tx_stats(dev, stats);
3361 else
3362 b43_dma_get_tx_stats(dev, stats);
Michael Buesche4d6b792007-09-18 15:39:42 -04003363 err = 0;
3364 }
Michael Buesch36dbd952009-09-04 22:51:29 +02003365 mutex_unlock(&wl->mutex);
3366
Michael Buesche4d6b792007-09-18 15:39:42 -04003367 return err;
3368}
3369
Michael Buesch40faacc2007-10-28 16:29:32 +01003370static int b43_op_get_stats(struct ieee80211_hw *hw,
3371 struct ieee80211_low_level_stats *stats)
Michael Buesche4d6b792007-09-18 15:39:42 -04003372{
3373 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Buesche4d6b792007-09-18 15:39:42 -04003374
Michael Buesch36dbd952009-09-04 22:51:29 +02003375 mutex_lock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003376 memcpy(stats, &wl->ieee_stats, sizeof(*stats));
Michael Buesch36dbd952009-09-04 22:51:29 +02003377 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003378
3379 return 0;
3380}
3381
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01003382static u64 b43_op_get_tsf(struct ieee80211_hw *hw)
3383{
3384 struct b43_wl *wl = hw_to_b43_wl(hw);
3385 struct b43_wldev *dev;
3386 u64 tsf;
3387
3388 mutex_lock(&wl->mutex);
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01003389 dev = wl->current_dev;
3390
3391 if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED))
3392 b43_tsf_read(dev, &tsf);
3393 else
3394 tsf = 0;
3395
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01003396 mutex_unlock(&wl->mutex);
3397
3398 return tsf;
3399}
3400
3401static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
3402{
3403 struct b43_wl *wl = hw_to_b43_wl(hw);
3404 struct b43_wldev *dev;
3405
3406 mutex_lock(&wl->mutex);
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01003407 dev = wl->current_dev;
3408
3409 if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED))
3410 b43_tsf_write(dev, tsf);
3411
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01003412 mutex_unlock(&wl->mutex);
3413}
3414
Michael Buesche4d6b792007-09-18 15:39:42 -04003415static void b43_put_phy_into_reset(struct b43_wldev *dev)
3416{
3417 struct ssb_device *sdev = dev->dev;
3418 u32 tmslow;
3419
3420 tmslow = ssb_read32(sdev, SSB_TMSLOW);
3421 tmslow &= ~B43_TMSLOW_GMODE;
3422 tmslow |= B43_TMSLOW_PHYRESET;
3423 tmslow |= SSB_TMSLOW_FGC;
3424 ssb_write32(sdev, SSB_TMSLOW, tmslow);
3425 msleep(1);
3426
3427 tmslow = ssb_read32(sdev, SSB_TMSLOW);
3428 tmslow &= ~SSB_TMSLOW_FGC;
3429 tmslow |= B43_TMSLOW_PHYRESET;
3430 ssb_write32(sdev, SSB_TMSLOW, tmslow);
3431 msleep(1);
3432}
3433
John Daiker99da1852009-02-24 02:16:42 -08003434static const char *band_to_string(enum ieee80211_band band)
Michael Buesche4d6b792007-09-18 15:39:42 -04003435{
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003436 switch (band) {
3437 case IEEE80211_BAND_5GHZ:
3438 return "5";
3439 case IEEE80211_BAND_2GHZ:
3440 return "2.4";
3441 default:
3442 break;
3443 }
3444 B43_WARN_ON(1);
3445 return "";
3446}
3447
3448/* Expects wl->mutex locked */
3449static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan)
3450{
3451 struct b43_wldev *up_dev = NULL;
Michael Buesche4d6b792007-09-18 15:39:42 -04003452 struct b43_wldev *down_dev;
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003453 struct b43_wldev *d;
Michael Buesche4d6b792007-09-18 15:39:42 -04003454 int err;
John W. Linville922d8a02009-01-12 14:40:20 -05003455 bool uninitialized_var(gmode);
Michael Buesche4d6b792007-09-18 15:39:42 -04003456 int prev_status;
3457
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003458 /* Find a device and PHY which supports the band. */
3459 list_for_each_entry(d, &wl->devlist, list) {
3460 switch (chan->band) {
3461 case IEEE80211_BAND_5GHZ:
3462 if (d->phy.supports_5ghz) {
3463 up_dev = d;
3464 gmode = 0;
3465 }
3466 break;
3467 case IEEE80211_BAND_2GHZ:
3468 if (d->phy.supports_2ghz) {
3469 up_dev = d;
3470 gmode = 1;
3471 }
3472 break;
3473 default:
3474 B43_WARN_ON(1);
3475 return -EINVAL;
3476 }
3477 if (up_dev)
3478 break;
3479 }
3480 if (!up_dev) {
3481 b43err(wl, "Could not find a device for %s-GHz band operation\n",
3482 band_to_string(chan->band));
3483 return -ENODEV;
Michael Buesche4d6b792007-09-18 15:39:42 -04003484 }
3485 if ((up_dev == wl->current_dev) &&
3486 (!!wl->current_dev->phy.gmode == !!gmode)) {
3487 /* This device is already running. */
3488 return 0;
3489 }
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003490 b43dbg(wl, "Switching to %s-GHz band\n",
3491 band_to_string(chan->band));
Michael Buesche4d6b792007-09-18 15:39:42 -04003492 down_dev = wl->current_dev;
3493
3494 prev_status = b43_status(down_dev);
3495 /* Shutdown the currently running core. */
3496 if (prev_status >= B43_STAT_STARTED)
Michael Buesch36dbd952009-09-04 22:51:29 +02003497 down_dev = b43_wireless_core_stop(down_dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003498 if (prev_status >= B43_STAT_INITIALIZED)
3499 b43_wireless_core_exit(down_dev);
3500
3501 if (down_dev != up_dev) {
3502 /* We switch to a different core, so we put PHY into
3503 * RESET on the old core. */
3504 b43_put_phy_into_reset(down_dev);
3505 }
3506
3507 /* Now start the new core. */
3508 up_dev->phy.gmode = gmode;
3509 if (prev_status >= B43_STAT_INITIALIZED) {
3510 err = b43_wireless_core_init(up_dev);
3511 if (err) {
3512 b43err(wl, "Fatal: Could not initialize device for "
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003513 "selected %s-GHz band\n",
3514 band_to_string(chan->band));
Michael Buesche4d6b792007-09-18 15:39:42 -04003515 goto init_failure;
3516 }
3517 }
3518 if (prev_status >= B43_STAT_STARTED) {
3519 err = b43_wireless_core_start(up_dev);
3520 if (err) {
3521 b43err(wl, "Fatal: Coult not start device for "
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003522 "selected %s-GHz band\n",
3523 band_to_string(chan->band));
Michael Buesche4d6b792007-09-18 15:39:42 -04003524 b43_wireless_core_exit(up_dev);
3525 goto init_failure;
3526 }
3527 }
3528 B43_WARN_ON(b43_status(up_dev) != prev_status);
3529
3530 wl->current_dev = up_dev;
3531
3532 return 0;
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003533init_failure:
Michael Buesche4d6b792007-09-18 15:39:42 -04003534 /* Whoops, failed to init the new core. No core is operating now. */
3535 wl->current_dev = NULL;
3536 return err;
3537}
3538
Johannes Berg9124b072008-10-14 19:17:54 +02003539/* Write the short and long frame retry limit values. */
3540static void b43_set_retry_limits(struct b43_wldev *dev,
3541 unsigned int short_retry,
3542 unsigned int long_retry)
3543{
3544 /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
3545 * the chip-internal counter. */
3546 short_retry = min(short_retry, (unsigned int)0xF);
3547 long_retry = min(long_retry, (unsigned int)0xF);
3548
3549 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
3550 short_retry);
3551 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
3552 long_retry);
3553}
3554
Johannes Berge8975582008-10-09 12:18:51 +02003555static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
Michael Buesche4d6b792007-09-18 15:39:42 -04003556{
3557 struct b43_wl *wl = hw_to_b43_wl(hw);
3558 struct b43_wldev *dev;
3559 struct b43_phy *phy;
Johannes Berge8975582008-10-09 12:18:51 +02003560 struct ieee80211_conf *conf = &hw->conf;
Michael Buesch9db1f6d2007-12-22 21:54:20 +01003561 int antenna;
Michael Buesche4d6b792007-09-18 15:39:42 -04003562 int err = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04003563
Michael Buesche4d6b792007-09-18 15:39:42 -04003564 mutex_lock(&wl->mutex);
3565
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003566 /* Switch the band (if necessary). This might change the active core. */
3567 err = b43_switch_band(wl, conf->channel);
Michael Buesche4d6b792007-09-18 15:39:42 -04003568 if (err)
3569 goto out_unlock_mutex;
3570 dev = wl->current_dev;
3571 phy = &dev->phy;
3572
Michael Bueschd10d0e52008-12-18 22:13:39 +01003573 b43_mac_suspend(dev);
3574
Johannes Berg9124b072008-10-14 19:17:54 +02003575 if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
3576 b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
3577 conf->long_frame_max_tx_count);
3578 changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
3579 if (!changed)
Michael Bueschd10d0e52008-12-18 22:13:39 +01003580 goto out_mac_enable;
Michael Buesche4d6b792007-09-18 15:39:42 -04003581
3582 /* Switch to the requested channel.
3583 * The firmware takes care of races with the TX handler. */
Johannes Berg8318d782008-01-24 19:38:38 +01003584 if (conf->channel->hw_value != phy->channel)
Michael Bueschef1a6282008-08-27 18:53:02 +02003585 b43_switch_channel(dev, conf->channel->hw_value);
Michael Buesche4d6b792007-09-18 15:39:42 -04003586
Johannes Berg0869aea2009-10-28 10:03:35 +01003587 dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR);
Johannes Bergd42ce842007-11-23 14:50:51 +01003588
Michael Buesche4d6b792007-09-18 15:39:42 -04003589 /* Adjust the desired TX power level. */
3590 if (conf->power_level != 0) {
Michael Buesch18c8ade2008-08-28 19:33:40 +02003591 if (conf->power_level != phy->desired_txpower) {
3592 phy->desired_txpower = conf->power_level;
3593 b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME |
3594 B43_TXPWR_IGNORE_TSSI);
Michael Buesche4d6b792007-09-18 15:39:42 -04003595 }
3596 }
3597
3598 /* Antennas for RX and management frame TX. */
Johannes Berg0f4ac382008-10-09 12:18:04 +02003599 antenna = B43_ANTENNA_DEFAULT;
Michael Buesch9db1f6d2007-12-22 21:54:20 +01003600 b43_mgmtframe_txantenna(dev, antenna);
Johannes Berg0f4ac382008-10-09 12:18:04 +02003601 antenna = B43_ANTENNA_DEFAULT;
Michael Bueschef1a6282008-08-27 18:53:02 +02003602 if (phy->ops->set_rx_antenna)
3603 phy->ops->set_rx_antenna(dev, antenna);
Michael Buesche4d6b792007-09-18 15:39:42 -04003604
Larry Fingerfd4973c2009-06-20 12:58:11 -05003605 if (wl->radio_enabled != phy->radio_on) {
3606 if (wl->radio_enabled) {
Johannes Berg19d337d2009-06-02 13:01:37 +02003607 b43_software_rfkill(dev, false);
Michael Bueschfda9abc2007-09-20 22:14:18 +02003608 b43info(dev->wl, "Radio turned on by software\n");
3609 if (!dev->radio_hw_enable) {
3610 b43info(dev->wl, "The hardware RF-kill button "
3611 "still turns the radio physically off. "
3612 "Press the button to turn it on.\n");
3613 }
3614 } else {
Johannes Berg19d337d2009-06-02 13:01:37 +02003615 b43_software_rfkill(dev, true);
Michael Bueschfda9abc2007-09-20 22:14:18 +02003616 b43info(dev->wl, "Radio turned off by software\n");
3617 }
3618 }
3619
Michael Bueschd10d0e52008-12-18 22:13:39 +01003620out_mac_enable:
3621 b43_mac_enable(dev);
3622out_unlock_mutex:
Michael Buesche4d6b792007-09-18 15:39:42 -04003623 mutex_unlock(&wl->mutex);
3624
3625 return err;
3626}
3627
Johannes Berg881d9482009-01-21 15:13:48 +01003628static void b43_update_basic_rates(struct b43_wldev *dev, u32 brates)
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003629{
3630 struct ieee80211_supported_band *sband =
3631 dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)];
3632 struct ieee80211_rate *rate;
3633 int i;
3634 u16 basic, direct, offset, basic_offset, rateptr;
3635
3636 for (i = 0; i < sband->n_bitrates; i++) {
3637 rate = &sband->bitrates[i];
3638
3639 if (b43_is_cck_rate(rate->hw_value)) {
3640 direct = B43_SHM_SH_CCKDIRECT;
3641 basic = B43_SHM_SH_CCKBASIC;
3642 offset = b43_plcp_get_ratecode_cck(rate->hw_value);
3643 offset &= 0xF;
3644 } else {
3645 direct = B43_SHM_SH_OFDMDIRECT;
3646 basic = B43_SHM_SH_OFDMBASIC;
3647 offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
3648 offset &= 0xF;
3649 }
3650
3651 rate = ieee80211_get_response_rate(sband, brates, rate->bitrate);
3652
3653 if (b43_is_cck_rate(rate->hw_value)) {
3654 basic_offset = b43_plcp_get_ratecode_cck(rate->hw_value);
3655 basic_offset &= 0xF;
3656 } else {
3657 basic_offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
3658 basic_offset &= 0xF;
3659 }
3660
3661 /*
3662 * Get the pointer that we need to point to
3663 * from the direct map
3664 */
3665 rateptr = b43_shm_read16(dev, B43_SHM_SHARED,
3666 direct + 2 * basic_offset);
3667 /* and write it to the basic map */
3668 b43_shm_write16(dev, B43_SHM_SHARED, basic + 2 * offset,
3669 rateptr);
3670 }
3671}
3672
3673static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
3674 struct ieee80211_vif *vif,
3675 struct ieee80211_bss_conf *conf,
3676 u32 changed)
3677{
3678 struct b43_wl *wl = hw_to_b43_wl(hw);
3679 struct b43_wldev *dev;
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003680
3681 mutex_lock(&wl->mutex);
3682
3683 dev = wl->current_dev;
Michael Bueschd10d0e52008-12-18 22:13:39 +01003684 if (!dev || b43_status(dev) < B43_STAT_STARTED)
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003685 goto out_unlock_mutex;
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003686
3687 B43_WARN_ON(wl->vif != vif);
3688
3689 if (changed & BSS_CHANGED_BSSID) {
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003690 if (conf->bssid)
3691 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
3692 else
3693 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003694 }
3695
Johannes Berg3f0d8432009-05-18 10:53:18 +02003696 if (b43_status(dev) >= B43_STAT_INITIALIZED) {
3697 if (changed & BSS_CHANGED_BEACON &&
3698 (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
3699 b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) ||
3700 b43_is_mode(wl, NL80211_IFTYPE_ADHOC)))
3701 b43_update_templates(wl);
3702
3703 if (changed & BSS_CHANGED_BSSID)
3704 b43_write_mac_bssid_templates(dev);
3705 }
Johannes Berg3f0d8432009-05-18 10:53:18 +02003706
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003707 b43_mac_suspend(dev);
3708
Johannes Berg57c4d7b2009-04-23 16:10:04 +02003709 /* Update templates for AP/mesh mode. */
3710 if (changed & BSS_CHANGED_BEACON_INT &&
3711 (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
3712 b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) ||
3713 b43_is_mode(wl, NL80211_IFTYPE_ADHOC)))
3714 b43_set_beacon_int(dev, conf->beacon_int);
3715
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003716 if (changed & BSS_CHANGED_BASIC_RATES)
3717 b43_update_basic_rates(dev, conf->basic_rates);
3718
3719 if (changed & BSS_CHANGED_ERP_SLOT) {
3720 if (conf->use_short_slot)
3721 b43_short_slot_timing_enable(dev);
3722 else
3723 b43_short_slot_timing_disable(dev);
3724 }
3725
3726 b43_mac_enable(dev);
Michael Bueschd10d0e52008-12-18 22:13:39 +01003727out_unlock_mutex:
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003728 mutex_unlock(&wl->mutex);
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01003729}
3730
Michael Buesch40faacc2007-10-28 16:29:32 +01003731static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
Johannes Bergdc822b52008-12-29 12:55:09 +01003732 struct ieee80211_vif *vif, struct ieee80211_sta *sta,
3733 struct ieee80211_key_conf *key)
Michael Buesche4d6b792007-09-18 15:39:42 -04003734{
3735 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003736 struct b43_wldev *dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04003737 u8 algorithm;
3738 u8 index;
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003739 int err;
Michael Buesch060210f2009-01-25 15:49:59 +01003740 static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
Michael Buesche4d6b792007-09-18 15:39:42 -04003741
3742 if (modparam_nohwcrypt)
3743 return -ENOSPC; /* User disabled HW-crypto */
3744
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003745 mutex_lock(&wl->mutex);
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003746
3747 dev = wl->current_dev;
3748 err = -ENODEV;
3749 if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
3750 goto out_unlock;
3751
Michael Buesch403a3a12009-06-08 21:04:57 +02003752 if (dev->fw.pcm_request_failed || !dev->hwcrypto_enabled) {
Michael Buesch68217832008-05-17 23:43:57 +02003753 /* We don't have firmware for the crypto engine.
3754 * Must use software-crypto. */
3755 err = -EOPNOTSUPP;
3756 goto out_unlock;
3757 }
3758
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003759 err = -EINVAL;
Michael Buesche4d6b792007-09-18 15:39:42 -04003760 switch (key->alg) {
Michael Buesche4d6b792007-09-18 15:39:42 -04003761 case ALG_WEP:
Zhu Yie31a16d2009-05-21 21:47:03 +08003762 if (key->keylen == WLAN_KEY_LEN_WEP40)
Michael Buesche4d6b792007-09-18 15:39:42 -04003763 algorithm = B43_SEC_ALGO_WEP40;
3764 else
3765 algorithm = B43_SEC_ALGO_WEP104;
3766 break;
3767 case ALG_TKIP:
3768 algorithm = B43_SEC_ALGO_TKIP;
3769 break;
3770 case ALG_CCMP:
3771 algorithm = B43_SEC_ALGO_AES;
3772 break;
3773 default:
3774 B43_WARN_ON(1);
Michael Buesche4d6b792007-09-18 15:39:42 -04003775 goto out_unlock;
3776 }
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003777 index = (u8) (key->keyidx);
3778 if (index > 3)
3779 goto out_unlock;
Michael Buesche4d6b792007-09-18 15:39:42 -04003780
3781 switch (cmd) {
3782 case SET_KEY:
gregor kowski035d0242009-08-19 22:35:45 +02003783 if (algorithm == B43_SEC_ALGO_TKIP &&
3784 (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
3785 !modparam_hwtkip)) {
3786 /* We support only pairwise key */
Michael Buesche4d6b792007-09-18 15:39:42 -04003787 err = -EOPNOTSUPP;
3788 goto out_unlock;
3789 }
3790
Michael Buesche808e582008-12-19 21:30:52 +01003791 if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
Johannes Bergdc822b52008-12-29 12:55:09 +01003792 if (WARN_ON(!sta)) {
3793 err = -EOPNOTSUPP;
3794 goto out_unlock;
3795 }
Michael Buesche808e582008-12-19 21:30:52 +01003796 /* Pairwise key with an assigned MAC address. */
Michael Buesche4d6b792007-09-18 15:39:42 -04003797 err = b43_key_write(dev, -1, algorithm,
Johannes Bergdc822b52008-12-29 12:55:09 +01003798 key->key, key->keylen,
3799 sta->addr, key);
Michael Buesche808e582008-12-19 21:30:52 +01003800 } else {
3801 /* Group key */
3802 err = b43_key_write(dev, index, algorithm,
3803 key->key, key->keylen, NULL, key);
Michael Buesche4d6b792007-09-18 15:39:42 -04003804 }
3805 if (err)
3806 goto out_unlock;
3807
3808 if (algorithm == B43_SEC_ALGO_WEP40 ||
3809 algorithm == B43_SEC_ALGO_WEP104) {
3810 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_USEDEFKEYS);
3811 } else {
3812 b43_hf_write(dev,
3813 b43_hf_read(dev) & ~B43_HF_USEDEFKEYS);
3814 }
3815 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
gregor kowski035d0242009-08-19 22:35:45 +02003816 if (algorithm == B43_SEC_ALGO_TKIP)
3817 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
Michael Buesche4d6b792007-09-18 15:39:42 -04003818 break;
3819 case DISABLE_KEY: {
3820 err = b43_key_clear(dev, key->hw_key_idx);
3821 if (err)
3822 goto out_unlock;
3823 break;
3824 }
3825 default:
3826 B43_WARN_ON(1);
3827 }
Michael Buesch9cf7f242008-12-19 20:24:30 +01003828
Michael Buesche4d6b792007-09-18 15:39:42 -04003829out_unlock:
Michael Buesche4d6b792007-09-18 15:39:42 -04003830 if (!err) {
3831 b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
Johannes Berge1749612008-10-27 15:59:26 -07003832 "mac: %pM\n",
Michael Buesche4d6b792007-09-18 15:39:42 -04003833 cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
Larry Fingera1d882102009-01-14 11:15:25 -06003834 sta ? sta->addr : bcast_addr);
Michael Buesch9cf7f242008-12-19 20:24:30 +01003835 b43_dump_keymemory(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003836 }
Michael Buesch9cf7f242008-12-19 20:24:30 +01003837 mutex_unlock(&wl->mutex);
3838
Michael Buesche4d6b792007-09-18 15:39:42 -04003839 return err;
3840}
3841
Michael Buesch40faacc2007-10-28 16:29:32 +01003842static void b43_op_configure_filter(struct ieee80211_hw *hw,
3843 unsigned int changed, unsigned int *fflags,
Johannes Berg3ac64be2009-08-17 16:16:53 +02003844 u64 multicast)
Michael Buesche4d6b792007-09-18 15:39:42 -04003845{
3846 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Buesch36dbd952009-09-04 22:51:29 +02003847 struct b43_wldev *dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04003848
Michael Buesch36dbd952009-09-04 22:51:29 +02003849 mutex_lock(&wl->mutex);
3850 dev = wl->current_dev;
Johannes Berg4150c572007-09-17 01:29:23 -04003851 if (!dev) {
3852 *fflags = 0;
Michael Buesch36dbd952009-09-04 22:51:29 +02003853 goto out_unlock;
Michael Buesche4d6b792007-09-18 15:39:42 -04003854 }
Johannes Berg4150c572007-09-17 01:29:23 -04003855
Johannes Berg4150c572007-09-17 01:29:23 -04003856 *fflags &= FIF_PROMISC_IN_BSS |
3857 FIF_ALLMULTI |
3858 FIF_FCSFAIL |
3859 FIF_PLCPFAIL |
3860 FIF_CONTROL |
3861 FIF_OTHER_BSS |
3862 FIF_BCN_PRBRESP_PROMISC;
3863
3864 changed &= FIF_PROMISC_IN_BSS |
3865 FIF_ALLMULTI |
3866 FIF_FCSFAIL |
3867 FIF_PLCPFAIL |
3868 FIF_CONTROL |
3869 FIF_OTHER_BSS |
3870 FIF_BCN_PRBRESP_PROMISC;
3871
3872 wl->filter_flags = *fflags;
3873
3874 if (changed && b43_status(dev) >= B43_STAT_INITIALIZED)
3875 b43_adjust_opmode(dev);
Michael Buesch36dbd952009-09-04 22:51:29 +02003876
3877out_unlock:
3878 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003879}
3880
Michael Buesch36dbd952009-09-04 22:51:29 +02003881/* Locking: wl->mutex
3882 * Returns the current dev. This might be different from the passed in dev,
3883 * because the core might be gone away while we unlocked the mutex. */
3884static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04003885{
3886 struct b43_wl *wl = dev->wl;
Michael Buesch36dbd952009-09-04 22:51:29 +02003887 struct b43_wldev *orig_dev;
Michael Buesch49d965c2009-10-03 00:57:58 +02003888 u32 mask;
Michael Buesche4d6b792007-09-18 15:39:42 -04003889
Michael Buesch36dbd952009-09-04 22:51:29 +02003890redo:
3891 if (!dev || b43_status(dev) < B43_STAT_STARTED)
3892 return dev;
Stefano Brivioa19d12d2007-11-07 18:16:11 +01003893
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003894 /* Cancel work. Unlock to avoid deadlocks. */
Michael Buesche4d6b792007-09-18 15:39:42 -04003895 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003896 cancel_delayed_work_sync(&dev->periodic_work);
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003897 cancel_work_sync(&wl->tx_work);
Michael Buesche4d6b792007-09-18 15:39:42 -04003898 mutex_lock(&wl->mutex);
Michael Buesch36dbd952009-09-04 22:51:29 +02003899 dev = wl->current_dev;
3900 if (!dev || b43_status(dev) < B43_STAT_STARTED) {
3901 /* Whoops, aliens ate up the device while we were unlocked. */
3902 return dev;
3903 }
Michael Buesche4d6b792007-09-18 15:39:42 -04003904
Michael Buesch36dbd952009-09-04 22:51:29 +02003905 /* Disable interrupts on the device. */
3906 b43_set_status(dev, B43_STAT_INITIALIZED);
Albert Herranz3dbba8e2009-09-10 19:34:49 +02003907 if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
Michael Buesch36dbd952009-09-04 22:51:29 +02003908 /* wl->mutex is locked. That is enough. */
3909 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
3910 b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
3911 } else {
3912 spin_lock_irq(&wl->hardirq_lock);
3913 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
3914 b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
3915 spin_unlock_irq(&wl->hardirq_lock);
3916 }
Michael Buesch176e9f62009-09-11 23:04:04 +02003917 /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
Michael Buesch36dbd952009-09-04 22:51:29 +02003918 orig_dev = dev;
3919 mutex_unlock(&wl->mutex);
Michael Buesch176e9f62009-09-11 23:04:04 +02003920 if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
3921 b43_sdio_free_irq(dev);
3922 } else {
3923 synchronize_irq(dev->dev->irq);
3924 free_irq(dev->dev->irq, dev);
3925 }
Michael Buesch36dbd952009-09-04 22:51:29 +02003926 mutex_lock(&wl->mutex);
3927 dev = wl->current_dev;
3928 if (!dev)
3929 return dev;
3930 if (dev != orig_dev) {
3931 if (b43_status(dev) >= B43_STAT_STARTED)
3932 goto redo;
3933 return dev;
3934 }
Michael Buesch49d965c2009-10-03 00:57:58 +02003935 mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
3936 B43_WARN_ON(mask != 0xFFFFFFFF && mask);
Michael Buesch36dbd952009-09-04 22:51:29 +02003937
Michael Bueschf5d40ee2009-09-04 22:53:18 +02003938 /* Drain the TX queue */
3939 while (skb_queue_len(&wl->tx_queue))
3940 dev_kfree_skb(skb_dequeue(&wl->tx_queue));
3941
Michael Buesche4d6b792007-09-18 15:39:42 -04003942 b43_mac_suspend(dev);
Michael Buescha78b3bb2009-09-11 21:44:05 +02003943 b43_leds_exit(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003944 b43dbg(wl, "Wireless interface stopped\n");
Michael Buesch36dbd952009-09-04 22:51:29 +02003945
3946 return dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04003947}
3948
3949/* Locking: wl->mutex */
3950static int b43_wireless_core_start(struct b43_wldev *dev)
3951{
3952 int err;
3953
3954 B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
3955
3956 drain_txstatus_queue(dev);
Albert Herranz3dbba8e2009-09-10 19:34:49 +02003957 if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
3958 err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler);
3959 if (err) {
3960 b43err(dev->wl, "Cannot request SDIO IRQ\n");
3961 goto out;
3962 }
3963 } else {
3964 err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
3965 b43_interrupt_thread_handler,
3966 IRQF_SHARED, KBUILD_MODNAME, dev);
3967 if (err) {
3968 b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
3969 goto out;
3970 }
Michael Buesche4d6b792007-09-18 15:39:42 -04003971 }
3972
3973 /* We are ready to run. */
3974 b43_set_status(dev, B43_STAT_STARTED);
3975
3976 /* Start data flow (TX/RX). */
3977 b43_mac_enable(dev);
Michael Buesch13790722009-04-08 21:26:27 +02003978 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
Michael Buesche4d6b792007-09-18 15:39:42 -04003979
3980 /* Start maintainance work */
3981 b43_periodic_tasks_setup(dev);
3982
Michael Buescha78b3bb2009-09-11 21:44:05 +02003983 b43_leds_init(dev);
3984
Michael Buesche4d6b792007-09-18 15:39:42 -04003985 b43dbg(dev->wl, "Wireless interface started\n");
Michael Buescha78b3bb2009-09-11 21:44:05 +02003986out:
Michael Buesche4d6b792007-09-18 15:39:42 -04003987 return err;
3988}
3989
3990/* Get PHY and RADIO versioning numbers */
3991static int b43_phy_versioning(struct b43_wldev *dev)
3992{
3993 struct b43_phy *phy = &dev->phy;
3994 u32 tmp;
3995 u8 analog_type;
3996 u8 phy_type;
3997 u8 phy_rev;
3998 u16 radio_manuf;
3999 u16 radio_ver;
4000 u16 radio_rev;
4001 int unsupported = 0;
4002
4003 /* Get PHY versioning */
4004 tmp = b43_read16(dev, B43_MMIO_PHY_VER);
4005 analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT;
4006 phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT;
4007 phy_rev = (tmp & B43_PHYVER_VERSION);
4008 switch (phy_type) {
4009 case B43_PHYTYPE_A:
4010 if (phy_rev >= 4)
4011 unsupported = 1;
4012 break;
4013 case B43_PHYTYPE_B:
4014 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6
4015 && phy_rev != 7)
4016 unsupported = 1;
4017 break;
4018 case B43_PHYTYPE_G:
Larry Finger013978b2007-11-26 10:29:47 -06004019 if (phy_rev > 9)
Michael Buesche4d6b792007-09-18 15:39:42 -04004020 unsupported = 1;
4021 break;
Michael Bueschd5c71e42008-01-04 17:06:29 +01004022#ifdef CONFIG_B43_NPHY
4023 case B43_PHYTYPE_N:
Johannes Bergbb519be2008-12-24 15:26:40 +01004024 if (phy_rev > 4)
Michael Bueschd5c71e42008-01-04 17:06:29 +01004025 unsupported = 1;
4026 break;
4027#endif
Michael Buesch6b1c7c62008-12-25 00:39:28 +01004028#ifdef CONFIG_B43_PHY_LP
4029 case B43_PHYTYPE_LP:
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02004030 if (phy_rev > 2)
Michael Buesch6b1c7c62008-12-25 00:39:28 +01004031 unsupported = 1;
4032 break;
4033#endif
Michael Buesche4d6b792007-09-18 15:39:42 -04004034 default:
4035 unsupported = 1;
4036 };
4037 if (unsupported) {
4038 b43err(dev->wl, "FOUND UNSUPPORTED PHY "
4039 "(Analog %u, Type %u, Revision %u)\n",
4040 analog_type, phy_type, phy_rev);
4041 return -EOPNOTSUPP;
4042 }
4043 b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
4044 analog_type, phy_type, phy_rev);
4045
4046 /* Get RADIO versioning */
4047 if (dev->dev->bus->chip_id == 0x4317) {
4048 if (dev->dev->bus->chip_rev == 0)
4049 tmp = 0x3205017F;
4050 else if (dev->dev->bus->chip_rev == 1)
4051 tmp = 0x4205017F;
4052 else
4053 tmp = 0x5205017F;
4054 } else {
4055 b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
Michael Buesch243dcfc2008-01-13 14:12:44 +01004056 tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
Michael Buesche4d6b792007-09-18 15:39:42 -04004057 b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
Michael Buesch243dcfc2008-01-13 14:12:44 +01004058 tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
Michael Buesche4d6b792007-09-18 15:39:42 -04004059 }
4060 radio_manuf = (tmp & 0x00000FFF);
4061 radio_ver = (tmp & 0x0FFFF000) >> 12;
4062 radio_rev = (tmp & 0xF0000000) >> 28;
Michael Buesch96c755a2008-01-06 00:09:46 +01004063 if (radio_manuf != 0x17F /* Broadcom */)
4064 unsupported = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004065 switch (phy_type) {
4066 case B43_PHYTYPE_A:
4067 if (radio_ver != 0x2060)
4068 unsupported = 1;
4069 if (radio_rev != 1)
4070 unsupported = 1;
4071 if (radio_manuf != 0x17F)
4072 unsupported = 1;
4073 break;
4074 case B43_PHYTYPE_B:
4075 if ((radio_ver & 0xFFF0) != 0x2050)
4076 unsupported = 1;
4077 break;
4078 case B43_PHYTYPE_G:
4079 if (radio_ver != 0x2050)
4080 unsupported = 1;
4081 break;
Michael Buesch96c755a2008-01-06 00:09:46 +01004082 case B43_PHYTYPE_N:
Johannes Bergbb519be2008-12-24 15:26:40 +01004083 if (radio_ver != 0x2055 && radio_ver != 0x2056)
Michael Buesch96c755a2008-01-06 00:09:46 +01004084 unsupported = 1;
4085 break;
Michael Buesch6b1c7c62008-12-25 00:39:28 +01004086 case B43_PHYTYPE_LP:
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02004087 if (radio_ver != 0x2062 && radio_ver != 0x2063)
Michael Buesch6b1c7c62008-12-25 00:39:28 +01004088 unsupported = 1;
4089 break;
Michael Buesche4d6b792007-09-18 15:39:42 -04004090 default:
4091 B43_WARN_ON(1);
4092 }
4093 if (unsupported) {
4094 b43err(dev->wl, "FOUND UNSUPPORTED RADIO "
4095 "(Manuf 0x%X, Version 0x%X, Revision %u)\n",
4096 radio_manuf, radio_ver, radio_rev);
4097 return -EOPNOTSUPP;
4098 }
4099 b43dbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X, Revision %u\n",
4100 radio_manuf, radio_ver, radio_rev);
4101
4102 phy->radio_manuf = radio_manuf;
4103 phy->radio_ver = radio_ver;
4104 phy->radio_rev = radio_rev;
4105
4106 phy->analog = analog_type;
4107 phy->type = phy_type;
4108 phy->rev = phy_rev;
4109
4110 return 0;
4111}
4112
4113static void setup_struct_phy_for_init(struct b43_wldev *dev,
4114 struct b43_phy *phy)
4115{
Michael Buesche4d6b792007-09-18 15:39:42 -04004116 phy->hardware_power_control = !!modparam_hwpctl;
Michael Buesch18c8ade2008-08-28 19:33:40 +02004117 phy->next_txpwr_check_time = jiffies;
Michael Buesch8ed7fc42007-12-09 22:34:59 +01004118 /* PHY TX errors counter. */
4119 atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
Michael Buesch591f3dc2009-03-31 12:27:32 +02004120
4121#if B43_DEBUG
4122 phy->phy_locked = 0;
4123 phy->radio_locked = 0;
4124#endif
Michael Buesche4d6b792007-09-18 15:39:42 -04004125}
4126
4127static void setup_struct_wldev_for_init(struct b43_wldev *dev)
4128{
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01004129 dev->dfq_valid = 0;
4130
Michael Buesch6a724d62007-09-20 22:12:58 +02004131 /* Assume the radio is enabled. If it's not enabled, the state will
4132 * immediately get fixed on the first periodic work run. */
4133 dev->radio_hw_enable = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004134
4135 /* Stats */
4136 memset(&dev->stats, 0, sizeof(dev->stats));
4137
4138 setup_struct_phy_for_init(dev, &dev->phy);
4139
4140 /* IRQ related flags */
4141 dev->irq_reason = 0;
4142 memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
Michael Buesch13790722009-04-08 21:26:27 +02004143 dev->irq_mask = B43_IRQ_MASKTEMPLATE;
Michael Buesch3e3ccb32009-03-19 19:27:21 +01004144 if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
Michael Buesch13790722009-04-08 21:26:27 +02004145 dev->irq_mask &= ~B43_IRQ_PHY_TXERR;
Michael Buesche4d6b792007-09-18 15:39:42 -04004146
4147 dev->mac_suspended = 1;
4148
4149 /* Noise calculation context */
4150 memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
4151}
4152
4153static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
4154{
4155 struct ssb_sprom *sprom = &dev->dev->bus->sprom;
Michael Buescha259d6a2008-04-18 21:06:37 +02004156 u64 hf;
Michael Buesche4d6b792007-09-18 15:39:42 -04004157
Michael Buesch1855ba72008-04-18 20:51:41 +02004158 if (!modparam_btcoex)
4159 return;
Larry Finger95de2842007-11-09 16:57:18 -06004160 if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST))
Michael Buesche4d6b792007-09-18 15:39:42 -04004161 return;
4162 if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
4163 return;
4164
4165 hf = b43_hf_read(dev);
Larry Finger95de2842007-11-09 16:57:18 -06004166 if (sprom->boardflags_lo & B43_BFL_BTCMOD)
Michael Buesche4d6b792007-09-18 15:39:42 -04004167 hf |= B43_HF_BTCOEXALT;
4168 else
4169 hf |= B43_HF_BTCOEX;
4170 b43_hf_write(dev, hf);
Michael Buesche4d6b792007-09-18 15:39:42 -04004171}
4172
4173static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
Michael Buesch1855ba72008-04-18 20:51:41 +02004174{
4175 if (!modparam_btcoex)
4176 return;
4177 //TODO
Michael Buesche4d6b792007-09-18 15:39:42 -04004178}
4179
4180static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
4181{
4182#ifdef CONFIG_SSB_DRIVER_PCICORE
4183 struct ssb_bus *bus = dev->dev->bus;
4184 u32 tmp;
4185
4186 if (bus->pcicore.dev &&
4187 bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
4188 bus->pcicore.dev->id.revision <= 5) {
4189 /* IMCFGLO timeouts workaround. */
4190 tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
Michael Buesche4d6b792007-09-18 15:39:42 -04004191 switch (bus->bustype) {
4192 case SSB_BUSTYPE_PCI:
4193 case SSB_BUSTYPE_PCMCIA:
Michael Buesch98a1e2a2009-09-08 19:33:31 +02004194 tmp &= ~SSB_IMCFGLO_REQTO;
4195 tmp &= ~SSB_IMCFGLO_SERTO;
Michael Buesche4d6b792007-09-18 15:39:42 -04004196 tmp |= 0x32;
4197 break;
4198 case SSB_BUSTYPE_SSB:
Michael Buesch98a1e2a2009-09-08 19:33:31 +02004199 tmp &= ~SSB_IMCFGLO_REQTO;
4200 tmp &= ~SSB_IMCFGLO_SERTO;
Michael Buesche4d6b792007-09-18 15:39:42 -04004201 tmp |= 0x53;
4202 break;
Michael Buesch98a1e2a2009-09-08 19:33:31 +02004203 default:
4204 break;
Michael Buesche4d6b792007-09-18 15:39:42 -04004205 }
4206 ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
4207 }
4208#endif /* CONFIG_SSB_DRIVER_PCICORE */
4209}
4210
Michael Bueschd59f7202008-04-03 18:56:19 +02004211static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
4212{
4213 u16 pu_delay;
4214
4215 /* The time value is in microseconds. */
4216 if (dev->phy.type == B43_PHYTYPE_A)
4217 pu_delay = 3700;
4218 else
4219 pu_delay = 1050;
Johannes Berg05c914f2008-09-11 00:01:58 +02004220 if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle)
Michael Bueschd59f7202008-04-03 18:56:19 +02004221 pu_delay = 500;
4222 if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
4223 pu_delay = max(pu_delay, (u16)2400);
4224
4225 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SPUWKUP, pu_delay);
4226}
4227
4228/* Set the TSF CFP pre-TargetBeaconTransmissionTime. */
4229static void b43_set_pretbtt(struct b43_wldev *dev)
4230{
4231 u16 pretbtt;
4232
4233 /* The time value is in microseconds. */
Johannes Berg05c914f2008-09-11 00:01:58 +02004234 if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) {
Michael Bueschd59f7202008-04-03 18:56:19 +02004235 pretbtt = 2;
4236 } else {
4237 if (dev->phy.type == B43_PHYTYPE_A)
4238 pretbtt = 120;
4239 else
4240 pretbtt = 250;
4241 }
4242 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRETBTT, pretbtt);
4243 b43_write16(dev, B43_MMIO_TSF_CFP_PRETBTT, pretbtt);
4244}
4245
Michael Buesche4d6b792007-09-18 15:39:42 -04004246/* Shutdown a wireless core */
4247/* Locking: wl->mutex */
4248static void b43_wireless_core_exit(struct b43_wldev *dev)
4249{
Michael Buesch1f7d87b2008-01-22 20:23:34 +01004250 u32 macctl;
Michael Buesche4d6b792007-09-18 15:39:42 -04004251
Michael Buesch36dbd952009-09-04 22:51:29 +02004252 B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED);
4253 if (!dev || b43_status(dev) != B43_STAT_INITIALIZED)
Michael Buesche4d6b792007-09-18 15:39:42 -04004254 return;
4255 b43_set_status(dev, B43_STAT_UNINIT);
4256
Michael Buesch1f7d87b2008-01-22 20:23:34 +01004257 /* Stop the microcode PSM. */
4258 macctl = b43_read32(dev, B43_MMIO_MACCTL);
4259 macctl &= ~B43_MACCTL_PSM_RUN;
4260 macctl |= B43_MACCTL_PSM_JMP0;
4261 b43_write32(dev, B43_MMIO_MACCTL, macctl);
4262
Michael Buesche4d6b792007-09-18 15:39:42 -04004263 b43_dma_free(dev);
Michael Buesch5100d5a2008-03-29 21:01:16 +01004264 b43_pio_free(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004265 b43_chip_exit(dev);
Michael Bueschcb24f572008-09-03 12:12:20 +02004266 dev->phy.ops->switch_analog(dev, 0);
Michael Buesche66fee62007-12-26 17:47:10 +01004267 if (dev->wl->current_beacon) {
4268 dev_kfree_skb_any(dev->wl->current_beacon);
4269 dev->wl->current_beacon = NULL;
4270 }
4271
Michael Buesche4d6b792007-09-18 15:39:42 -04004272 ssb_device_disable(dev->dev, 0);
4273 ssb_bus_may_powerdown(dev->dev->bus);
4274}
4275
4276/* Initialize a wireless core */
4277static int b43_wireless_core_init(struct b43_wldev *dev)
4278{
Michael Buesche4d6b792007-09-18 15:39:42 -04004279 struct ssb_bus *bus = dev->dev->bus;
4280 struct ssb_sprom *sprom = &bus->sprom;
4281 struct b43_phy *phy = &dev->phy;
4282 int err;
Michael Buescha259d6a2008-04-18 21:06:37 +02004283 u64 hf;
4284 u32 tmp;
Michael Buesche4d6b792007-09-18 15:39:42 -04004285
4286 B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
4287
4288 err = ssb_bus_powerup(bus, 0);
4289 if (err)
4290 goto out;
4291 if (!ssb_device_is_enabled(dev->dev)) {
4292 tmp = phy->gmode ? B43_TMSLOW_GMODE : 0;
4293 b43_wireless_core_reset(dev, tmp);
4294 }
4295
Michael Bueschfb111372008-09-02 13:00:34 +02004296 /* Reset all data structures. */
Michael Buesche4d6b792007-09-18 15:39:42 -04004297 setup_struct_wldev_for_init(dev);
Michael Bueschfb111372008-09-02 13:00:34 +02004298 phy->ops->prepare_structs(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004299
4300 /* Enable IRQ routing to this device. */
4301 ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
4302
4303 b43_imcfglo_timeouts_workaround(dev);
4304 b43_bluetooth_coext_disable(dev);
Michael Bueschfb111372008-09-02 13:00:34 +02004305 if (phy->ops->prepare_hardware) {
4306 err = phy->ops->prepare_hardware(dev);
Michael Bueschef1a6282008-08-27 18:53:02 +02004307 if (err)
Michael Bueschfb111372008-09-02 13:00:34 +02004308 goto err_busdown;
Michael Bueschef1a6282008-08-27 18:53:02 +02004309 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004310 err = b43_chip_init(dev);
4311 if (err)
Michael Bueschfb111372008-09-02 13:00:34 +02004312 goto err_busdown;
Michael Buesche4d6b792007-09-18 15:39:42 -04004313 b43_shm_write16(dev, B43_SHM_SHARED,
4314 B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
4315 hf = b43_hf_read(dev);
4316 if (phy->type == B43_PHYTYPE_G) {
4317 hf |= B43_HF_SYMW;
4318 if (phy->rev == 1)
4319 hf |= B43_HF_GDCW;
Larry Finger95de2842007-11-09 16:57:18 -06004320 if (sprom->boardflags_lo & B43_BFL_PACTRL)
Michael Buesche4d6b792007-09-18 15:39:42 -04004321 hf |= B43_HF_OFDMPABOOST;
Michael Buesch969d15c2009-02-20 14:27:15 +01004322 }
4323 if (phy->radio_ver == 0x2050) {
4324 if (phy->radio_rev == 6)
4325 hf |= B43_HF_4318TSSI;
4326 if (phy->radio_rev < 6)
4327 hf |= B43_HF_VCORECALC;
Michael Buesche4d6b792007-09-18 15:39:42 -04004328 }
Michael Buesch1cc8f472009-02-20 14:47:56 +01004329 if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
4330 hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
Michael Buesch1a777332009-03-04 16:41:10 +01004331#ifdef CONFIG_SSB_DRIVER_PCICORE
Michael Buesch88219052009-02-20 14:58:59 +01004332 if ((bus->bustype == SSB_BUSTYPE_PCI) &&
4333 (bus->pcicore.dev->id.revision <= 10))
4334 hf |= B43_HF_PCISCW; /* PCI slow clock workaround. */
Michael Buesch1a777332009-03-04 16:41:10 +01004335#endif
Michael Buesch25d3ef52009-02-20 15:39:21 +01004336 hf &= ~B43_HF_SKCFPUP;
Michael Buesche4d6b792007-09-18 15:39:42 -04004337 b43_hf_write(dev, hf);
4338
Michael Buesch74cfdba2007-10-28 16:19:44 +01004339 b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
4340 B43_DEFAULT_LONG_RETRY_LIMIT);
Michael Buesche4d6b792007-09-18 15:39:42 -04004341 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
4342 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2);
4343
4344 /* Disable sending probe responses from firmware.
4345 * Setting the MaxTime to one usec will always trigger
4346 * a timeout, so we never send any probe resp.
4347 * A timeout of zero is infinite. */
4348 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1);
4349
4350 b43_rate_memory_init(dev);
Michael Buesch5042c502008-04-05 15:05:00 +02004351 b43_set_phytxctl_defaults(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004352
4353 /* Minimum Contention Window */
4354 if (phy->type == B43_PHYTYPE_B) {
4355 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F);
4356 } else {
4357 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF);
4358 }
4359 /* Maximum Contention Window */
4360 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
4361
Albert Herranz3dbba8e2009-09-10 19:34:49 +02004362 if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
4363 (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
Larry Fingerb02914a2009-12-10 17:35:01 -06004364 modparam_pio) {
Michael Buesch5100d5a2008-03-29 21:01:16 +01004365 dev->__using_pio_transfers = 1;
4366 err = b43_pio_init(dev);
4367 } else {
4368 dev->__using_pio_transfers = 0;
4369 err = b43_dma_init(dev);
4370 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004371 if (err)
4372 goto err_chip_exit;
Michael Buesch03b29772007-12-26 14:41:30 +01004373 b43_qos_init(dev);
Michael Bueschd59f7202008-04-03 18:56:19 +02004374 b43_set_synth_pu_delay(dev, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04004375 b43_bluetooth_coext_enable(dev);
4376
Michael Buesch1cc8f472009-02-20 14:47:56 +01004377 ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
Johannes Berg4150c572007-09-17 01:29:23 -04004378 b43_upload_card_macaddress(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004379 b43_security_init(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004380
Michael Buesch5ab95492009-09-10 20:31:46 +02004381 ieee80211_wake_queues(dev->wl->hw);
Michael Buesche4d6b792007-09-18 15:39:42 -04004382
Michael Buesch32f6afd2009-09-10 20:31:46 +02004383 ieee80211_wake_queues(dev->wl->hw);
4384
Michael Buesche4d6b792007-09-18 15:39:42 -04004385 b43_set_status(dev, B43_STAT_INITIALIZED);
4386
Larry Finger1a8d1222007-12-14 13:59:11 +01004387out:
Michael Buesche4d6b792007-09-18 15:39:42 -04004388 return err;
4389
Michael Bueschef1a6282008-08-27 18:53:02 +02004390err_chip_exit:
Michael Buesche4d6b792007-09-18 15:39:42 -04004391 b43_chip_exit(dev);
Michael Bueschef1a6282008-08-27 18:53:02 +02004392err_busdown:
Michael Buesche4d6b792007-09-18 15:39:42 -04004393 ssb_bus_may_powerdown(bus);
4394 B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
4395 return err;
4396}
4397
Michael Buesch40faacc2007-10-28 16:29:32 +01004398static int b43_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01004399 struct ieee80211_vif *vif)
Michael Buesche4d6b792007-09-18 15:39:42 -04004400{
4401 struct b43_wl *wl = hw_to_b43_wl(hw);
4402 struct b43_wldev *dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04004403 int err = -EOPNOTSUPP;
Johannes Berg4150c572007-09-17 01:29:23 -04004404
4405 /* TODO: allow WDS/AP devices to coexist */
4406
Johannes Berg1ed32e42009-12-23 13:15:45 +01004407 if (vif->type != NL80211_IFTYPE_AP &&
4408 vif->type != NL80211_IFTYPE_MESH_POINT &&
4409 vif->type != NL80211_IFTYPE_STATION &&
4410 vif->type != NL80211_IFTYPE_WDS &&
4411 vif->type != NL80211_IFTYPE_ADHOC)
Johannes Berg4150c572007-09-17 01:29:23 -04004412 return -EOPNOTSUPP;
Michael Buesche4d6b792007-09-18 15:39:42 -04004413
4414 mutex_lock(&wl->mutex);
Johannes Berg4150c572007-09-17 01:29:23 -04004415 if (wl->operating)
Michael Buesche4d6b792007-09-18 15:39:42 -04004416 goto out_mutex_unlock;
4417
Johannes Berg1ed32e42009-12-23 13:15:45 +01004418 b43dbg(wl, "Adding Interface type %d\n", vif->type);
Michael Buesche4d6b792007-09-18 15:39:42 -04004419
4420 dev = wl->current_dev;
Johannes Berg4150c572007-09-17 01:29:23 -04004421 wl->operating = 1;
Johannes Berg1ed32e42009-12-23 13:15:45 +01004422 wl->vif = vif;
4423 wl->if_type = vif->type;
4424 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Michael Buesche4d6b792007-09-18 15:39:42 -04004425
Michael Buesche4d6b792007-09-18 15:39:42 -04004426 b43_adjust_opmode(dev);
Michael Bueschd59f7202008-04-03 18:56:19 +02004427 b43_set_pretbtt(dev);
4428 b43_set_synth_pu_delay(dev, 0);
Johannes Berg4150c572007-09-17 01:29:23 -04004429 b43_upload_card_macaddress(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004430
4431 err = 0;
Johannes Berg4150c572007-09-17 01:29:23 -04004432 out_mutex_unlock:
Michael Buesche4d6b792007-09-18 15:39:42 -04004433 mutex_unlock(&wl->mutex);
4434
4435 return err;
4436}
4437
Michael Buesch40faacc2007-10-28 16:29:32 +01004438static void b43_op_remove_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);
Johannes Berg4150c572007-09-17 01:29:23 -04004442 struct b43_wldev *dev = wl->current_dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04004443
Johannes Berg1ed32e42009-12-23 13:15:45 +01004444 b43dbg(wl, "Removing Interface type %d\n", vif->type);
Michael Buesche4d6b792007-09-18 15:39:42 -04004445
4446 mutex_lock(&wl->mutex);
Johannes Berg4150c572007-09-17 01:29:23 -04004447
4448 B43_WARN_ON(!wl->operating);
Johannes Berg1ed32e42009-12-23 13:15:45 +01004449 B43_WARN_ON(wl->vif != vif);
Johannes Berg32bfd352007-12-19 01:31:26 +01004450 wl->vif = NULL;
Johannes Berg4150c572007-09-17 01:29:23 -04004451
4452 wl->operating = 0;
4453
Johannes Berg4150c572007-09-17 01:29:23 -04004454 b43_adjust_opmode(dev);
4455 memset(wl->mac_addr, 0, ETH_ALEN);
4456 b43_upload_card_macaddress(dev);
Johannes Berg4150c572007-09-17 01:29:23 -04004457
4458 mutex_unlock(&wl->mutex);
4459}
4460
Michael Buesch40faacc2007-10-28 16:29:32 +01004461static int b43_op_start(struct ieee80211_hw *hw)
Johannes Berg4150c572007-09-17 01:29:23 -04004462{
4463 struct b43_wl *wl = hw_to_b43_wl(hw);
4464 struct b43_wldev *dev = wl->current_dev;
4465 int did_init = 0;
WANG Cong923403b2007-10-16 14:29:38 -07004466 int err = 0;
Johannes Berg4150c572007-09-17 01:29:23 -04004467
Michael Buesch7be1bb62008-01-23 21:10:56 +01004468 /* Kill all old instance specific information to make sure
4469 * the card won't use it in the short timeframe between start
4470 * and mac80211 reconfiguring it. */
4471 memset(wl->bssid, 0, ETH_ALEN);
4472 memset(wl->mac_addr, 0, ETH_ALEN);
4473 wl->filter_flags = 0;
4474 wl->radiotap_enabled = 0;
Michael Buesche6f5b932008-03-05 21:18:49 +01004475 b43_qos_clear(wl);
Michael Buesch6b4bec012008-05-20 12:16:28 +02004476 wl->beacon0_uploaded = 0;
4477 wl->beacon1_uploaded = 0;
4478 wl->beacon_templates_virgin = 1;
Larry Fingerfd4973c2009-06-20 12:58:11 -05004479 wl->radio_enabled = 1;
Michael Buesch7be1bb62008-01-23 21:10:56 +01004480
Johannes Berg4150c572007-09-17 01:29:23 -04004481 mutex_lock(&wl->mutex);
4482
4483 if (b43_status(dev) < B43_STAT_INITIALIZED) {
4484 err = b43_wireless_core_init(dev);
Johannes Bergf41f3f32009-06-07 12:30:34 -05004485 if (err)
Johannes Berg4150c572007-09-17 01:29:23 -04004486 goto out_mutex_unlock;
4487 did_init = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004488 }
4489
Johannes Berg4150c572007-09-17 01:29:23 -04004490 if (b43_status(dev) < B43_STAT_STARTED) {
4491 err = b43_wireless_core_start(dev);
4492 if (err) {
4493 if (did_init)
4494 b43_wireless_core_exit(dev);
4495 goto out_mutex_unlock;
4496 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004497 }
Johannes Berg4150c572007-09-17 01:29:23 -04004498
Johannes Bergf41f3f32009-06-07 12:30:34 -05004499 /* XXX: only do if device doesn't support rfkill irq */
4500 wiphy_rfkill_start_polling(hw->wiphy);
4501
Johannes Berg4150c572007-09-17 01:29:23 -04004502 out_mutex_unlock:
4503 mutex_unlock(&wl->mutex);
4504
4505 return err;
4506}
4507
Michael Buesch40faacc2007-10-28 16:29:32 +01004508static void b43_op_stop(struct ieee80211_hw *hw)
Johannes Berg4150c572007-09-17 01:29:23 -04004509{
4510 struct b43_wl *wl = hw_to_b43_wl(hw);
4511 struct b43_wldev *dev = wl->current_dev;
4512
Michael Buescha82d9922008-04-04 21:40:06 +02004513 cancel_work_sync(&(wl->beacon_update_trigger));
Larry Finger1a8d1222007-12-14 13:59:11 +01004514
Johannes Berg4150c572007-09-17 01:29:23 -04004515 mutex_lock(&wl->mutex);
Michael Buesch36dbd952009-09-04 22:51:29 +02004516 if (b43_status(dev) >= B43_STAT_STARTED) {
4517 dev = b43_wireless_core_stop(dev);
4518 if (!dev)
4519 goto out_unlock;
4520 }
Johannes Berg4150c572007-09-17 01:29:23 -04004521 b43_wireless_core_exit(dev);
Larry Fingerfd4973c2009-06-20 12:58:11 -05004522 wl->radio_enabled = 0;
Michael Buesch36dbd952009-09-04 22:51:29 +02004523
4524out_unlock:
Michael Buesche4d6b792007-09-18 15:39:42 -04004525 mutex_unlock(&wl->mutex);
Michael Buesch18c8ade2008-08-28 19:33:40 +02004526
4527 cancel_work_sync(&(wl->txpower_adjust_work));
Michael Buesche4d6b792007-09-18 15:39:42 -04004528}
4529
Johannes Berg17741cd2008-09-11 00:02:02 +02004530static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
4531 struct ieee80211_sta *sta, bool set)
Michael Buesche66fee62007-12-26 17:47:10 +01004532{
4533 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Buesche66fee62007-12-26 17:47:10 +01004534
Felix Fietkau8f611282009-11-07 18:37:37 +01004535 /* FIXME: add locking */
Johannes Berg9d139c82008-07-09 14:40:37 +02004536 b43_update_templates(wl);
Michael Buesche66fee62007-12-26 17:47:10 +01004537
4538 return 0;
4539}
4540
Johannes Berg38968d02008-02-25 16:27:50 +01004541static void b43_op_sta_notify(struct ieee80211_hw *hw,
4542 struct ieee80211_vif *vif,
4543 enum sta_notify_cmd notify_cmd,
Johannes Berg17741cd2008-09-11 00:02:02 +02004544 struct ieee80211_sta *sta)
Johannes Berg38968d02008-02-25 16:27:50 +01004545{
4546 struct b43_wl *wl = hw_to_b43_wl(hw);
4547
4548 B43_WARN_ON(!vif || wl->vif != vif);
4549}
4550
Michael Buesch25d3ef52009-02-20 15:39:21 +01004551static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw)
4552{
4553 struct b43_wl *wl = hw_to_b43_wl(hw);
4554 struct b43_wldev *dev;
4555
4556 mutex_lock(&wl->mutex);
4557 dev = wl->current_dev;
4558 if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) {
4559 /* Disable CFP update during scan on other channels. */
4560 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_SKCFPUP);
4561 }
4562 mutex_unlock(&wl->mutex);
4563}
4564
4565static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw)
4566{
4567 struct b43_wl *wl = hw_to_b43_wl(hw);
4568 struct b43_wldev *dev;
4569
4570 mutex_lock(&wl->mutex);
4571 dev = wl->current_dev;
4572 if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) {
4573 /* Re-enable CFP update. */
4574 b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_SKCFPUP);
4575 }
4576 mutex_unlock(&wl->mutex);
4577}
4578
Michael Buesche4d6b792007-09-18 15:39:42 -04004579static const struct ieee80211_ops b43_hw_ops = {
Michael Buesch40faacc2007-10-28 16:29:32 +01004580 .tx = b43_op_tx,
4581 .conf_tx = b43_op_conf_tx,
4582 .add_interface = b43_op_add_interface,
4583 .remove_interface = b43_op_remove_interface,
4584 .config = b43_op_config,
Johannes Bergc7ab5ef2008-10-29 20:02:12 +01004585 .bss_info_changed = b43_op_bss_info_changed,
Michael Buesch40faacc2007-10-28 16:29:32 +01004586 .configure_filter = b43_op_configure_filter,
4587 .set_key = b43_op_set_key,
gregor kowski035d0242009-08-19 22:35:45 +02004588 .update_tkip_key = b43_op_update_tkip_key,
Michael Buesch40faacc2007-10-28 16:29:32 +01004589 .get_stats = b43_op_get_stats,
4590 .get_tx_stats = b43_op_get_tx_stats,
Alina Friedrichsen08e87a82009-01-25 15:28:28 +01004591 .get_tsf = b43_op_get_tsf,
4592 .set_tsf = b43_op_set_tsf,
Michael Buesch40faacc2007-10-28 16:29:32 +01004593 .start = b43_op_start,
4594 .stop = b43_op_stop,
Michael Buesche66fee62007-12-26 17:47:10 +01004595 .set_tim = b43_op_beacon_set_tim,
Johannes Berg38968d02008-02-25 16:27:50 +01004596 .sta_notify = b43_op_sta_notify,
Michael Buesch25d3ef52009-02-20 15:39:21 +01004597 .sw_scan_start = b43_op_sw_scan_start_notifier,
4598 .sw_scan_complete = b43_op_sw_scan_complete_notifier,
Johannes Bergf41f3f32009-06-07 12:30:34 -05004599 .rfkill_poll = b43_rfkill_poll,
Michael Buesche4d6b792007-09-18 15:39:42 -04004600};
4601
4602/* Hard-reset the chip. Do not call this directly.
4603 * Use b43_controller_restart()
4604 */
4605static void b43_chip_reset(struct work_struct *work)
4606{
4607 struct b43_wldev *dev =
4608 container_of(work, struct b43_wldev, restart_work);
4609 struct b43_wl *wl = dev->wl;
4610 int err = 0;
4611 int prev_status;
4612
4613 mutex_lock(&wl->mutex);
4614
4615 prev_status = b43_status(dev);
4616 /* Bring the device down... */
Michael Buesch36dbd952009-09-04 22:51:29 +02004617 if (prev_status >= B43_STAT_STARTED) {
4618 dev = b43_wireless_core_stop(dev);
4619 if (!dev) {
4620 err = -ENODEV;
4621 goto out;
4622 }
4623 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004624 if (prev_status >= B43_STAT_INITIALIZED)
4625 b43_wireless_core_exit(dev);
4626
4627 /* ...and up again. */
4628 if (prev_status >= B43_STAT_INITIALIZED) {
4629 err = b43_wireless_core_init(dev);
4630 if (err)
4631 goto out;
4632 }
4633 if (prev_status >= B43_STAT_STARTED) {
4634 err = b43_wireless_core_start(dev);
4635 if (err) {
4636 b43_wireless_core_exit(dev);
4637 goto out;
4638 }
4639 }
Michael Buesch3bf0a322008-05-22 16:32:16 +02004640out:
4641 if (err)
4642 wl->current_dev = NULL; /* Failed to init the dev. */
Michael Buesche4d6b792007-09-18 15:39:42 -04004643 mutex_unlock(&wl->mutex);
4644 if (err)
4645 b43err(wl, "Controller restart FAILED\n");
4646 else
4647 b43info(wl, "Controller restarted\n");
4648}
4649
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004650static int b43_setup_bands(struct b43_wldev *dev,
Michael Buesch96c755a2008-01-06 00:09:46 +01004651 bool have_2ghz_phy, bool have_5ghz_phy)
Michael Buesche4d6b792007-09-18 15:39:42 -04004652{
4653 struct ieee80211_hw *hw = dev->wl->hw;
Michael Buesche4d6b792007-09-18 15:39:42 -04004654
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004655 if (have_2ghz_phy)
4656 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz;
4657 if (dev->phy.type == B43_PHYTYPE_N) {
4658 if (have_5ghz_phy)
4659 hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_nphy;
4660 } else {
4661 if (have_5ghz_phy)
4662 hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_aphy;
4663 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004664
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004665 dev->phy.supports_2ghz = have_2ghz_phy;
4666 dev->phy.supports_5ghz = have_5ghz_phy;
Michael Buesche4d6b792007-09-18 15:39:42 -04004667
4668 return 0;
4669}
4670
4671static void b43_wireless_core_detach(struct b43_wldev *dev)
4672{
4673 /* We release firmware that late to not be required to re-request
4674 * is all the time when we reinit the core. */
4675 b43_release_firmware(dev);
Michael Bueschfb111372008-09-02 13:00:34 +02004676 b43_phy_free(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004677}
4678
4679static int b43_wireless_core_attach(struct b43_wldev *dev)
4680{
4681 struct b43_wl *wl = dev->wl;
4682 struct ssb_bus *bus = dev->dev->bus;
Michael Buesch899110f2009-10-09 20:30:10 +02004683 struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
Michael Buesche4d6b792007-09-18 15:39:42 -04004684 int err;
Michael Buesch96c755a2008-01-06 00:09:46 +01004685 bool have_2ghz_phy = 0, have_5ghz_phy = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04004686 u32 tmp;
4687
4688 /* Do NOT do any device initialization here.
4689 * Do it in wireless_core_init() instead.
4690 * This function is for gathering basic information about the HW, only.
4691 * Also some structs may be set up here. But most likely you want to have
4692 * that in core_init(), too.
4693 */
4694
4695 err = ssb_bus_powerup(bus, 0);
4696 if (err) {
4697 b43err(wl, "Bus powerup failed\n");
4698 goto out;
4699 }
4700 /* Get the PHY type. */
4701 if (dev->dev->id.revision >= 5) {
4702 u32 tmshigh;
4703
4704 tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
Michael Buesch96c755a2008-01-06 00:09:46 +01004705 have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
4706 have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
Michael Buesche4d6b792007-09-18 15:39:42 -04004707 } else
Michael Buesch96c755a2008-01-06 00:09:46 +01004708 B43_WARN_ON(1);
Michael Buesche4d6b792007-09-18 15:39:42 -04004709
Michael Buesch96c755a2008-01-06 00:09:46 +01004710 dev->phy.gmode = have_2ghz_phy;
Larry Fingerfd4973c2009-06-20 12:58:11 -05004711 dev->phy.radio_on = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004712 tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
4713 b43_wireless_core_reset(dev, tmp);
4714
4715 err = b43_phy_versioning(dev);
4716 if (err)
Michael Buesch21954c32007-09-27 15:31:40 +02004717 goto err_powerdown;
Michael Buesche4d6b792007-09-18 15:39:42 -04004718 /* Check if this device supports multiband. */
4719 if (!pdev ||
4720 (pdev->device != 0x4312 &&
4721 pdev->device != 0x4319 && pdev->device != 0x4324)) {
4722 /* No multiband support. */
Michael Buesch96c755a2008-01-06 00:09:46 +01004723 have_2ghz_phy = 0;
4724 have_5ghz_phy = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04004725 switch (dev->phy.type) {
4726 case B43_PHYTYPE_A:
Michael Buesch96c755a2008-01-06 00:09:46 +01004727 have_5ghz_phy = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004728 break;
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02004729 case B43_PHYTYPE_LP: //FIXME not always!
Gábor Stefanik86b28922009-08-16 20:22:41 +02004730#if 0 //FIXME enabling 5GHz causes a NULL pointer dereference
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02004731 have_5ghz_phy = 1;
Gábor Stefanik86b28922009-08-16 20:22:41 +02004732#endif
Michael Buesche4d6b792007-09-18 15:39:42 -04004733 case B43_PHYTYPE_G:
Michael Buesch96c755a2008-01-06 00:09:46 +01004734 case B43_PHYTYPE_N:
4735 have_2ghz_phy = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004736 break;
4737 default:
4738 B43_WARN_ON(1);
4739 }
4740 }
Michael Buesch96c755a2008-01-06 00:09:46 +01004741 if (dev->phy.type == B43_PHYTYPE_A) {
4742 /* FIXME */
4743 b43err(wl, "IEEE 802.11a devices are unsupported\n");
4744 err = -EOPNOTSUPP;
4745 goto err_powerdown;
4746 }
Michael Buesch2e35af12008-04-27 19:06:18 +02004747 if (1 /* disable A-PHY */) {
4748 /* FIXME: For now we disable the A-PHY on multi-PHY devices. */
Gábor Stefanik9d86a2d2009-08-14 14:54:46 +02004749 if (dev->phy.type != B43_PHYTYPE_N &&
4750 dev->phy.type != B43_PHYTYPE_LP) {
Michael Buesch2e35af12008-04-27 19:06:18 +02004751 have_2ghz_phy = 1;
4752 have_5ghz_phy = 0;
4753 }
4754 }
4755
Michael Bueschfb111372008-09-02 13:00:34 +02004756 err = b43_phy_allocate(dev);
4757 if (err)
4758 goto err_powerdown;
4759
Michael Buesch96c755a2008-01-06 00:09:46 +01004760 dev->phy.gmode = have_2ghz_phy;
Michael Buesche4d6b792007-09-18 15:39:42 -04004761 tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
4762 b43_wireless_core_reset(dev, tmp);
4763
4764 err = b43_validate_chipaccess(dev);
4765 if (err)
Michael Bueschfb111372008-09-02 13:00:34 +02004766 goto err_phy_free;
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004767 err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy);
Michael Buesche4d6b792007-09-18 15:39:42 -04004768 if (err)
Michael Bueschfb111372008-09-02 13:00:34 +02004769 goto err_phy_free;
Michael Buesche4d6b792007-09-18 15:39:42 -04004770
4771 /* Now set some default "current_dev" */
4772 if (!wl->current_dev)
4773 wl->current_dev = dev;
4774 INIT_WORK(&dev->restart_work, b43_chip_reset);
4775
Michael Bueschcb24f572008-09-03 12:12:20 +02004776 dev->phy.ops->switch_analog(dev, 0);
Michael Buesche4d6b792007-09-18 15:39:42 -04004777 ssb_device_disable(dev->dev, 0);
4778 ssb_bus_may_powerdown(bus);
4779
4780out:
4781 return err;
4782
Michael Bueschfb111372008-09-02 13:00:34 +02004783err_phy_free:
4784 b43_phy_free(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004785err_powerdown:
4786 ssb_bus_may_powerdown(bus);
4787 return err;
4788}
4789
4790static void b43_one_core_detach(struct ssb_device *dev)
4791{
4792 struct b43_wldev *wldev;
4793 struct b43_wl *wl;
4794
Michael Buesch3bf0a322008-05-22 16:32:16 +02004795 /* Do not cancel ieee80211-workqueue based work here.
4796 * See comment in b43_remove(). */
4797
Michael Buesche4d6b792007-09-18 15:39:42 -04004798 wldev = ssb_get_drvdata(dev);
4799 wl = wldev->wl;
Michael Buesche4d6b792007-09-18 15:39:42 -04004800 b43_debugfs_remove_device(wldev);
4801 b43_wireless_core_detach(wldev);
4802 list_del(&wldev->list);
4803 wl->nr_devs--;
4804 ssb_set_drvdata(dev, NULL);
4805 kfree(wldev);
4806}
4807
4808static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
4809{
4810 struct b43_wldev *wldev;
4811 struct pci_dev *pdev;
4812 int err = -ENOMEM;
4813
4814 if (!list_empty(&wl->devlist)) {
4815 /* We are not the first core on this chip. */
Michael Buesch899110f2009-10-09 20:30:10 +02004816 pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
Michael Buesche4d6b792007-09-18 15:39:42 -04004817 /* Only special chips support more than one wireless
4818 * core, although some of the other chips have more than
4819 * one wireless core as well. Check for this and
4820 * bail out early.
4821 */
4822 if (!pdev ||
4823 ((pdev->device != 0x4321) &&
4824 (pdev->device != 0x4313) && (pdev->device != 0x431A))) {
4825 b43dbg(wl, "Ignoring unconnected 802.11 core\n");
4826 return -ENODEV;
4827 }
4828 }
4829
4830 wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
4831 if (!wldev)
4832 goto out;
4833
4834 wldev->dev = dev;
4835 wldev->wl = wl;
4836 b43_set_status(wldev, B43_STAT_UNINIT);
4837 wldev->bad_frames_preempt = modparam_bad_frames_preempt;
Michael Buesche4d6b792007-09-18 15:39:42 -04004838 INIT_LIST_HEAD(&wldev->list);
4839
4840 err = b43_wireless_core_attach(wldev);
4841 if (err)
4842 goto err_kfree_wldev;
4843
4844 list_add(&wldev->list, &wl->devlist);
4845 wl->nr_devs++;
4846 ssb_set_drvdata(dev, wldev);
4847 b43_debugfs_add_device(wldev);
4848
4849 out:
4850 return err;
4851
4852 err_kfree_wldev:
4853 kfree(wldev);
4854 return err;
4855}
4856
Michael Buesch9fc38452008-04-19 16:53:00 +02004857#define IS_PDEV(pdev, _vendor, _device, _subvendor, _subdevice) ( \
4858 (pdev->vendor == PCI_VENDOR_ID_##_vendor) && \
4859 (pdev->device == _device) && \
4860 (pdev->subsystem_vendor == PCI_VENDOR_ID_##_subvendor) && \
4861 (pdev->subsystem_device == _subdevice) )
4862
Michael Buesche4d6b792007-09-18 15:39:42 -04004863static void b43_sprom_fixup(struct ssb_bus *bus)
4864{
Michael Buesch1855ba72008-04-18 20:51:41 +02004865 struct pci_dev *pdev;
4866
Michael Buesche4d6b792007-09-18 15:39:42 -04004867 /* boardflags workarounds */
4868 if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
4869 bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
Larry Finger95de2842007-11-09 16:57:18 -06004870 bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST;
Michael Buesche4d6b792007-09-18 15:39:42 -04004871 if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
4872 bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
Larry Finger95de2842007-11-09 16:57:18 -06004873 bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
Michael Buesch1855ba72008-04-18 20:51:41 +02004874 if (bus->bustype == SSB_BUSTYPE_PCI) {
4875 pdev = bus->host_pci;
Michael Buesch9fc38452008-04-19 16:53:00 +02004876 if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) ||
Larry Finger430cd472008-08-14 18:57:11 -05004877 IS_PDEV(pdev, BROADCOM, 0x4320, DELL, 0x0003) ||
Larry Finger570bdfb2008-09-26 08:23:00 -05004878 IS_PDEV(pdev, BROADCOM, 0x4320, HP, 0x12f8) ||
Michael Buesch9fc38452008-04-19 16:53:00 +02004879 IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) ||
Larry Fingera58d4522008-08-10 10:19:33 -05004880 IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0014) ||
Larry Finger3bb91bf2008-09-19 14:47:38 -05004881 IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013) ||
4882 IS_PDEV(pdev, BROADCOM, 0x4320, MOTOROLA, 0x7010))
Michael Buesch1855ba72008-04-18 20:51:41 +02004883 bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST;
4884 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004885}
4886
4887static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
4888{
4889 struct ieee80211_hw *hw = wl->hw;
4890
4891 ssb_set_devtypedata(dev, NULL);
4892 ieee80211_free_hw(hw);
4893}
4894
4895static int b43_wireless_init(struct ssb_device *dev)
4896{
4897 struct ssb_sprom *sprom = &dev->bus->sprom;
4898 struct ieee80211_hw *hw;
4899 struct b43_wl *wl;
4900 int err = -ENOMEM;
4901
4902 b43_sprom_fixup(dev->bus);
4903
4904 hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
4905 if (!hw) {
4906 b43err(NULL, "Could not allocate ieee80211 device\n");
4907 goto out;
4908 }
Michael Buesch403a3a12009-06-08 21:04:57 +02004909 wl = hw_to_b43_wl(hw);
Michael Buesche4d6b792007-09-18 15:39:42 -04004910
4911 /* fill hw info */
Johannes Berg605a0bd2008-07-15 10:10:01 +02004912 hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
Bruno Randolf566bfe52008-05-08 19:15:40 +02004913 IEEE80211_HW_SIGNAL_DBM |
4914 IEEE80211_HW_NOISE_DBM;
4915
Luis R. Rodriguezf59ac042008-08-29 16:26:43 -07004916 hw->wiphy->interface_modes =
4917 BIT(NL80211_IFTYPE_AP) |
4918 BIT(NL80211_IFTYPE_MESH_POINT) |
4919 BIT(NL80211_IFTYPE_STATION) |
4920 BIT(NL80211_IFTYPE_WDS) |
4921 BIT(NL80211_IFTYPE_ADHOC);
4922
Michael Buesch403a3a12009-06-08 21:04:57 +02004923 hw->queues = modparam_qos ? 4 : 1;
4924 wl->mac80211_initially_registered_queues = hw->queues;
Johannes Berge6a98542008-10-21 12:40:02 +02004925 hw->max_rates = 2;
Michael Buesche4d6b792007-09-18 15:39:42 -04004926 SET_IEEE80211_DEV(hw, dev->dev);
Larry Finger95de2842007-11-09 16:57:18 -06004927 if (is_valid_ether_addr(sprom->et1mac))
4928 SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
Michael Buesche4d6b792007-09-18 15:39:42 -04004929 else
Larry Finger95de2842007-11-09 16:57:18 -06004930 SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
Michael Buesche4d6b792007-09-18 15:39:42 -04004931
Michael Buesch403a3a12009-06-08 21:04:57 +02004932 /* Initialize struct b43_wl */
Michael Buesche4d6b792007-09-18 15:39:42 -04004933 wl->hw = hw;
Michael Buesche4d6b792007-09-18 15:39:42 -04004934 mutex_init(&wl->mutex);
Michael Buesch36dbd952009-09-04 22:51:29 +02004935 spin_lock_init(&wl->hardirq_lock);
Michael Buesche4d6b792007-09-18 15:39:42 -04004936 INIT_LIST_HEAD(&wl->devlist);
Michael Buescha82d9922008-04-04 21:40:06 +02004937 INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
Michael Buesch18c8ade2008-08-28 19:33:40 +02004938 INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
Michael Bueschf5d40ee2009-09-04 22:53:18 +02004939 INIT_WORK(&wl->tx_work, b43_tx_work);
4940 skb_queue_head_init(&wl->tx_queue);
Michael Buesche4d6b792007-09-18 15:39:42 -04004941
4942 ssb_set_devtypedata(dev, wl);
Michael Buesch060210f2009-01-25 15:49:59 +01004943 b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n",
4944 dev->bus->chip_id, dev->id.revision);
Michael Buesche4d6b792007-09-18 15:39:42 -04004945 err = 0;
Michael Buesch060210f2009-01-25 15:49:59 +01004946out:
Michael Buesche4d6b792007-09-18 15:39:42 -04004947 return err;
4948}
4949
4950static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
4951{
4952 struct b43_wl *wl;
4953 int err;
4954 int first = 0;
4955
4956 wl = ssb_get_devtypedata(dev);
4957 if (!wl) {
4958 /* Probing the first core. Must setup common struct b43_wl */
4959 first = 1;
4960 err = b43_wireless_init(dev);
4961 if (err)
4962 goto out;
4963 wl = ssb_get_devtypedata(dev);
4964 B43_WARN_ON(!wl);
4965 }
4966 err = b43_one_core_attach(dev, wl);
4967 if (err)
4968 goto err_wireless_exit;
4969
4970 if (first) {
4971 err = ieee80211_register_hw(wl->hw);
4972 if (err)
4973 goto err_one_core_detach;
Michael Buescha78b3bb2009-09-11 21:44:05 +02004974 b43_leds_register(wl->current_dev);
4975 b43_rng_init(wl);
Michael Buesche4d6b792007-09-18 15:39:42 -04004976 }
4977
4978 out:
4979 return err;
4980
4981 err_one_core_detach:
4982 b43_one_core_detach(dev);
4983 err_wireless_exit:
4984 if (first)
4985 b43_wireless_exit(dev, wl);
4986 return err;
4987}
4988
4989static void b43_remove(struct ssb_device *dev)
4990{
4991 struct b43_wl *wl = ssb_get_devtypedata(dev);
4992 struct b43_wldev *wldev = ssb_get_drvdata(dev);
4993
Michael Buesch3bf0a322008-05-22 16:32:16 +02004994 /* We must cancel any work here before unregistering from ieee80211,
4995 * as the ieee80211 unreg will destroy the workqueue. */
4996 cancel_work_sync(&wldev->restart_work);
4997
Michael Buesche4d6b792007-09-18 15:39:42 -04004998 B43_WARN_ON(!wl);
Michael Buesch403a3a12009-06-08 21:04:57 +02004999 if (wl->current_dev == wldev) {
5000 /* Restore the queues count before unregistering, because firmware detect
5001 * might have modified it. Restoring is important, so the networking
5002 * stack can properly free resources. */
5003 wl->hw->queues = wl->mac80211_initially_registered_queues;
Albert Herranz82905ac2009-09-16 00:26:19 +02005004 b43_leds_stop(wldev);
Michael Buesche4d6b792007-09-18 15:39:42 -04005005 ieee80211_unregister_hw(wl->hw);
Michael Buesch403a3a12009-06-08 21:04:57 +02005006 }
Michael Buesche4d6b792007-09-18 15:39:42 -04005007
5008 b43_one_core_detach(dev);
5009
5010 if (list_empty(&wl->devlist)) {
Michael Buescha78b3bb2009-09-11 21:44:05 +02005011 b43_rng_exit(wl);
Michael Buesch727c9882009-10-01 15:54:32 +02005012 b43_leds_unregister(wl);
Michael Buesche4d6b792007-09-18 15:39:42 -04005013 /* Last core on the chip unregistered.
5014 * We can destroy common struct b43_wl.
5015 */
5016 b43_wireless_exit(dev, wl);
5017 }
5018}
5019
5020/* Perform a hardware reset. This can be called from any context. */
5021void b43_controller_restart(struct b43_wldev *dev, const char *reason)
5022{
5023 /* Must avoid requeueing, if we are in shutdown. */
5024 if (b43_status(dev) < B43_STAT_INITIALIZED)
5025 return;
5026 b43info(dev->wl, "Controller RESET (%s) ...\n", reason);
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04005027 ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
Michael Buesche4d6b792007-09-18 15:39:42 -04005028}
5029
Michael Buesche4d6b792007-09-18 15:39:42 -04005030static struct ssb_driver b43_ssb_driver = {
5031 .name = KBUILD_MODNAME,
5032 .id_table = b43_ssb_tbl,
5033 .probe = b43_probe,
5034 .remove = b43_remove,
Michael Buesche4d6b792007-09-18 15:39:42 -04005035};
5036
Michael Buesch26bc7832008-02-09 00:18:35 +01005037static void b43_print_driverinfo(void)
5038{
5039 const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005040 *feat_leds = "", *feat_sdio = "";
Michael Buesch26bc7832008-02-09 00:18:35 +01005041
5042#ifdef CONFIG_B43_PCI_AUTOSELECT
5043 feat_pci = "P";
5044#endif
5045#ifdef CONFIG_B43_PCMCIA
5046 feat_pcmcia = "M";
5047#endif
5048#ifdef CONFIG_B43_NPHY
5049 feat_nphy = "N";
5050#endif
5051#ifdef CONFIG_B43_LEDS
5052 feat_leds = "L";
5053#endif
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005054#ifdef CONFIG_B43_SDIO
5055 feat_sdio = "S";
5056#endif
Michael Buesch26bc7832008-02-09 00:18:35 +01005057 printk(KERN_INFO "Broadcom 43xx driver loaded "
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005058 "[ Features: %s%s%s%s%s, Firmware-ID: "
Michael Buesch26bc7832008-02-09 00:18:35 +01005059 B43_SUPPORTED_FIRMWARE_ID " ]\n",
5060 feat_pci, feat_pcmcia, feat_nphy,
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005061 feat_leds, feat_sdio);
Michael Buesch26bc7832008-02-09 00:18:35 +01005062}
5063
Michael Buesche4d6b792007-09-18 15:39:42 -04005064static int __init b43_init(void)
5065{
5066 int err;
5067
5068 b43_debugfs_init();
5069 err = b43_pcmcia_init();
5070 if (err)
5071 goto err_dfs_exit;
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005072 err = b43_sdio_init();
Michael Buesche4d6b792007-09-18 15:39:42 -04005073 if (err)
5074 goto err_pcmcia_exit;
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005075 err = ssb_driver_register(&b43_ssb_driver);
5076 if (err)
5077 goto err_sdio_exit;
Michael Buesch26bc7832008-02-09 00:18:35 +01005078 b43_print_driverinfo();
Michael Buesche4d6b792007-09-18 15:39:42 -04005079
5080 return err;
5081
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005082err_sdio_exit:
5083 b43_sdio_exit();
Michael Buesche4d6b792007-09-18 15:39:42 -04005084err_pcmcia_exit:
5085 b43_pcmcia_exit();
5086err_dfs_exit:
5087 b43_debugfs_exit();
5088 return err;
5089}
5090
5091static void __exit b43_exit(void)
5092{
5093 ssb_driver_unregister(&b43_ssb_driver);
Albert Herranz3dbba8e2009-09-10 19:34:49 +02005094 b43_sdio_exit();
Michael Buesche4d6b792007-09-18 15:39:42 -04005095 b43_pcmcia_exit();
5096 b43_debugfs_exit();
5097}
5098
5099module_init(b43_init)
5100module_exit(b43_exit)