blob: 7bca8e9815129e158c5d4b13d834b92e57e72ea7 [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 Buesche4d6b792007-09-18 15:39:42 -04007 Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
8 Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
9 Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10
11 Some parts of the code in this file are derived from the ipw2200
12 driver Copyright(c) 2003 - 2004 Intel Corporation.
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING. If not, write to
26 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
27 Boston, MA 02110-1301, USA.
28
29*/
30
31#include <linux/delay.h>
32#include <linux/init.h>
33#include <linux/moduleparam.h>
34#include <linux/if_arp.h>
35#include <linux/etherdevice.h>
36#include <linux/version.h>
37#include <linux/firmware.h>
38#include <linux/wireless.h>
39#include <linux/workqueue.h>
40#include <linux/skbuff.h>
Andrew Morton96cf49a2008-02-04 22:27:19 -080041#include <linux/io.h>
Michael Buesche4d6b792007-09-18 15:39:42 -040042#include <linux/dma-mapping.h>
43#include <asm/unaligned.h>
44
45#include "b43.h"
46#include "main.h"
47#include "debugfs.h"
48#include "phy.h"
Michael Buesch7b584162008-04-03 18:01:12 +020049#include "nphy.h"
Michael Buesche4d6b792007-09-18 15:39:42 -040050#include "dma.h"
Michael Buesch5100d5a2008-03-29 21:01:16 +010051#include "pio.h"
Michael Buesche4d6b792007-09-18 15:39:42 -040052#include "sysfs.h"
53#include "xmit.h"
Michael Buesche4d6b792007-09-18 15:39:42 -040054#include "lo.h"
55#include "pcmcia.h"
56
57MODULE_DESCRIPTION("Broadcom B43 wireless driver");
58MODULE_AUTHOR("Martin Langer");
59MODULE_AUTHOR("Stefano Brivio");
60MODULE_AUTHOR("Michael Buesch");
61MODULE_LICENSE("GPL");
62
Michael Buesch9c7d99d2008-02-09 10:23:49 +010063MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
64
Michael Buesche4d6b792007-09-18 15:39:42 -040065
66static int modparam_bad_frames_preempt;
67module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
68MODULE_PARM_DESC(bad_frames_preempt,
69 "enable(1) / disable(0) Bad Frames Preemption");
70
Michael Buesche4d6b792007-09-18 15:39:42 -040071static char modparam_fwpostfix[16];
72module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
73MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
74
Michael Buesche4d6b792007-09-18 15:39:42 -040075static int modparam_hwpctl;
76module_param_named(hwpctl, modparam_hwpctl, int, 0444);
77MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)");
78
79static int modparam_nohwcrypt;
80module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
81MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
82
Michael Buesche6f5b932008-03-05 21:18:49 +010083int b43_modparam_qos = 1;
84module_param_named(qos, b43_modparam_qos, int, 0444);
85MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
86
Michael Buesch1855ba72008-04-18 20:51:41 +020087static int modparam_btcoex = 1;
88module_param_named(btcoex, modparam_btcoex, int, 0444);
89MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistance (default on)");
90
Michael Buesche6f5b932008-03-05 21:18:49 +010091
Michael Buesche4d6b792007-09-18 15:39:42 -040092static const struct ssb_device_id b43_ssb_tbl[] = {
93 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
94 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
95 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
96 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
97 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
Michael Bueschd5c71e42008-01-04 17:06:29 +010098 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
Larry Finger013978b2007-11-26 10:29:47 -060099 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
Michael Buesche4d6b792007-09-18 15:39:42 -0400100 SSB_DEVTABLE_END
101};
102
103MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
104
105/* Channel and ratetables are shared for all devices.
106 * They can't be const, because ieee80211 puts some precalculated
107 * data in there. This data is the same for all devices, so we don't
108 * get concurrency issues */
109#define RATETAB_ENT(_rateid, _flags) \
Johannes Berg8318d782008-01-24 19:38:38 +0100110 { \
111 .bitrate = B43_RATE_TO_BASE100KBPS(_rateid), \
112 .hw_value = (_rateid), \
113 .flags = (_flags), \
Michael Buesche4d6b792007-09-18 15:39:42 -0400114 }
Johannes Berg8318d782008-01-24 19:38:38 +0100115
116/*
117 * NOTE: When changing this, sync with xmit.c's
118 * b43_plcp_get_bitrate_idx_* functions!
119 */
Michael Buesche4d6b792007-09-18 15:39:42 -0400120static struct ieee80211_rate __b43_ratetable[] = {
Johannes Berg8318d782008-01-24 19:38:38 +0100121 RATETAB_ENT(B43_CCK_RATE_1MB, 0),
122 RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
123 RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
124 RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
125 RATETAB_ENT(B43_OFDM_RATE_6MB, 0),
126 RATETAB_ENT(B43_OFDM_RATE_9MB, 0),
127 RATETAB_ENT(B43_OFDM_RATE_12MB, 0),
128 RATETAB_ENT(B43_OFDM_RATE_18MB, 0),
129 RATETAB_ENT(B43_OFDM_RATE_24MB, 0),
130 RATETAB_ENT(B43_OFDM_RATE_36MB, 0),
131 RATETAB_ENT(B43_OFDM_RATE_48MB, 0),
132 RATETAB_ENT(B43_OFDM_RATE_54MB, 0),
Michael Buesche4d6b792007-09-18 15:39:42 -0400133};
134
135#define b43_a_ratetable (__b43_ratetable + 4)
136#define b43_a_ratetable_size 8
137#define b43_b_ratetable (__b43_ratetable + 0)
138#define b43_b_ratetable_size 4
139#define b43_g_ratetable (__b43_ratetable + 0)
140#define b43_g_ratetable_size 12
141
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100142#define CHAN4G(_channel, _freq, _flags) { \
143 .band = IEEE80211_BAND_2GHZ, \
144 .center_freq = (_freq), \
145 .hw_value = (_channel), \
146 .flags = (_flags), \
147 .max_antenna_gain = 0, \
148 .max_power = 30, \
149}
Michael Buesch96c755a2008-01-06 00:09:46 +0100150static struct ieee80211_channel b43_2ghz_chantable[] = {
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100151 CHAN4G(1, 2412, 0),
152 CHAN4G(2, 2417, 0),
153 CHAN4G(3, 2422, 0),
154 CHAN4G(4, 2427, 0),
155 CHAN4G(5, 2432, 0),
156 CHAN4G(6, 2437, 0),
157 CHAN4G(7, 2442, 0),
158 CHAN4G(8, 2447, 0),
159 CHAN4G(9, 2452, 0),
160 CHAN4G(10, 2457, 0),
161 CHAN4G(11, 2462, 0),
162 CHAN4G(12, 2467, 0),
163 CHAN4G(13, 2472, 0),
164 CHAN4G(14, 2484, 0),
165};
166#undef CHAN4G
167
168#define CHAN5G(_channel, _flags) { \
169 .band = IEEE80211_BAND_5GHZ, \
170 .center_freq = 5000 + (5 * (_channel)), \
171 .hw_value = (_channel), \
172 .flags = (_flags), \
173 .max_antenna_gain = 0, \
174 .max_power = 30, \
175}
176static struct ieee80211_channel b43_5ghz_nphy_chantable[] = {
177 CHAN5G(32, 0), CHAN5G(34, 0),
178 CHAN5G(36, 0), CHAN5G(38, 0),
179 CHAN5G(40, 0), CHAN5G(42, 0),
180 CHAN5G(44, 0), CHAN5G(46, 0),
181 CHAN5G(48, 0), CHAN5G(50, 0),
182 CHAN5G(52, 0), CHAN5G(54, 0),
183 CHAN5G(56, 0), CHAN5G(58, 0),
184 CHAN5G(60, 0), CHAN5G(62, 0),
185 CHAN5G(64, 0), CHAN5G(66, 0),
186 CHAN5G(68, 0), CHAN5G(70, 0),
187 CHAN5G(72, 0), CHAN5G(74, 0),
188 CHAN5G(76, 0), CHAN5G(78, 0),
189 CHAN5G(80, 0), CHAN5G(82, 0),
190 CHAN5G(84, 0), CHAN5G(86, 0),
191 CHAN5G(88, 0), CHAN5G(90, 0),
192 CHAN5G(92, 0), CHAN5G(94, 0),
193 CHAN5G(96, 0), CHAN5G(98, 0),
194 CHAN5G(100, 0), CHAN5G(102, 0),
195 CHAN5G(104, 0), CHAN5G(106, 0),
196 CHAN5G(108, 0), CHAN5G(110, 0),
197 CHAN5G(112, 0), CHAN5G(114, 0),
198 CHAN5G(116, 0), CHAN5G(118, 0),
199 CHAN5G(120, 0), CHAN5G(122, 0),
200 CHAN5G(124, 0), CHAN5G(126, 0),
201 CHAN5G(128, 0), CHAN5G(130, 0),
202 CHAN5G(132, 0), CHAN5G(134, 0),
203 CHAN5G(136, 0), CHAN5G(138, 0),
204 CHAN5G(140, 0), CHAN5G(142, 0),
205 CHAN5G(144, 0), CHAN5G(145, 0),
206 CHAN5G(146, 0), CHAN5G(147, 0),
207 CHAN5G(148, 0), CHAN5G(149, 0),
208 CHAN5G(150, 0), CHAN5G(151, 0),
209 CHAN5G(152, 0), CHAN5G(153, 0),
210 CHAN5G(154, 0), CHAN5G(155, 0),
211 CHAN5G(156, 0), CHAN5G(157, 0),
212 CHAN5G(158, 0), CHAN5G(159, 0),
213 CHAN5G(160, 0), CHAN5G(161, 0),
214 CHAN5G(162, 0), CHAN5G(163, 0),
215 CHAN5G(164, 0), CHAN5G(165, 0),
216 CHAN5G(166, 0), CHAN5G(168, 0),
217 CHAN5G(170, 0), CHAN5G(172, 0),
218 CHAN5G(174, 0), CHAN5G(176, 0),
219 CHAN5G(178, 0), CHAN5G(180, 0),
220 CHAN5G(182, 0), CHAN5G(184, 0),
221 CHAN5G(186, 0), CHAN5G(188, 0),
222 CHAN5G(190, 0), CHAN5G(192, 0),
223 CHAN5G(194, 0), CHAN5G(196, 0),
224 CHAN5G(198, 0), CHAN5G(200, 0),
225 CHAN5G(202, 0), CHAN5G(204, 0),
226 CHAN5G(206, 0), CHAN5G(208, 0),
227 CHAN5G(210, 0), CHAN5G(212, 0),
228 CHAN5G(214, 0), CHAN5G(216, 0),
229 CHAN5G(218, 0), CHAN5G(220, 0),
230 CHAN5G(222, 0), CHAN5G(224, 0),
231 CHAN5G(226, 0), CHAN5G(228, 0),
Michael Buesche4d6b792007-09-18 15:39:42 -0400232};
233
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100234static struct ieee80211_channel b43_5ghz_aphy_chantable[] = {
235 CHAN5G(34, 0), CHAN5G(36, 0),
236 CHAN5G(38, 0), CHAN5G(40, 0),
237 CHAN5G(42, 0), CHAN5G(44, 0),
238 CHAN5G(46, 0), CHAN5G(48, 0),
239 CHAN5G(52, 0), CHAN5G(56, 0),
240 CHAN5G(60, 0), CHAN5G(64, 0),
241 CHAN5G(100, 0), CHAN5G(104, 0),
242 CHAN5G(108, 0), CHAN5G(112, 0),
243 CHAN5G(116, 0), CHAN5G(120, 0),
244 CHAN5G(124, 0), CHAN5G(128, 0),
245 CHAN5G(132, 0), CHAN5G(136, 0),
246 CHAN5G(140, 0), CHAN5G(149, 0),
247 CHAN5G(153, 0), CHAN5G(157, 0),
248 CHAN5G(161, 0), CHAN5G(165, 0),
249 CHAN5G(184, 0), CHAN5G(188, 0),
250 CHAN5G(192, 0), CHAN5G(196, 0),
251 CHAN5G(200, 0), CHAN5G(204, 0),
252 CHAN5G(208, 0), CHAN5G(212, 0),
253 CHAN5G(216, 0),
254};
255#undef CHAN5G
256
257static struct ieee80211_supported_band b43_band_5GHz_nphy = {
258 .band = IEEE80211_BAND_5GHZ,
259 .channels = b43_5ghz_nphy_chantable,
260 .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable),
261 .bitrates = b43_a_ratetable,
262 .n_bitrates = b43_a_ratetable_size,
Michael Buesche4d6b792007-09-18 15:39:42 -0400263};
Johannes Berg8318d782008-01-24 19:38:38 +0100264
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100265static struct ieee80211_supported_band b43_band_5GHz_aphy = {
266 .band = IEEE80211_BAND_5GHZ,
267 .channels = b43_5ghz_aphy_chantable,
268 .n_channels = ARRAY_SIZE(b43_5ghz_aphy_chantable),
269 .bitrates = b43_a_ratetable,
270 .n_bitrates = b43_a_ratetable_size,
Johannes Berg8318d782008-01-24 19:38:38 +0100271};
Michael Buesche4d6b792007-09-18 15:39:42 -0400272
Johannes Berg8318d782008-01-24 19:38:38 +0100273static struct ieee80211_supported_band b43_band_2GHz = {
Michael Bueschbb1eeff2008-02-09 12:08:58 +0100274 .band = IEEE80211_BAND_2GHZ,
275 .channels = b43_2ghz_chantable,
276 .n_channels = ARRAY_SIZE(b43_2ghz_chantable),
277 .bitrates = b43_g_ratetable,
278 .n_bitrates = b43_g_ratetable_size,
Johannes Berg8318d782008-01-24 19:38:38 +0100279};
280
Michael Buesche4d6b792007-09-18 15:39:42 -0400281static void b43_wireless_core_exit(struct b43_wldev *dev);
282static int b43_wireless_core_init(struct b43_wldev *dev);
283static void b43_wireless_core_stop(struct b43_wldev *dev);
284static int b43_wireless_core_start(struct b43_wldev *dev);
285
286static int b43_ratelimit(struct b43_wl *wl)
287{
288 if (!wl || !wl->current_dev)
289 return 1;
290 if (b43_status(wl->current_dev) < B43_STAT_STARTED)
291 return 1;
292 /* We are up and running.
293 * Ratelimit the messages to avoid DoS over the net. */
294 return net_ratelimit();
295}
296
297void b43info(struct b43_wl *wl, const char *fmt, ...)
298{
299 va_list args;
300
301 if (!b43_ratelimit(wl))
302 return;
303 va_start(args, fmt);
304 printk(KERN_INFO "b43-%s: ",
305 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
306 vprintk(fmt, args);
307 va_end(args);
308}
309
310void b43err(struct b43_wl *wl, const char *fmt, ...)
311{
312 va_list args;
313
314 if (!b43_ratelimit(wl))
315 return;
316 va_start(args, fmt);
317 printk(KERN_ERR "b43-%s ERROR: ",
318 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
319 vprintk(fmt, args);
320 va_end(args);
321}
322
323void b43warn(struct b43_wl *wl, const char *fmt, ...)
324{
325 va_list args;
326
327 if (!b43_ratelimit(wl))
328 return;
329 va_start(args, fmt);
330 printk(KERN_WARNING "b43-%s warning: ",
331 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
332 vprintk(fmt, args);
333 va_end(args);
334}
335
336#if B43_DEBUG
337void b43dbg(struct b43_wl *wl, const char *fmt, ...)
338{
339 va_list args;
340
341 va_start(args, fmt);
342 printk(KERN_DEBUG "b43-%s debug: ",
343 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
344 vprintk(fmt, args);
345 va_end(args);
346}
347#endif /* DEBUG */
348
349static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
350{
351 u32 macctl;
352
353 B43_WARN_ON(offset % 4 != 0);
354
355 macctl = b43_read32(dev, B43_MMIO_MACCTL);
356 if (macctl & B43_MACCTL_BE)
357 val = swab32(val);
358
359 b43_write32(dev, B43_MMIO_RAM_CONTROL, offset);
360 mmiowb();
361 b43_write32(dev, B43_MMIO_RAM_DATA, val);
362}
363
Michael Buesch280d0e12007-12-26 18:26:17 +0100364static inline void b43_shm_control_word(struct b43_wldev *dev,
365 u16 routing, u16 offset)
Michael Buesche4d6b792007-09-18 15:39:42 -0400366{
367 u32 control;
368
369 /* "offset" is the WORD offset. */
Michael Buesche4d6b792007-09-18 15:39:42 -0400370 control = routing;
371 control <<= 16;
372 control |= offset;
373 b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
374}
375
376u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
377{
Michael Buesch280d0e12007-12-26 18:26:17 +0100378 struct b43_wl *wl = dev->wl;
379 unsigned long flags;
Michael Buesche4d6b792007-09-18 15:39:42 -0400380 u32 ret;
381
Michael Buesch280d0e12007-12-26 18:26:17 +0100382 spin_lock_irqsave(&wl->shm_lock, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -0400383 if (routing == B43_SHM_SHARED) {
384 B43_WARN_ON(offset & 0x0001);
385 if (offset & 0x0003) {
386 /* Unaligned access */
387 b43_shm_control_word(dev, routing, offset >> 2);
388 ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
389 ret <<= 16;
390 b43_shm_control_word(dev, routing, (offset >> 2) + 1);
391 ret |= b43_read16(dev, B43_MMIO_SHM_DATA);
392
Michael Buesch280d0e12007-12-26 18:26:17 +0100393 goto out;
Michael Buesche4d6b792007-09-18 15:39:42 -0400394 }
395 offset >>= 2;
396 }
397 b43_shm_control_word(dev, routing, offset);
398 ret = b43_read32(dev, B43_MMIO_SHM_DATA);
Michael Buesch280d0e12007-12-26 18:26:17 +0100399out:
400 spin_unlock_irqrestore(&wl->shm_lock, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -0400401
402 return ret;
403}
404
405u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
406{
Michael Buesch280d0e12007-12-26 18:26:17 +0100407 struct b43_wl *wl = dev->wl;
408 unsigned long flags;
Michael Buesche4d6b792007-09-18 15:39:42 -0400409 u16 ret;
410
Michael Buesch280d0e12007-12-26 18:26:17 +0100411 spin_lock_irqsave(&wl->shm_lock, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -0400412 if (routing == B43_SHM_SHARED) {
413 B43_WARN_ON(offset & 0x0001);
414 if (offset & 0x0003) {
415 /* Unaligned access */
416 b43_shm_control_word(dev, routing, offset >> 2);
417 ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
418
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_read16(dev, B43_MMIO_SHM_DATA);
Michael Buesch280d0e12007-12-26 18:26:17 +0100425out:
426 spin_unlock_irqrestore(&wl->shm_lock, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -0400427
428 return ret;
429}
430
431void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
432{
Michael Buesch280d0e12007-12-26 18:26:17 +0100433 struct b43_wl *wl = dev->wl;
434 unsigned long flags;
435
436 spin_lock_irqsave(&wl->shm_lock, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -0400437 if (routing == B43_SHM_SHARED) {
438 B43_WARN_ON(offset & 0x0001);
439 if (offset & 0x0003) {
440 /* Unaligned access */
441 b43_shm_control_word(dev, routing, offset >> 2);
Michael Buesche4d6b792007-09-18 15:39:42 -0400442 b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
443 (value >> 16) & 0xffff);
Michael Buesche4d6b792007-09-18 15:39:42 -0400444 b43_shm_control_word(dev, routing, (offset >> 2) + 1);
Michael Buesche4d6b792007-09-18 15:39:42 -0400445 b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
Michael Buesch280d0e12007-12-26 18:26:17 +0100446 goto out;
Michael Buesche4d6b792007-09-18 15:39:42 -0400447 }
448 offset >>= 2;
449 }
450 b43_shm_control_word(dev, routing, offset);
Michael Buesche4d6b792007-09-18 15:39:42 -0400451 b43_write32(dev, B43_MMIO_SHM_DATA, value);
Michael Buesch280d0e12007-12-26 18:26:17 +0100452out:
453 spin_unlock_irqrestore(&wl->shm_lock, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -0400454}
455
456void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
457{
Michael Buesch280d0e12007-12-26 18:26:17 +0100458 struct b43_wl *wl = dev->wl;
459 unsigned long flags;
460
461 spin_lock_irqsave(&wl->shm_lock, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -0400462 if (routing == B43_SHM_SHARED) {
463 B43_WARN_ON(offset & 0x0001);
464 if (offset & 0x0003) {
465 /* Unaligned access */
466 b43_shm_control_word(dev, routing, offset >> 2);
Michael Buesche4d6b792007-09-18 15:39:42 -0400467 b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
Michael Buesch280d0e12007-12-26 18:26:17 +0100468 goto out;
Michael Buesche4d6b792007-09-18 15:39:42 -0400469 }
470 offset >>= 2;
471 }
472 b43_shm_control_word(dev, routing, offset);
Michael Buesche4d6b792007-09-18 15:39:42 -0400473 b43_write16(dev, B43_MMIO_SHM_DATA, value);
Michael Buesch280d0e12007-12-26 18:26:17 +0100474out:
475 spin_unlock_irqrestore(&wl->shm_lock, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -0400476}
477
478/* Read HostFlags */
Michael Buesch35f0d352008-02-13 14:31:08 +0100479u64 b43_hf_read(struct b43_wldev * dev)
Michael Buesche4d6b792007-09-18 15:39:42 -0400480{
Michael Buesch35f0d352008-02-13 14:31:08 +0100481 u64 ret;
Michael Buesche4d6b792007-09-18 15:39:42 -0400482
483 ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
484 ret <<= 16;
Michael Buesch35f0d352008-02-13 14:31:08 +0100485 ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI);
486 ret <<= 16;
Michael Buesche4d6b792007-09-18 15:39:42 -0400487 ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);
488
489 return ret;
490}
491
492/* Write HostFlags */
Michael Buesch35f0d352008-02-13 14:31:08 +0100493void b43_hf_write(struct b43_wldev *dev, u64 value)
Michael Buesche4d6b792007-09-18 15:39:42 -0400494{
Michael Buesch35f0d352008-02-13 14:31:08 +0100495 u16 lo, mi, hi;
496
497 lo = (value & 0x00000000FFFFULL);
498 mi = (value & 0x0000FFFF0000ULL) >> 16;
499 hi = (value & 0xFFFF00000000ULL) >> 32;
500 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO, lo);
501 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI, mi);
502 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi);
Michael Buesche4d6b792007-09-18 15:39:42 -0400503}
504
505void b43_tsf_read(struct b43_wldev *dev, u64 * tsf)
506{
507 /* We need to be careful. As we read the TSF from multiple
508 * registers, we should take care of register overflows.
509 * In theory, the whole tsf read process should be atomic.
510 * We try to be atomic here, by restaring the read process,
511 * if any of the high registers changed (overflew).
512 */
513 if (dev->dev->id.revision >= 3) {
514 u32 low, high, high2;
515
516 do {
517 high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);
518 low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW);
519 high2 = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);
520 } while (unlikely(high != high2));
521
522 *tsf = high;
523 *tsf <<= 32;
524 *tsf |= low;
525 } else {
526 u64 tmp;
527 u16 v0, v1, v2, v3;
528 u16 test1, test2, test3;
529
530 do {
531 v3 = b43_read16(dev, B43_MMIO_TSF_3);
532 v2 = b43_read16(dev, B43_MMIO_TSF_2);
533 v1 = b43_read16(dev, B43_MMIO_TSF_1);
534 v0 = b43_read16(dev, B43_MMIO_TSF_0);
535
536 test3 = b43_read16(dev, B43_MMIO_TSF_3);
537 test2 = b43_read16(dev, B43_MMIO_TSF_2);
538 test1 = b43_read16(dev, B43_MMIO_TSF_1);
539 } while (v3 != test3 || v2 != test2 || v1 != test1);
540
541 *tsf = v3;
542 *tsf <<= 48;
543 tmp = v2;
544 tmp <<= 32;
545 *tsf |= tmp;
546 tmp = v1;
547 tmp <<= 16;
548 *tsf |= tmp;
549 *tsf |= v0;
550 }
551}
552
553static void b43_time_lock(struct b43_wldev *dev)
554{
555 u32 macctl;
556
557 macctl = b43_read32(dev, B43_MMIO_MACCTL);
558 macctl |= B43_MACCTL_TBTTHOLD;
559 b43_write32(dev, B43_MMIO_MACCTL, macctl);
560 /* Commit the write */
561 b43_read32(dev, B43_MMIO_MACCTL);
562}
563
564static void b43_time_unlock(struct b43_wldev *dev)
565{
566 u32 macctl;
567
568 macctl = b43_read32(dev, B43_MMIO_MACCTL);
569 macctl &= ~B43_MACCTL_TBTTHOLD;
570 b43_write32(dev, B43_MMIO_MACCTL, macctl);
571 /* Commit the write */
572 b43_read32(dev, B43_MMIO_MACCTL);
573}
574
575static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
576{
577 /* Be careful with the in-progress timer.
578 * First zero out the low register, so we have a full
579 * register-overflow duration to complete the operation.
580 */
581 if (dev->dev->id.revision >= 3) {
582 u32 lo = (tsf & 0x00000000FFFFFFFFULL);
583 u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
584
585 b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, 0);
586 mmiowb();
587 b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, hi);
588 mmiowb();
589 b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, lo);
590 } else {
591 u16 v0 = (tsf & 0x000000000000FFFFULL);
592 u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
593 u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
594 u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
595
596 b43_write16(dev, B43_MMIO_TSF_0, 0);
597 mmiowb();
598 b43_write16(dev, B43_MMIO_TSF_3, v3);
599 mmiowb();
600 b43_write16(dev, B43_MMIO_TSF_2, v2);
601 mmiowb();
602 b43_write16(dev, B43_MMIO_TSF_1, v1);
603 mmiowb();
604 b43_write16(dev, B43_MMIO_TSF_0, v0);
605 }
606}
607
608void b43_tsf_write(struct b43_wldev *dev, u64 tsf)
609{
610 b43_time_lock(dev);
611 b43_tsf_write_locked(dev, tsf);
612 b43_time_unlock(dev);
613}
614
615static
616void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 * mac)
617{
618 static const u8 zero_addr[ETH_ALEN] = { 0 };
619 u16 data;
620
621 if (!mac)
622 mac = zero_addr;
623
624 offset |= 0x0020;
625 b43_write16(dev, B43_MMIO_MACFILTER_CONTROL, offset);
626
627 data = mac[0];
628 data |= mac[1] << 8;
629 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
630 data = mac[2];
631 data |= mac[3] << 8;
632 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
633 data = mac[4];
634 data |= mac[5] << 8;
635 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
636}
637
638static void b43_write_mac_bssid_templates(struct b43_wldev *dev)
639{
640 const u8 *mac;
641 const u8 *bssid;
642 u8 mac_bssid[ETH_ALEN * 2];
643 int i;
644 u32 tmp;
645
646 bssid = dev->wl->bssid;
647 mac = dev->wl->mac_addr;
648
649 b43_macfilter_set(dev, B43_MACFILTER_BSSID, bssid);
650
651 memcpy(mac_bssid, mac, ETH_ALEN);
652 memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
653
654 /* Write our MAC address and BSSID to template ram */
655 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
656 tmp = (u32) (mac_bssid[i + 0]);
657 tmp |= (u32) (mac_bssid[i + 1]) << 8;
658 tmp |= (u32) (mac_bssid[i + 2]) << 16;
659 tmp |= (u32) (mac_bssid[i + 3]) << 24;
660 b43_ram_write(dev, 0x20 + i, tmp);
661 }
662}
663
Johannes Berg4150c572007-09-17 01:29:23 -0400664static void b43_upload_card_macaddress(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -0400665{
Michael Buesche4d6b792007-09-18 15:39:42 -0400666 b43_write_mac_bssid_templates(dev);
Johannes Berg4150c572007-09-17 01:29:23 -0400667 b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr);
Michael Buesche4d6b792007-09-18 15:39:42 -0400668}
669
670static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
671{
672 /* slot_time is in usec. */
673 if (dev->phy.type != B43_PHYTYPE_G)
674 return;
675 b43_write16(dev, 0x684, 510 + slot_time);
676 b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
677}
678
679static void b43_short_slot_timing_enable(struct b43_wldev *dev)
680{
681 b43_set_slot_time(dev, 9);
682 dev->short_slot = 1;
683}
684
685static void b43_short_slot_timing_disable(struct b43_wldev *dev)
686{
687 b43_set_slot_time(dev, 20);
688 dev->short_slot = 0;
689}
690
691/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
692 * Returns the _previously_ enabled IRQ mask.
693 */
694static inline u32 b43_interrupt_enable(struct b43_wldev *dev, u32 mask)
695{
696 u32 old_mask;
697
698 old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
699 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask | mask);
700
701 return old_mask;
702}
703
704/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
705 * Returns the _previously_ enabled IRQ mask.
706 */
707static inline u32 b43_interrupt_disable(struct b43_wldev *dev, u32 mask)
708{
709 u32 old_mask;
710
711 old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
712 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
713
714 return old_mask;
715}
716
717/* Synchronize IRQ top- and bottom-half.
718 * IRQs must be masked before calling this.
719 * This must not be called with the irq_lock held.
720 */
721static void b43_synchronize_irq(struct b43_wldev *dev)
722{
723 synchronize_irq(dev->dev->irq);
724 tasklet_kill(&dev->isr_tasklet);
725}
726
727/* DummyTransmission function, as documented on
728 * http://bcm-specs.sipsolutions.net/DummyTransmission
729 */
730void b43_dummy_transmission(struct b43_wldev *dev)
731{
Michael Buesch21a75d72008-04-25 19:29:08 +0200732 struct b43_wl *wl = dev->wl;
Michael Buesche4d6b792007-09-18 15:39:42 -0400733 struct b43_phy *phy = &dev->phy;
734 unsigned int i, max_loop;
735 u16 value;
736 u32 buffer[5] = {
737 0x00000000,
738 0x00D40000,
739 0x00000000,
740 0x01000000,
741 0x00000000,
742 };
743
744 switch (phy->type) {
745 case B43_PHYTYPE_A:
746 max_loop = 0x1E;
747 buffer[0] = 0x000201CC;
748 break;
749 case B43_PHYTYPE_B:
750 case B43_PHYTYPE_G:
751 max_loop = 0xFA;
752 buffer[0] = 0x000B846E;
753 break;
754 default:
755 B43_WARN_ON(1);
756 return;
757 }
758
Michael Buesch21a75d72008-04-25 19:29:08 +0200759 spin_lock_irq(&wl->irq_lock);
760 write_lock(&wl->tx_lock);
761
Michael Buesche4d6b792007-09-18 15:39:42 -0400762 for (i = 0; i < 5; i++)
763 b43_ram_write(dev, i * 4, buffer[i]);
764
765 /* Commit writes */
766 b43_read32(dev, B43_MMIO_MACCTL);
767
768 b43_write16(dev, 0x0568, 0x0000);
769 b43_write16(dev, 0x07C0, 0x0000);
770 value = ((phy->type == B43_PHYTYPE_A) ? 1 : 0);
771 b43_write16(dev, 0x050C, value);
772 b43_write16(dev, 0x0508, 0x0000);
773 b43_write16(dev, 0x050A, 0x0000);
774 b43_write16(dev, 0x054C, 0x0000);
775 b43_write16(dev, 0x056A, 0x0014);
776 b43_write16(dev, 0x0568, 0x0826);
777 b43_write16(dev, 0x0500, 0x0000);
778 b43_write16(dev, 0x0502, 0x0030);
779
780 if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
781 b43_radio_write16(dev, 0x0051, 0x0017);
782 for (i = 0x00; i < max_loop; i++) {
783 value = b43_read16(dev, 0x050E);
784 if (value & 0x0080)
785 break;
786 udelay(10);
787 }
788 for (i = 0x00; i < 0x0A; i++) {
789 value = b43_read16(dev, 0x050E);
790 if (value & 0x0400)
791 break;
792 udelay(10);
793 }
794 for (i = 0x00; i < 0x0A; i++) {
795 value = b43_read16(dev, 0x0690);
796 if (!(value & 0x0100))
797 break;
798 udelay(10);
799 }
800 if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
801 b43_radio_write16(dev, 0x0051, 0x0037);
Michael Buesch21a75d72008-04-25 19:29:08 +0200802
803 write_unlock(&wl->tx_lock);
804 spin_unlock_irq(&wl->irq_lock);
Michael Buesche4d6b792007-09-18 15:39:42 -0400805}
806
807static void key_write(struct b43_wldev *dev,
808 u8 index, u8 algorithm, const u8 * key)
809{
810 unsigned int i;
811 u32 offset;
812 u16 value;
813 u16 kidx;
814
815 /* Key index/algo block */
816 kidx = b43_kidx_to_fw(dev, index);
817 value = ((kidx << 4) | algorithm);
818 b43_shm_write16(dev, B43_SHM_SHARED,
819 B43_SHM_SH_KEYIDXBLOCK + (kidx * 2), value);
820
821 /* Write the key to the Key Table Pointer offset */
822 offset = dev->ktp + (index * B43_SEC_KEYSIZE);
823 for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
824 value = key[i];
825 value |= (u16) (key[i + 1]) << 8;
826 b43_shm_write16(dev, B43_SHM_SHARED, offset + i, value);
827 }
828}
829
830static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr)
831{
832 u32 addrtmp[2] = { 0, 0, };
833 u8 per_sta_keys_start = 8;
834
835 if (b43_new_kidx_api(dev))
836 per_sta_keys_start = 4;
837
838 B43_WARN_ON(index < per_sta_keys_start);
839 /* We have two default TX keys and possibly two default RX keys.
840 * Physical mac 0 is mapped to physical key 4 or 8, depending
841 * on the firmware version.
842 * So we must adjust the index here.
843 */
844 index -= per_sta_keys_start;
845
846 if (addr) {
847 addrtmp[0] = addr[0];
848 addrtmp[0] |= ((u32) (addr[1]) << 8);
849 addrtmp[0] |= ((u32) (addr[2]) << 16);
850 addrtmp[0] |= ((u32) (addr[3]) << 24);
851 addrtmp[1] = addr[4];
852 addrtmp[1] |= ((u32) (addr[5]) << 8);
853 }
854
855 if (dev->dev->id.revision >= 5) {
856 /* Receive match transmitter address mechanism */
857 b43_shm_write32(dev, B43_SHM_RCMTA,
858 (index * 2) + 0, addrtmp[0]);
859 b43_shm_write16(dev, B43_SHM_RCMTA,
860 (index * 2) + 1, addrtmp[1]);
861 } else {
862 /* RXE (Receive Engine) and
863 * PSM (Programmable State Machine) mechanism
864 */
865 if (index < 8) {
866 /* TODO write to RCM 16, 19, 22 and 25 */
867 } else {
868 b43_shm_write32(dev, B43_SHM_SHARED,
869 B43_SHM_SH_PSM + (index * 6) + 0,
870 addrtmp[0]);
871 b43_shm_write16(dev, B43_SHM_SHARED,
872 B43_SHM_SH_PSM + (index * 6) + 4,
873 addrtmp[1]);
874 }
875 }
876}
877
878static void do_key_write(struct b43_wldev *dev,
879 u8 index, u8 algorithm,
880 const u8 * key, size_t key_len, const u8 * mac_addr)
881{
882 u8 buf[B43_SEC_KEYSIZE] = { 0, };
883 u8 per_sta_keys_start = 8;
884
885 if (b43_new_kidx_api(dev))
886 per_sta_keys_start = 4;
887
888 B43_WARN_ON(index >= dev->max_nr_keys);
889 B43_WARN_ON(key_len > B43_SEC_KEYSIZE);
890
891 if (index >= per_sta_keys_start)
892 keymac_write(dev, index, NULL); /* First zero out mac. */
893 if (key)
894 memcpy(buf, key, key_len);
895 key_write(dev, index, algorithm, buf);
896 if (index >= per_sta_keys_start)
897 keymac_write(dev, index, mac_addr);
898
899 dev->key[index].algorithm = algorithm;
900}
901
902static int b43_key_write(struct b43_wldev *dev,
903 int index, u8 algorithm,
904 const u8 * key, size_t key_len,
905 const u8 * mac_addr,
906 struct ieee80211_key_conf *keyconf)
907{
908 int i;
909 int sta_keys_start;
910
911 if (key_len > B43_SEC_KEYSIZE)
912 return -EINVAL;
913 for (i = 0; i < dev->max_nr_keys; i++) {
914 /* Check that we don't already have this key. */
915 B43_WARN_ON(dev->key[i].keyconf == keyconf);
916 }
917 if (index < 0) {
918 /* Either pairwise key or address is 00:00:00:00:00:00
919 * for transmit-only keys. Search the index. */
920 if (b43_new_kidx_api(dev))
921 sta_keys_start = 4;
922 else
923 sta_keys_start = 8;
924 for (i = sta_keys_start; i < dev->max_nr_keys; i++) {
925 if (!dev->key[i].keyconf) {
926 /* found empty */
927 index = i;
928 break;
929 }
930 }
931 if (index < 0) {
932 b43err(dev->wl, "Out of hardware key memory\n");
933 return -ENOSPC;
934 }
935 } else
936 B43_WARN_ON(index > 3);
937
938 do_key_write(dev, index, algorithm, key, key_len, mac_addr);
939 if ((index <= 3) && !b43_new_kidx_api(dev)) {
940 /* Default RX key */
941 B43_WARN_ON(mac_addr);
942 do_key_write(dev, index + 4, algorithm, key, key_len, NULL);
943 }
944 keyconf->hw_key_idx = index;
945 dev->key[index].keyconf = keyconf;
946
947 return 0;
948}
949
950static int b43_key_clear(struct b43_wldev *dev, int index)
951{
952 if (B43_WARN_ON((index < 0) || (index >= dev->max_nr_keys)))
953 return -EINVAL;
954 do_key_write(dev, index, B43_SEC_ALGO_NONE,
955 NULL, B43_SEC_KEYSIZE, NULL);
956 if ((index <= 3) && !b43_new_kidx_api(dev)) {
957 do_key_write(dev, index + 4, B43_SEC_ALGO_NONE,
958 NULL, B43_SEC_KEYSIZE, NULL);
959 }
960 dev->key[index].keyconf = NULL;
961
962 return 0;
963}
964
965static void b43_clear_keys(struct b43_wldev *dev)
966{
967 int i;
968
969 for (i = 0; i < dev->max_nr_keys; i++)
970 b43_key_clear(dev, i);
971}
972
973void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
974{
975 u32 macctl;
976 u16 ucstat;
977 bool hwps;
978 bool awake;
979 int i;
980
981 B43_WARN_ON((ps_flags & B43_PS_ENABLED) &&
982 (ps_flags & B43_PS_DISABLED));
983 B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP));
984
985 if (ps_flags & B43_PS_ENABLED) {
986 hwps = 1;
987 } else if (ps_flags & B43_PS_DISABLED) {
988 hwps = 0;
989 } else {
990 //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
991 // and thus is not an AP and we are associated, set bit 25
992 }
993 if (ps_flags & B43_PS_AWAKE) {
994 awake = 1;
995 } else if (ps_flags & B43_PS_ASLEEP) {
996 awake = 0;
997 } else {
998 //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
999 // or we are associated, or FIXME, or the latest PS-Poll packet sent was
1000 // successful, set bit26
1001 }
1002
1003/* FIXME: For now we force awake-on and hwps-off */
1004 hwps = 0;
1005 awake = 1;
1006
1007 macctl = b43_read32(dev, B43_MMIO_MACCTL);
1008 if (hwps)
1009 macctl |= B43_MACCTL_HWPS;
1010 else
1011 macctl &= ~B43_MACCTL_HWPS;
1012 if (awake)
1013 macctl |= B43_MACCTL_AWAKE;
1014 else
1015 macctl &= ~B43_MACCTL_AWAKE;
1016 b43_write32(dev, B43_MMIO_MACCTL, macctl);
1017 /* Commit write */
1018 b43_read32(dev, B43_MMIO_MACCTL);
1019 if (awake && dev->dev->id.revision >= 5) {
1020 /* Wait for the microcode to wake up. */
1021 for (i = 0; i < 100; i++) {
1022 ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
1023 B43_SHM_SH_UCODESTAT);
1024 if (ucstat != B43_SHM_SH_UCODESTAT_SLEEP)
1025 break;
1026 udelay(10);
1027 }
1028 }
1029}
1030
1031/* Turn the Analog ON/OFF */
1032static void b43_switch_analog(struct b43_wldev *dev, int on)
1033{
Michael Buesch7b584162008-04-03 18:01:12 +02001034 switch (dev->phy.type) {
1035 case B43_PHYTYPE_A:
1036 case B43_PHYTYPE_G:
1037 b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
1038 break;
1039 case B43_PHYTYPE_N:
1040 b43_phy_write(dev, B43_NPHY_AFECTL_OVER,
1041 on ? 0 : 0x7FFF);
1042 break;
1043 default:
1044 B43_WARN_ON(1);
1045 }
Michael Buesche4d6b792007-09-18 15:39:42 -04001046}
1047
1048void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
1049{
1050 u32 tmslow;
1051 u32 macctl;
1052
1053 flags |= B43_TMSLOW_PHYCLKEN;
1054 flags |= B43_TMSLOW_PHYRESET;
1055 ssb_device_enable(dev->dev, flags);
1056 msleep(2); /* Wait for the PLL to turn on. */
1057
1058 /* Now take the PHY out of Reset again */
1059 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
1060 tmslow |= SSB_TMSLOW_FGC;
1061 tmslow &= ~B43_TMSLOW_PHYRESET;
1062 ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
1063 ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
1064 msleep(1);
1065 tmslow &= ~SSB_TMSLOW_FGC;
1066 ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
1067 ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
1068 msleep(1);
1069
1070 /* Turn Analog ON */
1071 b43_switch_analog(dev, 1);
1072
1073 macctl = b43_read32(dev, B43_MMIO_MACCTL);
1074 macctl &= ~B43_MACCTL_GMODE;
1075 if (flags & B43_TMSLOW_GMODE)
1076 macctl |= B43_MACCTL_GMODE;
1077 macctl |= B43_MACCTL_IHR_ENABLED;
1078 b43_write32(dev, B43_MMIO_MACCTL, macctl);
1079}
1080
1081static void handle_irq_transmit_status(struct b43_wldev *dev)
1082{
1083 u32 v0, v1;
1084 u16 tmp;
1085 struct b43_txstatus stat;
1086
1087 while (1) {
1088 v0 = b43_read32(dev, B43_MMIO_XMITSTAT_0);
1089 if (!(v0 & 0x00000001))
1090 break;
1091 v1 = b43_read32(dev, B43_MMIO_XMITSTAT_1);
1092
1093 stat.cookie = (v0 >> 16);
1094 stat.seq = (v1 & 0x0000FFFF);
1095 stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
1096 tmp = (v0 & 0x0000FFFF);
1097 stat.frame_count = ((tmp & 0xF000) >> 12);
1098 stat.rts_count = ((tmp & 0x0F00) >> 8);
1099 stat.supp_reason = ((tmp & 0x001C) >> 2);
1100 stat.pm_indicated = !!(tmp & 0x0080);
1101 stat.intermediate = !!(tmp & 0x0040);
1102 stat.for_ampdu = !!(tmp & 0x0020);
1103 stat.acked = !!(tmp & 0x0002);
1104
1105 b43_handle_txstatus(dev, &stat);
1106 }
1107}
1108
1109static void drain_txstatus_queue(struct b43_wldev *dev)
1110{
1111 u32 dummy;
1112
1113 if (dev->dev->id.revision < 5)
1114 return;
1115 /* Read all entries from the microcode TXstatus FIFO
1116 * and throw them away.
1117 */
1118 while (1) {
1119 dummy = b43_read32(dev, B43_MMIO_XMITSTAT_0);
1120 if (!(dummy & 0x00000001))
1121 break;
1122 dummy = b43_read32(dev, B43_MMIO_XMITSTAT_1);
1123 }
1124}
1125
1126static u32 b43_jssi_read(struct b43_wldev *dev)
1127{
1128 u32 val = 0;
1129
1130 val = b43_shm_read16(dev, B43_SHM_SHARED, 0x08A);
1131 val <<= 16;
1132 val |= b43_shm_read16(dev, B43_SHM_SHARED, 0x088);
1133
1134 return val;
1135}
1136
1137static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
1138{
1139 b43_shm_write16(dev, B43_SHM_SHARED, 0x088, (jssi & 0x0000FFFF));
1140 b43_shm_write16(dev, B43_SHM_SHARED, 0x08A, (jssi & 0xFFFF0000) >> 16);
1141}
1142
1143static void b43_generate_noise_sample(struct b43_wldev *dev)
1144{
1145 b43_jssi_write(dev, 0x7F7F7F7F);
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01001146 b43_write32(dev, B43_MMIO_MACCMD,
1147 b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE);
Michael Buesche4d6b792007-09-18 15:39:42 -04001148}
1149
1150static void b43_calculate_link_quality(struct b43_wldev *dev)
1151{
1152 /* Top half of Link Quality calculation. */
1153
1154 if (dev->noisecalc.calculation_running)
1155 return;
Michael Buesche4d6b792007-09-18 15:39:42 -04001156 dev->noisecalc.calculation_running = 1;
1157 dev->noisecalc.nr_samples = 0;
1158
1159 b43_generate_noise_sample(dev);
1160}
1161
1162static void handle_irq_noise(struct b43_wldev *dev)
1163{
1164 struct b43_phy *phy = &dev->phy;
1165 u16 tmp;
1166 u8 noise[4];
1167 u8 i, j;
1168 s32 average;
1169
1170 /* Bottom half of Link Quality calculation. */
1171
Michael Buesch98a3b2f2008-06-12 12:36:29 +02001172 /* Possible race condition: It might be possible that the user
1173 * changed to a different channel in the meantime since we
1174 * started the calculation. We ignore that fact, since it's
1175 * not really that much of a problem. The background noise is
1176 * an estimation only anyway. Slightly wrong results will get damped
1177 * by the averaging of the 8 sample rounds. Additionally the
1178 * value is shortlived. So it will be replaced by the next noise
1179 * calculation round soon. */
1180
Michael Buesche4d6b792007-09-18 15:39:42 -04001181 B43_WARN_ON(!dev->noisecalc.calculation_running);
Michael Buesch1a094042007-09-20 11:13:40 -07001182 *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev));
Michael Buesche4d6b792007-09-18 15:39:42 -04001183 if (noise[0] == 0x7F || noise[1] == 0x7F ||
1184 noise[2] == 0x7F || noise[3] == 0x7F)
1185 goto generate_new;
1186
1187 /* Get the noise samples. */
1188 B43_WARN_ON(dev->noisecalc.nr_samples >= 8);
1189 i = dev->noisecalc.nr_samples;
Harvey Harrisoncdbf0842008-05-02 13:47:48 -07001190 noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1191 noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1192 noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
1193 noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04001194 dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
1195 dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
1196 dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
1197 dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
1198 dev->noisecalc.nr_samples++;
1199 if (dev->noisecalc.nr_samples == 8) {
1200 /* Calculate the Link Quality by the noise samples. */
1201 average = 0;
1202 for (i = 0; i < 8; i++) {
1203 for (j = 0; j < 4; j++)
1204 average += dev->noisecalc.samples[i][j];
1205 }
1206 average /= (8 * 4);
1207 average *= 125;
1208 average += 64;
1209 average /= 128;
1210 tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x40C);
1211 tmp = (tmp / 128) & 0x1F;
1212 if (tmp >= 8)
1213 average += 2;
1214 else
1215 average -= 25;
1216 if (tmp == 8)
1217 average -= 72;
1218 else
1219 average -= 48;
1220
1221 dev->stats.link_noise = average;
Michael Buesche4d6b792007-09-18 15:39:42 -04001222 dev->noisecalc.calculation_running = 0;
1223 return;
1224 }
Michael Buesch98a3b2f2008-06-12 12:36:29 +02001225generate_new:
Michael Buesche4d6b792007-09-18 15:39:42 -04001226 b43_generate_noise_sample(dev);
1227}
1228
1229static void handle_irq_tbtt_indication(struct b43_wldev *dev)
1230{
1231 if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
1232 ///TODO: PS TBTT
1233 } else {
1234 if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
1235 b43_power_saving_ctl_bits(dev, 0);
1236 }
Michael Buesche4d6b792007-09-18 15:39:42 -04001237 if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01001238 dev->dfq_valid = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04001239}
1240
1241static void handle_irq_atim_end(struct b43_wldev *dev)
1242{
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01001243 if (dev->dfq_valid) {
1244 b43_write32(dev, B43_MMIO_MACCMD,
1245 b43_read32(dev, B43_MMIO_MACCMD)
1246 | B43_MACCMD_DFQ_VALID);
1247 dev->dfq_valid = 0;
1248 }
Michael Buesche4d6b792007-09-18 15:39:42 -04001249}
1250
1251static void handle_irq_pmq(struct b43_wldev *dev)
1252{
1253 u32 tmp;
1254
1255 //TODO: AP mode.
1256
1257 while (1) {
1258 tmp = b43_read32(dev, B43_MMIO_PS_STATUS);
1259 if (!(tmp & 0x00000008))
1260 break;
1261 }
1262 /* 16bit write is odd, but correct. */
1263 b43_write16(dev, B43_MMIO_PS_STATUS, 0x0002);
1264}
1265
1266static void b43_write_template_common(struct b43_wldev *dev,
1267 const u8 * data, u16 size,
1268 u16 ram_offset,
1269 u16 shm_size_offset, u8 rate)
1270{
1271 u32 i, tmp;
1272 struct b43_plcp_hdr4 plcp;
1273
1274 plcp.data = 0;
1275 b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
1276 b43_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
1277 ram_offset += sizeof(u32);
1278 /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
1279 * So leave the first two bytes of the next write blank.
1280 */
1281 tmp = (u32) (data[0]) << 16;
1282 tmp |= (u32) (data[1]) << 24;
1283 b43_ram_write(dev, ram_offset, tmp);
1284 ram_offset += sizeof(u32);
1285 for (i = 2; i < size; i += sizeof(u32)) {
1286 tmp = (u32) (data[i + 0]);
1287 if (i + 1 < size)
1288 tmp |= (u32) (data[i + 1]) << 8;
1289 if (i + 2 < size)
1290 tmp |= (u32) (data[i + 2]) << 16;
1291 if (i + 3 < size)
1292 tmp |= (u32) (data[i + 3]) << 24;
1293 b43_ram_write(dev, ram_offset + i - 2, tmp);
1294 }
1295 b43_shm_write16(dev, B43_SHM_SHARED, shm_size_offset,
1296 size + sizeof(struct b43_plcp_hdr6));
1297}
1298
Michael Buesch5042c502008-04-05 15:05:00 +02001299/* Check if the use of the antenna that ieee80211 told us to
1300 * use is possible. This will fall back to DEFAULT.
1301 * "antenna_nr" is the antenna identifier we got from ieee80211. */
1302u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
1303 u8 antenna_nr)
1304{
1305 u8 antenna_mask;
1306
1307 if (antenna_nr == 0) {
1308 /* Zero means "use default antenna". That's always OK. */
1309 return 0;
1310 }
1311
1312 /* Get the mask of available antennas. */
1313 if (dev->phy.gmode)
1314 antenna_mask = dev->dev->bus->sprom.ant_available_bg;
1315 else
1316 antenna_mask = dev->dev->bus->sprom.ant_available_a;
1317
1318 if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
1319 /* This antenna is not available. Fall back to default. */
1320 return 0;
1321 }
1322
1323 return antenna_nr;
1324}
1325
1326static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
1327{
1328 antenna = b43_ieee80211_antenna_sanitize(dev, antenna);
1329 switch (antenna) {
1330 case 0: /* default/diversity */
1331 return B43_ANTENNA_DEFAULT;
1332 case 1: /* Antenna 0 */
1333 return B43_ANTENNA0;
1334 case 2: /* Antenna 1 */
1335 return B43_ANTENNA1;
1336 case 3: /* Antenna 2 */
1337 return B43_ANTENNA2;
1338 case 4: /* Antenna 3 */
1339 return B43_ANTENNA3;
1340 default:
1341 return B43_ANTENNA_DEFAULT;
1342 }
1343}
1344
1345/* Convert a b43 antenna number value to the PHY TX control value. */
1346static u16 b43_antenna_to_phyctl(int antenna)
1347{
1348 switch (antenna) {
1349 case B43_ANTENNA0:
1350 return B43_TXH_PHY_ANT0;
1351 case B43_ANTENNA1:
1352 return B43_TXH_PHY_ANT1;
1353 case B43_ANTENNA2:
1354 return B43_TXH_PHY_ANT2;
1355 case B43_ANTENNA3:
1356 return B43_TXH_PHY_ANT3;
1357 case B43_ANTENNA_AUTO:
1358 return B43_TXH_PHY_ANT01AUTO;
1359 }
1360 B43_WARN_ON(1);
1361 return 0;
1362}
1363
Michael Buesche4d6b792007-09-18 15:39:42 -04001364static void b43_write_beacon_template(struct b43_wldev *dev,
1365 u16 ram_offset,
Michael Buesch5042c502008-04-05 15:05:00 +02001366 u16 shm_size_offset)
Michael Buesche4d6b792007-09-18 15:39:42 -04001367{
Michael Buesch47f76ca2007-12-27 22:15:11 +01001368 unsigned int i, len, variable_len;
Michael Buesche66fee62007-12-26 17:47:10 +01001369 const struct ieee80211_mgmt *bcn;
1370 const u8 *ie;
1371 bool tim_found = 0;
Michael Buesch5042c502008-04-05 15:05:00 +02001372 unsigned int rate;
1373 u16 ctl;
1374 int antenna;
Johannes Berge039fa42008-05-15 12:55:29 +02001375 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
Michael Buesche4d6b792007-09-18 15:39:42 -04001376
Michael Buesche66fee62007-12-26 17:47:10 +01001377 bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
1378 len = min((size_t) dev->wl->current_beacon->len,
Michael Buesche4d6b792007-09-18 15:39:42 -04001379 0x200 - sizeof(struct b43_plcp_hdr6));
Johannes Berge039fa42008-05-15 12:55:29 +02001380 rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
Michael Buesche66fee62007-12-26 17:47:10 +01001381
1382 b43_write_template_common(dev, (const u8 *)bcn,
Michael Buesche4d6b792007-09-18 15:39:42 -04001383 len, ram_offset, shm_size_offset, rate);
Michael Buesche66fee62007-12-26 17:47:10 +01001384
Michael Buesch5042c502008-04-05 15:05:00 +02001385 /* Write the PHY TX control parameters. */
Johannes Berge039fa42008-05-15 12:55:29 +02001386 antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx);
Michael Buesch5042c502008-04-05 15:05:00 +02001387 antenna = b43_antenna_to_phyctl(antenna);
1388 ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
1389 /* We can't send beacons with short preamble. Would get PHY errors. */
1390 ctl &= ~B43_TXH_PHY_SHORTPRMBL;
1391 ctl &= ~B43_TXH_PHY_ANT;
1392 ctl &= ~B43_TXH_PHY_ENC;
1393 ctl |= antenna;
1394 if (b43_is_cck_rate(rate))
1395 ctl |= B43_TXH_PHY_ENC_CCK;
1396 else
1397 ctl |= B43_TXH_PHY_ENC_OFDM;
1398 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);
1399
Michael Buesche66fee62007-12-26 17:47:10 +01001400 /* Find the position of the TIM and the DTIM_period value
1401 * and write them to SHM. */
1402 ie = bcn->u.beacon.variable;
Michael Buesch47f76ca2007-12-27 22:15:11 +01001403 variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
1404 for (i = 0; i < variable_len - 2; ) {
Michael Buesche66fee62007-12-26 17:47:10 +01001405 uint8_t ie_id, ie_len;
1406
1407 ie_id = ie[i];
1408 ie_len = ie[i + 1];
1409 if (ie_id == 5) {
1410 u16 tim_position;
1411 u16 dtim_period;
1412 /* This is the TIM Information Element */
1413
1414 /* Check whether the ie_len is in the beacon data range. */
Michael Buesch47f76ca2007-12-27 22:15:11 +01001415 if (variable_len < ie_len + 2 + i)
Michael Buesche66fee62007-12-26 17:47:10 +01001416 break;
1417 /* A valid TIM is at least 4 bytes long. */
1418 if (ie_len < 4)
1419 break;
1420 tim_found = 1;
1421
1422 tim_position = sizeof(struct b43_plcp_hdr6);
1423 tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable);
1424 tim_position += i;
1425
1426 dtim_period = ie[i + 3];
1427
1428 b43_shm_write16(dev, B43_SHM_SHARED,
1429 B43_SHM_SH_TIMBPOS, tim_position);
1430 b43_shm_write16(dev, B43_SHM_SHARED,
1431 B43_SHM_SH_DTIMPER, dtim_period);
1432 break;
1433 }
1434 i += ie_len + 2;
1435 }
1436 if (!tim_found) {
Johannes Berg04dea132008-05-20 12:10:49 +02001437 /*
1438 * If ucode wants to modify TIM do it behind the beacon, this
1439 * will happen, for example, when doing mesh networking.
1440 */
1441 b43_shm_write16(dev, B43_SHM_SHARED,
1442 B43_SHM_SH_TIMBPOS,
1443 len + sizeof(struct b43_plcp_hdr6));
1444 b43_shm_write16(dev, B43_SHM_SHARED,
1445 B43_SHM_SH_DTIMPER, 0);
1446 }
1447 b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
Michael Buesche4d6b792007-09-18 15:39:42 -04001448}
1449
1450static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
Johannes Berg8318d782008-01-24 19:38:38 +01001451 u16 shm_offset, u16 size,
1452 struct ieee80211_rate *rate)
Michael Buesche4d6b792007-09-18 15:39:42 -04001453{
1454 struct b43_plcp_hdr4 plcp;
1455 u32 tmp;
1456 __le16 dur;
1457
1458 plcp.data = 0;
Johannes Berg8318d782008-01-24 19:38:38 +01001459 b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
Michael Buesche4d6b792007-09-18 15:39:42 -04001460 dur = ieee80211_generic_frame_duration(dev->wl->hw,
Johannes Berg32bfd352007-12-19 01:31:26 +01001461 dev->wl->vif, size,
Johannes Berg8318d782008-01-24 19:38:38 +01001462 rate);
Michael Buesche4d6b792007-09-18 15:39:42 -04001463 /* Write PLCP in two parts and timing for packet transfer */
1464 tmp = le32_to_cpu(plcp.data);
1465 b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF);
1466 b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 2, tmp >> 16);
1467 b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 6, le16_to_cpu(dur));
1468}
1469
1470/* Instead of using custom probe response template, this function
1471 * just patches custom beacon template by:
1472 * 1) Changing packet type
1473 * 2) Patching duration field
1474 * 3) Stripping TIM
1475 */
Michael Buesche66fee62007-12-26 17:47:10 +01001476static const u8 * b43_generate_probe_resp(struct b43_wldev *dev,
Johannes Berg8318d782008-01-24 19:38:38 +01001477 u16 *dest_size,
1478 struct ieee80211_rate *rate)
Michael Buesche4d6b792007-09-18 15:39:42 -04001479{
1480 const u8 *src_data;
1481 u8 *dest_data;
1482 u16 src_size, elem_size, src_pos, dest_pos;
1483 __le16 dur;
1484 struct ieee80211_hdr *hdr;
Michael Buesche66fee62007-12-26 17:47:10 +01001485 size_t ie_start;
Michael Buesche4d6b792007-09-18 15:39:42 -04001486
Michael Buesche66fee62007-12-26 17:47:10 +01001487 src_size = dev->wl->current_beacon->len;
1488 src_data = (const u8 *)dev->wl->current_beacon->data;
Michael Buesche4d6b792007-09-18 15:39:42 -04001489
Michael Buesche66fee62007-12-26 17:47:10 +01001490 /* Get the start offset of the variable IEs in the packet. */
1491 ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
1492 B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable));
1493
1494 if (B43_WARN_ON(src_size < ie_start))
Michael Buesche4d6b792007-09-18 15:39:42 -04001495 return NULL;
Michael Buesche4d6b792007-09-18 15:39:42 -04001496
1497 dest_data = kmalloc(src_size, GFP_ATOMIC);
1498 if (unlikely(!dest_data))
1499 return NULL;
1500
Michael Buesche66fee62007-12-26 17:47:10 +01001501 /* Copy the static data and all Information Elements, except the TIM. */
1502 memcpy(dest_data, src_data, ie_start);
1503 src_pos = ie_start;
1504 dest_pos = ie_start;
1505 for ( ; src_pos < src_size - 2; src_pos += elem_size) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001506 elem_size = src_data[src_pos + 1] + 2;
Michael Buesche66fee62007-12-26 17:47:10 +01001507 if (src_data[src_pos] == 5) {
1508 /* This is the TIM. */
1509 continue;
Michael Buesche4d6b792007-09-18 15:39:42 -04001510 }
Michael Buesche66fee62007-12-26 17:47:10 +01001511 memcpy(dest_data + dest_pos, src_data + src_pos,
1512 elem_size);
1513 dest_pos += elem_size;
Michael Buesche4d6b792007-09-18 15:39:42 -04001514 }
1515 *dest_size = dest_pos;
1516 hdr = (struct ieee80211_hdr *)dest_data;
1517
1518 /* Set the frame control. */
1519 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1520 IEEE80211_STYPE_PROBE_RESP);
1521 dur = ieee80211_generic_frame_duration(dev->wl->hw,
Johannes Berg32bfd352007-12-19 01:31:26 +01001522 dev->wl->vif, *dest_size,
Johannes Berg8318d782008-01-24 19:38:38 +01001523 rate);
Michael Buesche4d6b792007-09-18 15:39:42 -04001524 hdr->duration_id = dur;
1525
1526 return dest_data;
1527}
1528
1529static void b43_write_probe_resp_template(struct b43_wldev *dev,
1530 u16 ram_offset,
Johannes Berg8318d782008-01-24 19:38:38 +01001531 u16 shm_size_offset,
1532 struct ieee80211_rate *rate)
Michael Buesche4d6b792007-09-18 15:39:42 -04001533{
Michael Buesche66fee62007-12-26 17:47:10 +01001534 const u8 *probe_resp_data;
Michael Buesche4d6b792007-09-18 15:39:42 -04001535 u16 size;
1536
Michael Buesche66fee62007-12-26 17:47:10 +01001537 size = dev->wl->current_beacon->len;
Michael Buesche4d6b792007-09-18 15:39:42 -04001538 probe_resp_data = b43_generate_probe_resp(dev, &size, rate);
1539 if (unlikely(!probe_resp_data))
1540 return;
1541
1542 /* Looks like PLCP headers plus packet timings are stored for
1543 * all possible basic rates
1544 */
Johannes Berg8318d782008-01-24 19:38:38 +01001545 b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]);
1546 b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]);
1547 b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]);
1548 b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]);
Michael Buesche4d6b792007-09-18 15:39:42 -04001549
1550 size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
1551 b43_write_template_common(dev, probe_resp_data,
Johannes Berg8318d782008-01-24 19:38:38 +01001552 size, ram_offset, shm_size_offset,
1553 rate->hw_value);
Michael Buesche4d6b792007-09-18 15:39:42 -04001554 kfree(probe_resp_data);
1555}
1556
Michael Buesch6b4bec02008-05-20 12:16:28 +02001557static void b43_upload_beacon0(struct b43_wldev *dev)
1558{
1559 struct b43_wl *wl = dev->wl;
1560
1561 if (wl->beacon0_uploaded)
1562 return;
1563 b43_write_beacon_template(dev, 0x68, 0x18);
1564 /* FIXME: Probe resp upload doesn't really belong here,
1565 * but we don't use that feature anyway. */
1566 b43_write_probe_resp_template(dev, 0x268, 0x4A,
1567 &__b43_ratetable[3]);
1568 wl->beacon0_uploaded = 1;
1569}
1570
1571static void b43_upload_beacon1(struct b43_wldev *dev)
1572{
1573 struct b43_wl *wl = dev->wl;
1574
1575 if (wl->beacon1_uploaded)
1576 return;
1577 b43_write_beacon_template(dev, 0x468, 0x1A);
1578 wl->beacon1_uploaded = 1;
1579}
1580
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001581static void handle_irq_beacon(struct b43_wldev *dev)
1582{
1583 struct b43_wl *wl = dev->wl;
1584 u32 cmd, beacon0_valid, beacon1_valid;
1585
Johannes Berg04dea132008-05-20 12:10:49 +02001586 if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) &&
1587 !b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001588 return;
1589
1590 /* This is the bottom half of the asynchronous beacon update. */
1591
1592 /* Ignore interrupt in the future. */
1593 dev->irq_savedstate &= ~B43_IRQ_BEACON;
1594
1595 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1596 beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID);
1597 beacon1_valid = (cmd & B43_MACCMD_BEACON1_VALID);
1598
1599 /* Schedule interrupt manually, if busy. */
1600 if (beacon0_valid && beacon1_valid) {
1601 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
1602 dev->irq_savedstate |= B43_IRQ_BEACON;
1603 return;
1604 }
1605
Michael Buesch6b4bec02008-05-20 12:16:28 +02001606 if (unlikely(wl->beacon_templates_virgin)) {
1607 /* We never uploaded a beacon before.
1608 * Upload both templates now, but only mark one valid. */
1609 wl->beacon_templates_virgin = 0;
1610 b43_upload_beacon0(dev);
1611 b43_upload_beacon1(dev);
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001612 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1613 cmd |= B43_MACCMD_BEACON0_VALID;
1614 b43_write32(dev, B43_MMIO_MACCMD, cmd);
Michael Buesch6b4bec02008-05-20 12:16:28 +02001615 } else {
1616 if (!beacon0_valid) {
1617 b43_upload_beacon0(dev);
1618 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1619 cmd |= B43_MACCMD_BEACON0_VALID;
1620 b43_write32(dev, B43_MMIO_MACCMD, cmd);
1621 } else if (!beacon1_valid) {
1622 b43_upload_beacon1(dev);
1623 cmd = b43_read32(dev, B43_MMIO_MACCMD);
1624 cmd |= B43_MACCMD_BEACON1_VALID;
1625 b43_write32(dev, B43_MMIO_MACCMD, cmd);
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001626 }
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001627 }
1628}
1629
Michael Buescha82d9922008-04-04 21:40:06 +02001630static void b43_beacon_update_trigger_work(struct work_struct *work)
1631{
1632 struct b43_wl *wl = container_of(work, struct b43_wl,
1633 beacon_update_trigger);
1634 struct b43_wldev *dev;
1635
1636 mutex_lock(&wl->mutex);
1637 dev = wl->current_dev;
1638 if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
Michael Buescha82d9922008-04-04 21:40:06 +02001639 spin_lock_irq(&wl->irq_lock);
Michael Bueschc97a4cc2008-04-05 15:02:09 +02001640 /* update beacon right away or defer to irq */
1641 dev->irq_savedstate = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
1642 handle_irq_beacon(dev);
1643 /* The handler might have updated the IRQ mask. */
1644 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK,
1645 dev->irq_savedstate);
1646 mmiowb();
Michael Buescha82d9922008-04-04 21:40:06 +02001647 spin_unlock_irq(&wl->irq_lock);
1648 }
1649 mutex_unlock(&wl->mutex);
1650}
1651
Michael Bueschd4df6f12007-12-26 18:04:14 +01001652/* Asynchronously update the packet templates in template RAM.
1653 * Locking: Requires wl->irq_lock to be locked. */
Johannes Berge039fa42008-05-15 12:55:29 +02001654static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
Michael Buesche4d6b792007-09-18 15:39:42 -04001655{
Michael Buesche66fee62007-12-26 17:47:10 +01001656 /* This is the top half of the ansynchronous beacon update.
1657 * The bottom half is the beacon IRQ.
1658 * Beacon update must be asynchronous to avoid sending an
1659 * invalid beacon. This can happen for example, if the firmware
1660 * transmits a beacon while we are updating it. */
Michael Buesche4d6b792007-09-18 15:39:42 -04001661
Michael Buesche66fee62007-12-26 17:47:10 +01001662 if (wl->current_beacon)
1663 dev_kfree_skb_any(wl->current_beacon);
1664 wl->current_beacon = beacon;
1665 wl->beacon0_uploaded = 0;
1666 wl->beacon1_uploaded = 0;
Michael Buescha82d9922008-04-04 21:40:06 +02001667 queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
Michael Buesche4d6b792007-09-18 15:39:42 -04001668}
1669
1670static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
1671{
1672 u32 tmp;
1673 u16 i, len;
1674
1675 len = min((u16) ssid_len, (u16) 0x100);
1676 for (i = 0; i < len; i += sizeof(u32)) {
1677 tmp = (u32) (ssid[i + 0]);
1678 if (i + 1 < len)
1679 tmp |= (u32) (ssid[i + 1]) << 8;
1680 if (i + 2 < len)
1681 tmp |= (u32) (ssid[i + 2]) << 16;
1682 if (i + 3 < len)
1683 tmp |= (u32) (ssid[i + 3]) << 24;
1684 b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp);
1685 }
1686 b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len);
1687}
1688
1689static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
1690{
1691 b43_time_lock(dev);
1692 if (dev->dev->id.revision >= 3) {
Michael Buescha82d9922008-04-04 21:40:06 +02001693 b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16));
1694 b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));
Michael Buesche4d6b792007-09-18 15:39:42 -04001695 } else {
1696 b43_write16(dev, 0x606, (beacon_int >> 6));
1697 b43_write16(dev, 0x610, beacon_int);
1698 }
1699 b43_time_unlock(dev);
Michael Buescha82d9922008-04-04 21:40:06 +02001700 b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
Michael Buesche4d6b792007-09-18 15:39:42 -04001701}
1702
Michael Bueschafa83e22008-05-19 23:51:37 +02001703static void b43_handle_firmware_panic(struct b43_wldev *dev)
1704{
1705 u16 reason;
1706
1707 /* Read the register that contains the reason code for the panic. */
1708 reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG);
1709 b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason);
1710
1711 switch (reason) {
1712 default:
1713 b43dbg(dev->wl, "The panic reason is unknown.\n");
1714 /* fallthrough */
1715 case B43_FWPANIC_DIE:
1716 /* Do not restart the controller or firmware.
1717 * The device is nonfunctional from now on.
1718 * Restarting would result in this panic to trigger again,
1719 * so we avoid that recursion. */
1720 break;
1721 case B43_FWPANIC_RESTART:
1722 b43_controller_restart(dev, "Microcode panic");
1723 break;
1724 }
1725}
1726
Michael Buesche4d6b792007-09-18 15:39:42 -04001727static void handle_irq_ucode_debug(struct b43_wldev *dev)
1728{
Michael Buesche48b0ee2008-05-17 22:44:35 +02001729 unsigned int i, cnt;
Michael Buesch53c06852008-05-20 00:24:36 +02001730 u16 reason, marker_id, marker_line;
Michael Buesche48b0ee2008-05-17 22:44:35 +02001731 __le16 *buf;
1732
1733 /* The proprietary firmware doesn't have this IRQ. */
1734 if (!dev->fw.opensource)
1735 return;
1736
Michael Bueschafa83e22008-05-19 23:51:37 +02001737 /* Read the register that contains the reason code for this IRQ. */
1738 reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG);
1739
Michael Buesche48b0ee2008-05-17 22:44:35 +02001740 switch (reason) {
1741 case B43_DEBUGIRQ_PANIC:
Michael Bueschafa83e22008-05-19 23:51:37 +02001742 b43_handle_firmware_panic(dev);
Michael Buesche48b0ee2008-05-17 22:44:35 +02001743 break;
1744 case B43_DEBUGIRQ_DUMP_SHM:
1745 if (!B43_DEBUG)
1746 break; /* Only with driver debugging enabled. */
1747 buf = kmalloc(4096, GFP_ATOMIC);
1748 if (!buf) {
1749 b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n");
1750 goto out;
1751 }
1752 for (i = 0; i < 4096; i += 2) {
1753 u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i);
1754 buf[i / 2] = cpu_to_le16(tmp);
1755 }
1756 b43info(dev->wl, "Shared memory dump:\n");
1757 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET,
1758 16, 2, buf, 4096, 1);
1759 kfree(buf);
1760 break;
1761 case B43_DEBUGIRQ_DUMP_REGS:
1762 if (!B43_DEBUG)
1763 break; /* Only with driver debugging enabled. */
1764 b43info(dev->wl, "Microcode register dump:\n");
1765 for (i = 0, cnt = 0; i < 64; i++) {
1766 u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i);
1767 if (cnt == 0)
1768 printk(KERN_INFO);
1769 printk("r%02u: 0x%04X ", i, tmp);
1770 cnt++;
1771 if (cnt == 6) {
1772 printk("\n");
1773 cnt = 0;
1774 }
1775 }
1776 printk("\n");
1777 break;
Michael Buesch53c06852008-05-20 00:24:36 +02001778 case B43_DEBUGIRQ_MARKER:
1779 if (!B43_DEBUG)
1780 break; /* Only with driver debugging enabled. */
1781 marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH,
1782 B43_MARKER_ID_REG);
1783 marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH,
1784 B43_MARKER_LINE_REG);
1785 b43info(dev->wl, "The firmware just executed the MARKER(%u) "
1786 "at line number %u\n",
1787 marker_id, marker_line);
1788 break;
Michael Buesche48b0ee2008-05-17 22:44:35 +02001789 default:
1790 b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n",
1791 reason);
1792 }
1793out:
Michael Bueschafa83e22008-05-19 23:51:37 +02001794 /* Acknowledge the debug-IRQ, so the firmware can continue. */
1795 b43_shm_write16(dev, B43_SHM_SCRATCH,
1796 B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK);
Michael Buesche4d6b792007-09-18 15:39:42 -04001797}
1798
1799/* Interrupt handler bottom-half */
1800static void b43_interrupt_tasklet(struct b43_wldev *dev)
1801{
1802 u32 reason;
1803 u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
1804 u32 merged_dma_reason = 0;
Michael Buesch21954c32007-09-27 15:31:40 +02001805 int i;
Michael Buesche4d6b792007-09-18 15:39:42 -04001806 unsigned long flags;
1807
1808 spin_lock_irqsave(&dev->wl->irq_lock, flags);
1809
1810 B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED);
1811
1812 reason = dev->irq_reason;
1813 for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
1814 dma_reason[i] = dev->dma_reason[i];
1815 merged_dma_reason |= dma_reason[i];
1816 }
1817
1818 if (unlikely(reason & B43_IRQ_MAC_TXERR))
1819 b43err(dev->wl, "MAC transmission error\n");
1820
Stefano Brivio00e0b8c2007-11-25 11:10:33 +01001821 if (unlikely(reason & B43_IRQ_PHY_TXERR)) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001822 b43err(dev->wl, "PHY transmission error\n");
Stefano Brivio00e0b8c2007-11-25 11:10:33 +01001823 rmb();
1824 if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) {
1825 atomic_set(&dev->phy.txerr_cnt,
1826 B43_PHY_TX_BADNESS_LIMIT);
1827 b43err(dev->wl, "Too many PHY TX errors, "
1828 "restarting the controller\n");
1829 b43_controller_restart(dev, "PHY TX errors");
1830 }
1831 }
Michael Buesche4d6b792007-09-18 15:39:42 -04001832
1833 if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
1834 B43_DMAIRQ_NONFATALMASK))) {
1835 if (merged_dma_reason & B43_DMAIRQ_FATALMASK) {
1836 b43err(dev->wl, "Fatal DMA error: "
1837 "0x%08X, 0x%08X, 0x%08X, "
1838 "0x%08X, 0x%08X, 0x%08X\n",
1839 dma_reason[0], dma_reason[1],
1840 dma_reason[2], dma_reason[3],
1841 dma_reason[4], dma_reason[5]);
1842 b43_controller_restart(dev, "DMA error");
1843 mmiowb();
1844 spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
1845 return;
1846 }
1847 if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
1848 b43err(dev->wl, "DMA error: "
1849 "0x%08X, 0x%08X, 0x%08X, "
1850 "0x%08X, 0x%08X, 0x%08X\n",
1851 dma_reason[0], dma_reason[1],
1852 dma_reason[2], dma_reason[3],
1853 dma_reason[4], dma_reason[5]);
1854 }
1855 }
1856
1857 if (unlikely(reason & B43_IRQ_UCODE_DEBUG))
1858 handle_irq_ucode_debug(dev);
1859 if (reason & B43_IRQ_TBTT_INDI)
1860 handle_irq_tbtt_indication(dev);
1861 if (reason & B43_IRQ_ATIM_END)
1862 handle_irq_atim_end(dev);
1863 if (reason & B43_IRQ_BEACON)
1864 handle_irq_beacon(dev);
1865 if (reason & B43_IRQ_PMQ)
1866 handle_irq_pmq(dev);
Michael Buesch21954c32007-09-27 15:31:40 +02001867 if (reason & B43_IRQ_TXFIFO_FLUSH_OK)
1868 ;/* TODO */
1869 if (reason & B43_IRQ_NOISESAMPLE_OK)
Michael Buesche4d6b792007-09-18 15:39:42 -04001870 handle_irq_noise(dev);
1871
1872 /* Check the DMA reason registers for received data. */
Michael Buesch5100d5a2008-03-29 21:01:16 +01001873 if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
1874 if (b43_using_pio_transfers(dev))
1875 b43_pio_rx(dev->pio.rx_queue);
1876 else
1877 b43_dma_rx(dev->dma.rx_ring);
1878 }
Michael Buesche4d6b792007-09-18 15:39:42 -04001879 B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
1880 B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
Michael Bueschb27faf82008-03-06 16:32:46 +01001881 B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE);
Michael Buesche4d6b792007-09-18 15:39:42 -04001882 B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
1883 B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
1884
Michael Buesch21954c32007-09-27 15:31:40 +02001885 if (reason & B43_IRQ_TX_OK)
Michael Buesche4d6b792007-09-18 15:39:42 -04001886 handle_irq_transmit_status(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04001887
Michael Buesche4d6b792007-09-18 15:39:42 -04001888 b43_interrupt_enable(dev, dev->irq_savedstate);
1889 mmiowb();
1890 spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
1891}
1892
Michael Buesche4d6b792007-09-18 15:39:42 -04001893static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason)
1894{
Michael Buesche4d6b792007-09-18 15:39:42 -04001895 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
1896
1897 b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
1898 b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]);
1899 b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
1900 b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
1901 b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
1902 b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
1903}
1904
1905/* Interrupt handler top-half */
1906static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
1907{
1908 irqreturn_t ret = IRQ_NONE;
1909 struct b43_wldev *dev = dev_id;
1910 u32 reason;
1911
1912 if (!dev)
1913 return IRQ_NONE;
1914
1915 spin_lock(&dev->wl->irq_lock);
1916
1917 if (b43_status(dev) < B43_STAT_STARTED)
1918 goto out;
1919 reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
1920 if (reason == 0xffffffff) /* shared IRQ */
1921 goto out;
1922 ret = IRQ_HANDLED;
1923 reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
1924 if (!reason)
1925 goto out;
1926
1927 dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
1928 & 0x0001DC00;
1929 dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON)
1930 & 0x0000DC00;
1931 dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON)
1932 & 0x0000DC00;
1933 dev->dma_reason[3] = b43_read32(dev, B43_MMIO_DMA3_REASON)
1934 & 0x0001DC00;
1935 dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON)
1936 & 0x0000DC00;
1937 dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON)
1938 & 0x0000DC00;
1939
1940 b43_interrupt_ack(dev, reason);
1941 /* disable all IRQs. They are enabled again in the bottom half. */
1942 dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
1943 /* save the reason code and call our bottom half. */
1944 dev->irq_reason = reason;
1945 tasklet_schedule(&dev->isr_tasklet);
1946 out:
1947 mmiowb();
1948 spin_unlock(&dev->wl->irq_lock);
1949
1950 return ret;
1951}
1952
Michael Buesch61cb5dd2008-01-21 19:55:09 +01001953static void do_release_fw(struct b43_firmware_file *fw)
1954{
1955 release_firmware(fw->data);
1956 fw->data = NULL;
1957 fw->filename = NULL;
1958}
1959
Michael Buesche4d6b792007-09-18 15:39:42 -04001960static void b43_release_firmware(struct b43_wldev *dev)
1961{
Michael Buesch61cb5dd2008-01-21 19:55:09 +01001962 do_release_fw(&dev->fw.ucode);
1963 do_release_fw(&dev->fw.pcm);
1964 do_release_fw(&dev->fw.initvals);
1965 do_release_fw(&dev->fw.initvals_band);
Michael Buesche4d6b792007-09-18 15:39:42 -04001966}
1967
Michael Buescheb189d8b2008-01-28 14:47:41 -08001968static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
Michael Buesche4d6b792007-09-18 15:39:42 -04001969{
Michael Buescheb189d8b2008-01-28 14:47:41 -08001970 const char *text;
1971
1972 text = "You must go to "
Stefano Brivio354807e2007-11-19 20:21:31 +01001973 "http://linuxwireless.org/en/users/Drivers/b43#devicefirmware "
Michael Buescheb189d8b2008-01-28 14:47:41 -08001974 "and download the latest firmware (version 4).\n";
1975 if (error)
1976 b43err(wl, text);
1977 else
1978 b43warn(wl, text);
Michael Buesche4d6b792007-09-18 15:39:42 -04001979}
1980
1981static int do_request_fw(struct b43_wldev *dev,
1982 const char *name,
Michael Buesch68217832008-05-17 23:43:57 +02001983 struct b43_firmware_file *fw,
1984 bool silent)
Michael Buesche4d6b792007-09-18 15:39:42 -04001985{
Michael Buesch1a094042007-09-20 11:13:40 -07001986 char path[sizeof(modparam_fwpostfix) + 32];
Michael Buesch61cb5dd2008-01-21 19:55:09 +01001987 const struct firmware *blob;
Michael Buesche4d6b792007-09-18 15:39:42 -04001988 struct b43_fw_header *hdr;
1989 u32 size;
1990 int err;
1991
Michael Buesch61cb5dd2008-01-21 19:55:09 +01001992 if (!name) {
1993 /* Don't fetch anything. Free possibly cached firmware. */
1994 do_release_fw(fw);
Michael Buesche4d6b792007-09-18 15:39:42 -04001995 return 0;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01001996 }
1997 if (fw->filename) {
1998 if (strcmp(fw->filename, name) == 0)
1999 return 0; /* Already have this fw. */
2000 /* Free the cached firmware first. */
2001 do_release_fw(fw);
2002 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002003
2004 snprintf(path, ARRAY_SIZE(path),
2005 "b43%s/%s.fw",
2006 modparam_fwpostfix, name);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002007 err = request_firmware(&blob, path, dev->dev->dev);
Michael Buesch68217832008-05-17 23:43:57 +02002008 if (err == -ENOENT) {
2009 if (!silent) {
2010 b43err(dev->wl, "Firmware file \"%s\" not found\n",
2011 path);
2012 }
2013 return err;
2014 } else if (err) {
2015 b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n",
2016 path, err);
Michael Buesche4d6b792007-09-18 15:39:42 -04002017 return err;
2018 }
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002019 if (blob->size < sizeof(struct b43_fw_header))
Michael Buesche4d6b792007-09-18 15:39:42 -04002020 goto err_format;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002021 hdr = (struct b43_fw_header *)(blob->data);
Michael Buesche4d6b792007-09-18 15:39:42 -04002022 switch (hdr->type) {
2023 case B43_FW_TYPE_UCODE:
2024 case B43_FW_TYPE_PCM:
2025 size = be32_to_cpu(hdr->size);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002026 if (size != blob->size - sizeof(struct b43_fw_header))
Michael Buesche4d6b792007-09-18 15:39:42 -04002027 goto err_format;
2028 /* fallthrough */
2029 case B43_FW_TYPE_IV:
2030 if (hdr->ver != 1)
2031 goto err_format;
2032 break;
2033 default:
2034 goto err_format;
2035 }
2036
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002037 fw->data = blob;
2038 fw->filename = name;
2039
2040 return 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04002041
2042err_format:
2043 b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002044 release_firmware(blob);
2045
Michael Buesche4d6b792007-09-18 15:39:42 -04002046 return -EPROTO;
2047}
2048
2049static int b43_request_firmware(struct b43_wldev *dev)
2050{
2051 struct b43_firmware *fw = &dev->fw;
2052 const u8 rev = dev->dev->id.revision;
2053 const char *filename;
2054 u32 tmshigh;
2055 int err;
2056
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002057 /* Get microcode */
Michael Buesche4d6b792007-09-18 15:39:42 -04002058 tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002059 if ((rev >= 5) && (rev <= 10))
2060 filename = "ucode5";
2061 else if ((rev >= 11) && (rev <= 12))
2062 filename = "ucode11";
2063 else if (rev >= 13)
2064 filename = "ucode13";
2065 else
2066 goto err_no_ucode;
Michael Buesch68217832008-05-17 23:43:57 +02002067 err = do_request_fw(dev, filename, &fw->ucode, 0);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002068 if (err)
2069 goto err_load;
2070
2071 /* Get PCM code */
2072 if ((rev >= 5) && (rev <= 10))
2073 filename = "pcm5";
2074 else if (rev >= 11)
2075 filename = NULL;
2076 else
2077 goto err_no_pcm;
Michael Buesch68217832008-05-17 23:43:57 +02002078 fw->pcm_request_failed = 0;
2079 err = do_request_fw(dev, filename, &fw->pcm, 1);
2080 if (err == -ENOENT) {
2081 /* We did not find a PCM file? Not fatal, but
2082 * core rev <= 10 must do without hwcrypto then. */
2083 fw->pcm_request_failed = 1;
2084 } else if (err)
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002085 goto err_load;
2086
2087 /* Get initvals */
2088 switch (dev->phy.type) {
2089 case B43_PHYTYPE_A:
2090 if ((rev >= 5) && (rev <= 10)) {
2091 if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
2092 filename = "a0g1initvals5";
2093 else
2094 filename = "a0g0initvals5";
2095 } else
2096 goto err_no_initvals;
2097 break;
2098 case B43_PHYTYPE_G:
Michael Buesche4d6b792007-09-18 15:39:42 -04002099 if ((rev >= 5) && (rev <= 10))
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002100 filename = "b0g0initvals5";
Michael Buesche4d6b792007-09-18 15:39:42 -04002101 else if (rev >= 13)
Larry.Finger@lwfinger.nete9304882008-05-15 14:07:36 -05002102 filename = "b0g0initvals13";
Michael Buesche4d6b792007-09-18 15:39:42 -04002103 else
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002104 goto err_no_initvals;
2105 break;
2106 case B43_PHYTYPE_N:
2107 if ((rev >= 11) && (rev <= 12))
2108 filename = "n0initvals11";
2109 else
2110 goto err_no_initvals;
2111 break;
2112 default:
2113 goto err_no_initvals;
Michael Buesche4d6b792007-09-18 15:39:42 -04002114 }
Michael Buesch68217832008-05-17 23:43:57 +02002115 err = do_request_fw(dev, filename, &fw->initvals, 0);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002116 if (err)
2117 goto err_load;
2118
2119 /* Get bandswitch initvals */
2120 switch (dev->phy.type) {
2121 case B43_PHYTYPE_A:
2122 if ((rev >= 5) && (rev <= 10)) {
2123 if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
2124 filename = "a0g1bsinitvals5";
2125 else
2126 filename = "a0g0bsinitvals5";
2127 } else if (rev >= 11)
2128 filename = NULL;
2129 else
2130 goto err_no_initvals;
2131 break;
2132 case B43_PHYTYPE_G:
Michael Buesche4d6b792007-09-18 15:39:42 -04002133 if ((rev >= 5) && (rev <= 10))
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002134 filename = "b0g0bsinitvals5";
Michael Buesche4d6b792007-09-18 15:39:42 -04002135 else if (rev >= 11)
2136 filename = NULL;
2137 else
Michael Buesche4d6b792007-09-18 15:39:42 -04002138 goto err_no_initvals;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002139 break;
2140 case B43_PHYTYPE_N:
2141 if ((rev >= 11) && (rev <= 12))
2142 filename = "n0bsinitvals11";
2143 else
Michael Buesche4d6b792007-09-18 15:39:42 -04002144 goto err_no_initvals;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002145 break;
2146 default:
2147 goto err_no_initvals;
Michael Buesche4d6b792007-09-18 15:39:42 -04002148 }
Michael Buesch68217832008-05-17 23:43:57 +02002149 err = do_request_fw(dev, filename, &fw->initvals_band, 0);
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002150 if (err)
2151 goto err_load;
Michael Buesche4d6b792007-09-18 15:39:42 -04002152
2153 return 0;
2154
2155err_load:
Michael Buescheb189d8b2008-01-28 14:47:41 -08002156 b43_print_fw_helptext(dev->wl, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002157 goto error;
2158
2159err_no_ucode:
2160 err = -ENODEV;
2161 b43err(dev->wl, "No microcode available for core rev %u\n", rev);
2162 goto error;
2163
2164err_no_pcm:
2165 err = -ENODEV;
2166 b43err(dev->wl, "No PCM available for core rev %u\n", rev);
2167 goto error;
2168
2169err_no_initvals:
2170 err = -ENODEV;
2171 b43err(dev->wl, "No Initial Values firmware file for PHY %u, "
2172 "core rev %u\n", dev->phy.type, rev);
2173 goto error;
2174
2175error:
2176 b43_release_firmware(dev);
2177 return err;
2178}
2179
2180static int b43_upload_microcode(struct b43_wldev *dev)
2181{
2182 const size_t hdr_len = sizeof(struct b43_fw_header);
2183 const __be32 *data;
2184 unsigned int i, len;
2185 u16 fwrev, fwpatch, fwdate, fwtime;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002186 u32 tmp, macctl;
Michael Buesche4d6b792007-09-18 15:39:42 -04002187 int err = 0;
2188
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002189 /* Jump the microcode PSM to offset 0 */
2190 macctl = b43_read32(dev, B43_MMIO_MACCTL);
2191 B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN);
2192 macctl |= B43_MACCTL_PSM_JMP0;
2193 b43_write32(dev, B43_MMIO_MACCTL, macctl);
2194 /* Zero out all microcode PSM registers and shared memory. */
2195 for (i = 0; i < 64; i++)
2196 b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0);
2197 for (i = 0; i < 4096; i += 2)
2198 b43_shm_write16(dev, B43_SHM_SHARED, i, 0);
2199
Michael Buesche4d6b792007-09-18 15:39:42 -04002200 /* Upload Microcode. */
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002201 data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
2202 len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
Michael Buesche4d6b792007-09-18 15:39:42 -04002203 b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
2204 for (i = 0; i < len; i++) {
2205 b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
2206 udelay(10);
2207 }
2208
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002209 if (dev->fw.pcm.data) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002210 /* Upload PCM data. */
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002211 data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
2212 len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
Michael Buesche4d6b792007-09-18 15:39:42 -04002213 b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
2214 b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
2215 /* No need for autoinc bit in SHM_HW */
2216 b43_shm_control_word(dev, B43_SHM_HW, 0x01EB);
2217 for (i = 0; i < len; i++) {
2218 b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
2219 udelay(10);
2220 }
2221 }
2222
2223 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002224
2225 /* Start the microcode PSM */
2226 macctl = b43_read32(dev, B43_MMIO_MACCTL);
2227 macctl &= ~B43_MACCTL_PSM_JMP0;
2228 macctl |= B43_MACCTL_PSM_RUN;
2229 b43_write32(dev, B43_MMIO_MACCTL, macctl);
Michael Buesche4d6b792007-09-18 15:39:42 -04002230
2231 /* Wait for the microcode to load and respond */
2232 i = 0;
2233 while (1) {
2234 tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2235 if (tmp == B43_IRQ_MAC_SUSPENDED)
2236 break;
2237 i++;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002238 if (i >= 20) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002239 b43err(dev->wl, "Microcode not responding\n");
Michael Buescheb189d8b2008-01-28 14:47:41 -08002240 b43_print_fw_helptext(dev->wl, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002241 err = -ENODEV;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002242 goto error;
Michael Buesche4d6b792007-09-18 15:39:42 -04002243 }
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002244 msleep_interruptible(50);
2245 if (signal_pending(current)) {
2246 err = -EINTR;
2247 goto error;
2248 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002249 }
2250 b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */
2251
2252 /* Get and check the revisions. */
2253 fwrev = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEREV);
2254 fwpatch = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEPATCH);
2255 fwdate = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEDATE);
2256 fwtime = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODETIME);
2257
2258 if (fwrev <= 0x128) {
2259 b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
2260 "binary drivers older than version 4.x is unsupported. "
2261 "You must upgrade your firmware files.\n");
Michael Buescheb189d8b2008-01-28 14:47:41 -08002262 b43_print_fw_helptext(dev->wl, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002263 err = -EOPNOTSUPP;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002264 goto error;
Michael Buesche4d6b792007-09-18 15:39:42 -04002265 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002266 dev->fw.rev = fwrev;
2267 dev->fw.patch = fwpatch;
Michael Buesche48b0ee2008-05-17 22:44:35 +02002268 dev->fw.opensource = (fwdate == 0xFFFF);
2269
2270 if (dev->fw.opensource) {
2271 /* Patchlevel info is encoded in the "time" field. */
2272 dev->fw.patch = fwtime;
Michael Buesch68217832008-05-17 23:43:57 +02002273 b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n",
2274 dev->fw.rev, dev->fw.patch,
2275 dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : "");
Michael Buesche48b0ee2008-05-17 22:44:35 +02002276 } else {
2277 b43info(dev->wl, "Loading firmware version %u.%u "
2278 "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
2279 fwrev, fwpatch,
2280 (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
2281 (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
Michael Buesch68217832008-05-17 23:43:57 +02002282 if (dev->fw.pcm_request_failed) {
2283 b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. "
2284 "Hardware accelerated cryptography is disabled.\n");
2285 b43_print_fw_helptext(dev->wl, 0);
2286 }
Michael Buesche48b0ee2008-05-17 22:44:35 +02002287 }
Michael Buesche4d6b792007-09-18 15:39:42 -04002288
Michael Buescheb189d8b2008-01-28 14:47:41 -08002289 if (b43_is_old_txhdr_format(dev)) {
2290 b43warn(dev->wl, "You are using an old firmware image. "
2291 "Support for old firmware will be removed in July 2008.\n");
2292 b43_print_fw_helptext(dev->wl, 0);
2293 }
2294
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002295 return 0;
2296
2297error:
2298 macctl = b43_read32(dev, B43_MMIO_MACCTL);
2299 macctl &= ~B43_MACCTL_PSM_RUN;
2300 macctl |= B43_MACCTL_PSM_JMP0;
2301 b43_write32(dev, B43_MMIO_MACCTL, macctl);
2302
Michael Buesche4d6b792007-09-18 15:39:42 -04002303 return err;
2304}
2305
2306static int b43_write_initvals(struct b43_wldev *dev,
2307 const struct b43_iv *ivals,
2308 size_t count,
2309 size_t array_size)
2310{
2311 const struct b43_iv *iv;
2312 u16 offset;
2313 size_t i;
2314 bool bit32;
2315
2316 BUILD_BUG_ON(sizeof(struct b43_iv) != 6);
2317 iv = ivals;
2318 for (i = 0; i < count; i++) {
2319 if (array_size < sizeof(iv->offset_size))
2320 goto err_format;
2321 array_size -= sizeof(iv->offset_size);
2322 offset = be16_to_cpu(iv->offset_size);
2323 bit32 = !!(offset & B43_IV_32BIT);
2324 offset &= B43_IV_OFFSET_MASK;
2325 if (offset >= 0x1000)
2326 goto err_format;
2327 if (bit32) {
2328 u32 value;
2329
2330 if (array_size < sizeof(iv->data.d32))
2331 goto err_format;
2332 array_size -= sizeof(iv->data.d32);
2333
Harvey Harrison533dd1b2008-04-29 01:03:36 -07002334 value = get_unaligned_be32(&iv->data.d32);
Michael Buesche4d6b792007-09-18 15:39:42 -04002335 b43_write32(dev, offset, value);
2336
2337 iv = (const struct b43_iv *)((const uint8_t *)iv +
2338 sizeof(__be16) +
2339 sizeof(__be32));
2340 } else {
2341 u16 value;
2342
2343 if (array_size < sizeof(iv->data.d16))
2344 goto err_format;
2345 array_size -= sizeof(iv->data.d16);
2346
2347 value = be16_to_cpu(iv->data.d16);
2348 b43_write16(dev, offset, value);
2349
2350 iv = (const struct b43_iv *)((const uint8_t *)iv +
2351 sizeof(__be16) +
2352 sizeof(__be16));
2353 }
2354 }
2355 if (array_size)
2356 goto err_format;
2357
2358 return 0;
2359
2360err_format:
2361 b43err(dev->wl, "Initial Values Firmware file-format error.\n");
Michael Buescheb189d8b2008-01-28 14:47:41 -08002362 b43_print_fw_helptext(dev->wl, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002363
2364 return -EPROTO;
2365}
2366
2367static int b43_upload_initvals(struct b43_wldev *dev)
2368{
2369 const size_t hdr_len = sizeof(struct b43_fw_header);
2370 const struct b43_fw_header *hdr;
2371 struct b43_firmware *fw = &dev->fw;
2372 const struct b43_iv *ivals;
2373 size_t count;
2374 int err;
2375
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002376 hdr = (const struct b43_fw_header *)(fw->initvals.data->data);
2377 ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002378 count = be32_to_cpu(hdr->size);
2379 err = b43_write_initvals(dev, ivals, count,
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002380 fw->initvals.data->size - hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002381 if (err)
2382 goto out;
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002383 if (fw->initvals_band.data) {
2384 hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data);
2385 ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002386 count = be32_to_cpu(hdr->size);
2387 err = b43_write_initvals(dev, ivals, count,
Michael Buesch61cb5dd2008-01-21 19:55:09 +01002388 fw->initvals_band.data->size - hdr_len);
Michael Buesche4d6b792007-09-18 15:39:42 -04002389 if (err)
2390 goto out;
2391 }
2392out:
2393
2394 return err;
2395}
2396
2397/* Initialize the GPIOs
2398 * http://bcm-specs.sipsolutions.net/GPIO
2399 */
2400static int b43_gpio_init(struct b43_wldev *dev)
2401{
2402 struct ssb_bus *bus = dev->dev->bus;
2403 struct ssb_device *gpiodev, *pcidev = NULL;
2404 u32 mask, set;
2405
2406 b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
2407 & ~B43_MACCTL_GPOUTSMSK);
2408
Michael Buesche4d6b792007-09-18 15:39:42 -04002409 b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK)
2410 | 0x000F);
2411
2412 mask = 0x0000001F;
2413 set = 0x0000000F;
2414 if (dev->dev->bus->chip_id == 0x4301) {
2415 mask |= 0x0060;
2416 set |= 0x0060;
2417 }
2418 if (0 /* FIXME: conditional unknown */ ) {
2419 b43_write16(dev, B43_MMIO_GPIO_MASK,
2420 b43_read16(dev, B43_MMIO_GPIO_MASK)
2421 | 0x0100);
2422 mask |= 0x0180;
2423 set |= 0x0180;
2424 }
Larry Finger95de2842007-11-09 16:57:18 -06002425 if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002426 b43_write16(dev, B43_MMIO_GPIO_MASK,
2427 b43_read16(dev, B43_MMIO_GPIO_MASK)
2428 | 0x0200);
2429 mask |= 0x0200;
2430 set |= 0x0200;
2431 }
2432 if (dev->dev->id.revision >= 2)
2433 mask |= 0x0010; /* FIXME: This is redundant. */
2434
2435#ifdef CONFIG_SSB_DRIVER_PCICORE
2436 pcidev = bus->pcicore.dev;
2437#endif
2438 gpiodev = bus->chipco.dev ? : pcidev;
2439 if (!gpiodev)
2440 return 0;
2441 ssb_write32(gpiodev, B43_GPIO_CONTROL,
2442 (ssb_read32(gpiodev, B43_GPIO_CONTROL)
2443 & mask) | set);
2444
2445 return 0;
2446}
2447
2448/* Turn off all GPIO stuff. Call this on module unload, for example. */
2449static void b43_gpio_cleanup(struct b43_wldev *dev)
2450{
2451 struct ssb_bus *bus = dev->dev->bus;
2452 struct ssb_device *gpiodev, *pcidev = NULL;
2453
2454#ifdef CONFIG_SSB_DRIVER_PCICORE
2455 pcidev = bus->pcicore.dev;
2456#endif
2457 gpiodev = bus->chipco.dev ? : pcidev;
2458 if (!gpiodev)
2459 return;
2460 ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
2461}
2462
2463/* http://bcm-specs.sipsolutions.net/EnableMac */
Michael Bueschf5eda472008-04-20 16:03:32 +02002464void b43_mac_enable(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04002465{
2466 dev->mac_suspended--;
2467 B43_WARN_ON(dev->mac_suspended < 0);
2468 if (dev->mac_suspended == 0) {
2469 b43_write32(dev, B43_MMIO_MACCTL,
2470 b43_read32(dev, B43_MMIO_MACCTL)
2471 | B43_MACCTL_ENABLED);
2472 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON,
2473 B43_IRQ_MAC_SUSPENDED);
2474 /* Commit writes */
2475 b43_read32(dev, B43_MMIO_MACCTL);
2476 b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2477 b43_power_saving_ctl_bits(dev, 0);
2478 }
2479}
2480
2481/* http://bcm-specs.sipsolutions.net/SuspendMAC */
Michael Bueschf5eda472008-04-20 16:03:32 +02002482void b43_mac_suspend(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -04002483{
2484 int i;
2485 u32 tmp;
2486
Michael Buesch05b64b32007-09-28 16:19:03 +02002487 might_sleep();
Michael Buesche4d6b792007-09-18 15:39:42 -04002488 B43_WARN_ON(dev->mac_suspended < 0);
Michael Buesch05b64b32007-09-28 16:19:03 +02002489
Michael Buesche4d6b792007-09-18 15:39:42 -04002490 if (dev->mac_suspended == 0) {
2491 b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
2492 b43_write32(dev, B43_MMIO_MACCTL,
2493 b43_read32(dev, B43_MMIO_MACCTL)
2494 & ~B43_MACCTL_ENABLED);
2495 /* force pci to flush the write */
2496 b43_read32(dev, B43_MMIO_MACCTL);
Michael Bueschba380012008-04-15 21:13:36 +02002497 for (i = 35; i; i--) {
2498 tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2499 if (tmp & B43_IRQ_MAC_SUSPENDED)
2500 goto out;
2501 udelay(10);
2502 }
2503 /* Hm, it seems this will take some time. Use msleep(). */
Michael Buesch05b64b32007-09-28 16:19:03 +02002504 for (i = 40; i; i--) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002505 tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
2506 if (tmp & B43_IRQ_MAC_SUSPENDED)
2507 goto out;
Michael Buesch05b64b32007-09-28 16:19:03 +02002508 msleep(1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002509 }
2510 b43err(dev->wl, "MAC suspend failed\n");
2511 }
Michael Buesch05b64b32007-09-28 16:19:03 +02002512out:
Michael Buesche4d6b792007-09-18 15:39:42 -04002513 dev->mac_suspended++;
2514}
2515
2516static void b43_adjust_opmode(struct b43_wldev *dev)
2517{
2518 struct b43_wl *wl = dev->wl;
2519 u32 ctl;
2520 u16 cfp_pretbtt;
2521
2522 ctl = b43_read32(dev, B43_MMIO_MACCTL);
2523 /* Reset status to STA infrastructure mode. */
2524 ctl &= ~B43_MACCTL_AP;
2525 ctl &= ~B43_MACCTL_KEEP_CTL;
2526 ctl &= ~B43_MACCTL_KEEP_BADPLCP;
2527 ctl &= ~B43_MACCTL_KEEP_BAD;
2528 ctl &= ~B43_MACCTL_PROMISC;
Johannes Berg4150c572007-09-17 01:29:23 -04002529 ctl &= ~B43_MACCTL_BEACPROMISC;
Michael Buesche4d6b792007-09-18 15:39:42 -04002530 ctl |= B43_MACCTL_INFRA;
2531
Johannes Berg04dea132008-05-20 12:10:49 +02002532 if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
2533 b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
Johannes Berg4150c572007-09-17 01:29:23 -04002534 ctl |= B43_MACCTL_AP;
2535 else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
2536 ctl &= ~B43_MACCTL_INFRA;
2537
2538 if (wl->filter_flags & FIF_CONTROL)
Michael Buesche4d6b792007-09-18 15:39:42 -04002539 ctl |= B43_MACCTL_KEEP_CTL;
Johannes Berg4150c572007-09-17 01:29:23 -04002540 if (wl->filter_flags & FIF_FCSFAIL)
2541 ctl |= B43_MACCTL_KEEP_BAD;
2542 if (wl->filter_flags & FIF_PLCPFAIL)
2543 ctl |= B43_MACCTL_KEEP_BADPLCP;
2544 if (wl->filter_flags & FIF_PROMISC_IN_BSS)
Michael Buesche4d6b792007-09-18 15:39:42 -04002545 ctl |= B43_MACCTL_PROMISC;
Johannes Berg4150c572007-09-17 01:29:23 -04002546 if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
2547 ctl |= B43_MACCTL_BEACPROMISC;
2548
Michael Buesche4d6b792007-09-18 15:39:42 -04002549 /* Workaround: On old hardware the HW-MAC-address-filter
2550 * doesn't work properly, so always run promisc in filter
2551 * it in software. */
2552 if (dev->dev->id.revision <= 4)
2553 ctl |= B43_MACCTL_PROMISC;
2554
2555 b43_write32(dev, B43_MMIO_MACCTL, ctl);
2556
2557 cfp_pretbtt = 2;
2558 if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
2559 if (dev->dev->bus->chip_id == 0x4306 &&
2560 dev->dev->bus->chip_rev == 3)
2561 cfp_pretbtt = 100;
2562 else
2563 cfp_pretbtt = 50;
2564 }
2565 b43_write16(dev, 0x612, cfp_pretbtt);
2566}
2567
2568static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm)
2569{
2570 u16 offset;
2571
2572 if (is_ofdm) {
2573 offset = 0x480;
2574 offset += (b43_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
2575 } else {
2576 offset = 0x4C0;
2577 offset += (b43_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
2578 }
2579 b43_shm_write16(dev, B43_SHM_SHARED, offset + 0x20,
2580 b43_shm_read16(dev, B43_SHM_SHARED, offset));
2581}
2582
2583static void b43_rate_memory_init(struct b43_wldev *dev)
2584{
2585 switch (dev->phy.type) {
2586 case B43_PHYTYPE_A:
2587 case B43_PHYTYPE_G:
Michael Buesch53a6e232008-01-13 21:23:44 +01002588 case B43_PHYTYPE_N:
Michael Buesche4d6b792007-09-18 15:39:42 -04002589 b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
2590 b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
2591 b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
2592 b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1);
2593 b43_rate_memory_write(dev, B43_OFDM_RATE_36MB, 1);
2594 b43_rate_memory_write(dev, B43_OFDM_RATE_48MB, 1);
2595 b43_rate_memory_write(dev, B43_OFDM_RATE_54MB, 1);
2596 if (dev->phy.type == B43_PHYTYPE_A)
2597 break;
2598 /* fallthrough */
2599 case B43_PHYTYPE_B:
2600 b43_rate_memory_write(dev, B43_CCK_RATE_1MB, 0);
2601 b43_rate_memory_write(dev, B43_CCK_RATE_2MB, 0);
2602 b43_rate_memory_write(dev, B43_CCK_RATE_5MB, 0);
2603 b43_rate_memory_write(dev, B43_CCK_RATE_11MB, 0);
2604 break;
2605 default:
2606 B43_WARN_ON(1);
2607 }
2608}
2609
Michael Buesch5042c502008-04-05 15:05:00 +02002610/* Set the default values for the PHY TX Control Words. */
2611static void b43_set_phytxctl_defaults(struct b43_wldev *dev)
2612{
2613 u16 ctl = 0;
2614
2615 ctl |= B43_TXH_PHY_ENC_CCK;
2616 ctl |= B43_TXH_PHY_ANT01AUTO;
2617 ctl |= B43_TXH_PHY_TXPWR;
2618
2619 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);
2620 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, ctl);
2621 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, ctl);
2622}
2623
Michael Buesche4d6b792007-09-18 15:39:42 -04002624/* Set the TX-Antenna for management frames sent by firmware. */
2625static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
2626{
Michael Buesch5042c502008-04-05 15:05:00 +02002627 u16 ant;
Michael Buesche4d6b792007-09-18 15:39:42 -04002628 u16 tmp;
2629
Michael Buesch5042c502008-04-05 15:05:00 +02002630 ant = b43_antenna_to_phyctl(antenna);
Michael Buesche4d6b792007-09-18 15:39:42 -04002631
Michael Buesche4d6b792007-09-18 15:39:42 -04002632 /* For ACK/CTS */
2633 tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
Michael Buescheb189d8b2008-01-28 14:47:41 -08002634 tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
Michael Buesche4d6b792007-09-18 15:39:42 -04002635 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
2636 /* For Probe Resposes */
2637 tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
Michael Buescheb189d8b2008-01-28 14:47:41 -08002638 tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
Michael Buesche4d6b792007-09-18 15:39:42 -04002639 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
2640}
2641
2642/* This is the opposite of b43_chip_init() */
2643static void b43_chip_exit(struct b43_wldev *dev)
2644{
Michael Buesch8e9f7522007-09-27 21:35:34 +02002645 b43_radio_turn_off(dev, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002646 b43_gpio_cleanup(dev);
Michael Bueschf5eda472008-04-20 16:03:32 +02002647 b43_lo_g_cleanup(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002648 /* firmware is released later */
2649}
2650
2651/* Initialize the chip
2652 * http://bcm-specs.sipsolutions.net/ChipInit
2653 */
2654static int b43_chip_init(struct b43_wldev *dev)
2655{
2656 struct b43_phy *phy = &dev->phy;
2657 int err, tmp;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002658 u32 value32, macctl;
Michael Buesche4d6b792007-09-18 15:39:42 -04002659 u16 value16;
2660
Michael Buesch1f7d87b2008-01-22 20:23:34 +01002661 /* Initialize the MAC control */
2662 macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED;
2663 if (dev->phy.gmode)
2664 macctl |= B43_MACCTL_GMODE;
2665 macctl |= B43_MACCTL_INFRA;
2666 b43_write32(dev, B43_MMIO_MACCTL, macctl);
Michael Buesche4d6b792007-09-18 15:39:42 -04002667
2668 err = b43_request_firmware(dev);
2669 if (err)
2670 goto out;
2671 err = b43_upload_microcode(dev);
2672 if (err)
2673 goto out; /* firmware is released later */
2674
2675 err = b43_gpio_init(dev);
2676 if (err)
2677 goto out; /* firmware is released later */
Michael Buesch21954c32007-09-27 15:31:40 +02002678
Michael Buesche4d6b792007-09-18 15:39:42 -04002679 err = b43_upload_initvals(dev);
2680 if (err)
Larry Finger1a8d1222007-12-14 13:59:11 +01002681 goto err_gpio_clean;
Michael Buesche4d6b792007-09-18 15:39:42 -04002682 b43_radio_turn_on(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002683
2684 b43_write16(dev, 0x03E6, 0x0000);
2685 err = b43_phy_init(dev);
2686 if (err)
2687 goto err_radio_off;
2688
2689 /* Select initial Interference Mitigation. */
2690 tmp = phy->interfmode;
2691 phy->interfmode = B43_INTERFMODE_NONE;
2692 b43_radio_set_interference_mitigation(dev, tmp);
2693
2694 b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
2695 b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
2696
2697 if (phy->type == B43_PHYTYPE_B) {
2698 value16 = b43_read16(dev, 0x005E);
2699 value16 |= 0x0004;
2700 b43_write16(dev, 0x005E, value16);
2701 }
2702 b43_write32(dev, 0x0100, 0x01000000);
2703 if (dev->dev->id.revision < 5)
2704 b43_write32(dev, 0x010C, 0x01000000);
2705
2706 b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
2707 & ~B43_MACCTL_INFRA);
2708 b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
2709 | B43_MACCTL_INFRA);
Michael Buesche4d6b792007-09-18 15:39:42 -04002710
Michael Buesche4d6b792007-09-18 15:39:42 -04002711 /* Probe Response Timeout value */
2712 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2713 b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
2714
2715 /* Initially set the wireless operation mode. */
2716 b43_adjust_opmode(dev);
2717
2718 if (dev->dev->id.revision < 3) {
2719 b43_write16(dev, 0x060E, 0x0000);
2720 b43_write16(dev, 0x0610, 0x8000);
2721 b43_write16(dev, 0x0604, 0x0000);
2722 b43_write16(dev, 0x0606, 0x0200);
2723 } else {
2724 b43_write32(dev, 0x0188, 0x80000000);
2725 b43_write32(dev, 0x018C, 0x02000000);
2726 }
2727 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, 0x00004000);
2728 b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
2729 b43_write32(dev, B43_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
2730 b43_write32(dev, B43_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2731 b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
2732 b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
2733 b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
2734
2735 value32 = ssb_read32(dev->dev, SSB_TMSLOW);
2736 value32 |= 0x00100000;
2737 ssb_write32(dev->dev, SSB_TMSLOW, value32);
2738
2739 b43_write16(dev, B43_MMIO_POWERUP_DELAY,
2740 dev->dev->bus->chipco.fast_pwrup_delay);
2741
2742 err = 0;
2743 b43dbg(dev->wl, "Chip initialized\n");
Michael Buesch21954c32007-09-27 15:31:40 +02002744out:
Michael Buesche4d6b792007-09-18 15:39:42 -04002745 return err;
2746
Michael Buesch21954c32007-09-27 15:31:40 +02002747err_radio_off:
Michael Buesch8e9f7522007-09-27 21:35:34 +02002748 b43_radio_turn_off(dev, 1);
Larry Finger1a8d1222007-12-14 13:59:11 +01002749err_gpio_clean:
Michael Buesche4d6b792007-09-18 15:39:42 -04002750 b43_gpio_cleanup(dev);
Michael Buesch21954c32007-09-27 15:31:40 +02002751 return err;
Michael Buesche4d6b792007-09-18 15:39:42 -04002752}
2753
Michael Buesche4d6b792007-09-18 15:39:42 -04002754static void b43_periodic_every60sec(struct b43_wldev *dev)
2755{
2756 struct b43_phy *phy = &dev->phy;
2757
Michael Buesch53a6e232008-01-13 21:23:44 +01002758 if (phy->type != B43_PHYTYPE_G)
2759 return;
Larry Finger95de2842007-11-09 16:57:18 -06002760 if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002761 b43_mac_suspend(dev);
2762 b43_calc_nrssi_slope(dev);
2763 if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
2764 u8 old_chan = phy->channel;
2765
2766 /* VCO Calibration */
2767 if (old_chan >= 8)
2768 b43_radio_selectchannel(dev, 1, 0);
2769 else
2770 b43_radio_selectchannel(dev, 13, 0);
2771 b43_radio_selectchannel(dev, old_chan, 0);
2772 }
2773 b43_mac_enable(dev);
2774 }
2775}
2776
2777static void b43_periodic_every30sec(struct b43_wldev *dev)
2778{
2779 /* Update device statistics. */
2780 b43_calculate_link_quality(dev);
2781}
2782
2783static void b43_periodic_every15sec(struct b43_wldev *dev)
2784{
2785 struct b43_phy *phy = &dev->phy;
2786
2787 if (phy->type == B43_PHYTYPE_G) {
2788 //TODO: update_aci_moving_average
2789 if (phy->aci_enable && phy->aci_wlan_automatic) {
2790 b43_mac_suspend(dev);
2791 if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) {
2792 if (0 /*TODO: bunch of conditions */ ) {
2793 b43_radio_set_interference_mitigation
2794 (dev, B43_INTERFMODE_MANUALWLAN);
2795 }
2796 } else if (1 /*TODO*/) {
2797 /*
2798 if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) {
2799 b43_radio_set_interference_mitigation(dev,
2800 B43_INTERFMODE_NONE);
2801 }
2802 */
2803 }
2804 b43_mac_enable(dev);
2805 } else if (phy->interfmode == B43_INTERFMODE_NONWLAN &&
2806 phy->rev == 1) {
2807 //TODO: implement rev1 workaround
2808 }
2809 }
2810 b43_phy_xmitpower(dev); //FIXME: unless scanning?
Michael Bueschf5eda472008-04-20 16:03:32 +02002811 b43_lo_g_maintanance_work(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002812 //TODO for APHY (temperature?)
Stefano Brivio00e0b8c2007-11-25 11:10:33 +01002813
2814 atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
2815 wmb();
Michael Buesche4d6b792007-09-18 15:39:42 -04002816}
2817
Michael Buesche4d6b792007-09-18 15:39:42 -04002818static void do_periodic_work(struct b43_wldev *dev)
2819{
2820 unsigned int state;
2821
2822 state = dev->periodic_state;
Michael Buesch42bb4cd2007-09-28 14:22:33 +02002823 if (state % 4 == 0)
Michael Buesche4d6b792007-09-18 15:39:42 -04002824 b43_periodic_every60sec(dev);
Michael Buesch42bb4cd2007-09-28 14:22:33 +02002825 if (state % 2 == 0)
Michael Buesche4d6b792007-09-18 15:39:42 -04002826 b43_periodic_every30sec(dev);
Michael Buesch42bb4cd2007-09-28 14:22:33 +02002827 b43_periodic_every15sec(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002828}
2829
Michael Buesch05b64b32007-09-28 16:19:03 +02002830/* Periodic work locking policy:
2831 * The whole periodic work handler is protected by
2832 * wl->mutex. If another lock is needed somewhere in the
2833 * pwork callchain, it's aquired in-place, where it's needed.
Michael Buesche4d6b792007-09-18 15:39:42 -04002834 */
Michael Buesche4d6b792007-09-18 15:39:42 -04002835static void b43_periodic_work_handler(struct work_struct *work)
2836{
Michael Buesch05b64b32007-09-28 16:19:03 +02002837 struct b43_wldev *dev = container_of(work, struct b43_wldev,
2838 periodic_work.work);
2839 struct b43_wl *wl = dev->wl;
2840 unsigned long delay;
Michael Buesche4d6b792007-09-18 15:39:42 -04002841
Michael Buesch05b64b32007-09-28 16:19:03 +02002842 mutex_lock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04002843
2844 if (unlikely(b43_status(dev) != B43_STAT_STARTED))
2845 goto out;
2846 if (b43_debug(dev, B43_DBG_PWORK_STOP))
2847 goto out_requeue;
2848
Michael Buesch05b64b32007-09-28 16:19:03 +02002849 do_periodic_work(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002850
Michael Buesche4d6b792007-09-18 15:39:42 -04002851 dev->periodic_state++;
Michael Buesch42bb4cd2007-09-28 14:22:33 +02002852out_requeue:
Michael Buesche4d6b792007-09-18 15:39:42 -04002853 if (b43_debug(dev, B43_DBG_PWORK_FAST))
2854 delay = msecs_to_jiffies(50);
2855 else
Anton Blanchard82cd6822007-10-15 00:42:23 -05002856 delay = round_jiffies_relative(HZ * 15);
Michael Buesch05b64b32007-09-28 16:19:03 +02002857 queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
Michael Buesch42bb4cd2007-09-28 14:22:33 +02002858out:
Michael Buesch05b64b32007-09-28 16:19:03 +02002859 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04002860}
2861
2862static void b43_periodic_tasks_setup(struct b43_wldev *dev)
2863{
2864 struct delayed_work *work = &dev->periodic_work;
2865
2866 dev->periodic_state = 0;
2867 INIT_DELAYED_WORK(work, b43_periodic_work_handler);
2868 queue_delayed_work(dev->wl->hw->workqueue, work, 0);
2869}
2870
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01002871/* Check if communication with the device works correctly. */
Michael Buesche4d6b792007-09-18 15:39:42 -04002872static int b43_validate_chipaccess(struct b43_wldev *dev)
2873{
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01002874 u32 v, backup;
Michael Buesche4d6b792007-09-18 15:39:42 -04002875
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01002876 backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
2877
2878 /* Check for read/write and endianness problems. */
Michael Buesche4d6b792007-09-18 15:39:42 -04002879 b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
2880 if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55)
2881 goto error;
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01002882 b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
2883 if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
Michael Buesche4d6b792007-09-18 15:39:42 -04002884 goto error;
2885
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01002886 b43_shm_write32(dev, B43_SHM_SHARED, 0, backup);
2887
2888 if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) {
2889 /* The 32bit register shadows the two 16bit registers
2890 * with update sideeffects. Validate this. */
2891 b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
2892 b43_write32(dev, B43_MMIO_TSF_CFP_START, 0xCCCCBBBB);
2893 if (b43_read16(dev, B43_MMIO_TSF_CFP_START_LOW) != 0xBBBB)
2894 goto error;
2895 if (b43_read16(dev, B43_MMIO_TSF_CFP_START_HIGH) != 0xCCCC)
2896 goto error;
2897 }
2898 b43_write32(dev, B43_MMIO_TSF_CFP_START, 0);
2899
2900 v = b43_read32(dev, B43_MMIO_MACCTL);
2901 v |= B43_MACCTL_GMODE;
2902 if (v != (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
Michael Buesche4d6b792007-09-18 15:39:42 -04002903 goto error;
2904
2905 return 0;
Michael Bueschf3dd3fc2007-12-22 21:56:30 +01002906error:
Michael Buesche4d6b792007-09-18 15:39:42 -04002907 b43err(dev->wl, "Failed to validate the chipaccess\n");
2908 return -ENODEV;
2909}
2910
2911static void b43_security_init(struct b43_wldev *dev)
2912{
2913 dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20;
2914 B43_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key));
2915 dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP);
2916 /* KTP is a word address, but we address SHM bytewise.
2917 * So multiply by two.
2918 */
2919 dev->ktp *= 2;
2920 if (dev->dev->id.revision >= 5) {
2921 /* Number of RCMTA address slots */
2922 b43_write16(dev, B43_MMIO_RCMTA_COUNT, dev->max_nr_keys - 8);
2923 }
2924 b43_clear_keys(dev);
2925}
2926
2927static int b43_rng_read(struct hwrng *rng, u32 * data)
2928{
2929 struct b43_wl *wl = (struct b43_wl *)rng->priv;
2930 unsigned long flags;
2931
2932 /* Don't take wl->mutex here, as it could deadlock with
2933 * hwrng internal locking. It's not needed to take
2934 * wl->mutex here, anyway. */
2935
2936 spin_lock_irqsave(&wl->irq_lock, flags);
2937 *data = b43_read16(wl->current_dev, B43_MMIO_RNG);
2938 spin_unlock_irqrestore(&wl->irq_lock, flags);
2939
2940 return (sizeof(u16));
2941}
2942
Rafael J. Wysockib844eba2008-03-23 20:28:24 +01002943static void b43_rng_exit(struct b43_wl *wl)
Michael Buesche4d6b792007-09-18 15:39:42 -04002944{
2945 if (wl->rng_initialized)
Rafael J. Wysockib844eba2008-03-23 20:28:24 +01002946 hwrng_unregister(&wl->rng);
Michael Buesche4d6b792007-09-18 15:39:42 -04002947}
2948
2949static int b43_rng_init(struct b43_wl *wl)
2950{
2951 int err;
2952
2953 snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
2954 "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
2955 wl->rng.name = wl->rng_name;
2956 wl->rng.data_read = b43_rng_read;
2957 wl->rng.priv = (unsigned long)wl;
2958 wl->rng_initialized = 1;
2959 err = hwrng_register(&wl->rng);
2960 if (err) {
2961 wl->rng_initialized = 0;
2962 b43err(wl, "Failed to register the random "
2963 "number generator (%d)\n", err);
2964 }
2965
2966 return err;
2967}
2968
Michael Buesch40faacc2007-10-28 16:29:32 +01002969static int b43_op_tx(struct ieee80211_hw *hw,
Johannes Berge039fa42008-05-15 12:55:29 +02002970 struct sk_buff *skb)
Michael Buesche4d6b792007-09-18 15:39:42 -04002971{
2972 struct b43_wl *wl = hw_to_b43_wl(hw);
2973 struct b43_wldev *dev = wl->current_dev;
Michael Buesch21a75d72008-04-25 19:29:08 +02002974 unsigned long flags;
2975 int err;
Michael Buesche4d6b792007-09-18 15:39:42 -04002976
Michael Buesch5100d5a2008-03-29 21:01:16 +01002977 if (unlikely(skb->len < 2 + 2 + 6)) {
2978 /* Too short, this can't be a valid frame. */
Michael Buesch21a75d72008-04-25 19:29:08 +02002979 dev_kfree_skb_any(skb);
2980 return NETDEV_TX_OK;
Michael Buesch5100d5a2008-03-29 21:01:16 +01002981 }
2982 B43_WARN_ON(skb_shinfo(skb)->nr_frags);
Michael Buesche4d6b792007-09-18 15:39:42 -04002983 if (unlikely(!dev))
Michael Buesch21a75d72008-04-25 19:29:08 +02002984 return NETDEV_TX_BUSY;
2985
2986 /* Transmissions on seperate queues can run concurrently. */
2987 read_lock_irqsave(&wl->tx_lock, flags);
2988
2989 err = -ENODEV;
2990 if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
2991 if (b43_using_pio_transfers(dev))
Johannes Berge039fa42008-05-15 12:55:29 +02002992 err = b43_pio_tx(dev, skb);
Michael Buesch21a75d72008-04-25 19:29:08 +02002993 else
Johannes Berge039fa42008-05-15 12:55:29 +02002994 err = b43_dma_tx(dev, skb);
Michael Buesch21a75d72008-04-25 19:29:08 +02002995 }
2996
2997 read_unlock_irqrestore(&wl->tx_lock, flags);
2998
Michael Buesche4d6b792007-09-18 15:39:42 -04002999 if (unlikely(err))
3000 return NETDEV_TX_BUSY;
3001 return NETDEV_TX_OK;
3002}
3003
Michael Buesche6f5b932008-03-05 21:18:49 +01003004/* Locking: wl->irq_lock */
3005static void b43_qos_params_upload(struct b43_wldev *dev,
3006 const struct ieee80211_tx_queue_params *p,
3007 u16 shm_offset)
3008{
3009 u16 params[B43_NR_QOSPARAMS];
3010 int cw_min, cw_max, aifs, bslots, tmp;
3011 unsigned int i;
3012
3013 const u16 aCWmin = 0x0001;
3014 const u16 aCWmax = 0x03FF;
3015
3016 /* Calculate the default values for the parameters, if needed. */
3017 switch (shm_offset) {
3018 case B43_QOS_VOICE:
3019 aifs = (p->aifs == -1) ? 2 : p->aifs;
3020 cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 4 - 1) : p->cw_min;
3021 cw_max = (p->cw_max == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_max;
3022 break;
3023 case B43_QOS_VIDEO:
3024 aifs = (p->aifs == -1) ? 2 : p->aifs;
3025 cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_min;
3026 cw_max = (p->cw_max == 0) ? aCWmin : p->cw_max;
3027 break;
3028 case B43_QOS_BESTEFFORT:
3029 aifs = (p->aifs == -1) ? 3 : p->aifs;
3030 cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min;
3031 cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max;
3032 break;
3033 case B43_QOS_BACKGROUND:
3034 aifs = (p->aifs == -1) ? 7 : p->aifs;
3035 cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min;
3036 cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max;
3037 break;
3038 default:
3039 B43_WARN_ON(1);
3040 return;
3041 }
3042 if (cw_min <= 0)
3043 cw_min = aCWmin;
3044 if (cw_max <= 0)
3045 cw_max = aCWmin;
3046 bslots = b43_read16(dev, B43_MMIO_RNG) % cw_min;
3047
3048 memset(&params, 0, sizeof(params));
3049
3050 params[B43_QOSPARAM_TXOP] = p->txop * 32;
3051 params[B43_QOSPARAM_CWMIN] = cw_min;
3052 params[B43_QOSPARAM_CWMAX] = cw_max;
3053 params[B43_QOSPARAM_CWCUR] = cw_min;
3054 params[B43_QOSPARAM_AIFS] = aifs;
3055 params[B43_QOSPARAM_BSLOTS] = bslots;
3056 params[B43_QOSPARAM_REGGAP] = bslots + aifs;
3057
3058 for (i = 0; i < ARRAY_SIZE(params); i++) {
3059 if (i == B43_QOSPARAM_STATUS) {
3060 tmp = b43_shm_read16(dev, B43_SHM_SHARED,
3061 shm_offset + (i * 2));
3062 /* Mark the parameters as updated. */
3063 tmp |= 0x100;
3064 b43_shm_write16(dev, B43_SHM_SHARED,
3065 shm_offset + (i * 2),
3066 tmp);
3067 } else {
3068 b43_shm_write16(dev, B43_SHM_SHARED,
3069 shm_offset + (i * 2),
3070 params[i]);
3071 }
3072 }
3073}
3074
3075/* Update the QOS parameters in hardware. */
3076static void b43_qos_update(struct b43_wldev *dev)
3077{
3078 struct b43_wl *wl = dev->wl;
3079 struct b43_qos_params *params;
3080 unsigned long flags;
3081 unsigned int i;
3082
3083 /* Mapping of mac80211 queues to b43 SHM offsets. */
3084 static const u16 qos_shm_offsets[] = {
3085 [0] = B43_QOS_VOICE,
3086 [1] = B43_QOS_VIDEO,
3087 [2] = B43_QOS_BESTEFFORT,
3088 [3] = B43_QOS_BACKGROUND,
3089 };
3090 BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params));
3091
3092 b43_mac_suspend(dev);
3093 spin_lock_irqsave(&wl->irq_lock, flags);
3094
3095 for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
3096 params = &(wl->qos_params[i]);
3097 if (params->need_hw_update) {
3098 b43_qos_params_upload(dev, &(params->p),
3099 qos_shm_offsets[i]);
3100 params->need_hw_update = 0;
3101 }
3102 }
3103
3104 spin_unlock_irqrestore(&wl->irq_lock, flags);
3105 b43_mac_enable(dev);
3106}
3107
3108static void b43_qos_clear(struct b43_wl *wl)
3109{
3110 struct b43_qos_params *params;
3111 unsigned int i;
3112
3113 for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
3114 params = &(wl->qos_params[i]);
3115
3116 memset(&(params->p), 0, sizeof(params->p));
3117 params->p.aifs = -1;
3118 params->need_hw_update = 1;
3119 }
3120}
3121
3122/* Initialize the core's QOS capabilities */
3123static void b43_qos_init(struct b43_wldev *dev)
3124{
3125 struct b43_wl *wl = dev->wl;
3126 unsigned int i;
3127
3128 /* Upload the current QOS parameters. */
3129 for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++)
3130 wl->qos_params[i].need_hw_update = 1;
3131 b43_qos_update(dev);
3132
3133 /* Enable QOS support. */
3134 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
3135 b43_write16(dev, B43_MMIO_IFSCTL,
3136 b43_read16(dev, B43_MMIO_IFSCTL)
3137 | B43_MMIO_IFSCTL_USE_EDCF);
3138}
3139
3140static void b43_qos_update_work(struct work_struct *work)
3141{
3142 struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work);
3143 struct b43_wldev *dev;
3144
3145 mutex_lock(&wl->mutex);
3146 dev = wl->current_dev;
3147 if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED)))
3148 b43_qos_update(dev);
3149 mutex_unlock(&wl->mutex);
3150}
3151
Johannes Berge100bb62008-04-30 18:51:21 +02003152static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue,
Michael Buesch40faacc2007-10-28 16:29:32 +01003153 const struct ieee80211_tx_queue_params *params)
Michael Buesche4d6b792007-09-18 15:39:42 -04003154{
Michael Buesche6f5b932008-03-05 21:18:49 +01003155 struct b43_wl *wl = hw_to_b43_wl(hw);
3156 unsigned long flags;
3157 unsigned int queue = (unsigned int)_queue;
3158 struct b43_qos_params *p;
3159
3160 if (queue >= ARRAY_SIZE(wl->qos_params)) {
3161 /* Queue not available or don't support setting
3162 * params on this queue. Return success to not
3163 * confuse mac80211. */
3164 return 0;
3165 }
3166
3167 spin_lock_irqsave(&wl->irq_lock, flags);
3168 p = &(wl->qos_params[queue]);
3169 memcpy(&(p->p), params, sizeof(p->p));
3170 p->need_hw_update = 1;
3171 spin_unlock_irqrestore(&wl->irq_lock, flags);
3172
3173 queue_work(hw->workqueue, &wl->qos_update_work);
3174
Michael Buesche4d6b792007-09-18 15:39:42 -04003175 return 0;
3176}
3177
Michael Buesch40faacc2007-10-28 16:29:32 +01003178static int b43_op_get_tx_stats(struct ieee80211_hw *hw,
3179 struct ieee80211_tx_queue_stats *stats)
Michael Buesche4d6b792007-09-18 15:39:42 -04003180{
3181 struct b43_wl *wl = hw_to_b43_wl(hw);
3182 struct b43_wldev *dev = wl->current_dev;
3183 unsigned long flags;
3184 int err = -ENODEV;
3185
3186 if (!dev)
3187 goto out;
3188 spin_lock_irqsave(&wl->irq_lock, flags);
3189 if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
Michael Buesch5100d5a2008-03-29 21:01:16 +01003190 if (b43_using_pio_transfers(dev))
3191 b43_pio_get_tx_stats(dev, stats);
3192 else
3193 b43_dma_get_tx_stats(dev, stats);
Michael Buesche4d6b792007-09-18 15:39:42 -04003194 err = 0;
3195 }
3196 spin_unlock_irqrestore(&wl->irq_lock, flags);
Michael Buesch40faacc2007-10-28 16:29:32 +01003197out:
Michael Buesche4d6b792007-09-18 15:39:42 -04003198 return err;
3199}
3200
Michael Buesch40faacc2007-10-28 16:29:32 +01003201static int b43_op_get_stats(struct ieee80211_hw *hw,
3202 struct ieee80211_low_level_stats *stats)
Michael Buesche4d6b792007-09-18 15:39:42 -04003203{
3204 struct b43_wl *wl = hw_to_b43_wl(hw);
3205 unsigned long flags;
3206
3207 spin_lock_irqsave(&wl->irq_lock, flags);
3208 memcpy(stats, &wl->ieee_stats, sizeof(*stats));
3209 spin_unlock_irqrestore(&wl->irq_lock, flags);
3210
3211 return 0;
3212}
3213
Michael Buesche4d6b792007-09-18 15:39:42 -04003214static void b43_put_phy_into_reset(struct b43_wldev *dev)
3215{
3216 struct ssb_device *sdev = dev->dev;
3217 u32 tmslow;
3218
3219 tmslow = ssb_read32(sdev, SSB_TMSLOW);
3220 tmslow &= ~B43_TMSLOW_GMODE;
3221 tmslow |= B43_TMSLOW_PHYRESET;
3222 tmslow |= SSB_TMSLOW_FGC;
3223 ssb_write32(sdev, SSB_TMSLOW, tmslow);
3224 msleep(1);
3225
3226 tmslow = ssb_read32(sdev, SSB_TMSLOW);
3227 tmslow &= ~SSB_TMSLOW_FGC;
3228 tmslow |= B43_TMSLOW_PHYRESET;
3229 ssb_write32(sdev, SSB_TMSLOW, tmslow);
3230 msleep(1);
3231}
3232
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003233static const char * band_to_string(enum ieee80211_band band)
Michael Buesche4d6b792007-09-18 15:39:42 -04003234{
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003235 switch (band) {
3236 case IEEE80211_BAND_5GHZ:
3237 return "5";
3238 case IEEE80211_BAND_2GHZ:
3239 return "2.4";
3240 default:
3241 break;
3242 }
3243 B43_WARN_ON(1);
3244 return "";
3245}
3246
3247/* Expects wl->mutex locked */
3248static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan)
3249{
3250 struct b43_wldev *up_dev = NULL;
Michael Buesche4d6b792007-09-18 15:39:42 -04003251 struct b43_wldev *down_dev;
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003252 struct b43_wldev *d;
Michael Buesche4d6b792007-09-18 15:39:42 -04003253 int err;
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003254 bool gmode;
Michael Buesche4d6b792007-09-18 15:39:42 -04003255 int prev_status;
3256
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003257 /* Find a device and PHY which supports the band. */
3258 list_for_each_entry(d, &wl->devlist, list) {
3259 switch (chan->band) {
3260 case IEEE80211_BAND_5GHZ:
3261 if (d->phy.supports_5ghz) {
3262 up_dev = d;
3263 gmode = 0;
3264 }
3265 break;
3266 case IEEE80211_BAND_2GHZ:
3267 if (d->phy.supports_2ghz) {
3268 up_dev = d;
3269 gmode = 1;
3270 }
3271 break;
3272 default:
3273 B43_WARN_ON(1);
3274 return -EINVAL;
3275 }
3276 if (up_dev)
3277 break;
3278 }
3279 if (!up_dev) {
3280 b43err(wl, "Could not find a device for %s-GHz band operation\n",
3281 band_to_string(chan->band));
3282 return -ENODEV;
Michael Buesche4d6b792007-09-18 15:39:42 -04003283 }
3284 if ((up_dev == wl->current_dev) &&
3285 (!!wl->current_dev->phy.gmode == !!gmode)) {
3286 /* This device is already running. */
3287 return 0;
3288 }
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003289 b43dbg(wl, "Switching to %s-GHz band\n",
3290 band_to_string(chan->band));
Michael Buesche4d6b792007-09-18 15:39:42 -04003291 down_dev = wl->current_dev;
3292
3293 prev_status = b43_status(down_dev);
3294 /* Shutdown the currently running core. */
3295 if (prev_status >= B43_STAT_STARTED)
3296 b43_wireless_core_stop(down_dev);
3297 if (prev_status >= B43_STAT_INITIALIZED)
3298 b43_wireless_core_exit(down_dev);
3299
3300 if (down_dev != up_dev) {
3301 /* We switch to a different core, so we put PHY into
3302 * RESET on the old core. */
3303 b43_put_phy_into_reset(down_dev);
3304 }
3305
3306 /* Now start the new core. */
3307 up_dev->phy.gmode = gmode;
3308 if (prev_status >= B43_STAT_INITIALIZED) {
3309 err = b43_wireless_core_init(up_dev);
3310 if (err) {
3311 b43err(wl, "Fatal: Could not initialize device for "
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003312 "selected %s-GHz band\n",
3313 band_to_string(chan->band));
Michael Buesche4d6b792007-09-18 15:39:42 -04003314 goto init_failure;
3315 }
3316 }
3317 if (prev_status >= B43_STAT_STARTED) {
3318 err = b43_wireless_core_start(up_dev);
3319 if (err) {
3320 b43err(wl, "Fatal: Coult not start device for "
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003321 "selected %s-GHz band\n",
3322 band_to_string(chan->band));
Michael Buesche4d6b792007-09-18 15:39:42 -04003323 b43_wireless_core_exit(up_dev);
3324 goto init_failure;
3325 }
3326 }
3327 B43_WARN_ON(b43_status(up_dev) != prev_status);
3328
3329 wl->current_dev = up_dev;
3330
3331 return 0;
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003332init_failure:
Michael Buesche4d6b792007-09-18 15:39:42 -04003333 /* Whoops, failed to init the new core. No core is operating now. */
3334 wl->current_dev = NULL;
3335 return err;
3336}
3337
Michael Buesch40faacc2007-10-28 16:29:32 +01003338static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
Michael Buesche4d6b792007-09-18 15:39:42 -04003339{
3340 struct b43_wl *wl = hw_to_b43_wl(hw);
3341 struct b43_wldev *dev;
3342 struct b43_phy *phy;
3343 unsigned long flags;
Michael Buesch9db1f6d2007-12-22 21:54:20 +01003344 int antenna;
Michael Buesche4d6b792007-09-18 15:39:42 -04003345 int err = 0;
3346 u32 savedirqs;
3347
Michael Buesche4d6b792007-09-18 15:39:42 -04003348 mutex_lock(&wl->mutex);
3349
Michael Bueschbb1eeff2008-02-09 12:08:58 +01003350 /* Switch the band (if necessary). This might change the active core. */
3351 err = b43_switch_band(wl, conf->channel);
Michael Buesche4d6b792007-09-18 15:39:42 -04003352 if (err)
3353 goto out_unlock_mutex;
3354 dev = wl->current_dev;
3355 phy = &dev->phy;
3356
3357 /* Disable IRQs while reconfiguring the device.
3358 * This makes it possible to drop the spinlock throughout
3359 * the reconfiguration process. */
3360 spin_lock_irqsave(&wl->irq_lock, flags);
3361 if (b43_status(dev) < B43_STAT_STARTED) {
3362 spin_unlock_irqrestore(&wl->irq_lock, flags);
3363 goto out_unlock_mutex;
3364 }
3365 savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
3366 spin_unlock_irqrestore(&wl->irq_lock, flags);
3367 b43_synchronize_irq(dev);
3368
3369 /* Switch to the requested channel.
3370 * The firmware takes care of races with the TX handler. */
Johannes Berg8318d782008-01-24 19:38:38 +01003371 if (conf->channel->hw_value != phy->channel)
3372 b43_radio_selectchannel(dev, conf->channel->hw_value, 0);
Michael Buesche4d6b792007-09-18 15:39:42 -04003373
3374 /* Enable/Disable ShortSlot timing. */
3375 if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
3376 dev->short_slot) {
3377 B43_WARN_ON(phy->type != B43_PHYTYPE_G);
3378 if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
3379 b43_short_slot_timing_enable(dev);
3380 else
3381 b43_short_slot_timing_disable(dev);
3382 }
3383
Johannes Bergd42ce842007-11-23 14:50:51 +01003384 dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
3385
Michael Buesche4d6b792007-09-18 15:39:42 -04003386 /* Adjust the desired TX power level. */
3387 if (conf->power_level != 0) {
3388 if (conf->power_level != phy->power_level) {
3389 phy->power_level = conf->power_level;
3390 b43_phy_xmitpower(dev);
3391 }
3392 }
3393
3394 /* Antennas for RX and management frame TX. */
Michael Buesch9db1f6d2007-12-22 21:54:20 +01003395 antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
3396 b43_mgmtframe_txantenna(dev, antenna);
3397 antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
3398 b43_set_rx_antenna(dev, antenna);
Michael Buesche4d6b792007-09-18 15:39:42 -04003399
Johannes Berg04dea132008-05-20 12:10:49 +02003400 /* Update templates for AP/mesh mode. */
3401 if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
3402 b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
Michael Buesche4d6b792007-09-18 15:39:42 -04003403 b43_set_beacon_int(dev, conf->beacon_int);
3404
Michael Bueschfda9abc2007-09-20 22:14:18 +02003405 if (!!conf->radio_enabled != phy->radio_on) {
3406 if (conf->radio_enabled) {
3407 b43_radio_turn_on(dev);
3408 b43info(dev->wl, "Radio turned on by software\n");
3409 if (!dev->radio_hw_enable) {
3410 b43info(dev->wl, "The hardware RF-kill button "
3411 "still turns the radio physically off. "
3412 "Press the button to turn it on.\n");
3413 }
3414 } else {
Michael Buesch8e9f7522007-09-27 21:35:34 +02003415 b43_radio_turn_off(dev, 0);
Michael Bueschfda9abc2007-09-20 22:14:18 +02003416 b43info(dev->wl, "Radio turned off by software\n");
3417 }
3418 }
3419
Michael Buesche4d6b792007-09-18 15:39:42 -04003420 spin_lock_irqsave(&wl->irq_lock, flags);
3421 b43_interrupt_enable(dev, savedirqs);
3422 mmiowb();
3423 spin_unlock_irqrestore(&wl->irq_lock, flags);
3424 out_unlock_mutex:
3425 mutex_unlock(&wl->mutex);
3426
3427 return err;
3428}
3429
Michael Buesch40faacc2007-10-28 16:29:32 +01003430static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
Johannes Berg4150c572007-09-17 01:29:23 -04003431 const u8 *local_addr, const u8 *addr,
3432 struct ieee80211_key_conf *key)
Michael Buesche4d6b792007-09-18 15:39:42 -04003433{
3434 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003435 struct b43_wldev *dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04003436 unsigned long flags;
3437 u8 algorithm;
3438 u8 index;
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003439 int err;
Joe Perches0795af52007-10-03 17:59:30 -07003440 DECLARE_MAC_BUF(mac);
Michael Buesche4d6b792007-09-18 15:39:42 -04003441
3442 if (modparam_nohwcrypt)
3443 return -ENOSPC; /* User disabled HW-crypto */
3444
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003445 mutex_lock(&wl->mutex);
3446 spin_lock_irqsave(&wl->irq_lock, flags);
3447
3448 dev = wl->current_dev;
3449 err = -ENODEV;
3450 if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
3451 goto out_unlock;
3452
Michael Buesch68217832008-05-17 23:43:57 +02003453 if (dev->fw.pcm_request_failed) {
3454 /* We don't have firmware for the crypto engine.
3455 * Must use software-crypto. */
3456 err = -EOPNOTSUPP;
3457 goto out_unlock;
3458 }
3459
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003460 err = -EINVAL;
Michael Buesche4d6b792007-09-18 15:39:42 -04003461 switch (key->alg) {
Michael Buesche4d6b792007-09-18 15:39:42 -04003462 case ALG_WEP:
3463 if (key->keylen == 5)
3464 algorithm = B43_SEC_ALGO_WEP40;
3465 else
3466 algorithm = B43_SEC_ALGO_WEP104;
3467 break;
3468 case ALG_TKIP:
3469 algorithm = B43_SEC_ALGO_TKIP;
3470 break;
3471 case ALG_CCMP:
3472 algorithm = B43_SEC_ALGO_AES;
3473 break;
3474 default:
3475 B43_WARN_ON(1);
Michael Buesche4d6b792007-09-18 15:39:42 -04003476 goto out_unlock;
3477 }
Michael Bueschc6dfc9a2007-10-28 15:59:58 +01003478 index = (u8) (key->keyidx);
3479 if (index > 3)
3480 goto out_unlock;
Michael Buesche4d6b792007-09-18 15:39:42 -04003481
3482 switch (cmd) {
3483 case SET_KEY:
3484 if (algorithm == B43_SEC_ALGO_TKIP) {
3485 /* FIXME: No TKIP hardware encryption for now. */
3486 err = -EOPNOTSUPP;
3487 goto out_unlock;
3488 }
3489
3490 if (is_broadcast_ether_addr(addr)) {
3491 /* addr is FF:FF:FF:FF:FF:FF for default keys */
3492 err = b43_key_write(dev, index, algorithm,
3493 key->key, key->keylen, NULL, key);
3494 } else {
3495 /*
3496 * either pairwise key or address is 00:00:00:00:00:00
3497 * for transmit-only keys
3498 */
3499 err = b43_key_write(dev, -1, algorithm,
3500 key->key, key->keylen, addr, key);
3501 }
3502 if (err)
3503 goto out_unlock;
3504
3505 if (algorithm == B43_SEC_ALGO_WEP40 ||
3506 algorithm == B43_SEC_ALGO_WEP104) {
3507 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_USEDEFKEYS);
3508 } else {
3509 b43_hf_write(dev,
3510 b43_hf_read(dev) & ~B43_HF_USEDEFKEYS);
3511 }
3512 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
3513 break;
3514 case DISABLE_KEY: {
3515 err = b43_key_clear(dev, key->hw_key_idx);
3516 if (err)
3517 goto out_unlock;
3518 break;
3519 }
3520 default:
3521 B43_WARN_ON(1);
3522 }
3523out_unlock:
3524 spin_unlock_irqrestore(&wl->irq_lock, flags);
3525 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04003526 if (!err) {
3527 b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
Joe Perches0795af52007-10-03 17:59:30 -07003528 "mac: %s\n",
Michael Buesche4d6b792007-09-18 15:39:42 -04003529 cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
Joe Perches0795af52007-10-03 17:59:30 -07003530 print_mac(mac, addr));
Michael Buesche4d6b792007-09-18 15:39:42 -04003531 }
3532 return err;
3533}
3534
Michael Buesch40faacc2007-10-28 16:29:32 +01003535static void b43_op_configure_filter(struct ieee80211_hw *hw,
3536 unsigned int changed, unsigned int *fflags,
3537 int mc_count, struct dev_addr_list *mc_list)
Michael Buesche4d6b792007-09-18 15:39:42 -04003538{
3539 struct b43_wl *wl = hw_to_b43_wl(hw);
3540 struct b43_wldev *dev = wl->current_dev;
3541 unsigned long flags;
3542
Johannes Berg4150c572007-09-17 01:29:23 -04003543 if (!dev) {
3544 *fflags = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04003545 return;
Michael Buesche4d6b792007-09-18 15:39:42 -04003546 }
Johannes Berg4150c572007-09-17 01:29:23 -04003547
3548 spin_lock_irqsave(&wl->irq_lock, flags);
3549 *fflags &= FIF_PROMISC_IN_BSS |
3550 FIF_ALLMULTI |
3551 FIF_FCSFAIL |
3552 FIF_PLCPFAIL |
3553 FIF_CONTROL |
3554 FIF_OTHER_BSS |
3555 FIF_BCN_PRBRESP_PROMISC;
3556
3557 changed &= FIF_PROMISC_IN_BSS |
3558 FIF_ALLMULTI |
3559 FIF_FCSFAIL |
3560 FIF_PLCPFAIL |
3561 FIF_CONTROL |
3562 FIF_OTHER_BSS |
3563 FIF_BCN_PRBRESP_PROMISC;
3564
3565 wl->filter_flags = *fflags;
3566
3567 if (changed && b43_status(dev) >= B43_STAT_INITIALIZED)
3568 b43_adjust_opmode(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003569 spin_unlock_irqrestore(&wl->irq_lock, flags);
3570}
3571
Michael Buesch40faacc2007-10-28 16:29:32 +01003572static int b43_op_config_interface(struct ieee80211_hw *hw,
Johannes Berg32bfd352007-12-19 01:31:26 +01003573 struct ieee80211_vif *vif,
Michael Buesch40faacc2007-10-28 16:29:32 +01003574 struct ieee80211_if_conf *conf)
Michael Buesche4d6b792007-09-18 15:39:42 -04003575{
3576 struct b43_wl *wl = hw_to_b43_wl(hw);
3577 struct b43_wldev *dev = wl->current_dev;
3578 unsigned long flags;
3579
3580 if (!dev)
3581 return -ENODEV;
3582 mutex_lock(&wl->mutex);
3583 spin_lock_irqsave(&wl->irq_lock, flags);
Johannes Berg32bfd352007-12-19 01:31:26 +01003584 B43_WARN_ON(wl->vif != vif);
Johannes Berg4150c572007-09-17 01:29:23 -04003585 if (conf->bssid)
3586 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
3587 else
3588 memset(wl->bssid, 0, ETH_ALEN);
3589 if (b43_status(dev) >= B43_STAT_INITIALIZED) {
Johannes Berg04dea132008-05-20 12:10:49 +02003590 if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
3591 b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
3592 B43_WARN_ON(conf->type != wl->if_type);
Johannes Berg4150c572007-09-17 01:29:23 -04003593 b43_set_ssid(dev, conf->ssid, conf->ssid_len);
Johannes Berge039fa42008-05-15 12:55:29 +02003594 if (conf->beacon)
3595 b43_update_templates(wl, conf->beacon);
Michael Buesche4d6b792007-09-18 15:39:42 -04003596 }
Johannes Berg4150c572007-09-17 01:29:23 -04003597 b43_write_mac_bssid_templates(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003598 }
3599 spin_unlock_irqrestore(&wl->irq_lock, flags);
3600 mutex_unlock(&wl->mutex);
3601
3602 return 0;
3603}
3604
3605/* Locking: wl->mutex */
3606static void b43_wireless_core_stop(struct b43_wldev *dev)
3607{
3608 struct b43_wl *wl = dev->wl;
3609 unsigned long flags;
3610
3611 if (b43_status(dev) < B43_STAT_STARTED)
3612 return;
Stefano Brivioa19d12d2007-11-07 18:16:11 +01003613
3614 /* Disable and sync interrupts. We must do this before than
3615 * setting the status to INITIALIZED, as the interrupt handler
3616 * won't care about IRQs then. */
3617 spin_lock_irqsave(&wl->irq_lock, flags);
3618 dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
3619 b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */
3620 spin_unlock_irqrestore(&wl->irq_lock, flags);
3621 b43_synchronize_irq(dev);
3622
Michael Buesch21a75d72008-04-25 19:29:08 +02003623 write_lock_irqsave(&wl->tx_lock, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -04003624 b43_set_status(dev, B43_STAT_INITIALIZED);
Michael Buesch21a75d72008-04-25 19:29:08 +02003625 write_unlock_irqrestore(&wl->tx_lock, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -04003626
Michael Buesch5100d5a2008-03-29 21:01:16 +01003627 b43_pio_stop(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003628 mutex_unlock(&wl->mutex);
3629 /* Must unlock as it would otherwise deadlock. No races here.
3630 * Cancel the possibly running self-rearming periodic work. */
3631 cancel_delayed_work_sync(&dev->periodic_work);
3632 mutex_lock(&wl->mutex);
3633
Michael Buesche4d6b792007-09-18 15:39:42 -04003634 b43_mac_suspend(dev);
3635 free_irq(dev->dev->irq, dev);
3636 b43dbg(wl, "Wireless interface stopped\n");
3637}
3638
3639/* Locking: wl->mutex */
3640static int b43_wireless_core_start(struct b43_wldev *dev)
3641{
3642 int err;
3643
3644 B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
3645
3646 drain_txstatus_queue(dev);
3647 err = request_irq(dev->dev->irq, b43_interrupt_handler,
3648 IRQF_SHARED, KBUILD_MODNAME, dev);
3649 if (err) {
3650 b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
3651 goto out;
3652 }
3653
3654 /* We are ready to run. */
3655 b43_set_status(dev, B43_STAT_STARTED);
3656
3657 /* Start data flow (TX/RX). */
3658 b43_mac_enable(dev);
3659 b43_interrupt_enable(dev, dev->irq_savedstate);
Michael Buesche4d6b792007-09-18 15:39:42 -04003660
3661 /* Start maintainance work */
3662 b43_periodic_tasks_setup(dev);
3663
3664 b43dbg(dev->wl, "Wireless interface started\n");
3665 out:
3666 return err;
3667}
3668
3669/* Get PHY and RADIO versioning numbers */
3670static int b43_phy_versioning(struct b43_wldev *dev)
3671{
3672 struct b43_phy *phy = &dev->phy;
3673 u32 tmp;
3674 u8 analog_type;
3675 u8 phy_type;
3676 u8 phy_rev;
3677 u16 radio_manuf;
3678 u16 radio_ver;
3679 u16 radio_rev;
3680 int unsupported = 0;
3681
3682 /* Get PHY versioning */
3683 tmp = b43_read16(dev, B43_MMIO_PHY_VER);
3684 analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT;
3685 phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT;
3686 phy_rev = (tmp & B43_PHYVER_VERSION);
3687 switch (phy_type) {
3688 case B43_PHYTYPE_A:
3689 if (phy_rev >= 4)
3690 unsupported = 1;
3691 break;
3692 case B43_PHYTYPE_B:
3693 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6
3694 && phy_rev != 7)
3695 unsupported = 1;
3696 break;
3697 case B43_PHYTYPE_G:
Larry Finger013978b2007-11-26 10:29:47 -06003698 if (phy_rev > 9)
Michael Buesche4d6b792007-09-18 15:39:42 -04003699 unsupported = 1;
3700 break;
Michael Bueschd5c71e42008-01-04 17:06:29 +01003701#ifdef CONFIG_B43_NPHY
3702 case B43_PHYTYPE_N:
3703 if (phy_rev > 1)
3704 unsupported = 1;
3705 break;
3706#endif
Michael Buesche4d6b792007-09-18 15:39:42 -04003707 default:
3708 unsupported = 1;
3709 };
3710 if (unsupported) {
3711 b43err(dev->wl, "FOUND UNSUPPORTED PHY "
3712 "(Analog %u, Type %u, Revision %u)\n",
3713 analog_type, phy_type, phy_rev);
3714 return -EOPNOTSUPP;
3715 }
3716 b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
3717 analog_type, phy_type, phy_rev);
3718
3719 /* Get RADIO versioning */
3720 if (dev->dev->bus->chip_id == 0x4317) {
3721 if (dev->dev->bus->chip_rev == 0)
3722 tmp = 0x3205017F;
3723 else if (dev->dev->bus->chip_rev == 1)
3724 tmp = 0x4205017F;
3725 else
3726 tmp = 0x5205017F;
3727 } else {
3728 b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
Michael Buesch243dcfc2008-01-13 14:12:44 +01003729 tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
Michael Buesche4d6b792007-09-18 15:39:42 -04003730 b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
Michael Buesch243dcfc2008-01-13 14:12:44 +01003731 tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
Michael Buesche4d6b792007-09-18 15:39:42 -04003732 }
3733 radio_manuf = (tmp & 0x00000FFF);
3734 radio_ver = (tmp & 0x0FFFF000) >> 12;
3735 radio_rev = (tmp & 0xF0000000) >> 28;
Michael Buesch96c755a2008-01-06 00:09:46 +01003736 if (radio_manuf != 0x17F /* Broadcom */)
3737 unsupported = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04003738 switch (phy_type) {
3739 case B43_PHYTYPE_A:
3740 if (radio_ver != 0x2060)
3741 unsupported = 1;
3742 if (radio_rev != 1)
3743 unsupported = 1;
3744 if (radio_manuf != 0x17F)
3745 unsupported = 1;
3746 break;
3747 case B43_PHYTYPE_B:
3748 if ((radio_ver & 0xFFF0) != 0x2050)
3749 unsupported = 1;
3750 break;
3751 case B43_PHYTYPE_G:
3752 if (radio_ver != 0x2050)
3753 unsupported = 1;
3754 break;
Michael Buesch96c755a2008-01-06 00:09:46 +01003755 case B43_PHYTYPE_N:
Michael Buesch243dcfc2008-01-13 14:12:44 +01003756 if (radio_ver != 0x2055)
Michael Buesch96c755a2008-01-06 00:09:46 +01003757 unsupported = 1;
3758 break;
Michael Buesche4d6b792007-09-18 15:39:42 -04003759 default:
3760 B43_WARN_ON(1);
3761 }
3762 if (unsupported) {
3763 b43err(dev->wl, "FOUND UNSUPPORTED RADIO "
3764 "(Manuf 0x%X, Version 0x%X, Revision %u)\n",
3765 radio_manuf, radio_ver, radio_rev);
3766 return -EOPNOTSUPP;
3767 }
3768 b43dbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X, Revision %u\n",
3769 radio_manuf, radio_ver, radio_rev);
3770
3771 phy->radio_manuf = radio_manuf;
3772 phy->radio_ver = radio_ver;
3773 phy->radio_rev = radio_rev;
3774
3775 phy->analog = analog_type;
3776 phy->type = phy_type;
3777 phy->rev = phy_rev;
3778
3779 return 0;
3780}
3781
3782static void setup_struct_phy_for_init(struct b43_wldev *dev,
3783 struct b43_phy *phy)
3784{
3785 struct b43_txpower_lo_control *lo;
3786 int i;
3787
3788 memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
3789 memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
3790
Michael Buesche4d6b792007-09-18 15:39:42 -04003791 phy->aci_enable = 0;
3792 phy->aci_wlan_automatic = 0;
3793 phy->aci_hw_rssi = 0;
3794
Michael Bueschfda9abc2007-09-20 22:14:18 +02003795 phy->radio_off_context.valid = 0;
3796
Michael Buesche4d6b792007-09-18 15:39:42 -04003797 lo = phy->lo_control;
3798 if (lo) {
3799 memset(lo, 0, sizeof(*(phy->lo_control)));
Michael Buesche4d6b792007-09-18 15:39:42 -04003800 lo->tx_bias = 0xFF;
Michael Bueschf5eda472008-04-20 16:03:32 +02003801 INIT_LIST_HEAD(&lo->calib_list);
Michael Buesche4d6b792007-09-18 15:39:42 -04003802 }
3803 phy->max_lb_gain = 0;
3804 phy->trsw_rx_gain = 0;
3805 phy->txpwr_offset = 0;
3806
3807 /* NRSSI */
3808 phy->nrssislope = 0;
3809 for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
3810 phy->nrssi[i] = -1000;
3811 for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
3812 phy->nrssi_lt[i] = i;
3813
3814 phy->lofcal = 0xFFFF;
3815 phy->initval = 0xFFFF;
3816
Michael Buesche4d6b792007-09-18 15:39:42 -04003817 phy->interfmode = B43_INTERFMODE_NONE;
3818 phy->channel = 0xFF;
3819
3820 phy->hardware_power_control = !!modparam_hwpctl;
Michael Buesch8ed7fc42007-12-09 22:34:59 +01003821
3822 /* PHY TX errors counter. */
3823 atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
3824
3825 /* OFDM-table address caching. */
3826 phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
Michael Buesche4d6b792007-09-18 15:39:42 -04003827}
3828
3829static void setup_struct_wldev_for_init(struct b43_wldev *dev)
3830{
Michael Bueschaa6c7ae2007-12-26 16:26:36 +01003831 dev->dfq_valid = 0;
3832
Michael Buesch6a724d62007-09-20 22:12:58 +02003833 /* Assume the radio is enabled. If it's not enabled, the state will
3834 * immediately get fixed on the first periodic work run. */
3835 dev->radio_hw_enable = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04003836
3837 /* Stats */
3838 memset(&dev->stats, 0, sizeof(dev->stats));
3839
3840 setup_struct_phy_for_init(dev, &dev->phy);
3841
3842 /* IRQ related flags */
3843 dev->irq_reason = 0;
3844 memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
3845 dev->irq_savedstate = B43_IRQ_MASKTEMPLATE;
3846
3847 dev->mac_suspended = 1;
3848
3849 /* Noise calculation context */
3850 memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
3851}
3852
3853static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
3854{
3855 struct ssb_sprom *sprom = &dev->dev->bus->sprom;
Michael Buescha259d6a2008-04-18 21:06:37 +02003856 u64 hf;
Michael Buesche4d6b792007-09-18 15:39:42 -04003857
Michael Buesch1855ba72008-04-18 20:51:41 +02003858 if (!modparam_btcoex)
3859 return;
Larry Finger95de2842007-11-09 16:57:18 -06003860 if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST))
Michael Buesche4d6b792007-09-18 15:39:42 -04003861 return;
3862 if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
3863 return;
3864
3865 hf = b43_hf_read(dev);
Larry Finger95de2842007-11-09 16:57:18 -06003866 if (sprom->boardflags_lo & B43_BFL_BTCMOD)
Michael Buesche4d6b792007-09-18 15:39:42 -04003867 hf |= B43_HF_BTCOEXALT;
3868 else
3869 hf |= B43_HF_BTCOEX;
3870 b43_hf_write(dev, hf);
Michael Buesche4d6b792007-09-18 15:39:42 -04003871}
3872
3873static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
Michael Buesch1855ba72008-04-18 20:51:41 +02003874{
3875 if (!modparam_btcoex)
3876 return;
3877 //TODO
Michael Buesche4d6b792007-09-18 15:39:42 -04003878}
3879
3880static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
3881{
3882#ifdef CONFIG_SSB_DRIVER_PCICORE
3883 struct ssb_bus *bus = dev->dev->bus;
3884 u32 tmp;
3885
3886 if (bus->pcicore.dev &&
3887 bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
3888 bus->pcicore.dev->id.revision <= 5) {
3889 /* IMCFGLO timeouts workaround. */
3890 tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
3891 tmp &= ~SSB_IMCFGLO_REQTO;
3892 tmp &= ~SSB_IMCFGLO_SERTO;
3893 switch (bus->bustype) {
3894 case SSB_BUSTYPE_PCI:
3895 case SSB_BUSTYPE_PCMCIA:
3896 tmp |= 0x32;
3897 break;
3898 case SSB_BUSTYPE_SSB:
3899 tmp |= 0x53;
3900 break;
3901 }
3902 ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
3903 }
3904#endif /* CONFIG_SSB_DRIVER_PCICORE */
3905}
3906
Michael Buesch74cfdba2007-10-28 16:19:44 +01003907/* Write the short and long frame retry limit values. */
3908static void b43_set_retry_limits(struct b43_wldev *dev,
3909 unsigned int short_retry,
3910 unsigned int long_retry)
3911{
3912 /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
3913 * the chip-internal counter. */
3914 short_retry = min(short_retry, (unsigned int)0xF);
3915 long_retry = min(long_retry, (unsigned int)0xF);
3916
3917 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
3918 short_retry);
3919 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
3920 long_retry);
3921}
3922
Michael Bueschd59f7202008-04-03 18:56:19 +02003923static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
3924{
3925 u16 pu_delay;
3926
3927 /* The time value is in microseconds. */
3928 if (dev->phy.type == B43_PHYTYPE_A)
3929 pu_delay = 3700;
3930 else
3931 pu_delay = 1050;
Michael Buesch8cf6a312008-04-05 15:19:36 +02003932 if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle)
Michael Bueschd59f7202008-04-03 18:56:19 +02003933 pu_delay = 500;
3934 if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
3935 pu_delay = max(pu_delay, (u16)2400);
3936
3937 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SPUWKUP, pu_delay);
3938}
3939
3940/* Set the TSF CFP pre-TargetBeaconTransmissionTime. */
3941static void b43_set_pretbtt(struct b43_wldev *dev)
3942{
3943 u16 pretbtt;
3944
3945 /* The time value is in microseconds. */
Michael Buesch8cf6a312008-04-05 15:19:36 +02003946 if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) {
Michael Bueschd59f7202008-04-03 18:56:19 +02003947 pretbtt = 2;
3948 } else {
3949 if (dev->phy.type == B43_PHYTYPE_A)
3950 pretbtt = 120;
3951 else
3952 pretbtt = 250;
3953 }
3954 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRETBTT, pretbtt);
3955 b43_write16(dev, B43_MMIO_TSF_CFP_PRETBTT, pretbtt);
3956}
3957
Michael Buesche4d6b792007-09-18 15:39:42 -04003958/* Shutdown a wireless core */
3959/* Locking: wl->mutex */
3960static void b43_wireless_core_exit(struct b43_wldev *dev)
3961{
3962 struct b43_phy *phy = &dev->phy;
Michael Buesch1f7d87b2008-01-22 20:23:34 +01003963 u32 macctl;
Michael Buesche4d6b792007-09-18 15:39:42 -04003964
3965 B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
3966 if (b43_status(dev) != B43_STAT_INITIALIZED)
3967 return;
3968 b43_set_status(dev, B43_STAT_UNINIT);
3969
Michael Buesch1f7d87b2008-01-22 20:23:34 +01003970 /* Stop the microcode PSM. */
3971 macctl = b43_read32(dev, B43_MMIO_MACCTL);
3972 macctl &= ~B43_MACCTL_PSM_RUN;
3973 macctl |= B43_MACCTL_PSM_JMP0;
3974 b43_write32(dev, B43_MMIO_MACCTL, macctl);
3975
Rafael J. Wysocki3506e0c2008-02-04 22:30:15 -08003976 if (!dev->suspend_in_progress) {
3977 b43_leds_exit(dev);
Rafael J. Wysockib844eba2008-03-23 20:28:24 +01003978 b43_rng_exit(dev->wl);
Rafael J. Wysocki3506e0c2008-02-04 22:30:15 -08003979 }
Michael Buesche4d6b792007-09-18 15:39:42 -04003980 b43_dma_free(dev);
Michael Buesch5100d5a2008-03-29 21:01:16 +01003981 b43_pio_free(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04003982 b43_chip_exit(dev);
Michael Buesch8e9f7522007-09-27 21:35:34 +02003983 b43_radio_turn_off(dev, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04003984 b43_switch_analog(dev, 0);
3985 if (phy->dyn_tssi_tbl)
3986 kfree(phy->tssi2dbm);
3987 kfree(phy->lo_control);
3988 phy->lo_control = NULL;
Michael Buesche66fee62007-12-26 17:47:10 +01003989 if (dev->wl->current_beacon) {
3990 dev_kfree_skb_any(dev->wl->current_beacon);
3991 dev->wl->current_beacon = NULL;
3992 }
3993
Michael Buesche4d6b792007-09-18 15:39:42 -04003994 ssb_device_disable(dev->dev, 0);
3995 ssb_bus_may_powerdown(dev->dev->bus);
3996}
3997
3998/* Initialize a wireless core */
3999static int b43_wireless_core_init(struct b43_wldev *dev)
4000{
4001 struct b43_wl *wl = dev->wl;
4002 struct ssb_bus *bus = dev->dev->bus;
4003 struct ssb_sprom *sprom = &bus->sprom;
4004 struct b43_phy *phy = &dev->phy;
4005 int err;
Michael Buescha259d6a2008-04-18 21:06:37 +02004006 u64 hf;
4007 u32 tmp;
Michael Buesche4d6b792007-09-18 15:39:42 -04004008
4009 B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
4010
4011 err = ssb_bus_powerup(bus, 0);
4012 if (err)
4013 goto out;
4014 if (!ssb_device_is_enabled(dev->dev)) {
4015 tmp = phy->gmode ? B43_TMSLOW_GMODE : 0;
4016 b43_wireless_core_reset(dev, tmp);
4017 }
4018
4019 if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) {
4020 phy->lo_control =
4021 kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL);
4022 if (!phy->lo_control) {
4023 err = -ENOMEM;
4024 goto err_busdown;
4025 }
4026 }
4027 setup_struct_wldev_for_init(dev);
4028
4029 err = b43_phy_init_tssi2dbm_table(dev);
4030 if (err)
4031 goto err_kfree_lo_control;
4032
4033 /* Enable IRQ routing to this device. */
4034 ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
4035
4036 b43_imcfglo_timeouts_workaround(dev);
4037 b43_bluetooth_coext_disable(dev);
4038 b43_phy_early_init(dev);
4039 err = b43_chip_init(dev);
4040 if (err)
4041 goto err_kfree_tssitbl;
4042 b43_shm_write16(dev, B43_SHM_SHARED,
4043 B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
4044 hf = b43_hf_read(dev);
4045 if (phy->type == B43_PHYTYPE_G) {
4046 hf |= B43_HF_SYMW;
4047 if (phy->rev == 1)
4048 hf |= B43_HF_GDCW;
Larry Finger95de2842007-11-09 16:57:18 -06004049 if (sprom->boardflags_lo & B43_BFL_PACTRL)
Michael Buesche4d6b792007-09-18 15:39:42 -04004050 hf |= B43_HF_OFDMPABOOST;
4051 } else if (phy->type == B43_PHYTYPE_B) {
4052 hf |= B43_HF_SYMW;
4053 if (phy->rev >= 2 && phy->radio_ver == 0x2050)
4054 hf &= ~B43_HF_GDCW;
4055 }
4056 b43_hf_write(dev, hf);
4057
Michael Buesch74cfdba2007-10-28 16:19:44 +01004058 b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
4059 B43_DEFAULT_LONG_RETRY_LIMIT);
Michael Buesche4d6b792007-09-18 15:39:42 -04004060 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
4061 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2);
4062
4063 /* Disable sending probe responses from firmware.
4064 * Setting the MaxTime to one usec will always trigger
4065 * a timeout, so we never send any probe resp.
4066 * A timeout of zero is infinite. */
4067 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1);
4068
4069 b43_rate_memory_init(dev);
Michael Buesch5042c502008-04-05 15:05:00 +02004070 b43_set_phytxctl_defaults(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004071
4072 /* Minimum Contention Window */
4073 if (phy->type == B43_PHYTYPE_B) {
4074 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F);
4075 } else {
4076 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF);
4077 }
4078 /* Maximum Contention Window */
4079 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
4080
Michael Buesch5100d5a2008-03-29 21:01:16 +01004081 if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) {
4082 dev->__using_pio_transfers = 1;
4083 err = b43_pio_init(dev);
4084 } else {
4085 dev->__using_pio_transfers = 0;
4086 err = b43_dma_init(dev);
4087 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004088 if (err)
4089 goto err_chip_exit;
Michael Buesch03b29772007-12-26 14:41:30 +01004090 b43_qos_init(dev);
Michael Bueschd59f7202008-04-03 18:56:19 +02004091 b43_set_synth_pu_delay(dev, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04004092 b43_bluetooth_coext_enable(dev);
4093
4094 ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
Johannes Berg4150c572007-09-17 01:29:23 -04004095 b43_upload_card_macaddress(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004096 b43_security_init(dev);
Rafael J. Wysocki3506e0c2008-02-04 22:30:15 -08004097 if (!dev->suspend_in_progress)
4098 b43_rng_init(wl);
Michael Buesche4d6b792007-09-18 15:39:42 -04004099
4100 b43_set_status(dev, B43_STAT_INITIALIZED);
4101
Rafael J. Wysocki3506e0c2008-02-04 22:30:15 -08004102 if (!dev->suspend_in_progress)
4103 b43_leds_init(dev);
Larry Finger1a8d1222007-12-14 13:59:11 +01004104out:
Michael Buesche4d6b792007-09-18 15:39:42 -04004105 return err;
4106
4107 err_chip_exit:
4108 b43_chip_exit(dev);
4109 err_kfree_tssitbl:
4110 if (phy->dyn_tssi_tbl)
4111 kfree(phy->tssi2dbm);
4112 err_kfree_lo_control:
4113 kfree(phy->lo_control);
4114 phy->lo_control = NULL;
4115 err_busdown:
4116 ssb_bus_may_powerdown(bus);
4117 B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
4118 return err;
4119}
4120
Michael Buesch40faacc2007-10-28 16:29:32 +01004121static int b43_op_add_interface(struct ieee80211_hw *hw,
4122 struct ieee80211_if_init_conf *conf)
Michael Buesche4d6b792007-09-18 15:39:42 -04004123{
4124 struct b43_wl *wl = hw_to_b43_wl(hw);
4125 struct b43_wldev *dev;
4126 unsigned long flags;
4127 int err = -EOPNOTSUPP;
Johannes Berg4150c572007-09-17 01:29:23 -04004128
4129 /* TODO: allow WDS/AP devices to coexist */
4130
4131 if (conf->type != IEEE80211_IF_TYPE_AP &&
Johannes Berg04dea132008-05-20 12:10:49 +02004132 conf->type != IEEE80211_IF_TYPE_MESH_POINT &&
Johannes Berg4150c572007-09-17 01:29:23 -04004133 conf->type != IEEE80211_IF_TYPE_STA &&
4134 conf->type != IEEE80211_IF_TYPE_WDS &&
4135 conf->type != IEEE80211_IF_TYPE_IBSS)
4136 return -EOPNOTSUPP;
Michael Buesche4d6b792007-09-18 15:39:42 -04004137
4138 mutex_lock(&wl->mutex);
Johannes Berg4150c572007-09-17 01:29:23 -04004139 if (wl->operating)
Michael Buesche4d6b792007-09-18 15:39:42 -04004140 goto out_mutex_unlock;
4141
4142 b43dbg(wl, "Adding Interface type %d\n", conf->type);
4143
4144 dev = wl->current_dev;
Johannes Berg4150c572007-09-17 01:29:23 -04004145 wl->operating = 1;
Johannes Berg32bfd352007-12-19 01:31:26 +01004146 wl->vif = conf->vif;
Johannes Berg4150c572007-09-17 01:29:23 -04004147 wl->if_type = conf->type;
4148 memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
Michael Buesche4d6b792007-09-18 15:39:42 -04004149
4150 spin_lock_irqsave(&wl->irq_lock, flags);
Michael Buesche4d6b792007-09-18 15:39:42 -04004151 b43_adjust_opmode(dev);
Michael Bueschd59f7202008-04-03 18:56:19 +02004152 b43_set_pretbtt(dev);
4153 b43_set_synth_pu_delay(dev, 0);
Johannes Berg4150c572007-09-17 01:29:23 -04004154 b43_upload_card_macaddress(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004155 spin_unlock_irqrestore(&wl->irq_lock, flags);
4156
4157 err = 0;
Johannes Berg4150c572007-09-17 01:29:23 -04004158 out_mutex_unlock:
Michael Buesche4d6b792007-09-18 15:39:42 -04004159 mutex_unlock(&wl->mutex);
4160
4161 return err;
4162}
4163
Michael Buesch40faacc2007-10-28 16:29:32 +01004164static void b43_op_remove_interface(struct ieee80211_hw *hw,
4165 struct ieee80211_if_init_conf *conf)
Michael Buesche4d6b792007-09-18 15:39:42 -04004166{
4167 struct b43_wl *wl = hw_to_b43_wl(hw);
Johannes Berg4150c572007-09-17 01:29:23 -04004168 struct b43_wldev *dev = wl->current_dev;
Michael Buesche4d6b792007-09-18 15:39:42 -04004169 unsigned long flags;
4170
4171 b43dbg(wl, "Removing Interface type %d\n", conf->type);
4172
4173 mutex_lock(&wl->mutex);
Johannes Berg4150c572007-09-17 01:29:23 -04004174
4175 B43_WARN_ON(!wl->operating);
Johannes Berg32bfd352007-12-19 01:31:26 +01004176 B43_WARN_ON(wl->vif != conf->vif);
4177 wl->vif = NULL;
Johannes Berg4150c572007-09-17 01:29:23 -04004178
4179 wl->operating = 0;
4180
4181 spin_lock_irqsave(&wl->irq_lock, flags);
4182 b43_adjust_opmode(dev);
4183 memset(wl->mac_addr, 0, ETH_ALEN);
4184 b43_upload_card_macaddress(dev);
4185 spin_unlock_irqrestore(&wl->irq_lock, flags);
4186
4187 mutex_unlock(&wl->mutex);
4188}
4189
Michael Buesch40faacc2007-10-28 16:29:32 +01004190static int b43_op_start(struct ieee80211_hw *hw)
Johannes Berg4150c572007-09-17 01:29:23 -04004191{
4192 struct b43_wl *wl = hw_to_b43_wl(hw);
4193 struct b43_wldev *dev = wl->current_dev;
4194 int did_init = 0;
WANG Cong923403b2007-10-16 14:29:38 -07004195 int err = 0;
Michael Buesch1946a2c2008-01-23 12:02:35 +01004196 bool do_rfkill_exit = 0;
Johannes Berg4150c572007-09-17 01:29:23 -04004197
Michael Buesch7be1bb62008-01-23 21:10:56 +01004198 /* Kill all old instance specific information to make sure
4199 * the card won't use it in the short timeframe between start
4200 * and mac80211 reconfiguring it. */
4201 memset(wl->bssid, 0, ETH_ALEN);
4202 memset(wl->mac_addr, 0, ETH_ALEN);
4203 wl->filter_flags = 0;
4204 wl->radiotap_enabled = 0;
Michael Buesche6f5b932008-03-05 21:18:49 +01004205 b43_qos_clear(wl);
Michael Buesch6b4bec02008-05-20 12:16:28 +02004206 wl->beacon0_uploaded = 0;
4207 wl->beacon1_uploaded = 0;
4208 wl->beacon_templates_virgin = 1;
Michael Buesch7be1bb62008-01-23 21:10:56 +01004209
Larry Finger1a8d1222007-12-14 13:59:11 +01004210 /* First register RFkill.
4211 * LEDs that are registered later depend on it. */
4212 b43_rfkill_init(dev);
4213
Johannes Berg4150c572007-09-17 01:29:23 -04004214 mutex_lock(&wl->mutex);
4215
4216 if (b43_status(dev) < B43_STAT_INITIALIZED) {
4217 err = b43_wireless_core_init(dev);
Michael Buesch1946a2c2008-01-23 12:02:35 +01004218 if (err) {
4219 do_rfkill_exit = 1;
Johannes Berg4150c572007-09-17 01:29:23 -04004220 goto out_mutex_unlock;
Michael Buesch1946a2c2008-01-23 12:02:35 +01004221 }
Johannes Berg4150c572007-09-17 01:29:23 -04004222 did_init = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004223 }
4224
Johannes Berg4150c572007-09-17 01:29:23 -04004225 if (b43_status(dev) < B43_STAT_STARTED) {
4226 err = b43_wireless_core_start(dev);
4227 if (err) {
4228 if (did_init)
4229 b43_wireless_core_exit(dev);
Michael Buesch1946a2c2008-01-23 12:02:35 +01004230 do_rfkill_exit = 1;
Johannes Berg4150c572007-09-17 01:29:23 -04004231 goto out_mutex_unlock;
4232 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004233 }
Johannes Berg4150c572007-09-17 01:29:23 -04004234
4235 out_mutex_unlock:
4236 mutex_unlock(&wl->mutex);
4237
Michael Buesch1946a2c2008-01-23 12:02:35 +01004238 if (do_rfkill_exit)
4239 b43_rfkill_exit(dev);
4240
Johannes Berg4150c572007-09-17 01:29:23 -04004241 return err;
4242}
4243
Michael Buesch40faacc2007-10-28 16:29:32 +01004244static void b43_op_stop(struct ieee80211_hw *hw)
Johannes Berg4150c572007-09-17 01:29:23 -04004245{
4246 struct b43_wl *wl = hw_to_b43_wl(hw);
4247 struct b43_wldev *dev = wl->current_dev;
4248
Larry Finger1a8d1222007-12-14 13:59:11 +01004249 b43_rfkill_exit(dev);
Michael Buesche6f5b932008-03-05 21:18:49 +01004250 cancel_work_sync(&(wl->qos_update_work));
Michael Buescha82d9922008-04-04 21:40:06 +02004251 cancel_work_sync(&(wl->beacon_update_trigger));
Larry Finger1a8d1222007-12-14 13:59:11 +01004252
Johannes Berg4150c572007-09-17 01:29:23 -04004253 mutex_lock(&wl->mutex);
4254 if (b43_status(dev) >= B43_STAT_STARTED)
4255 b43_wireless_core_stop(dev);
4256 b43_wireless_core_exit(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004257 mutex_unlock(&wl->mutex);
4258}
4259
Michael Buesch74cfdba2007-10-28 16:19:44 +01004260static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
4261 u32 short_retry_limit, u32 long_retry_limit)
4262{
4263 struct b43_wl *wl = hw_to_b43_wl(hw);
4264 struct b43_wldev *dev;
4265 int err = 0;
4266
4267 mutex_lock(&wl->mutex);
4268 dev = wl->current_dev;
4269 if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) {
4270 err = -ENODEV;
4271 goto out_unlock;
4272 }
4273 b43_set_retry_limits(dev, short_retry_limit, long_retry_limit);
4274out_unlock:
4275 mutex_unlock(&wl->mutex);
4276
4277 return err;
4278}
4279
Michael Buesche66fee62007-12-26 17:47:10 +01004280static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
4281{
4282 struct b43_wl *wl = hw_to_b43_wl(hw);
4283 struct sk_buff *beacon;
Michael Bueschd4df6f12007-12-26 18:04:14 +01004284 unsigned long flags;
Michael Buesche66fee62007-12-26 17:47:10 +01004285
4286 /* We could modify the existing beacon and set the aid bit in
4287 * the TIM field, but that would probably require resizing and
4288 * moving of data within the beacon template.
4289 * Simply request a new beacon and let mac80211 do the hard work. */
Johannes Berge039fa42008-05-15 12:55:29 +02004290 beacon = ieee80211_beacon_get(hw, wl->vif);
Michael Buesche66fee62007-12-26 17:47:10 +01004291 if (unlikely(!beacon))
4292 return -ENOMEM;
Michael Bueschd4df6f12007-12-26 18:04:14 +01004293 spin_lock_irqsave(&wl->irq_lock, flags);
Johannes Berge039fa42008-05-15 12:55:29 +02004294 b43_update_templates(wl, beacon);
Michael Bueschd4df6f12007-12-26 18:04:14 +01004295 spin_unlock_irqrestore(&wl->irq_lock, flags);
Michael Buesche66fee62007-12-26 17:47:10 +01004296
4297 return 0;
4298}
4299
4300static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
Johannes Berge039fa42008-05-15 12:55:29 +02004301 struct sk_buff *beacon)
Michael Buesche66fee62007-12-26 17:47:10 +01004302{
4303 struct b43_wl *wl = hw_to_b43_wl(hw);
Michael Bueschd4df6f12007-12-26 18:04:14 +01004304 unsigned long flags;
Michael Buesche66fee62007-12-26 17:47:10 +01004305
Michael Bueschd4df6f12007-12-26 18:04:14 +01004306 spin_lock_irqsave(&wl->irq_lock, flags);
Johannes Berge039fa42008-05-15 12:55:29 +02004307 b43_update_templates(wl, beacon);
Michael Bueschd4df6f12007-12-26 18:04:14 +01004308 spin_unlock_irqrestore(&wl->irq_lock, flags);
Michael Buesche66fee62007-12-26 17:47:10 +01004309
4310 return 0;
4311}
4312
Johannes Berg38968d02008-02-25 16:27:50 +01004313static void b43_op_sta_notify(struct ieee80211_hw *hw,
4314 struct ieee80211_vif *vif,
4315 enum sta_notify_cmd notify_cmd,
4316 const u8 *addr)
4317{
4318 struct b43_wl *wl = hw_to_b43_wl(hw);
4319
4320 B43_WARN_ON(!vif || wl->vif != vif);
4321}
4322
Michael Buesche4d6b792007-09-18 15:39:42 -04004323static const struct ieee80211_ops b43_hw_ops = {
Michael Buesch40faacc2007-10-28 16:29:32 +01004324 .tx = b43_op_tx,
4325 .conf_tx = b43_op_conf_tx,
4326 .add_interface = b43_op_add_interface,
4327 .remove_interface = b43_op_remove_interface,
4328 .config = b43_op_config,
4329 .config_interface = b43_op_config_interface,
4330 .configure_filter = b43_op_configure_filter,
4331 .set_key = b43_op_set_key,
4332 .get_stats = b43_op_get_stats,
4333 .get_tx_stats = b43_op_get_tx_stats,
4334 .start = b43_op_start,
4335 .stop = b43_op_stop,
Michael Buesch74cfdba2007-10-28 16:19:44 +01004336 .set_retry_limit = b43_op_set_retry_limit,
Michael Buesche66fee62007-12-26 17:47:10 +01004337 .set_tim = b43_op_beacon_set_tim,
4338 .beacon_update = b43_op_ibss_beacon_update,
Johannes Berg38968d02008-02-25 16:27:50 +01004339 .sta_notify = b43_op_sta_notify,
Michael Buesche4d6b792007-09-18 15:39:42 -04004340};
4341
4342/* Hard-reset the chip. Do not call this directly.
4343 * Use b43_controller_restart()
4344 */
4345static void b43_chip_reset(struct work_struct *work)
4346{
4347 struct b43_wldev *dev =
4348 container_of(work, struct b43_wldev, restart_work);
4349 struct b43_wl *wl = dev->wl;
4350 int err = 0;
4351 int prev_status;
4352
4353 mutex_lock(&wl->mutex);
4354
4355 prev_status = b43_status(dev);
4356 /* Bring the device down... */
4357 if (prev_status >= B43_STAT_STARTED)
4358 b43_wireless_core_stop(dev);
4359 if (prev_status >= B43_STAT_INITIALIZED)
4360 b43_wireless_core_exit(dev);
4361
4362 /* ...and up again. */
4363 if (prev_status >= B43_STAT_INITIALIZED) {
4364 err = b43_wireless_core_init(dev);
4365 if (err)
4366 goto out;
4367 }
4368 if (prev_status >= B43_STAT_STARTED) {
4369 err = b43_wireless_core_start(dev);
4370 if (err) {
4371 b43_wireless_core_exit(dev);
4372 goto out;
4373 }
4374 }
Michael Buesch3bf0a322008-05-22 16:32:16 +02004375out:
4376 if (err)
4377 wl->current_dev = NULL; /* Failed to init the dev. */
Michael Buesche4d6b792007-09-18 15:39:42 -04004378 mutex_unlock(&wl->mutex);
4379 if (err)
4380 b43err(wl, "Controller restart FAILED\n");
4381 else
4382 b43info(wl, "Controller restarted\n");
4383}
4384
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004385static int b43_setup_bands(struct b43_wldev *dev,
Michael Buesch96c755a2008-01-06 00:09:46 +01004386 bool have_2ghz_phy, bool have_5ghz_phy)
Michael Buesche4d6b792007-09-18 15:39:42 -04004387{
4388 struct ieee80211_hw *hw = dev->wl->hw;
Michael Buesche4d6b792007-09-18 15:39:42 -04004389
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004390 if (have_2ghz_phy)
4391 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz;
4392 if (dev->phy.type == B43_PHYTYPE_N) {
4393 if (have_5ghz_phy)
4394 hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_nphy;
4395 } else {
4396 if (have_5ghz_phy)
4397 hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_aphy;
4398 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004399
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004400 dev->phy.supports_2ghz = have_2ghz_phy;
4401 dev->phy.supports_5ghz = have_5ghz_phy;
Michael Buesche4d6b792007-09-18 15:39:42 -04004402
4403 return 0;
4404}
4405
4406static void b43_wireless_core_detach(struct b43_wldev *dev)
4407{
4408 /* We release firmware that late to not be required to re-request
4409 * is all the time when we reinit the core. */
4410 b43_release_firmware(dev);
4411}
4412
4413static int b43_wireless_core_attach(struct b43_wldev *dev)
4414{
4415 struct b43_wl *wl = dev->wl;
4416 struct ssb_bus *bus = dev->dev->bus;
4417 struct pci_dev *pdev = bus->host_pci;
4418 int err;
Michael Buesch96c755a2008-01-06 00:09:46 +01004419 bool have_2ghz_phy = 0, have_5ghz_phy = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04004420 u32 tmp;
4421
4422 /* Do NOT do any device initialization here.
4423 * Do it in wireless_core_init() instead.
4424 * This function is for gathering basic information about the HW, only.
4425 * Also some structs may be set up here. But most likely you want to have
4426 * that in core_init(), too.
4427 */
4428
4429 err = ssb_bus_powerup(bus, 0);
4430 if (err) {
4431 b43err(wl, "Bus powerup failed\n");
4432 goto out;
4433 }
4434 /* Get the PHY type. */
4435 if (dev->dev->id.revision >= 5) {
4436 u32 tmshigh;
4437
4438 tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
Michael Buesch96c755a2008-01-06 00:09:46 +01004439 have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
4440 have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
Michael Buesche4d6b792007-09-18 15:39:42 -04004441 } else
Michael Buesch96c755a2008-01-06 00:09:46 +01004442 B43_WARN_ON(1);
Michael Buesche4d6b792007-09-18 15:39:42 -04004443
Michael Buesch96c755a2008-01-06 00:09:46 +01004444 dev->phy.gmode = have_2ghz_phy;
Michael Buesche4d6b792007-09-18 15:39:42 -04004445 tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
4446 b43_wireless_core_reset(dev, tmp);
4447
4448 err = b43_phy_versioning(dev);
4449 if (err)
Michael Buesch21954c32007-09-27 15:31:40 +02004450 goto err_powerdown;
Michael Buesche4d6b792007-09-18 15:39:42 -04004451 /* Check if this device supports multiband. */
4452 if (!pdev ||
4453 (pdev->device != 0x4312 &&
4454 pdev->device != 0x4319 && pdev->device != 0x4324)) {
4455 /* No multiband support. */
Michael Buesch96c755a2008-01-06 00:09:46 +01004456 have_2ghz_phy = 0;
4457 have_5ghz_phy = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04004458 switch (dev->phy.type) {
4459 case B43_PHYTYPE_A:
Michael Buesch96c755a2008-01-06 00:09:46 +01004460 have_5ghz_phy = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004461 break;
4462 case B43_PHYTYPE_G:
Michael Buesch96c755a2008-01-06 00:09:46 +01004463 case B43_PHYTYPE_N:
4464 have_2ghz_phy = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004465 break;
4466 default:
4467 B43_WARN_ON(1);
4468 }
4469 }
Michael Buesch96c755a2008-01-06 00:09:46 +01004470 if (dev->phy.type == B43_PHYTYPE_A) {
4471 /* FIXME */
4472 b43err(wl, "IEEE 802.11a devices are unsupported\n");
4473 err = -EOPNOTSUPP;
4474 goto err_powerdown;
4475 }
Michael Buesch2e35af12008-04-27 19:06:18 +02004476 if (1 /* disable A-PHY */) {
4477 /* FIXME: For now we disable the A-PHY on multi-PHY devices. */
4478 if (dev->phy.type != B43_PHYTYPE_N) {
4479 have_2ghz_phy = 1;
4480 have_5ghz_phy = 0;
4481 }
4482 }
4483
Michael Buesch96c755a2008-01-06 00:09:46 +01004484 dev->phy.gmode = have_2ghz_phy;
Michael Buesche4d6b792007-09-18 15:39:42 -04004485 tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
4486 b43_wireless_core_reset(dev, tmp);
4487
4488 err = b43_validate_chipaccess(dev);
4489 if (err)
Michael Buesch21954c32007-09-27 15:31:40 +02004490 goto err_powerdown;
Michael Bueschbb1eeff2008-02-09 12:08:58 +01004491 err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy);
Michael Buesche4d6b792007-09-18 15:39:42 -04004492 if (err)
Michael Buesch21954c32007-09-27 15:31:40 +02004493 goto err_powerdown;
Michael Buesche4d6b792007-09-18 15:39:42 -04004494
4495 /* Now set some default "current_dev" */
4496 if (!wl->current_dev)
4497 wl->current_dev = dev;
4498 INIT_WORK(&dev->restart_work, b43_chip_reset);
4499
Michael Buesch8e9f7522007-09-27 21:35:34 +02004500 b43_radio_turn_off(dev, 1);
Michael Buesche4d6b792007-09-18 15:39:42 -04004501 b43_switch_analog(dev, 0);
4502 ssb_device_disable(dev->dev, 0);
4503 ssb_bus_may_powerdown(bus);
4504
4505out:
4506 return err;
4507
Michael Buesche4d6b792007-09-18 15:39:42 -04004508err_powerdown:
4509 ssb_bus_may_powerdown(bus);
4510 return err;
4511}
4512
4513static void b43_one_core_detach(struct ssb_device *dev)
4514{
4515 struct b43_wldev *wldev;
4516 struct b43_wl *wl;
4517
Michael Buesch3bf0a322008-05-22 16:32:16 +02004518 /* Do not cancel ieee80211-workqueue based work here.
4519 * See comment in b43_remove(). */
4520
Michael Buesche4d6b792007-09-18 15:39:42 -04004521 wldev = ssb_get_drvdata(dev);
4522 wl = wldev->wl;
Michael Buesche4d6b792007-09-18 15:39:42 -04004523 b43_debugfs_remove_device(wldev);
4524 b43_wireless_core_detach(wldev);
4525 list_del(&wldev->list);
4526 wl->nr_devs--;
4527 ssb_set_drvdata(dev, NULL);
4528 kfree(wldev);
4529}
4530
4531static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
4532{
4533 struct b43_wldev *wldev;
4534 struct pci_dev *pdev;
4535 int err = -ENOMEM;
4536
4537 if (!list_empty(&wl->devlist)) {
4538 /* We are not the first core on this chip. */
4539 pdev = dev->bus->host_pci;
4540 /* Only special chips support more than one wireless
4541 * core, although some of the other chips have more than
4542 * one wireless core as well. Check for this and
4543 * bail out early.
4544 */
4545 if (!pdev ||
4546 ((pdev->device != 0x4321) &&
4547 (pdev->device != 0x4313) && (pdev->device != 0x431A))) {
4548 b43dbg(wl, "Ignoring unconnected 802.11 core\n");
4549 return -ENODEV;
4550 }
4551 }
4552
4553 wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
4554 if (!wldev)
4555 goto out;
4556
4557 wldev->dev = dev;
4558 wldev->wl = wl;
4559 b43_set_status(wldev, B43_STAT_UNINIT);
4560 wldev->bad_frames_preempt = modparam_bad_frames_preempt;
4561 tasklet_init(&wldev->isr_tasklet,
4562 (void (*)(unsigned long))b43_interrupt_tasklet,
4563 (unsigned long)wldev);
Michael Buesche4d6b792007-09-18 15:39:42 -04004564 INIT_LIST_HEAD(&wldev->list);
4565
4566 err = b43_wireless_core_attach(wldev);
4567 if (err)
4568 goto err_kfree_wldev;
4569
4570 list_add(&wldev->list, &wl->devlist);
4571 wl->nr_devs++;
4572 ssb_set_drvdata(dev, wldev);
4573 b43_debugfs_add_device(wldev);
4574
4575 out:
4576 return err;
4577
4578 err_kfree_wldev:
4579 kfree(wldev);
4580 return err;
4581}
4582
Michael Buesch9fc38452008-04-19 16:53:00 +02004583#define IS_PDEV(pdev, _vendor, _device, _subvendor, _subdevice) ( \
4584 (pdev->vendor == PCI_VENDOR_ID_##_vendor) && \
4585 (pdev->device == _device) && \
4586 (pdev->subsystem_vendor == PCI_VENDOR_ID_##_subvendor) && \
4587 (pdev->subsystem_device == _subdevice) )
4588
Michael Buesche4d6b792007-09-18 15:39:42 -04004589static void b43_sprom_fixup(struct ssb_bus *bus)
4590{
Michael Buesch1855ba72008-04-18 20:51:41 +02004591 struct pci_dev *pdev;
4592
Michael Buesche4d6b792007-09-18 15:39:42 -04004593 /* boardflags workarounds */
4594 if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
4595 bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
Larry Finger95de2842007-11-09 16:57:18 -06004596 bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST;
Michael Buesche4d6b792007-09-18 15:39:42 -04004597 if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
4598 bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
Larry Finger95de2842007-11-09 16:57:18 -06004599 bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
Michael Buesch1855ba72008-04-18 20:51:41 +02004600 if (bus->bustype == SSB_BUSTYPE_PCI) {
4601 pdev = bus->host_pci;
Michael Buesch9fc38452008-04-19 16:53:00 +02004602 if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) ||
4603 IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) ||
4604 IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013))
Michael Buesch1855ba72008-04-18 20:51:41 +02004605 bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST;
4606 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004607}
4608
4609static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
4610{
4611 struct ieee80211_hw *hw = wl->hw;
4612
4613 ssb_set_devtypedata(dev, NULL);
4614 ieee80211_free_hw(hw);
4615}
4616
4617static int b43_wireless_init(struct ssb_device *dev)
4618{
4619 struct ssb_sprom *sprom = &dev->bus->sprom;
4620 struct ieee80211_hw *hw;
4621 struct b43_wl *wl;
4622 int err = -ENOMEM;
4623
4624 b43_sprom_fixup(dev->bus);
4625
4626 hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
4627 if (!hw) {
4628 b43err(NULL, "Could not allocate ieee80211 device\n");
4629 goto out;
4630 }
4631
4632 /* fill hw info */
Johannes Bergd8be11e2007-11-24 15:06:33 +01004633 hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
Bruno Randolf566bfe52008-05-08 19:15:40 +02004634 IEEE80211_HW_RX_INCLUDES_FCS |
4635 IEEE80211_HW_SIGNAL_DBM |
4636 IEEE80211_HW_NOISE_DBM;
4637
Michael Buesche6f5b932008-03-05 21:18:49 +01004638 hw->queues = b43_modparam_qos ? 4 : 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04004639 SET_IEEE80211_DEV(hw, dev->dev);
Larry Finger95de2842007-11-09 16:57:18 -06004640 if (is_valid_ether_addr(sprom->et1mac))
4641 SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
Michael Buesche4d6b792007-09-18 15:39:42 -04004642 else
Larry Finger95de2842007-11-09 16:57:18 -06004643 SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
Michael Buesche4d6b792007-09-18 15:39:42 -04004644
4645 /* Get and initialize struct b43_wl */
4646 wl = hw_to_b43_wl(hw);
4647 memset(wl, 0, sizeof(*wl));
4648 wl->hw = hw;
4649 spin_lock_init(&wl->irq_lock);
Michael Buesch21a75d72008-04-25 19:29:08 +02004650 rwlock_init(&wl->tx_lock);
Michael Buesche4d6b792007-09-18 15:39:42 -04004651 spin_lock_init(&wl->leds_lock);
Michael Buesch280d0e12007-12-26 18:26:17 +01004652 spin_lock_init(&wl->shm_lock);
Michael Buesche4d6b792007-09-18 15:39:42 -04004653 mutex_init(&wl->mutex);
4654 INIT_LIST_HEAD(&wl->devlist);
Michael Buesche6f5b932008-03-05 21:18:49 +01004655 INIT_WORK(&wl->qos_update_work, b43_qos_update_work);
Michael Buescha82d9922008-04-04 21:40:06 +02004656 INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
Michael Buesche4d6b792007-09-18 15:39:42 -04004657
4658 ssb_set_devtypedata(dev, wl);
4659 b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
4660 err = 0;
4661 out:
4662 return err;
4663}
4664
4665static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
4666{
4667 struct b43_wl *wl;
4668 int err;
4669 int first = 0;
4670
4671 wl = ssb_get_devtypedata(dev);
4672 if (!wl) {
4673 /* Probing the first core. Must setup common struct b43_wl */
4674 first = 1;
4675 err = b43_wireless_init(dev);
4676 if (err)
4677 goto out;
4678 wl = ssb_get_devtypedata(dev);
4679 B43_WARN_ON(!wl);
4680 }
4681 err = b43_one_core_attach(dev, wl);
4682 if (err)
4683 goto err_wireless_exit;
4684
4685 if (first) {
4686 err = ieee80211_register_hw(wl->hw);
4687 if (err)
4688 goto err_one_core_detach;
4689 }
4690
4691 out:
4692 return err;
4693
4694 err_one_core_detach:
4695 b43_one_core_detach(dev);
4696 err_wireless_exit:
4697 if (first)
4698 b43_wireless_exit(dev, wl);
4699 return err;
4700}
4701
4702static void b43_remove(struct ssb_device *dev)
4703{
4704 struct b43_wl *wl = ssb_get_devtypedata(dev);
4705 struct b43_wldev *wldev = ssb_get_drvdata(dev);
4706
Michael Buesch3bf0a322008-05-22 16:32:16 +02004707 /* We must cancel any work here before unregistering from ieee80211,
4708 * as the ieee80211 unreg will destroy the workqueue. */
4709 cancel_work_sync(&wldev->restart_work);
4710
Michael Buesche4d6b792007-09-18 15:39:42 -04004711 B43_WARN_ON(!wl);
4712 if (wl->current_dev == wldev)
4713 ieee80211_unregister_hw(wl->hw);
4714
4715 b43_one_core_detach(dev);
4716
4717 if (list_empty(&wl->devlist)) {
4718 /* Last core on the chip unregistered.
4719 * We can destroy common struct b43_wl.
4720 */
4721 b43_wireless_exit(dev, wl);
4722 }
4723}
4724
4725/* Perform a hardware reset. This can be called from any context. */
4726void b43_controller_restart(struct b43_wldev *dev, const char *reason)
4727{
4728 /* Must avoid requeueing, if we are in shutdown. */
4729 if (b43_status(dev) < B43_STAT_INITIALIZED)
4730 return;
4731 b43info(dev->wl, "Controller RESET (%s) ...\n", reason);
4732 queue_work(dev->wl->hw->workqueue, &dev->restart_work);
4733}
4734
4735#ifdef CONFIG_PM
4736
4737static int b43_suspend(struct ssb_device *dev, pm_message_t state)
4738{
4739 struct b43_wldev *wldev = ssb_get_drvdata(dev);
4740 struct b43_wl *wl = wldev->wl;
4741
4742 b43dbg(wl, "Suspending...\n");
4743
4744 mutex_lock(&wl->mutex);
Rafael J. Wysocki3506e0c2008-02-04 22:30:15 -08004745 wldev->suspend_in_progress = true;
Michael Buesche4d6b792007-09-18 15:39:42 -04004746 wldev->suspend_init_status = b43_status(wldev);
4747 if (wldev->suspend_init_status >= B43_STAT_STARTED)
4748 b43_wireless_core_stop(wldev);
4749 if (wldev->suspend_init_status >= B43_STAT_INITIALIZED)
4750 b43_wireless_core_exit(wldev);
4751 mutex_unlock(&wl->mutex);
4752
4753 b43dbg(wl, "Device suspended.\n");
4754
4755 return 0;
4756}
4757
4758static int b43_resume(struct ssb_device *dev)
4759{
4760 struct b43_wldev *wldev = ssb_get_drvdata(dev);
4761 struct b43_wl *wl = wldev->wl;
4762 int err = 0;
4763
4764 b43dbg(wl, "Resuming...\n");
4765
4766 mutex_lock(&wl->mutex);
4767 if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) {
4768 err = b43_wireless_core_init(wldev);
4769 if (err) {
4770 b43err(wl, "Resume failed at core init\n");
4771 goto out;
4772 }
4773 }
4774 if (wldev->suspend_init_status >= B43_STAT_STARTED) {
4775 err = b43_wireless_core_start(wldev);
4776 if (err) {
Rafael J. Wysocki3506e0c2008-02-04 22:30:15 -08004777 b43_leds_exit(wldev);
Rafael J. Wysockib844eba2008-03-23 20:28:24 +01004778 b43_rng_exit(wldev->wl);
Michael Buesche4d6b792007-09-18 15:39:42 -04004779 b43_wireless_core_exit(wldev);
4780 b43err(wl, "Resume failed at core start\n");
4781 goto out;
4782 }
4783 }
Michael Buesche4d6b792007-09-18 15:39:42 -04004784 b43dbg(wl, "Device resumed.\n");
Rafael J. Wysocki3506e0c2008-02-04 22:30:15 -08004785 out:
4786 wldev->suspend_in_progress = false;
4787 mutex_unlock(&wl->mutex);
Michael Buesche4d6b792007-09-18 15:39:42 -04004788 return err;
4789}
4790
4791#else /* CONFIG_PM */
4792# define b43_suspend NULL
4793# define b43_resume NULL
4794#endif /* CONFIG_PM */
4795
4796static struct ssb_driver b43_ssb_driver = {
4797 .name = KBUILD_MODNAME,
4798 .id_table = b43_ssb_tbl,
4799 .probe = b43_probe,
4800 .remove = b43_remove,
4801 .suspend = b43_suspend,
4802 .resume = b43_resume,
4803};
4804
Michael Buesch26bc7832008-02-09 00:18:35 +01004805static void b43_print_driverinfo(void)
4806{
4807 const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
4808 *feat_leds = "", *feat_rfkill = "";
4809
4810#ifdef CONFIG_B43_PCI_AUTOSELECT
4811 feat_pci = "P";
4812#endif
4813#ifdef CONFIG_B43_PCMCIA
4814 feat_pcmcia = "M";
4815#endif
4816#ifdef CONFIG_B43_NPHY
4817 feat_nphy = "N";
4818#endif
4819#ifdef CONFIG_B43_LEDS
4820 feat_leds = "L";
4821#endif
4822#ifdef CONFIG_B43_RFKILL
4823 feat_rfkill = "R";
4824#endif
4825 printk(KERN_INFO "Broadcom 43xx driver loaded "
4826 "[ Features: %s%s%s%s%s, Firmware-ID: "
4827 B43_SUPPORTED_FIRMWARE_ID " ]\n",
4828 feat_pci, feat_pcmcia, feat_nphy,
4829 feat_leds, feat_rfkill);
4830}
4831
Michael Buesche4d6b792007-09-18 15:39:42 -04004832static int __init b43_init(void)
4833{
4834 int err;
4835
4836 b43_debugfs_init();
4837 err = b43_pcmcia_init();
4838 if (err)
4839 goto err_dfs_exit;
4840 err = ssb_driver_register(&b43_ssb_driver);
4841 if (err)
4842 goto err_pcmcia_exit;
Michael Buesch26bc7832008-02-09 00:18:35 +01004843 b43_print_driverinfo();
Michael Buesche4d6b792007-09-18 15:39:42 -04004844
4845 return err;
4846
4847err_pcmcia_exit:
4848 b43_pcmcia_exit();
4849err_dfs_exit:
4850 b43_debugfs_exit();
4851 return err;
4852}
4853
4854static void __exit b43_exit(void)
4855{
4856 ssb_driver_unregister(&b43_ssb_driver);
4857 b43_pcmcia_exit();
4858 b43_debugfs_exit();
4859}
4860
4861module_init(b43_init)
4862module_exit(b43_exit)