blob: b7192559833ccef62b767853ec779cafcb88cb89 [file] [log] [blame]
John W. Linvillef2223132006-01-23 16:59:58 -05001/*
2
3 Broadcom BCM43xx wireless driver
4
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6 Stefano Brivio <st3@riseup.net>
7 Michael Buesch <mbuesch@freenet.de>
8 Danny van Dyk <kugelfang@gentoo.org>
9 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>
41#include <net/iw_handler.h>
42
43#include "bcm43xx.h"
44#include "bcm43xx_main.h"
45#include "bcm43xx_debugfs.h"
46#include "bcm43xx_radio.h"
47#include "bcm43xx_phy.h"
48#include "bcm43xx_dma.h"
49#include "bcm43xx_pio.h"
50#include "bcm43xx_power.h"
51#include "bcm43xx_wx.h"
Michael Buesch6465ce12006-02-02 19:11:08 +010052#include "bcm43xx_ethtool.h"
Michael Bueschf398f022006-02-23 21:15:39 +010053#include "bcm43xx_xmit.h"
John W. Linvillef2223132006-01-23 16:59:58 -050054
55
56MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
57MODULE_AUTHOR("Martin Langer");
58MODULE_AUTHOR("Stefano Brivio");
59MODULE_AUTHOR("Michael Buesch");
60MODULE_LICENSE("GPL");
61
62#ifdef CONFIG_BCM947XX
63extern char *nvram_get(char *name);
64#endif
65
Michael Buesch77db31e2006-02-12 16:47:44 +010066#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
John W. Linvillef2223132006-01-23 16:59:58 -050067static int modparam_pio;
68module_param_named(pio, modparam_pio, int, 0444);
69MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
Michael Buesch77db31e2006-02-12 16:47:44 +010070#elif defined(CONFIG_BCM43XX_DMA)
71# define modparam_pio 0
72#elif defined(CONFIG_BCM43XX_PIO)
73# define modparam_pio 1
74#endif
John W. Linvillef2223132006-01-23 16:59:58 -050075
76static int modparam_bad_frames_preempt;
77module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
78MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption");
79
80static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT;
81module_param_named(short_retry, modparam_short_retry, int, 0444);
82MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
83
84static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT;
85module_param_named(long_retry, modparam_long_retry, int, 0444);
86MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
87
88static int modparam_locale = -1;
89module_param_named(locale, modparam_locale, int, 0444);
90MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)");
91
John W. Linvillef2223132006-01-23 16:59:58 -050092static int modparam_noleds;
93module_param_named(noleds, modparam_noleds, int, 0444);
94MODULE_PARM_DESC(noleds, "Turn off all LED activity");
95
96#ifdef CONFIG_BCM43XX_DEBUG
97static char modparam_fwpostfix[64];
98module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
99MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
100#else
101# define modparam_fwpostfix ""
102#endif /* CONFIG_BCM43XX_DEBUG*/
103
104
105/* If you want to debug with just a single device, enable this,
106 * where the string is the pci device ID (as given by the kernel's
107 * pci_name function) of the device to be used.
108 */
109//#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0"
110
111/* If you want to enable printing of each MMIO access, enable this. */
112//#define DEBUG_ENABLE_MMIO_PRINT
113
114/* If you want to enable printing of MMIO access within
115 * ucode/pcm upload, initvals write, enable this.
116 */
117//#define DEBUG_ENABLE_UCODE_MMIO_PRINT
118
119/* If you want to enable printing of PCI Config Space access, enable this */
120//#define DEBUG_ENABLE_PCILOG
121
122
Michael Buesch489423c2006-02-13 00:11:07 +0100123/* Detailed list maintained at:
124 * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices
125 */
126 static struct pci_device_id bcm43xx_pci_tbl[] = {
127 /* Broadcom 4303 802.11b */
128 { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
129 /* Broadcom 4307 802.11b */
130 { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
131 /* Broadcom 4318 802.11b/g */
132 { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
133 /* Broadcom 4306 802.11b/g */
134 { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
135 /* Broadcom 4306 802.11a */
136// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
137 /* Broadcom 4309 802.11a/b/g */
138 { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
139 /* Broadcom 43XG 802.11b/g */
140 { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
John W. Linvillef2223132006-01-23 16:59:58 -0500141#ifdef CONFIG_BCM947XX
142 /* SB bus on BCM947xx */
143 { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
144#endif
Michael Buesch489423c2006-02-13 00:11:07 +0100145 { 0 },
John W. Linvillef2223132006-01-23 16:59:58 -0500146};
147MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
148
149static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val)
150{
151 u32 status;
152
153 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
154 if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP))
155 val = swab32(val);
156
157 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset);
158 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val);
159}
160
161static inline
162void bcm43xx_shm_control_word(struct bcm43xx_private *bcm,
163 u16 routing, u16 offset)
164{
165 u32 control;
166
167 /* "offset" is the WORD offset. */
168
169 control = routing;
170 control <<= 16;
171 control |= offset;
172 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control);
173}
174
175u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
176 u16 routing, u16 offset)
177{
178 u32 ret;
179
180 if (routing == BCM43xx_SHM_SHARED) {
181 if (offset & 0x0003) {
182 /* Unaligned access */
183 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
184 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
185 ret <<= 16;
186 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
187 ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
188
189 return ret;
190 }
191 offset >>= 2;
192 }
193 bcm43xx_shm_control_word(bcm, routing, offset);
194 ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA);
195
196 return ret;
197}
198
199u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
200 u16 routing, u16 offset)
201{
202 u16 ret;
203
204 if (routing == BCM43xx_SHM_SHARED) {
205 if (offset & 0x0003) {
206 /* Unaligned access */
207 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
208 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
209
210 return ret;
211 }
212 offset >>= 2;
213 }
214 bcm43xx_shm_control_word(bcm, routing, offset);
215 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
216
217 return ret;
218}
219
220void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
221 u16 routing, u16 offset,
222 u32 value)
223{
224 if (routing == BCM43xx_SHM_SHARED) {
225 if (offset & 0x0003) {
226 /* Unaligned access */
227 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
228 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
229 (value >> 16) & 0xffff);
230 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
231 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA,
232 value & 0xffff);
233 return;
234 }
235 offset >>= 2;
236 }
237 bcm43xx_shm_control_word(bcm, routing, offset);
238 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value);
239}
240
241void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
242 u16 routing, u16 offset,
243 u16 value)
244{
245 if (routing == BCM43xx_SHM_SHARED) {
246 if (offset & 0x0003) {
247 /* Unaligned access */
248 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
249 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
250 value);
251 return;
252 }
253 offset >>= 2;
254 }
255 bcm43xx_shm_control_word(bcm, routing, offset);
256 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value);
257}
258
259void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf)
260{
261 /* We need to be careful. As we read the TSF from multiple
262 * registers, we should take care of register overflows.
263 * In theory, the whole tsf read process should be atomic.
264 * We try to be atomic here, by restaring the read process,
265 * if any of the high registers changed (overflew).
266 */
267 if (bcm->current_core->rev >= 3) {
268 u32 low, high, high2;
269
270 do {
271 high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
272 low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW);
273 high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
274 } while (unlikely(high != high2));
275
276 *tsf = high;
277 *tsf <<= 32;
278 *tsf |= low;
279 } else {
280 u64 tmp;
281 u16 v0, v1, v2, v3;
282 u16 test1, test2, test3;
283
284 do {
285 v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
286 v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
287 v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
288 v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0);
289
290 test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
291 test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
292 test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
293 } while (v3 != test3 || v2 != test2 || v1 != test1);
294
295 *tsf = v3;
296 *tsf <<= 48;
297 tmp = v2;
298 tmp <<= 32;
299 *tsf |= tmp;
300 tmp = v1;
301 tmp <<= 16;
302 *tsf |= tmp;
303 *tsf |= v0;
304 }
305}
306
307void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf)
308{
309 u32 status;
310
311 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
312 status |= BCM43xx_SBF_TIME_UPDATE;
313 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
314
315 /* Be careful with the in-progress timer.
316 * First zero out the low register, so we have a full
317 * register-overflow duration to complete the operation.
318 */
319 if (bcm->current_core->rev >= 3) {
320 u32 lo = (tsf & 0x00000000FFFFFFFFULL);
321 u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
322
323 barrier();
324 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0);
325 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi);
326 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo);
327 } else {
328 u16 v0 = (tsf & 0x000000000000FFFFULL);
329 u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
330 u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
331 u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
332
333 barrier();
334 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0);
335 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3);
336 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2);
337 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1);
338 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0);
339 }
340
341 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
342 status &= ~BCM43xx_SBF_TIME_UPDATE;
343 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
344}
345
John W. Linvillef2223132006-01-23 16:59:58 -0500346static
347void bcm43xx_macfilter_set(struct bcm43xx_private *bcm,
348 u16 offset,
349 const u8 *mac)
350{
351 u16 data;
352
353 offset |= 0x0020;
354 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset);
355
356 data = mac[0];
357 data |= mac[1] << 8;
358 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
359 data = mac[2];
360 data |= mac[3] << 8;
361 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
362 data = mac[4];
363 data |= mac[5] << 8;
364 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
365}
366
Michael Buesch489423c2006-02-13 00:11:07 +0100367static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm,
368 u16 offset)
John W. Linvillef2223132006-01-23 16:59:58 -0500369{
370 const u8 zero_addr[ETH_ALEN] = { 0 };
371
372 bcm43xx_macfilter_set(bcm, offset, zero_addr);
373}
374
375static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm)
376{
377 const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr);
378 const u8 *bssid = (const u8 *)(bcm->ieee->bssid);
379 u8 mac_bssid[ETH_ALEN * 2];
380 int i;
381
382 memcpy(mac_bssid, mac, ETH_ALEN);
383 memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
384
385 /* Write our MAC address and BSSID to template ram */
386 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
387 bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i)));
388 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
389 bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i)));
390 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
391 bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i)));
392}
393
Michael Buesch489423c2006-02-13 00:11:07 +0100394static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time)
John W. Linvillef2223132006-01-23 16:59:58 -0500395{
396 /* slot_time is in usec. */
397 if (bcm->current_core->phy->type != BCM43xx_PHYTYPE_G)
398 return;
399 bcm43xx_write16(bcm, 0x684, 510 + slot_time);
400 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time);
401}
402
Michael Buesch489423c2006-02-13 00:11:07 +0100403static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -0500404{
405 bcm43xx_set_slot_time(bcm, 9);
406}
407
Michael Buesch489423c2006-02-13 00:11:07 +0100408static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -0500409{
410 bcm43xx_set_slot_time(bcm, 20);
411}
412
413//FIXME: rename this func?
414static void bcm43xx_disassociate(struct bcm43xx_private *bcm)
415{
416 bcm43xx_mac_suspend(bcm);
417 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
418
419 bcm43xx_ram_write(bcm, 0x0026, 0x0000);
420 bcm43xx_ram_write(bcm, 0x0028, 0x0000);
421 bcm43xx_ram_write(bcm, 0x007E, 0x0000);
422 bcm43xx_ram_write(bcm, 0x0080, 0x0000);
423 bcm43xx_ram_write(bcm, 0x047E, 0x0000);
424 bcm43xx_ram_write(bcm, 0x0480, 0x0000);
425
426 if (bcm->current_core->rev < 3) {
427 bcm43xx_write16(bcm, 0x0610, 0x8000);
428 bcm43xx_write16(bcm, 0x060E, 0x0000);
429 } else
430 bcm43xx_write32(bcm, 0x0188, 0x80000000);
431
432 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
433
434 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G &&
435 ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate))
436 bcm43xx_short_slot_timing_enable(bcm);
437
438 bcm43xx_mac_enable(bcm);
439}
440
441//FIXME: rename this func?
442static void bcm43xx_associate(struct bcm43xx_private *bcm,
443 const u8 *mac)
444{
445 memcpy(bcm->ieee->bssid, mac, ETH_ALEN);
446
447 bcm43xx_mac_suspend(bcm);
448 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac);
449 bcm43xx_write_mac_bssid_templates(bcm);
450 bcm43xx_mac_enable(bcm);
451}
452
453/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
454 * Returns the _previously_ enabled IRQ mask.
455 */
456static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask)
457{
458 u32 old_mask;
459
460 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
461 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask);
462
463 return old_mask;
464}
465
466/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
467 * Returns the _previously_ enabled IRQ mask.
468 */
469static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask)
470{
471 u32 old_mask;
472
473 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
474 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
475
476 return old_mask;
477}
478
479/* Make sure we don't receive more data from the device. */
480static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
481{
482 u32 old;
483 unsigned long flags;
484
Michael Bueschefccb642006-03-11 13:39:14 +0100485 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500486 if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
Michael Bueschefccb642006-03-11 13:39:14 +0100487 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500488 return -EBUSY;
489 }
490 old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
491 tasklet_disable(&bcm->isr_tasklet);
Michael Bueschefccb642006-03-11 13:39:14 +0100492 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500493 if (oldstate)
494 *oldstate = old;
495
496 return 0;
497}
498
499static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
500{
Michael Buesch489423c2006-02-13 00:11:07 +0100501 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
502 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -0500503 u32 radio_id;
504 u16 manufact;
505 u16 version;
506 u8 revision;
507 s8 i;
508
509 if (bcm->chip_id == 0x4317) {
510 if (bcm->chip_rev == 0x00)
511 radio_id = 0x3205017F;
512 else if (bcm->chip_rev == 0x01)
513 radio_id = 0x4205017F;
514 else
515 radio_id = 0x5205017F;
516 } else {
517 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
518 radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH);
519 radio_id <<= 16;
520 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
521 radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
522 }
523
524 manufact = (radio_id & 0x00000FFF);
525 version = (radio_id & 0x0FFFF000) >> 12;
526 revision = (radio_id & 0xF0000000) >> 28;
527
Michael Buesch489423c2006-02-13 00:11:07 +0100528 dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n",
John W. Linvillef2223132006-01-23 16:59:58 -0500529 radio_id, manufact, version, revision);
530
Michael Buesch489423c2006-02-13 00:11:07 +0100531 switch (phy->type) {
John W. Linvillef2223132006-01-23 16:59:58 -0500532 case BCM43xx_PHYTYPE_A:
533 if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f))
534 goto err_unsupported_radio;
535 break;
536 case BCM43xx_PHYTYPE_B:
537 if ((version & 0xFFF0) != 0x2050)
538 goto err_unsupported_radio;
539 break;
540 case BCM43xx_PHYTYPE_G:
541 if (version != 0x2050)
542 goto err_unsupported_radio;
543 break;
544 }
545
Michael Buesch489423c2006-02-13 00:11:07 +0100546 radio->manufact = manufact;
547 radio->version = version;
548 radio->revision = revision;
John W. Linvillef2223132006-01-23 16:59:58 -0500549
550 /* Set default attenuation values. */
Michael Buesch489423c2006-02-13 00:11:07 +0100551 radio->txpower[0] = 2;
552 radio->txpower[1] = 2;
John W. Linvillef2223132006-01-23 16:59:58 -0500553 if (revision == 1)
Michael Buesch489423c2006-02-13 00:11:07 +0100554 radio->txpower[2] = 3;
John W. Linvillef2223132006-01-23 16:59:58 -0500555 else
Michael Buesch489423c2006-02-13 00:11:07 +0100556 radio->txpower[2] = 0;
Michael Buesch393344f2006-02-05 15:28:20 +0100557 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
Michael Buesch489423c2006-02-13 00:11:07 +0100558 radio->txpower_desired = bcm->sprom.maxpower_aphy;
Michael Buesch393344f2006-02-05 15:28:20 +0100559 else
560 bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_bgphy;
John W. Linvillef2223132006-01-23 16:59:58 -0500561
562 /* Initialize the in-memory nrssi Lookup Table. */
563 for (i = 0; i < 64; i++)
Michael Buesch489423c2006-02-13 00:11:07 +0100564 radio->nrssi_lt[i] = i;
John W. Linvillef2223132006-01-23 16:59:58 -0500565
566 return 0;
567
568err_unsupported_radio:
569 printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n");
570 return -ENODEV;
571}
572
573static const char * bcm43xx_locale_iso(u8 locale)
574{
575 /* ISO 3166-1 country codes.
576 * Note that there aren't ISO 3166-1 codes for
577 * all or locales. (Not all locales are countries)
578 */
579 switch (locale) {
580 case BCM43xx_LOCALE_WORLD:
581 case BCM43xx_LOCALE_ALL:
582 return "XX";
583 case BCM43xx_LOCALE_THAILAND:
584 return "TH";
585 case BCM43xx_LOCALE_ISRAEL:
586 return "IL";
587 case BCM43xx_LOCALE_JORDAN:
588 return "JO";
589 case BCM43xx_LOCALE_CHINA:
590 return "CN";
591 case BCM43xx_LOCALE_JAPAN:
592 case BCM43xx_LOCALE_JAPAN_HIGH:
593 return "JP";
594 case BCM43xx_LOCALE_USA_CANADA_ANZ:
595 case BCM43xx_LOCALE_USA_LOW:
596 return "US";
597 case BCM43xx_LOCALE_EUROPE:
598 return "EU";
599 case BCM43xx_LOCALE_NONE:
600 return " ";
601 }
602 assert(0);
603 return " ";
604}
605
606static const char * bcm43xx_locale_string(u8 locale)
607{
608 switch (locale) {
609 case BCM43xx_LOCALE_WORLD:
610 return "World";
611 case BCM43xx_LOCALE_THAILAND:
612 return "Thailand";
613 case BCM43xx_LOCALE_ISRAEL:
614 return "Israel";
615 case BCM43xx_LOCALE_JORDAN:
616 return "Jordan";
617 case BCM43xx_LOCALE_CHINA:
618 return "China";
619 case BCM43xx_LOCALE_JAPAN:
620 return "Japan";
621 case BCM43xx_LOCALE_USA_CANADA_ANZ:
622 return "USA/Canada/ANZ";
623 case BCM43xx_LOCALE_EUROPE:
624 return "Europe";
625 case BCM43xx_LOCALE_USA_LOW:
626 return "USAlow";
627 case BCM43xx_LOCALE_JAPAN_HIGH:
628 return "JapanHigh";
629 case BCM43xx_LOCALE_ALL:
630 return "All";
631 case BCM43xx_LOCALE_NONE:
632 return "None";
633 }
634 assert(0);
635 return "";
636}
637
638static inline u8 bcm43xx_crc8(u8 crc, u8 data)
639{
640 static const u8 t[] = {
641 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
642 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
643 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
644 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
645 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
646 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
647 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
648 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
649 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
650 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
651 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
652 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
653 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
654 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
655 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
656 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
657 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
658 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
659 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
660 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
661 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
662 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
663 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
664 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
665 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
666 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
667 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
668 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
669 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
670 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
671 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
672 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
673 };
674 return t[crc ^ data];
675}
676
Michael Bueschad3f0862006-02-19 14:12:22 +0100677static u8 bcm43xx_sprom_crc(const u16 *sprom)
John W. Linvillef2223132006-01-23 16:59:58 -0500678{
679 int word;
680 u8 crc = 0xFF;
681
682 for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) {
683 crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF);
684 crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8);
685 }
686 crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF);
687 crc ^= 0xFF;
688
689 return crc;
690}
691
Michael Bueschea0922b2006-02-19 14:09:20 +0100692int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom)
John W. Linvillef2223132006-01-23 16:59:58 -0500693{
694 int i;
Michael Bueschea0922b2006-02-19 14:09:20 +0100695 u8 crc, expected_crc;
696
697 for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
698 sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
699 /* CRC-8 check. */
700 crc = bcm43xx_sprom_crc(sprom);
701 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
702 if (crc != expected_crc) {
703 printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum "
704 "(0x%02X, expected: 0x%02X)\n",
705 crc, expected_crc);
706 return -EINVAL;
707 }
708
709 return 0;
710}
711
712int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
713{
714 int i, err;
715 u8 crc, expected_crc;
716 u32 spromctl;
717
718 /* CRC-8 validation of the input data. */
719 crc = bcm43xx_sprom_crc(sprom);
720 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
721 if (crc != expected_crc) {
722 printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
723 return -EINVAL;
724 }
725
726 printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
727 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
728 if (err)
729 goto err_ctlreg;
730 spromctl |= 0x10; /* SPROM WRITE enable. */
731 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
732 if (err)
733 goto err_ctlreg;
734 /* We must burn lots of CPU cycles here, but that does not
735 * really matter as one does not write the SPROM every other minute...
736 */
737 printk(KERN_INFO PFX "[ 0%%");
738 mdelay(500);
739 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
740 if (i == 16)
741 printk("25%%");
742 else if (i == 32)
743 printk("50%%");
744 else if (i == 48)
745 printk("75%%");
746 else if (i % 2)
747 printk(".");
748 bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
Michael Bueschefccb642006-03-11 13:39:14 +0100749 mmiowb();
Michael Bueschea0922b2006-02-19 14:09:20 +0100750 mdelay(20);
751 }
752 spromctl &= ~0x10; /* SPROM WRITE enable. */
753 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
754 if (err)
755 goto err_ctlreg;
756 mdelay(500);
757 printk("100%% ]\n");
758 printk(KERN_INFO PFX "SPROM written.\n");
759 bcm43xx_controller_restart(bcm, "SPROM update");
760
761 return 0;
762err_ctlreg:
763 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
764 return -ENODEV;
765}
766
767static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
768{
John W. Linvillef2223132006-01-23 16:59:58 -0500769 u16 value;
770 u16 *sprom;
John W. Linvillef2223132006-01-23 16:59:58 -0500771#ifdef CONFIG_BCM947XX
772 char *c;
773#endif
774
775 sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
776 GFP_KERNEL);
777 if (!sprom) {
Michael Bueschea0922b2006-02-19 14:09:20 +0100778 printk(KERN_ERR PFX "sprom_extract OOM\n");
John W. Linvillef2223132006-01-23 16:59:58 -0500779 return -ENOMEM;
780 }
781#ifdef CONFIG_BCM947XX
782 sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
783 sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
784
785 if ((c = nvram_get("il0macaddr")) != NULL)
786 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
787
788 if ((c = nvram_get("et1macaddr")) != NULL)
789 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
790
791 sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
792 sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
793 sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
794
795 sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
796 sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
797 sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
798
799 sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
800#else
Michael Bueschea0922b2006-02-19 14:09:20 +0100801 bcm43xx_sprom_read(bcm, sprom);
John W. Linvillef2223132006-01-23 16:59:58 -0500802#endif
803
804 /* boardflags2 */
805 value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
806 bcm->sprom.boardflags2 = value;
807
808 /* il0macaddr */
809 value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
810 *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
811 value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
812 *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
813 value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
814 *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
815
816 /* et0macaddr */
817 value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
818 *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
819 value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
820 *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
821 value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
822 *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
823
824 /* et1macaddr */
825 value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
826 *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
827 value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
828 *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
829 value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
830 *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
831
832 /* ethernet phy settings */
833 value = sprom[BCM43xx_SPROM_ETHPHY];
834 bcm->sprom.et0phyaddr = (value & 0x001F);
835 bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;
836 bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;
837 bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;
838
839 /* boardrev, antennas, locale */
840 value = sprom[BCM43xx_SPROM_BOARDREV];
841 bcm->sprom.boardrev = (value & 0x00FF);
842 bcm->sprom.locale = (value & 0x0F00) >> 8;
843 bcm->sprom.antennas_aphy = (value & 0x3000) >> 12;
844 bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14;
845 if (modparam_locale != -1) {
846 if (modparam_locale >= 0 && modparam_locale <= 11) {
847 bcm->sprom.locale = modparam_locale;
848 printk(KERN_WARNING PFX "Operating with modified "
849 "LocaleCode %u (%s)\n",
850 bcm->sprom.locale,
851 bcm43xx_locale_string(bcm->sprom.locale));
852 } else {
853 printk(KERN_WARNING PFX "Module parameter \"locale\" "
854 "invalid value. (0 - 11)\n");
855 }
856 }
857
858 /* pa0b* */
859 value = sprom[BCM43xx_SPROM_PA0B0];
860 bcm->sprom.pa0b0 = value;
861 value = sprom[BCM43xx_SPROM_PA0B1];
862 bcm->sprom.pa0b1 = value;
863 value = sprom[BCM43xx_SPROM_PA0B2];
864 bcm->sprom.pa0b2 = value;
865
866 /* wl0gpio* */
867 value = sprom[BCM43xx_SPROM_WL0GPIO0];
868 if (value == 0x0000)
869 value = 0xFFFF;
870 bcm->sprom.wl0gpio0 = value & 0x00FF;
871 bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8;
872 value = sprom[BCM43xx_SPROM_WL0GPIO2];
873 if (value == 0x0000)
874 value = 0xFFFF;
875 bcm->sprom.wl0gpio2 = value & 0x00FF;
876 bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8;
877
878 /* maxpower */
879 value = sprom[BCM43xx_SPROM_MAXPWR];
880 bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8;
881 bcm->sprom.maxpower_bgphy = value & 0x00FF;
882
883 /* pa1b* */
884 value = sprom[BCM43xx_SPROM_PA1B0];
885 bcm->sprom.pa1b0 = value;
886 value = sprom[BCM43xx_SPROM_PA1B1];
887 bcm->sprom.pa1b1 = value;
888 value = sprom[BCM43xx_SPROM_PA1B2];
889 bcm->sprom.pa1b2 = value;
890
891 /* idle tssi target */
892 value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT];
893 bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF;
894 bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8;
895
896 /* boardflags */
897 value = sprom[BCM43xx_SPROM_BOARDFLAGS];
898 if (value == 0xFFFF)
899 value = 0x0000;
900 bcm->sprom.boardflags = value;
901
902 /* antenna gain */
903 value = sprom[BCM43xx_SPROM_ANTENNA_GAIN];
904 if (value == 0x0000 || value == 0xFFFF)
905 value = 0x0202;
906 /* convert values to Q5.2 */
907 bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4;
908 bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4;
909
910 kfree(sprom);
911
912 return 0;
913}
914
John W. Linvillef2223132006-01-23 16:59:58 -0500915static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
916{
917 struct ieee80211_geo geo;
918 struct ieee80211_channel *chan;
919 int have_a = 0, have_bg = 0;
920 int i, num80211;
Michael Buesch9e4a3752006-02-02 18:43:25 +0100921 u8 channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500922 struct bcm43xx_phyinfo *phy;
923 const char *iso_country;
924
925 memset(&geo, 0, sizeof(geo));
926 num80211 = bcm43xx_num_80211_cores(bcm);
927 for (i = 0; i < num80211; i++) {
928 phy = bcm->phy + i;
929 switch (phy->type) {
930 case BCM43xx_PHYTYPE_B:
931 case BCM43xx_PHYTYPE_G:
932 have_bg = 1;
933 break;
934 case BCM43xx_PHYTYPE_A:
935 have_a = 1;
936 break;
937 default:
938 assert(0);
939 }
940 }
941 iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
942
943 if (have_a) {
944 for (i = 0, channel = 0; channel < 201; channel++) {
John W. Linvillef2223132006-01-23 16:59:58 -0500945 chan = &geo.a[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +0100946 chan->freq = bcm43xx_channel_to_freq_a(channel);
John W. Linvillef2223132006-01-23 16:59:58 -0500947 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500948 }
949 geo.a_channels = i;
950 }
951 if (have_bg) {
952 for (i = 0, channel = 1; channel < 15; channel++) {
John W. Linvillef2223132006-01-23 16:59:58 -0500953 chan = &geo.bg[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +0100954 chan->freq = bcm43xx_channel_to_freq_bg(channel);
John W. Linvillef2223132006-01-23 16:59:58 -0500955 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500956 }
957 geo.bg_channels = i;
958 }
959 memcpy(geo.name, iso_country, 2);
960 if (0 /*TODO: Outdoor use only */)
961 geo.name[2] = 'O';
962 else if (0 /*TODO: Indoor use only */)
963 geo.name[2] = 'I';
964 else
965 geo.name[2] = ' ';
966 geo.name[3] = '\0';
967
968 ieee80211_set_geo(bcm->ieee, &geo);
969}
970
971/* DummyTransmission function, as documented on
972 * http://bcm-specs.sipsolutions.net/DummyTransmission
973 */
974void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
975{
Michael Buesch489423c2006-02-13 00:11:07 +0100976 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -0500977 unsigned int i, max_loop;
978 u16 value = 0;
979 u32 buffer[5] = {
980 0x00000000,
981 0x0000D400,
982 0x00000000,
983 0x00000001,
984 0x00000000,
985 };
986
Michael Buesch489423c2006-02-13 00:11:07 +0100987 switch (phy->type) {
John W. Linvillef2223132006-01-23 16:59:58 -0500988 case BCM43xx_PHYTYPE_A:
989 max_loop = 0x1E;
990 buffer[0] = 0xCC010200;
991 break;
992 case BCM43xx_PHYTYPE_B:
993 case BCM43xx_PHYTYPE_G:
994 max_loop = 0xFA;
995 buffer[0] = 0x6E840B00;
996 break;
997 default:
998 assert(0);
999 return;
1000 }
1001
1002 for (i = 0; i < 5; i++)
1003 bcm43xx_ram_write(bcm, i * 4, buffer[i]);
1004
1005 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
1006
1007 bcm43xx_write16(bcm, 0x0568, 0x0000);
1008 bcm43xx_write16(bcm, 0x07C0, 0x0000);
Michael Buesch489423c2006-02-13 00:11:07 +01001009 bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0));
John W. Linvillef2223132006-01-23 16:59:58 -05001010 bcm43xx_write16(bcm, 0x0508, 0x0000);
1011 bcm43xx_write16(bcm, 0x050A, 0x0000);
1012 bcm43xx_write16(bcm, 0x054C, 0x0000);
1013 bcm43xx_write16(bcm, 0x056A, 0x0014);
1014 bcm43xx_write16(bcm, 0x0568, 0x0826);
1015 bcm43xx_write16(bcm, 0x0500, 0x0000);
1016 bcm43xx_write16(bcm, 0x0502, 0x0030);
1017
1018 for (i = 0x00; i < max_loop; i++) {
1019 value = bcm43xx_read16(bcm, 0x050E);
1020 if ((value & 0x0080) != 0)
1021 break;
1022 udelay(10);
1023 }
1024 for (i = 0x00; i < 0x0A; i++) {
1025 value = bcm43xx_read16(bcm, 0x050E);
1026 if ((value & 0x0400) != 0)
1027 break;
1028 udelay(10);
1029 }
1030 for (i = 0x00; i < 0x0A; i++) {
1031 value = bcm43xx_read16(bcm, 0x0690);
1032 if ((value & 0x0100) == 0)
1033 break;
1034 udelay(10);
1035 }
1036}
1037
1038static void key_write(struct bcm43xx_private *bcm,
1039 u8 index, u8 algorithm, const u16 *key)
1040{
1041 unsigned int i, basic_wep = 0;
1042 u32 offset;
1043 u16 value;
1044
1045 /* Write associated key information */
1046 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2),
1047 ((index << 4) | (algorithm & 0x0F)));
1048
1049 /* The first 4 WEP keys need extra love */
1050 if (((algorithm == BCM43xx_SEC_ALGO_WEP) ||
1051 (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4))
1052 basic_wep = 1;
1053
1054 /* Write key payload, 8 little endian words */
1055 offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE);
1056 for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) {
1057 value = cpu_to_le16(key[i]);
1058 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1059 offset + (i * 2), value);
1060
1061 if (!basic_wep)
1062 continue;
1063
1064 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1065 offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE,
1066 value);
1067 }
1068}
1069
1070static void keymac_write(struct bcm43xx_private *bcm,
1071 u8 index, const u32 *addr)
1072{
1073 /* for keys 0-3 there is no associated mac address */
1074 if (index < 4)
1075 return;
1076
1077 index -= 4;
1078 if (bcm->current_core->rev >= 5) {
1079 bcm43xx_shm_write32(bcm,
1080 BCM43xx_SHM_HWMAC,
1081 index * 2,
1082 cpu_to_be32(*addr));
1083 bcm43xx_shm_write16(bcm,
1084 BCM43xx_SHM_HWMAC,
1085 (index * 2) + 1,
1086 cpu_to_be16(*((u16 *)(addr + 1))));
1087 } else {
1088 if (index < 8) {
1089 TODO(); /* Put them in the macaddress filter */
1090 } else {
1091 TODO();
1092 /* Put them BCM43xx_SHM_SHARED, stating index 0x0120.
1093 Keep in mind to update the count of keymacs in 0x003E as well! */
1094 }
1095 }
1096}
1097
1098static int bcm43xx_key_write(struct bcm43xx_private *bcm,
1099 u8 index, u8 algorithm,
1100 const u8 *_key, int key_len,
1101 const u8 *mac_addr)
1102{
1103 u8 key[BCM43xx_SEC_KEYSIZE] = { 0 };
1104
1105 if (index >= ARRAY_SIZE(bcm->key))
1106 return -EINVAL;
1107 if (key_len > ARRAY_SIZE(key))
1108 return -EINVAL;
1109 if (algorithm < 1 || algorithm > 5)
1110 return -EINVAL;
1111
1112 memcpy(key, _key, key_len);
1113 key_write(bcm, index, algorithm, (const u16 *)key);
1114 keymac_write(bcm, index, (const u32 *)mac_addr);
1115
1116 bcm->key[index].algorithm = algorithm;
1117
1118 return 0;
1119}
1120
1121static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
1122{
1123 static const u32 zero_mac[2] = { 0 };
1124 unsigned int i,j, nr_keys = 54;
1125 u16 offset;
1126
1127 if (bcm->current_core->rev < 5)
1128 nr_keys = 16;
1129 assert(nr_keys <= ARRAY_SIZE(bcm->key));
1130
1131 for (i = 0; i < nr_keys; i++) {
1132 bcm->key[i].enabled = 0;
1133 /* returns for i < 4 immediately */
1134 keymac_write(bcm, i, zero_mac);
1135 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1136 0x100 + (i * 2), 0x0000);
1137 for (j = 0; j < 8; j++) {
1138 offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE);
1139 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1140 offset, 0x0000);
1141 }
1142 }
1143 dprintk(KERN_INFO PFX "Keys cleared\n");
1144}
1145
John W. Linvillef2223132006-01-23 16:59:58 -05001146/* Lowlevel core-switch function. This is only to be used in
1147 * bcm43xx_switch_core() and bcm43xx_probe_cores()
1148 */
1149static int _switch_core(struct bcm43xx_private *bcm, int core)
1150{
1151 int err;
1152 int attempts = 0;
Michael Buesch489423c2006-02-13 00:11:07 +01001153 u32 current_core;
John W. Linvillef2223132006-01-23 16:59:58 -05001154
1155 assert(core >= 0);
Michael Buesch489423c2006-02-13 00:11:07 +01001156 while (1) {
1157 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
John W. Linvillef2223132006-01-23 16:59:58 -05001158 (core * 0x1000) + 0x18000000);
Michael Buesch489423c2006-02-13 00:11:07 +01001159 if (unlikely(err))
1160 goto error;
1161 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
1162 &current_core);
1163 if (unlikely(err))
1164 goto error;
1165 current_core = (current_core - 0x18000000) / 0x1000;
1166 if (current_core == core)
1167 break;
John W. Linvillef2223132006-01-23 16:59:58 -05001168
Michael Buesch489423c2006-02-13 00:11:07 +01001169 if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES))
1170 goto error;
1171 udelay(10);
1172 }
1173#ifdef CONFIG_BCM947XX
1174 if (bcm->pci_dev->bus->number == 0)
1175 bcm->current_core_offset = 0x1000 * core;
1176 else
1177 bcm->current_core_offset = 0;
1178#endif
1179
1180 return 0;
1181error:
1182 printk(KERN_ERR PFX "Failed to switch to core %d\n", core);
1183 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05001184}
1185
1186int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core)
1187{
1188 int err;
1189
Michael Buesch489423c2006-02-13 00:11:07 +01001190 if (unlikely(!new_core))
John W. Linvillef2223132006-01-23 16:59:58 -05001191 return 0;
John W. Linvillef2223132006-01-23 16:59:58 -05001192 if (!(new_core->flags & BCM43xx_COREFLAG_AVAILABLE))
1193 return -ENODEV;
1194 if (bcm->current_core == new_core)
1195 return 0;
1196 err = _switch_core(bcm, new_core->index);
Michael Buesch489423c2006-02-13 00:11:07 +01001197 if (likely(!err))
John W. Linvillef2223132006-01-23 16:59:58 -05001198 bcm->current_core = new_core;
1199
1200 return err;
1201}
1202
Michael Buesch489423c2006-02-13 00:11:07 +01001203static int bcm43xx_core_enabled(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001204{
1205 u32 value;
1206
1207 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1208 value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET
1209 | BCM43xx_SBTMSTATELOW_REJECT;
1210
1211 return (value == BCM43xx_SBTMSTATELOW_CLOCK);
1212}
1213
1214/* disable current core */
1215static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags)
1216{
1217 u32 sbtmstatelow;
1218 u32 sbtmstatehigh;
1219 int i;
1220
1221 /* fetch sbtmstatelow from core information registers */
1222 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1223
1224 /* core is already in reset */
1225 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET)
1226 goto out;
1227
1228 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) {
1229 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1230 BCM43xx_SBTMSTATELOW_REJECT;
1231 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1232
1233 for (i = 0; i < 1000; i++) {
1234 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1235 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) {
1236 i = -1;
1237 break;
1238 }
1239 udelay(10);
1240 }
1241 if (i != -1) {
1242 printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n");
1243 return -EBUSY;
1244 }
1245
1246 for (i = 0; i < 1000; i++) {
1247 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1248 if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) {
1249 i = -1;
1250 break;
1251 }
1252 udelay(10);
1253 }
1254 if (i != -1) {
1255 printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n");
1256 return -EBUSY;
1257 }
1258
1259 sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1260 BCM43xx_SBTMSTATELOW_REJECT |
1261 BCM43xx_SBTMSTATELOW_RESET |
1262 BCM43xx_SBTMSTATELOW_CLOCK |
1263 core_flags;
1264 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1265 udelay(10);
1266 }
1267
1268 sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET |
1269 BCM43xx_SBTMSTATELOW_REJECT |
1270 core_flags;
1271 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1272
1273out:
1274 bcm->current_core->flags &= ~ BCM43xx_COREFLAG_ENABLED;
1275 return 0;
1276}
1277
1278/* enable (reset) current core */
1279static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags)
1280{
1281 u32 sbtmstatelow;
1282 u32 sbtmstatehigh;
1283 u32 sbimstate;
1284 int err;
1285
1286 err = bcm43xx_core_disable(bcm, core_flags);
1287 if (err)
1288 goto out;
1289
1290 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1291 BCM43xx_SBTMSTATELOW_RESET |
1292 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1293 core_flags;
1294 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1295 udelay(1);
1296
1297 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1298 if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) {
1299 sbtmstatehigh = 0x00000000;
1300 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh);
1301 }
1302
1303 sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE);
1304 if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) {
1305 sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT);
1306 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate);
1307 }
1308
1309 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1310 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1311 core_flags;
1312 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1313 udelay(1);
1314
1315 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags;
1316 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1317 udelay(1);
1318
1319 bcm->current_core->flags |= BCM43xx_COREFLAG_ENABLED;
1320 assert(err == 0);
1321out:
1322 return err;
1323}
1324
1325/* http://bcm-specs.sipsolutions.net/80211CoreReset */
1326void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
1327{
1328 u32 flags = 0x00040000;
1329
Michael Buesch77db31e2006-02-12 16:47:44 +01001330 if ((bcm43xx_core_enabled(bcm)) &&
1331 !bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05001332//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
1333#ifndef CONFIG_BCM947XX
1334 /* reset all used DMA controllers. */
1335 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1336 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
1337 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
1338 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1339 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1340 if (bcm->current_core->rev < 5)
1341 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1342#endif
1343 }
1344 if (bcm->shutting_down) {
1345 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1346 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1347 & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
1348 } else {
1349 if (connect_phy)
1350 flags |= 0x20000000;
1351 bcm43xx_phy_connect(bcm, connect_phy);
1352 bcm43xx_core_enable(bcm, flags);
1353 bcm43xx_write16(bcm, 0x03E6, 0x0000);
1354 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1355 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1356 | BCM43xx_SBF_400);
1357 }
1358}
1359
1360static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
1361{
1362 bcm43xx_radio_turn_off(bcm);
1363 bcm43xx_write16(bcm, 0x03E6, 0x00F4);
1364 bcm43xx_core_disable(bcm, 0);
1365}
1366
1367/* Mark the current 80211 core inactive.
1368 * "active_80211_core" is the other 80211 core, which is used.
1369 */
1370static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
1371 struct bcm43xx_coreinfo *active_80211_core)
1372{
1373 u32 sbtmstatelow;
1374 struct bcm43xx_coreinfo *old_core;
1375 int err = 0;
1376
1377 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1378 bcm43xx_radio_turn_off(bcm);
1379 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1380 sbtmstatelow &= ~0x200a0000;
1381 sbtmstatelow |= 0xa0000;
1382 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1383 udelay(1);
1384 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1385 sbtmstatelow &= ~0xa0000;
1386 sbtmstatelow |= 0x80000;
1387 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1388 udelay(1);
1389
1390 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
1391 old_core = bcm->current_core;
1392 err = bcm43xx_switch_core(bcm, active_80211_core);
1393 if (err)
1394 goto out;
1395 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1396 sbtmstatelow &= ~0x20000000;
1397 sbtmstatelow |= 0x20000000;
1398 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1399 err = bcm43xx_switch_core(bcm, old_core);
1400 }
1401
1402out:
1403 return err;
1404}
1405
Michael Buesch489423c2006-02-13 00:11:07 +01001406static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001407{
1408 u32 v0, v1;
1409 u16 tmp;
1410 struct bcm43xx_xmitstatus stat;
1411
1412 assert(bcm->current_core->id == BCM43xx_COREID_80211);
1413 assert(bcm->current_core->rev >= 5);
1414
1415 while (1) {
1416 v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
1417 if (!v0)
1418 break;
1419 v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
1420
1421 stat.cookie = (v0 >> 16) & 0x0000FFFF;
1422 tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1));
1423 stat.flags = tmp & 0xFF;
1424 stat.cnt1 = (tmp & 0x0F00) >> 8;
1425 stat.cnt2 = (tmp & 0xF000) >> 12;
1426 stat.seq = (u16)(v1 & 0xFFFF);
1427 stat.unknown = (u16)((v1 >> 16) & 0xFF);
1428
1429 bcm43xx_debugfs_log_txstat(bcm, &stat);
1430
1431 if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE)
1432 continue;
1433 if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) {
1434 //TODO: packet was not acked (was lost)
1435 }
1436 //TODO: There are more (unknown) flags to test. see bcm43xx_main.h
1437
Michael Buesch77db31e2006-02-12 16:47:44 +01001438 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001439 bcm43xx_pio_handle_xmitstatus(bcm, &stat);
1440 else
1441 bcm43xx_dma_handle_xmitstatus(bcm, &stat);
1442 }
1443}
1444
Michael Buesch489423c2006-02-13 00:11:07 +01001445static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001446{
1447 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
1448 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F);
1449 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1450 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4));
1451 assert(bcm->noisecalc.core_at_start == bcm->current_core);
1452 assert(bcm->noisecalc.channel_at_start == bcm->current_core->radio->channel);
1453}
1454
1455static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm)
1456{
1457 /* Top half of Link Quality calculation. */
1458
1459 if (bcm->noisecalc.calculation_running)
1460 return;
1461 bcm->noisecalc.core_at_start = bcm->current_core;
1462 bcm->noisecalc.channel_at_start = bcm->current_core->radio->channel;
1463 bcm->noisecalc.calculation_running = 1;
1464 bcm->noisecalc.nr_samples = 0;
1465
1466 bcm43xx_generate_noise_sample(bcm);
1467}
1468
Michael Buesch489423c2006-02-13 00:11:07 +01001469static void handle_irq_noise(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001470{
1471 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1472 u16 tmp;
1473 u8 noise[4];
1474 u8 i, j;
1475 s32 average;
1476
1477 /* Bottom half of Link Quality calculation. */
1478
1479 assert(bcm->noisecalc.calculation_running);
1480 if (bcm->noisecalc.core_at_start != bcm->current_core ||
1481 bcm->noisecalc.channel_at_start != radio->channel)
1482 goto drop_calculation;
1483 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);
1484 noise[0] = (tmp & 0x00FF);
1485 noise[1] = (tmp & 0xFF00) >> 8;
1486 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A);
1487 noise[2] = (tmp & 0x00FF);
1488 noise[3] = (tmp & 0xFF00) >> 8;
1489 if (noise[0] == 0x7F || noise[1] == 0x7F ||
1490 noise[2] == 0x7F || noise[3] == 0x7F)
1491 goto generate_new;
1492
1493 /* Get the noise samples. */
1494 assert(bcm->noisecalc.nr_samples <= 8);
1495 i = bcm->noisecalc.nr_samples;
1496 noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1497 noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1498 noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1499 noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1500 bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]];
1501 bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]];
1502 bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]];
1503 bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]];
1504 bcm->noisecalc.nr_samples++;
1505 if (bcm->noisecalc.nr_samples == 8) {
1506 /* Calculate the Link Quality by the noise samples. */
1507 average = 0;
1508 for (i = 0; i < 8; i++) {
1509 for (j = 0; j < 4; j++)
1510 average += bcm->noisecalc.samples[i][j];
1511 }
1512 average /= (8 * 4);
1513 average *= 125;
1514 average += 64;
1515 average /= 128;
1516 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
1517 tmp = (tmp / 128) & 0x1F;
1518 if (tmp >= 8)
1519 average += 2;
1520 else
1521 average -= 25;
1522 if (tmp == 8)
1523 average -= 72;
1524 else
1525 average -= 48;
1526
1527 if (average > -65)
1528 bcm->stats.link_quality = 0;
1529 else if (average > -75)
1530 bcm->stats.link_quality = 1;
1531 else if (average > -85)
1532 bcm->stats.link_quality = 2;
1533 else
1534 bcm->stats.link_quality = 3;
1535// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
1536drop_calculation:
1537 bcm->noisecalc.calculation_running = 0;
1538 return;
1539 }
1540generate_new:
1541 bcm43xx_generate_noise_sample(bcm);
1542}
1543
Michael Buesch489423c2006-02-13 00:11:07 +01001544static void handle_irq_ps(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001545{
1546 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
1547 ///TODO: PS TBTT
1548 } else {
1549 if (1/*FIXME: the last PSpoll frame was sent successfully */)
1550 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
1551 }
1552 if (bcm->ieee->iw_mode == IW_MODE_ADHOC)
1553 bcm->reg124_set_0x4 = 1;
1554 //FIXME else set to false?
1555}
1556
Michael Buesch489423c2006-02-13 00:11:07 +01001557static void handle_irq_reg124(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001558{
1559 if (!bcm->reg124_set_0x4)
1560 return;
1561 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1562 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD)
1563 | 0x4);
1564 //FIXME: reset reg124_set_0x4 to false?
1565}
1566
Michael Buesch489423c2006-02-13 00:11:07 +01001567static void handle_irq_pmq(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001568{
1569 u32 tmp;
1570
1571 //TODO: AP mode.
1572
1573 while (1) {
1574 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS);
1575 if (!(tmp & 0x00000008))
1576 break;
1577 }
1578 /* 16bit write is odd, but correct. */
1579 bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);
1580}
1581
1582static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm,
1583 u16 ram_offset, u16 shm_size_offset)
1584{
1585 u32 value;
1586 u16 size = 0;
1587
1588 /* Timestamp. */
1589 //FIXME: assumption: The chip sets the timestamp
1590 value = 0;
1591 bcm43xx_ram_write(bcm, ram_offset++, value);
1592 bcm43xx_ram_write(bcm, ram_offset++, value);
1593 size += 8;
1594
1595 /* Beacon Interval / Capability Information */
1596 value = 0x0000;//FIXME: Which interval?
1597 value |= (1 << 0) << 16; /* ESS */
1598 value |= (1 << 2) << 16; /* CF Pollable */ //FIXME?
1599 value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME?
1600 if (!bcm->ieee->open_wep)
1601 value |= (1 << 4) << 16; /* Privacy */
1602 bcm43xx_ram_write(bcm, ram_offset++, value);
1603 size += 4;
1604
1605 /* SSID */
1606 //TODO
1607
1608 /* FH Parameter Set */
1609 //TODO
1610
1611 /* DS Parameter Set */
1612 //TODO
1613
1614 /* CF Parameter Set */
1615 //TODO
1616
1617 /* TIM */
1618 //TODO
1619
1620 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);
1621}
1622
Michael Buesch489423c2006-02-13 00:11:07 +01001623static void handle_irq_beacon(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001624{
1625 u32 status;
1626
1627 bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
1628 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
1629
1630 if ((status & 0x1) && (status & 0x2)) {
1631 /* ACK beacon IRQ. */
1632 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
1633 BCM43xx_IRQ_BEACON);
1634 bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;
1635 return;
1636 }
1637 if (!(status & 0x1)) {
1638 bcm43xx_generate_beacon_template(bcm, 0x68, 0x18);
1639 status |= 0x1;
1640 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1641 }
1642 if (!(status & 0x2)) {
1643 bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A);
1644 status |= 0x2;
1645 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1646 }
1647}
1648
1649/* Debug helper for irq bottom-half to print all reason registers. */
1650#define bcmirq_print_reasons(description) \
1651 do { \
1652 dprintkl(KERN_ERR PFX description "\n" \
1653 KERN_ERR PFX " Generic Reason: 0x%08x\n" \
1654 KERN_ERR PFX " DMA reasons: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n" \
1655 KERN_ERR PFX " DMA TX status: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", \
1656 reason, \
1657 dma_reason[0], dma_reason[1], \
1658 dma_reason[2], dma_reason[3], \
1659 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_BASE + BCM43xx_DMA_TX_STATUS), \
1660 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_BASE + BCM43xx_DMA_TX_STATUS), \
1661 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_BASE + BCM43xx_DMA_TX_STATUS), \
1662 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_BASE + BCM43xx_DMA_TX_STATUS)); \
1663 } while (0)
1664
1665/* Interrupt handler bottom-half */
1666static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
1667{
1668 u32 reason;
1669 u32 dma_reason[4];
1670 int activity = 0;
1671 unsigned long flags;
1672
1673#ifdef CONFIG_BCM43XX_DEBUG
1674 u32 _handled = 0x00000000;
1675# define bcmirq_handled(irq) do { _handled |= (irq); } while (0)
1676#else
1677# define bcmirq_handled(irq) do { /* nothing */ } while (0)
1678#endif /* CONFIG_BCM43XX_DEBUG*/
1679
Michael Bueschefccb642006-03-11 13:39:14 +01001680 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05001681 reason = bcm->irq_reason;
1682 dma_reason[0] = bcm->dma_reason[0];
1683 dma_reason[1] = bcm->dma_reason[1];
1684 dma_reason[2] = bcm->dma_reason[2];
1685 dma_reason[3] = bcm->dma_reason[3];
1686
1687 if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
1688 /* TX error. We get this when Template Ram is written in wrong endianess
1689 * in dummy_tx(). We also get this if something is wrong with the TX header
1690 * on DMA or PIO queues.
1691 * Maybe we get this in other error conditions, too.
1692 */
1693 bcmirq_print_reasons("XMIT ERROR");
1694 bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
1695 }
1696
1697 if (reason & BCM43xx_IRQ_PS) {
1698 handle_irq_ps(bcm);
1699 bcmirq_handled(BCM43xx_IRQ_PS);
1700 }
1701
1702 if (reason & BCM43xx_IRQ_REG124) {
1703 handle_irq_reg124(bcm);
1704 bcmirq_handled(BCM43xx_IRQ_REG124);
1705 }
1706
1707 if (reason & BCM43xx_IRQ_BEACON) {
1708 if (bcm->ieee->iw_mode == IW_MODE_MASTER)
1709 handle_irq_beacon(bcm);
1710 bcmirq_handled(BCM43xx_IRQ_BEACON);
1711 }
1712
1713 if (reason & BCM43xx_IRQ_PMQ) {
1714 handle_irq_pmq(bcm);
1715 bcmirq_handled(BCM43xx_IRQ_PMQ);
1716 }
1717
1718 if (reason & BCM43xx_IRQ_SCAN) {
1719 /*TODO*/
1720 //bcmirq_handled(BCM43xx_IRQ_SCAN);
1721 }
1722
1723 if (reason & BCM43xx_IRQ_NOISE) {
1724 handle_irq_noise(bcm);
1725 bcmirq_handled(BCM43xx_IRQ_NOISE);
1726 }
1727
1728 /* Check the DMA reason registers for received data. */
1729 assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
1730 assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
1731 if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
Michael Buesch77db31e2006-02-12 16:47:44 +01001732 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001733 bcm43xx_pio_rx(bcm->current_core->pio->queue0);
1734 else
1735 bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0);
Michael Bueschdcfd7202006-02-12 20:25:55 +01001736 /* We intentionally don't set "activity" to 1, here. */
John W. Linvillef2223132006-01-23 16:59:58 -05001737 }
1738 if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
1739 if (likely(bcm->current_core->rev < 5)) {
Michael Buesch77db31e2006-02-12 16:47:44 +01001740 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001741 bcm43xx_pio_rx(bcm->current_core->pio->queue3);
1742 else
1743 bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1);
1744 activity = 1;
1745 } else
1746 assert(0);
1747 }
1748 bcmirq_handled(BCM43xx_IRQ_RX);
1749
1750 if (reason & BCM43xx_IRQ_XMIT_STATUS) {
1751 if (bcm->current_core->rev >= 5) {
1752 handle_irq_transmit_status(bcm);
1753 activity = 1;
1754 }
1755 //TODO: In AP mode, this also causes sending of powersave responses.
1756 bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
1757 }
1758
1759 /* We get spurious IRQs, althought they are masked.
1760 * Assume they are void and ignore them.
1761 */
1762 bcmirq_handled(~(bcm->irq_savedstate));
1763 /* IRQ_PIO_WORKAROUND is handled in the top-half. */
1764 bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);
1765#ifdef CONFIG_BCM43XX_DEBUG
1766 if (unlikely(reason & ~_handled)) {
1767 printkl(KERN_WARNING PFX
1768 "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, "
1769 "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1770 reason, (reason & ~_handled),
1771 dma_reason[0], dma_reason[1],
1772 dma_reason[2], dma_reason[3]);
1773 }
1774#endif
1775#undef bcmirq_handled
1776
1777 if (!modparam_noleds)
1778 bcm43xx_leds_update(bcm, activity);
1779 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
Michael Bueschefccb642006-03-11 13:39:14 +01001780 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05001781}
1782
1783#undef bcmirq_print_reasons
1784
Michael Buesch489423c2006-02-13 00:11:07 +01001785static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm,
1786 u32 reason, u32 mask)
John W. Linvillef2223132006-01-23 16:59:58 -05001787{
1788 bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
1789 & 0x0001dc00;
1790 bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
1791 & 0x0000dc00;
1792 bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
1793 & 0x0000dc00;
1794 bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
1795 & 0x0001dc00;
1796
Michael Buesch77db31e2006-02-12 16:47:44 +01001797 if (bcm43xx_using_pio(bcm) &&
John W. Linvillef2223132006-01-23 16:59:58 -05001798 (bcm->current_core->rev < 3) &&
1799 (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
1800 /* Apply a PIO specific workaround to the dma_reasons */
1801
1802#define apply_pio_workaround(BASE, QNUM) \
1803 do { \
1804 if (bcm43xx_read16(bcm, BASE + BCM43xx_PIO_RXCTL) & BCM43xx_PIO_RXCTL_DATAAVAILABLE) \
1805 bcm->dma_reason[QNUM] |= 0x00010000; \
1806 else \
1807 bcm->dma_reason[QNUM] &= ~0x00010000; \
1808 } while (0)
1809
1810 apply_pio_workaround(BCM43xx_MMIO_PIO1_BASE, 0);
1811 apply_pio_workaround(BCM43xx_MMIO_PIO2_BASE, 1);
1812 apply_pio_workaround(BCM43xx_MMIO_PIO3_BASE, 2);
1813 apply_pio_workaround(BCM43xx_MMIO_PIO4_BASE, 3);
1814
1815#undef apply_pio_workaround
1816 }
1817
1818 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
1819 reason & mask);
1820
1821 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
1822 bcm->dma_reason[0]);
1823 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
1824 bcm->dma_reason[1]);
1825 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
1826 bcm->dma_reason[2]);
1827 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
1828 bcm->dma_reason[3]);
1829}
1830
1831/* Interrupt handler top-half */
1832static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
1833{
Michael Bueschefccb642006-03-11 13:39:14 +01001834 irqreturn_t ret = IRQ_HANDLED;
John W. Linvillef2223132006-01-23 16:59:58 -05001835 struct bcm43xx_private *bcm = dev_id;
1836 u32 reason, mask;
1837
1838 if (!bcm)
1839 return IRQ_NONE;
1840
Michael Bueschefccb642006-03-11 13:39:14 +01001841 spin_lock(&bcm->_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05001842
1843 reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
1844 if (reason == 0xffffffff) {
1845 /* irq not for us (shared irq) */
Michael Bueschefccb642006-03-11 13:39:14 +01001846 ret = IRQ_NONE;
1847 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05001848 }
1849 mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
Michael Bueschefccb642006-03-11 13:39:14 +01001850 if (!(reason & mask))
1851 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05001852
1853 bcm43xx_interrupt_ack(bcm, reason, mask);
1854
Michael Bueschbf7b8762006-02-21 17:58:18 +01001855 /* Only accept IRQs, if we are initialized properly.
1856 * This avoids an RX race while initializing.
1857 * We should probably not enable IRQs before we are initialized
1858 * completely, but some careful work is needed to fix this. I think it
1859 * is best to stay with this cheap workaround for now... .
1860 */
1861 if (likely(bcm->initialized)) {
1862 /* disable all IRQs. They are enabled again in the bottom half. */
1863 bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1864 /* save the reason code and call our bottom half. */
1865 bcm->irq_reason = reason;
1866 tasklet_schedule(&bcm->isr_tasklet);
1867 }
John W. Linvillef2223132006-01-23 16:59:58 -05001868
Michael Bueschefccb642006-03-11 13:39:14 +01001869out:
1870 mmiowb();
1871 spin_unlock(&bcm->_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05001872
Michael Bueschefccb642006-03-11 13:39:14 +01001873 return ret;
John W. Linvillef2223132006-01-23 16:59:58 -05001874}
1875
Michael Buescha4a600d2006-02-01 22:09:52 +01001876static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
John W. Linvillef2223132006-01-23 16:59:58 -05001877{
Michael Buescha4a600d2006-02-01 22:09:52 +01001878 if (bcm->firmware_norelease && !force)
John W. Linvillef2223132006-01-23 16:59:58 -05001879 return; /* Suspending or controller reset. */
1880 release_firmware(bcm->ucode);
1881 bcm->ucode = NULL;
1882 release_firmware(bcm->pcm);
1883 bcm->pcm = NULL;
1884 release_firmware(bcm->initvals0);
1885 bcm->initvals0 = NULL;
1886 release_firmware(bcm->initvals1);
1887 bcm->initvals1 = NULL;
1888}
1889
1890static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
1891{
1892 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1893 u8 rev = bcm->current_core->rev;
1894 int err = 0;
1895 int nr;
1896 char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
1897
1898 if (!bcm->ucode) {
1899 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
1900 (rev >= 5 ? 5 : rev),
1901 modparam_fwpostfix);
1902 err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
1903 if (err) {
1904 printk(KERN_ERR PFX
1905 "Error: Microcode \"%s\" not available or load failed.\n",
1906 buf);
1907 goto error;
1908 }
1909 }
1910
1911 if (!bcm->pcm) {
1912 snprintf(buf, ARRAY_SIZE(buf),
1913 "bcm43xx_pcm%d%s.fw",
1914 (rev < 5 ? 4 : 5),
1915 modparam_fwpostfix);
1916 err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
1917 if (err) {
1918 printk(KERN_ERR PFX
1919 "Error: PCM \"%s\" not available or load failed.\n",
1920 buf);
1921 goto error;
1922 }
1923 }
1924
1925 if (!bcm->initvals0) {
1926 if (rev == 2 || rev == 4) {
1927 switch (phy->type) {
1928 case BCM43xx_PHYTYPE_A:
1929 nr = 3;
1930 break;
1931 case BCM43xx_PHYTYPE_B:
1932 case BCM43xx_PHYTYPE_G:
1933 nr = 1;
1934 break;
1935 default:
1936 goto err_noinitval;
1937 }
1938
1939 } else if (rev >= 5) {
1940 switch (phy->type) {
1941 case BCM43xx_PHYTYPE_A:
1942 nr = 7;
1943 break;
1944 case BCM43xx_PHYTYPE_B:
1945 case BCM43xx_PHYTYPE_G:
1946 nr = 5;
1947 break;
1948 default:
1949 goto err_noinitval;
1950 }
1951 } else
1952 goto err_noinitval;
1953 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
1954 nr, modparam_fwpostfix);
1955
1956 err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
1957 if (err) {
1958 printk(KERN_ERR PFX
1959 "Error: InitVals \"%s\" not available or load failed.\n",
1960 buf);
1961 goto error;
1962 }
1963 if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
1964 printk(KERN_ERR PFX "InitVals fileformat error.\n");
1965 goto error;
1966 }
1967 }
1968
1969 if (!bcm->initvals1) {
1970 if (rev >= 5) {
1971 u32 sbtmstatehigh;
1972
1973 switch (phy->type) {
1974 case BCM43xx_PHYTYPE_A:
1975 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1976 if (sbtmstatehigh & 0x00010000)
1977 nr = 9;
1978 else
1979 nr = 10;
1980 break;
1981 case BCM43xx_PHYTYPE_B:
1982 case BCM43xx_PHYTYPE_G:
1983 nr = 6;
1984 break;
1985 default:
1986 goto err_noinitval;
1987 }
1988 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
1989 nr, modparam_fwpostfix);
1990
1991 err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
1992 if (err) {
1993 printk(KERN_ERR PFX
1994 "Error: InitVals \"%s\" not available or load failed.\n",
1995 buf);
1996 goto error;
1997 }
1998 if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
1999 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2000 goto error;
2001 }
2002 }
2003 }
2004
2005out:
2006 return err;
2007error:
Michael Buescha4a600d2006-02-01 22:09:52 +01002008 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002009 goto out;
2010err_noinitval:
2011 printk(KERN_ERR PFX "Error: No InitVals available!\n");
2012 err = -ENOENT;
2013 goto error;
2014}
2015
2016static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
2017{
2018 const u32 *data;
2019 unsigned int i, len;
2020
2021#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2022 bcm43xx_mmioprint_enable(bcm);
2023#else
2024 bcm43xx_mmioprint_disable(bcm);
2025#endif
2026
2027 /* Upload Microcode. */
2028 data = (u32 *)(bcm->ucode->data);
2029 len = bcm->ucode->size / sizeof(u32);
2030 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
2031 for (i = 0; i < len; i++) {
2032 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2033 be32_to_cpu(data[i]));
2034 udelay(10);
2035 }
2036
2037 /* Upload PCM data. */
2038 data = (u32 *)(bcm->pcm->data);
2039 len = bcm->pcm->size / sizeof(u32);
2040 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
2041 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
2042 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
2043 for (i = 0; i < len; i++) {
2044 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2045 be32_to_cpu(data[i]));
2046 udelay(10);
2047 }
2048
2049#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2050 bcm43xx_mmioprint_disable(bcm);
2051#else
2052 bcm43xx_mmioprint_enable(bcm);
2053#endif
2054}
2055
Michael Buescha4a600d2006-02-01 22:09:52 +01002056static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,
2057 const struct bcm43xx_initval *data,
2058 const unsigned int len)
John W. Linvillef2223132006-01-23 16:59:58 -05002059{
2060 u16 offset, size;
2061 u32 value;
2062 unsigned int i;
2063
2064 for (i = 0; i < len; i++) {
2065 offset = be16_to_cpu(data[i].offset);
2066 size = be16_to_cpu(data[i].size);
2067 value = be32_to_cpu(data[i].value);
2068
Michael Buescha4a600d2006-02-01 22:09:52 +01002069 if (unlikely(offset >= 0x1000))
2070 goto err_format;
2071 if (size == 2) {
2072 if (unlikely(value & 0xFFFF0000))
2073 goto err_format;
2074 bcm43xx_write16(bcm, offset, (u16)value);
2075 } else if (size == 4) {
John W. Linvillef2223132006-01-23 16:59:58 -05002076 bcm43xx_write32(bcm, offset, value);
Michael Buescha4a600d2006-02-01 22:09:52 +01002077 } else
2078 goto err_format;
John W. Linvillef2223132006-01-23 16:59:58 -05002079 }
Michael Buescha4a600d2006-02-01 22:09:52 +01002080
2081 return 0;
2082
2083err_format:
2084 printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. "
2085 "Please fix your bcm43xx firmware files.\n");
2086 return -EPROTO;
John W. Linvillef2223132006-01-23 16:59:58 -05002087}
2088
Michael Buescha4a600d2006-02-01 22:09:52 +01002089static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002090{
Michael Buescha4a600d2006-02-01 22:09:52 +01002091 int err;
2092
John W. Linvillef2223132006-01-23 16:59:58 -05002093#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2094 bcm43xx_mmioprint_enable(bcm);
2095#else
2096 bcm43xx_mmioprint_disable(bcm);
2097#endif
2098
Michael Buescha4a600d2006-02-01 22:09:52 +01002099 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
2100 bcm->initvals0->size / sizeof(struct bcm43xx_initval));
2101 if (err)
2102 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002103 if (bcm->initvals1) {
Michael Buescha4a600d2006-02-01 22:09:52 +01002104 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
2105 bcm->initvals1->size / sizeof(struct bcm43xx_initval));
2106 if (err)
2107 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002108 }
2109
Michael Buescha4a600d2006-02-01 22:09:52 +01002110out:
John W. Linvillef2223132006-01-23 16:59:58 -05002111#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2112 bcm43xx_mmioprint_disable(bcm);
2113#else
2114 bcm43xx_mmioprint_enable(bcm);
2115#endif
Michael Buescha4a600d2006-02-01 22:09:52 +01002116 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002117}
2118
2119static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
2120{
2121 int res;
2122 unsigned int i;
2123 u32 data;
2124
2125 bcm->irq = bcm->pci_dev->irq;
2126#ifdef CONFIG_BCM947XX
2127 if (bcm->pci_dev->bus->number == 0) {
2128 struct pci_dev *d = NULL;
2129 /* FIXME: we will probably need more device IDs here... */
2130 d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
2131 if (d != NULL) {
2132 bcm->irq = d->irq;
2133 }
2134 }
2135#endif
2136 res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
Michael Buesch65f3f192006-01-31 20:11:38 +01002137 SA_SHIRQ, KBUILD_MODNAME, bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002138 if (res) {
2139 printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
Michael Buesch489423c2006-02-13 00:11:07 +01002140 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002141 }
2142 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
2143 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
2144 i = 0;
2145 while (1) {
2146 data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2147 if (data == BCM43xx_IRQ_READY)
2148 break;
2149 i++;
2150 if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
2151 printk(KERN_ERR PFX "Card IRQ register not responding. "
2152 "Giving up.\n");
2153 free_irq(bcm->irq, bcm);
2154 return -ENODEV;
2155 }
2156 udelay(10);
2157 }
2158 // dummy read
2159 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2160
2161 return 0;
2162}
2163
2164/* Switch to the core used to write the GPIO register.
2165 * This is either the ChipCommon, or the PCI core.
2166 */
Michael Buesch489423c2006-02-13 00:11:07 +01002167static int switch_to_gpio_core(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002168{
2169 int err;
2170
2171 /* Where to find the GPIO register depends on the chipset.
2172 * If it has a ChipCommon, its register at offset 0x6c is the GPIO
2173 * control register. Otherwise the register at offset 0x6c in the
2174 * PCI core is the GPIO control register.
2175 */
2176 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
2177 if (err == -ENODEV) {
2178 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
Michael Buesch489423c2006-02-13 00:11:07 +01002179 if (unlikely(err == -ENODEV)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002180 printk(KERN_ERR PFX "gpio error: "
2181 "Neither ChipCommon nor PCI core available!\n");
2182 return -ENODEV;
Michael Buesch489423c2006-02-13 00:11:07 +01002183 } else if (unlikely(err != 0))
John W. Linvillef2223132006-01-23 16:59:58 -05002184 return -ENODEV;
Michael Buesch489423c2006-02-13 00:11:07 +01002185 } else if (unlikely(err != 0))
John W. Linvillef2223132006-01-23 16:59:58 -05002186 return -ENODEV;
2187
2188 return 0;
2189}
2190
2191/* Initialize the GPIOs
2192 * http://bcm-specs.sipsolutions.net/GPIO
2193 */
2194static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
2195{
2196 struct bcm43xx_coreinfo *old_core;
2197 int err;
2198 u32 mask, value;
2199
2200 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2201 value &= ~0xc000;
2202 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
2203
2204 mask = 0x0000001F;
2205 value = 0x0000000F;
2206 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL,
2207 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0);
2208 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2209 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
2210
2211 old_core = bcm->current_core;
2212
2213 err = switch_to_gpio_core(bcm);
2214 if (err)
2215 return err;
2216
2217 if (bcm->current_core->rev >= 2){
2218 mask |= 0x10;
2219 value |= 0x10;
2220 }
2221 if (bcm->chip_id == 0x4301) {
2222 mask |= 0x60;
2223 value |= 0x60;
2224 }
2225 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
2226 mask |= 0x200;
2227 value |= 0x200;
2228 }
2229
2230 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
2231 (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value);
2232
2233 err = bcm43xx_switch_core(bcm, old_core);
2234 assert(err == 0);
2235
2236 return 0;
2237}
2238
2239/* Turn off all GPIO stuff. Call this on module unload, for example. */
2240static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
2241{
2242 struct bcm43xx_coreinfo *old_core;
2243 int err;
2244
2245 old_core = bcm->current_core;
2246 err = switch_to_gpio_core(bcm);
2247 if (err)
2248 return err;
2249 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);
2250 err = bcm43xx_switch_core(bcm, old_core);
2251 assert(err == 0);
2252
2253 return 0;
2254}
2255
2256/* http://bcm-specs.sipsolutions.net/EnableMac */
2257void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
2258{
2259 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2260 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2261 | BCM43xx_SBF_MAC_ENABLED);
2262 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
2263 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
2264 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2265 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
2266}
2267
2268/* http://bcm-specs.sipsolutions.net/SuspendMAC */
2269void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
2270{
2271 int i;
2272 u32 tmp;
2273
2274 bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
2275 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2276 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2277 & ~BCM43xx_SBF_MAC_ENABLED);
2278 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
Michael Buesch921e4852006-02-08 17:55:55 +01002279 for (i = 100000; i; i--) {
John W. Linvillef2223132006-01-23 16:59:58 -05002280 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch921e4852006-02-08 17:55:55 +01002281 if (tmp & BCM43xx_IRQ_READY)
2282 return;
John W. Linvillef2223132006-01-23 16:59:58 -05002283 udelay(10);
2284 }
Michael Buesch921e4852006-02-08 17:55:55 +01002285 printkl(KERN_ERR PFX "MAC suspend failed\n");
John W. Linvillef2223132006-01-23 16:59:58 -05002286}
2287
2288void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
2289 int iw_mode)
2290{
2291 unsigned long flags;
2292 u32 status;
2293
2294 spin_lock_irqsave(&bcm->ieee->lock, flags);
2295 bcm->ieee->iw_mode = iw_mode;
2296 spin_unlock_irqrestore(&bcm->ieee->lock, flags);
2297 if (iw_mode == IW_MODE_MONITOR)
2298 bcm->net_dev->type = ARPHRD_IEEE80211;
2299 else
2300 bcm->net_dev->type = ARPHRD_ETHER;
2301
2302 if (!bcm->initialized)
2303 return;
2304
2305 bcm43xx_mac_suspend(bcm);
2306 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2307 /* Reset status to infrastructured mode */
2308 status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
2309 /*FIXME: We actually set promiscuous mode as well, until we don't
2310 * get the HW mac filter working */
2311 status |= BCM43xx_SBF_MODE_NOTADHOC | BCM43xx_SBF_MODE_PROMISC;
2312
2313 switch (iw_mode) {
2314 case IW_MODE_MONITOR:
2315 status |= (BCM43xx_SBF_MODE_PROMISC |
2316 BCM43xx_SBF_MODE_MONITOR);
2317 break;
2318 case IW_MODE_ADHOC:
2319 status &= ~BCM43xx_SBF_MODE_NOTADHOC;
2320 break;
2321 case IW_MODE_MASTER:
2322 case IW_MODE_SECOND:
2323 case IW_MODE_REPEAT:
2324 /* TODO: No AP/Repeater mode for now :-/ */
2325 TODO();
2326 break;
2327 case IW_MODE_INFRA:
2328 /* nothing to be done here... */
2329 break;
2330 default:
2331 printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode);
2332 }
2333
2334 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
2335 bcm43xx_mac_enable(bcm);
2336}
2337
2338/* This is the opposite of bcm43xx_chip_init() */
2339static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
2340{
2341 bcm43xx_radio_turn_off(bcm);
2342 if (!modparam_noleds)
2343 bcm43xx_leds_exit(bcm);
2344 bcm43xx_gpio_cleanup(bcm);
2345 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002346 bcm43xx_release_firmware(bcm, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05002347}
2348
2349/* Initialize the chip
2350 * http://bcm-specs.sipsolutions.net/ChipInit
2351 */
2352static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
2353{
2354 int err;
2355 int iw_mode = bcm->ieee->iw_mode;
2356 int tmp;
2357 u32 value32;
2358 u16 value16;
2359
2360 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2361 BCM43xx_SBF_CORE_READY
2362 | BCM43xx_SBF_400);
2363
2364 err = bcm43xx_request_firmware(bcm);
2365 if (err)
2366 goto out;
2367 bcm43xx_upload_microcode(bcm);
2368
2369 err = bcm43xx_initialize_irq(bcm);
2370 if (err)
Michael Buescha4a600d2006-02-01 22:09:52 +01002371 goto err_release_fw;
John W. Linvillef2223132006-01-23 16:59:58 -05002372
2373 err = bcm43xx_gpio_init(bcm);
2374 if (err)
2375 goto err_free_irq;
2376
Michael Buescha4a600d2006-02-01 22:09:52 +01002377 err = bcm43xx_upload_initvals(bcm);
2378 if (err)
2379 goto err_gpio_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002380 bcm43xx_radio_turn_on(bcm);
2381
2382 if (modparam_noleds)
2383 bcm43xx_leds_turn_off(bcm);
2384 else
2385 bcm43xx_leds_update(bcm, 0);
2386
2387 bcm43xx_write16(bcm, 0x03E6, 0x0000);
2388 err = bcm43xx_phy_init(bcm);
2389 if (err)
2390 goto err_radio_off;
2391
2392 /* Select initial Interference Mitigation. */
2393 tmp = bcm->current_core->radio->interfmode;
2394 bcm->current_core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
2395 bcm43xx_radio_set_interference_mitigation(bcm, tmp);
2396
2397 bcm43xx_phy_set_antenna_diversity(bcm);
2398 bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT);
2399 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) {
2400 value16 = bcm43xx_read16(bcm, 0x005E);
2401 value16 |= 0x0004;
2402 bcm43xx_write16(bcm, 0x005E, value16);
2403 }
2404 bcm43xx_write32(bcm, 0x0100, 0x01000000);
2405 if (bcm->current_core->rev < 5)
2406 bcm43xx_write32(bcm, 0x010C, 0x01000000);
2407
2408 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2409 value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC;
2410 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2411 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2412 value32 |= BCM43xx_SBF_MODE_NOTADHOC;
2413 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2414 /*FIXME: For now, use promiscuous mode at all times; otherwise we don't
2415 get broadcast or multicast packets */
2416 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2417 value32 |= BCM43xx_SBF_MODE_PROMISC;
2418 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2419
2420 if (iw_mode == IW_MODE_MONITOR) {
2421 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2422 value32 |= BCM43xx_SBF_MODE_PROMISC;
2423 value32 |= BCM43xx_SBF_MODE_MONITOR;
2424 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2425 }
2426 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2427 value32 |= 0x100000; //FIXME: What's this? Is this correct?
2428 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2429
Michael Buesch77db31e2006-02-12 16:47:44 +01002430 if (bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002431 bcm43xx_write32(bcm, 0x0210, 0x00000100);
2432 bcm43xx_write32(bcm, 0x0230, 0x00000100);
2433 bcm43xx_write32(bcm, 0x0250, 0x00000100);
2434 bcm43xx_write32(bcm, 0x0270, 0x00000100);
2435 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000);
2436 }
2437
2438 /* Probe Response Timeout value */
2439 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2440 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
2441
2442 if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
2443 if ((bcm->chip_id == 0x4306) && (bcm->chip_rev == 3))
2444 bcm43xx_write16(bcm, 0x0612, 0x0064);
2445 else
2446 bcm43xx_write16(bcm, 0x0612, 0x0032);
2447 } else
2448 bcm43xx_write16(bcm, 0x0612, 0x0002);
2449
2450 if (bcm->current_core->rev < 3) {
2451 bcm43xx_write16(bcm, 0x060E, 0x0000);
2452 bcm43xx_write16(bcm, 0x0610, 0x8000);
2453 bcm43xx_write16(bcm, 0x0604, 0x0000);
2454 bcm43xx_write16(bcm, 0x0606, 0x0200);
2455 } else {
2456 bcm43xx_write32(bcm, 0x0188, 0x80000000);
2457 bcm43xx_write32(bcm, 0x018C, 0x02000000);
2458 }
2459 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
2460 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
2461 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2462 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
2463 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
2464
2465 value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
2466 value32 |= 0x00100000;
2467 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
2468
2469 bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
2470
2471 assert(err == 0);
2472 dprintk(KERN_INFO PFX "Chip initialized\n");
2473out:
2474 return err;
2475
2476err_radio_off:
2477 bcm43xx_radio_turn_off(bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002478err_gpio_cleanup:
John W. Linvillef2223132006-01-23 16:59:58 -05002479 bcm43xx_gpio_cleanup(bcm);
2480err_free_irq:
2481 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002482err_release_fw:
2483 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002484 goto out;
2485}
2486
2487/* Validate chip access
2488 * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
2489static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
2490{
John W. Linvillef2223132006-01-23 16:59:58 -05002491 u32 value;
2492 u32 shm_backup;
2493
2494 shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000);
2495 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA);
Michael Buesch489423c2006-02-13 00:11:07 +01002496 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA)
2497 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002498 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
Michael Buesch489423c2006-02-13 00:11:07 +01002499 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55)
2500 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002501 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup);
2502
2503 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
Michael Buesch489423c2006-02-13 00:11:07 +01002504 if ((value | 0x80000000) != 0x80000400)
2505 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002506
2507 value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch489423c2006-02-13 00:11:07 +01002508 if (value != 0x00000000)
2509 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002510
Michael Buesch489423c2006-02-13 00:11:07 +01002511 return 0;
2512error:
2513 printk(KERN_ERR PFX "Failed to validate the chipaccess\n");
2514 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002515}
2516
2517static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
2518{
2519 int err, i;
2520 int current_core;
2521 u32 core_vendor, core_id, core_rev;
2522 u32 sb_id_hi, chip_id_32 = 0;
2523 u16 pci_device, chip_id_16;
2524 u8 core_count;
2525
2526 memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo));
2527 memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo));
2528 memset(&bcm->core_v90, 0, sizeof(struct bcm43xx_coreinfo));
2529 memset(&bcm->core_pcmcia, 0, sizeof(struct bcm43xx_coreinfo));
2530 memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo)
2531 * BCM43xx_MAX_80211_CORES);
2532
2533 memset(&bcm->phy, 0, sizeof(struct bcm43xx_phyinfo)
2534 * BCM43xx_MAX_80211_CORES);
2535 memset(&bcm->radio, 0, sizeof(struct bcm43xx_radioinfo)
2536 * BCM43xx_MAX_80211_CORES);
2537
2538 /* map core 0 */
2539 err = _switch_core(bcm, 0);
2540 if (err)
2541 goto out;
2542
2543 /* fetch sb_id_hi from core information registers */
2544 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2545
2546 core_id = (sb_id_hi & 0xFFF0) >> 4;
2547 core_rev = (sb_id_hi & 0xF);
2548 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2549
2550 /* if present, chipcommon is always core 0; read the chipid from it */
2551 if (core_id == BCM43xx_COREID_CHIPCOMMON) {
2552 chip_id_32 = bcm43xx_read32(bcm, 0);
2553 chip_id_16 = chip_id_32 & 0xFFFF;
2554 bcm->core_chipcommon.flags |= BCM43xx_COREFLAG_AVAILABLE;
2555 bcm->core_chipcommon.id = core_id;
2556 bcm->core_chipcommon.rev = core_rev;
2557 bcm->core_chipcommon.index = 0;
2558 /* While we are at it, also read the capabilities. */
2559 bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES);
2560 } else {
2561 /* without a chipCommon, use a hard coded table. */
2562 pci_device = bcm->pci_dev->device;
2563 if (pci_device == 0x4301)
2564 chip_id_16 = 0x4301;
2565 else if ((pci_device >= 0x4305) && (pci_device <= 0x4307))
2566 chip_id_16 = 0x4307;
2567 else if ((pci_device >= 0x4402) && (pci_device <= 0x4403))
2568 chip_id_16 = 0x4402;
2569 else if ((pci_device >= 0x4610) && (pci_device <= 0x4615))
2570 chip_id_16 = 0x4610;
2571 else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
2572 chip_id_16 = 0x4710;
2573#ifdef CONFIG_BCM947XX
2574 else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
2575 chip_id_16 = 0x4309;
2576#endif
2577 else {
2578 printk(KERN_ERR PFX "Could not determine Chip ID\n");
2579 return -ENODEV;
2580 }
2581 }
2582
2583 /* ChipCommon with Core Rev >=4 encodes number of cores,
2584 * otherwise consult hardcoded table */
2585 if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) {
2586 core_count = (chip_id_32 & 0x0F000000) >> 24;
2587 } else {
2588 switch (chip_id_16) {
2589 case 0x4610:
2590 case 0x4704:
2591 case 0x4710:
2592 core_count = 9;
2593 break;
2594 case 0x4310:
2595 core_count = 8;
2596 break;
2597 case 0x5365:
2598 core_count = 7;
2599 break;
2600 case 0x4306:
2601 core_count = 6;
2602 break;
2603 case 0x4301:
2604 case 0x4307:
2605 core_count = 5;
2606 break;
2607 case 0x4402:
2608 core_count = 3;
2609 break;
2610 default:
2611 /* SOL if we get here */
2612 assert(0);
2613 core_count = 1;
2614 }
2615 }
2616
2617 bcm->chip_id = chip_id_16;
2618 bcm->chip_rev = (chip_id_32 & 0x000f0000) >> 16;
2619
2620 dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
2621 bcm->chip_id, bcm->chip_rev);
2622 dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
2623 if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) {
2624 dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2625 core_id, core_rev, core_vendor,
2626 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
2627 }
2628
2629 if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE)
2630 current_core = 1;
2631 else
2632 current_core = 0;
2633 for ( ; current_core < core_count; current_core++) {
2634 struct bcm43xx_coreinfo *core;
2635
2636 err = _switch_core(bcm, current_core);
2637 if (err)
2638 goto out;
2639 /* Gather information */
2640 /* fetch sb_id_hi from core information registers */
2641 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2642
2643 /* extract core_id, core_rev, core_vendor */
2644 core_id = (sb_id_hi & 0xFFF0) >> 4;
2645 core_rev = (sb_id_hi & 0xF);
2646 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2647
2648 dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2649 current_core, core_id, core_rev, core_vendor,
2650 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
2651
2652 core = NULL;
2653 switch (core_id) {
2654 case BCM43xx_COREID_PCI:
2655 core = &bcm->core_pci;
2656 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2657 printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
2658 continue;
2659 }
2660 break;
2661 case BCM43xx_COREID_V90:
2662 core = &bcm->core_v90;
2663 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2664 printk(KERN_WARNING PFX "Multiple V90 cores found.\n");
2665 continue;
2666 }
2667 break;
2668 case BCM43xx_COREID_PCMCIA:
2669 core = &bcm->core_pcmcia;
2670 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2671 printk(KERN_WARNING PFX "Multiple PCMCIA cores found.\n");
2672 continue;
2673 }
2674 break;
2675 case BCM43xx_COREID_ETHERNET:
2676 core = &bcm->core_ethernet;
2677 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2678 printk(KERN_WARNING PFX "Multiple Ethernet cores found.\n");
2679 continue;
2680 }
2681 break;
2682 case BCM43xx_COREID_80211:
2683 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
2684 core = &(bcm->core_80211[i]);
2685 if (!(core->flags & BCM43xx_COREFLAG_AVAILABLE))
2686 break;
2687 core = NULL;
2688 }
2689 if (!core) {
2690 printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n",
2691 BCM43xx_MAX_80211_CORES);
2692 continue;
2693 }
2694 if (i != 0) {
2695 /* More than one 80211 core is only supported
2696 * by special chips.
2697 * There are chips with two 80211 cores, but with
2698 * dangling pins on the second core. Be careful
2699 * and ignore these cores here.
2700 */
2701 if (bcm->pci_dev->device != 0x4324) {
2702 dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
2703 continue;
2704 }
2705 }
2706 switch (core_rev) {
2707 case 2:
2708 case 4:
2709 case 5:
2710 case 6:
2711 case 7:
2712 case 9:
2713 break;
2714 default:
2715 printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
2716 core_rev);
2717 err = -ENODEV;
2718 goto out;
2719 }
2720 core->phy = &bcm->phy[i];
2721 core->phy->antenna_diversity = 0xffff;
2722 core->phy->savedpctlreg = 0xFFFF;
2723 core->phy->minlowsig[0] = 0xFFFF;
2724 core->phy->minlowsig[1] = 0xFFFF;
2725 core->phy->minlowsigpos[0] = 0;
2726 core->phy->minlowsigpos[1] = 0;
2727 spin_lock_init(&core->phy->lock);
2728 core->radio = &bcm->radio[i];
Michael Bueschab4977f2006-02-12 22:40:39 +01002729 core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
John W. Linvillef2223132006-01-23 16:59:58 -05002730 core->radio->channel = 0xFF;
2731 core->radio->initial_channel = 0xFF;
2732 core->radio->lofcal = 0xFFFF;
2733 core->radio->initval = 0xFFFF;
2734 core->radio->nrssi[0] = -1000;
2735 core->radio->nrssi[1] = -1000;
2736 core->dma = &bcm->dma[i];
2737 core->pio = &bcm->pio[i];
2738 break;
2739 case BCM43xx_COREID_CHIPCOMMON:
2740 printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
2741 break;
2742 default:
2743 printk(KERN_WARNING PFX "Unknown core found (ID 0x%x)\n", core_id);
2744 }
2745 if (core) {
2746 core->flags |= BCM43xx_COREFLAG_AVAILABLE;
2747 core->id = core_id;
2748 core->rev = core_rev;
2749 core->index = current_core;
2750 }
2751 }
2752
2753 if (!(bcm->core_80211[0].flags & BCM43xx_COREFLAG_AVAILABLE)) {
2754 printk(KERN_ERR PFX "Error: No 80211 core found!\n");
2755 err = -ENODEV;
2756 goto out;
2757 }
2758
2759 err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
2760
2761 assert(err == 0);
2762out:
2763 return err;
2764}
2765
2766static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm)
2767{
2768 const u8 *mac = (const u8*)(bcm->net_dev->dev_addr);
2769 u8 *bssid = bcm->ieee->bssid;
2770
2771 switch (bcm->ieee->iw_mode) {
2772 case IW_MODE_ADHOC:
2773 random_ether_addr(bssid);
2774 break;
2775 case IW_MODE_MASTER:
2776 case IW_MODE_INFRA:
2777 case IW_MODE_REPEAT:
2778 case IW_MODE_SECOND:
2779 case IW_MODE_MONITOR:
2780 memcpy(bssid, mac, ETH_ALEN);
2781 break;
2782 default:
2783 assert(0);
2784 }
2785}
2786
2787static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm,
2788 u16 rate,
2789 int is_ofdm)
2790{
2791 u16 offset;
2792
2793 if (is_ofdm) {
2794 offset = 0x480;
2795 offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
2796 }
2797 else {
2798 offset = 0x4C0;
2799 offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
2800 }
2801 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20,
2802 bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset));
2803}
2804
2805static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm)
2806{
2807 switch (bcm->current_core->phy->type) {
2808 case BCM43xx_PHYTYPE_A:
2809 case BCM43xx_PHYTYPE_G:
2810 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1);
2811 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1);
2812 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1);
2813 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1);
2814 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1);
2815 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1);
2816 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1);
2817 case BCM43xx_PHYTYPE_B:
2818 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0);
2819 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0);
2820 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0);
2821 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0);
2822 break;
2823 default:
2824 assert(0);
2825 }
2826}
2827
2828static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
2829{
2830 bcm43xx_chip_cleanup(bcm);
2831 bcm43xx_pio_free(bcm);
2832 bcm43xx_dma_free(bcm);
2833
2834 bcm->current_core->flags &= ~ BCM43xx_COREFLAG_INITIALIZED;
2835}
2836
2837/* http://bcm-specs.sipsolutions.net/80211Init */
2838static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
2839{
2840 u32 ucodeflags;
2841 int err;
2842 u32 sbimconfiglow;
2843 u8 limit;
2844
2845 if (bcm->chip_rev < 5) {
2846 sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
2847 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
2848 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
2849 if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
2850 sbimconfiglow |= 0x32;
2851 else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
2852 sbimconfiglow |= 0x53;
2853 else
2854 assert(0);
2855 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
2856 }
2857
2858 bcm43xx_phy_calibrate(bcm);
2859 err = bcm43xx_chip_init(bcm);
2860 if (err)
2861 goto out;
2862
2863 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
2864 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
2865
2866 if (0 /*FIXME: which condition has to be used here? */)
2867 ucodeflags |= 0x00000010;
2868
2869 /* HW decryption needs to be set now */
2870 ucodeflags |= 0x40000000;
2871
2872 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
2873 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
2874 if (bcm->current_core->phy->rev == 1)
2875 ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
2876 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
2877 ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
2878 } else if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) {
2879 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
2880 if ((bcm->current_core->phy->rev >= 2) &&
2881 (bcm->current_core->radio->version == 0x2050))
2882 ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY;
2883 }
2884
2885 if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
2886 BCM43xx_UCODEFLAGS_OFFSET)) {
2887 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
2888 BCM43xx_UCODEFLAGS_OFFSET, ucodeflags);
2889 }
2890
2891 /* Short/Long Retry Limit.
2892 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
2893 * the chip-internal counter.
2894 */
2895 limit = limit_value(modparam_short_retry, 0, 0xF);
2896 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit);
2897 limit = limit_value(modparam_long_retry, 0, 0xF);
2898 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit);
2899
2900 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3);
2901 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2);
2902
2903 bcm43xx_rate_memory_init(bcm);
2904
2905 /* Minimum Contention Window */
2906 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B)
2907 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f);
2908 else
2909 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f);
2910 /* Maximum Contention Window */
2911 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
2912
2913 bcm43xx_gen_bssid(bcm);
2914 bcm43xx_write_mac_bssid_templates(bcm);
2915
2916 if (bcm->current_core->rev >= 5)
2917 bcm43xx_write16(bcm, 0x043C, 0x000C);
2918
Michael Buesch77db31e2006-02-12 16:47:44 +01002919 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05002920 err = bcm43xx_pio_init(bcm);
Michael Buesch77db31e2006-02-12 16:47:44 +01002921 else
2922 err = bcm43xx_dma_init(bcm);
2923 if (err)
2924 goto err_chip_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002925 bcm43xx_write16(bcm, 0x0612, 0x0050);
2926 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
2927 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
2928
2929 bcm43xx_mac_enable(bcm);
2930 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
2931
2932 bcm->current_core->flags |= BCM43xx_COREFLAG_INITIALIZED;
2933out:
2934 return err;
2935
2936err_chip_cleanup:
2937 bcm43xx_chip_cleanup(bcm);
2938 goto out;
2939}
2940
2941static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
2942{
2943 int err;
2944 u16 pci_status;
2945
2946 err = bcm43xx_pctl_set_crystal(bcm, 1);
2947 if (err)
2948 goto out;
2949 bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
2950 bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
2951
2952out:
2953 return err;
2954}
2955
2956static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm)
2957{
2958 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
2959 bcm43xx_pctl_set_crystal(bcm, 0);
2960}
2961
Michael Buesch489423c2006-02-13 00:11:07 +01002962static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
2963 u32 address,
2964 u32 data)
John W. Linvillef2223132006-01-23 16:59:58 -05002965{
2966 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address);
2967 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data);
2968}
2969
2970static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
2971{
2972 int err;
2973 struct bcm43xx_coreinfo *old_core;
2974
2975 old_core = bcm->current_core;
2976 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2977 if (err)
2978 goto out;
2979
2980 bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
2981
2982 bcm43xx_switch_core(bcm, old_core);
2983 assert(err == 0);
2984out:
2985 return err;
2986}
2987
2988/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
2989 * To enable core 0, pass a core_mask of 1<<0
2990 */
2991static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
2992 u32 core_mask)
2993{
2994 u32 backplane_flag_nr;
2995 u32 value;
2996 struct bcm43xx_coreinfo *old_core;
2997 int err = 0;
2998
2999 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG);
3000 backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK;
3001
3002 old_core = bcm->current_core;
3003 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
3004 if (err)
3005 goto out;
3006
3007 if (bcm->core_pci.rev < 6) {
3008 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
3009 value |= (1 << backplane_flag_nr);
3010 bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
3011 } else {
3012 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value);
3013 if (err) {
3014 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3015 goto out_switch_back;
3016 }
3017 value |= core_mask << 8;
3018 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value);
3019 if (err) {
3020 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3021 goto out_switch_back;
3022 }
3023 }
3024
3025 value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
3026 value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
3027 bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
3028
3029 if (bcm->core_pci.rev < 5) {
3030 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
3031 value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
3032 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
3033 value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
3034 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
3035 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
3036 err = bcm43xx_pcicore_commit_settings(bcm);
3037 assert(err == 0);
3038 }
3039
3040out_switch_back:
3041 err = bcm43xx_switch_core(bcm, old_core);
3042out:
3043 return err;
3044}
3045
3046static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
3047{
3048 ieee80211softmac_start(bcm->net_dev);
3049}
3050
Michael Bueschab4977f2006-02-12 22:40:39 +01003051static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003052{
Michael Bueschab4977f2006-02-12 22:40:39 +01003053 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -05003054
Michael Bueschab4977f2006-02-12 22:40:39 +01003055 if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2)
3056 return;
John W. Linvillef2223132006-01-23 16:59:58 -05003057
Michael Bueschab4977f2006-02-12 22:40:39 +01003058 bcm43xx_mac_suspend(bcm);
3059 bcm43xx_phy_lo_g_measure(bcm);
3060 bcm43xx_mac_enable(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003061}
3062
Michael Bueschab4977f2006-02-12 22:40:39 +01003063static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003064{
John W. Linvillef2223132006-01-23 16:59:58 -05003065 bcm43xx_phy_lo_mark_all_unused(bcm);
3066 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3067 bcm43xx_mac_suspend(bcm);
3068 bcm43xx_calc_nrssi_slope(bcm);
3069 bcm43xx_mac_enable(bcm);
3070 }
John W. Linvillef2223132006-01-23 16:59:58 -05003071}
3072
Michael Bueschab4977f2006-02-12 22:40:39 +01003073static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003074{
John W. Linvillef2223132006-01-23 16:59:58 -05003075 /* Update device statistics. */
3076 bcm43xx_calculate_link_quality(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003077}
John W. Linvillef2223132006-01-23 16:59:58 -05003078
Michael Bueschab4977f2006-02-12 22:40:39 +01003079static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
3080{
3081 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
3082 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
3083
3084 if (phy->type == BCM43xx_PHYTYPE_G) {
3085 //TODO: update_aci_moving_average
3086 if (radio->aci_enable && radio->aci_wlan_automatic) {
3087 bcm43xx_mac_suspend(bcm);
3088 if (!radio->aci_enable && 1 /*TODO: not scanning? */) {
3089 if (0 /*TODO: bunch of conditions*/) {
3090 bcm43xx_radio_set_interference_mitigation(bcm,
3091 BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
3092 }
3093 } else if (1/*TODO*/) {
3094 /*
3095 if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) {
3096 bcm43xx_radio_set_interference_mitigation(bcm,
3097 BCM43xx_RADIO_INTERFMODE_NONE);
3098 }
3099 */
3100 }
3101 bcm43xx_mac_enable(bcm);
3102 } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN &&
3103 phy->rev == 1) {
3104 //TODO: implement rev1 workaround
3105 }
John W. Linvillef2223132006-01-23 16:59:58 -05003106 }
Michael Bueschab4977f2006-02-12 22:40:39 +01003107 bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
3108 //TODO for APHY (temperature?)
3109}
3110
3111static void bcm43xx_periodic_task_handler(unsigned long d)
3112{
3113 struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
3114 unsigned long flags;
3115 unsigned int state;
3116
Michael Bueschefccb642006-03-11 13:39:14 +01003117 bcm43xx_lock_mmio(bcm, flags);
Michael Bueschab4977f2006-02-12 22:40:39 +01003118
3119 assert(bcm->initialized);
3120 state = bcm->periodic_state;
3121 if (state % 8 == 0)
3122 bcm43xx_periodic_every120sec(bcm);
3123 if (state % 4 == 0)
3124 bcm43xx_periodic_every60sec(bcm);
3125 if (state % 2 == 0)
3126 bcm43xx_periodic_every30sec(bcm);
3127 bcm43xx_periodic_every15sec(bcm);
3128 bcm->periodic_state = state + 1;
3129
3130 mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
3131
Michael Bueschefccb642006-03-11 13:39:14 +01003132 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003133}
3134
John W. Linvillef2223132006-01-23 16:59:58 -05003135static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
3136{
Michael Bueschab4977f2006-02-12 22:40:39 +01003137 del_timer_sync(&bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003138}
3139
John W. Linvillef2223132006-01-23 16:59:58 -05003140static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
3141{
Michael Bueschab4977f2006-02-12 22:40:39 +01003142 struct timer_list *timer = &(bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003143
Michael Buesch1d1a73c2006-02-21 18:19:59 +01003144 assert(bcm->initialized);
Michael Bueschab4977f2006-02-12 22:40:39 +01003145 setup_timer(timer,
3146 bcm43xx_periodic_task_handler,
3147 (unsigned long)bcm);
3148 timer->expires = jiffies;
3149 add_timer(timer);
John W. Linvillef2223132006-01-23 16:59:58 -05003150}
3151
3152static void bcm43xx_security_init(struct bcm43xx_private *bcm)
3153{
3154 bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
3155 0x0056) * 2;
3156 bcm43xx_clear_keys(bcm);
3157}
3158
3159/* This is the opposite of bcm43xx_init_board() */
3160static void bcm43xx_free_board(struct bcm43xx_private *bcm)
3161{
3162 int i, err;
3163 unsigned long flags;
3164
Michael Buesch367f8992006-02-28 15:32:19 +01003165 bcm43xx_sysfs_unregister(bcm);
3166
Michael Bueschab4977f2006-02-12 22:40:39 +01003167 bcm43xx_periodic_tasks_delete(bcm);
3168
Michael Bueschefccb642006-03-11 13:39:14 +01003169 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003170 bcm->initialized = 0;
3171 bcm->shutting_down = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003172 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003173
John W. Linvillef2223132006-01-23 16:59:58 -05003174 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3175 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE))
3176 continue;
3177 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED))
3178 continue;
3179
3180 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3181 assert(err == 0);
3182 bcm43xx_wireless_core_cleanup(bcm);
3183 }
3184
3185 bcm43xx_pctl_set_crystal(bcm, 0);
3186
Michael Bueschefccb642006-03-11 13:39:14 +01003187 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003188 bcm->shutting_down = 0;
Michael Bueschefccb642006-03-11 13:39:14 +01003189 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003190}
3191
3192static int bcm43xx_init_board(struct bcm43xx_private *bcm)
3193{
3194 int i, err;
3195 int num_80211_cores;
3196 int connect_phy;
3197 unsigned long flags;
3198
3199 might_sleep();
3200
Michael Bueschefccb642006-03-11 13:39:14 +01003201 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003202 bcm->initialized = 0;
3203 bcm->shutting_down = 0;
Michael Bueschefccb642006-03-11 13:39:14 +01003204 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003205
3206 err = bcm43xx_pctl_set_crystal(bcm, 1);
3207 if (err)
3208 goto out;
3209 err = bcm43xx_pctl_init(bcm);
3210 if (err)
3211 goto err_crystal_off;
3212 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
3213 if (err)
3214 goto err_crystal_off;
3215
3216 tasklet_enable(&bcm->isr_tasklet);
3217 num_80211_cores = bcm43xx_num_80211_cores(bcm);
3218 for (i = 0; i < num_80211_cores; i++) {
3219 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3220 assert(err != -ENODEV);
3221 if (err)
3222 goto err_80211_unwind;
3223
3224 /* Enable the selected wireless core.
3225 * Connect PHY only on the first core.
3226 */
3227 if (!bcm43xx_core_enabled(bcm)) {
3228 if (num_80211_cores == 1) {
3229 connect_phy = bcm->current_core->phy->connected;
3230 } else {
3231 if (i == 0)
3232 connect_phy = 1;
3233 else
3234 connect_phy = 0;
3235 }
3236 bcm43xx_wireless_core_reset(bcm, connect_phy);
3237 }
3238
3239 if (i != 0)
3240 bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
3241
3242 err = bcm43xx_wireless_core_init(bcm);
3243 if (err)
3244 goto err_80211_unwind;
3245
3246 if (i != 0) {
3247 bcm43xx_mac_suspend(bcm);
3248 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3249 bcm43xx_radio_turn_off(bcm);
3250 }
3251 }
3252 bcm->active_80211_core = &bcm->core_80211[0];
3253 if (num_80211_cores >= 2) {
3254 bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
3255 bcm43xx_mac_enable(bcm);
3256 }
3257 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
3258 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
3259 dprintk(KERN_INFO PFX "80211 cores initialized\n");
3260 bcm43xx_security_init(bcm);
3261 bcm43xx_softmac_init(bcm);
3262
3263 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
3264
John W. Linvillef2223132006-01-23 16:59:58 -05003265 if (bcm->current_core->radio->initial_channel != 0xFF) {
3266 bcm43xx_mac_suspend(bcm);
3267 bcm43xx_radio_selectchannel(bcm, bcm->current_core->radio->initial_channel, 0);
3268 bcm43xx_mac_enable(bcm);
3269 }
Michael Bueschcad2b312006-02-21 18:08:55 +01003270
3271 /* Initialization of the board is done. Flag it as such. */
Michael Bueschefccb642006-03-11 13:39:14 +01003272 bcm43xx_lock(bcm, flags);
Michael Bueschcad2b312006-02-21 18:08:55 +01003273 bcm->initialized = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003274 bcm43xx_unlock(bcm, flags);
Michael Bueschcad2b312006-02-21 18:08:55 +01003275
John W. Linvillef2223132006-01-23 16:59:58 -05003276 bcm43xx_periodic_tasks_setup(bcm);
Michael Buesch367f8992006-02-28 15:32:19 +01003277 bcm43xx_sysfs_register(bcm);
3278 //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
John W. Linvillef2223132006-01-23 16:59:58 -05003279
3280 assert(err == 0);
3281out:
3282 return err;
3283
3284err_80211_unwind:
3285 tasklet_disable(&bcm->isr_tasklet);
3286 /* unwind all 80211 initialization */
3287 for (i = 0; i < num_80211_cores; i++) {
3288 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED))
3289 continue;
3290 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3291 bcm43xx_wireless_core_cleanup(bcm);
3292 }
3293err_crystal_off:
3294 bcm43xx_pctl_set_crystal(bcm, 0);
3295 goto out;
3296}
3297
3298static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
3299{
3300 struct pci_dev *pci_dev = bcm->pci_dev;
3301 int i;
3302
3303 bcm43xx_chipset_detach(bcm);
3304 /* Do _not_ access the chip, after it is detached. */
3305 iounmap(bcm->mmio_addr);
3306
3307 pci_release_regions(pci_dev);
3308 pci_disable_device(pci_dev);
3309
3310 /* Free allocated structures/fields */
3311 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3312 kfree(bcm->phy[i]._lo_pairs);
3313 if (bcm->phy[i].dyn_tssi_tbl)
3314 kfree(bcm->phy[i].tssi2dbm);
3315 }
3316}
3317
3318static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
3319{
Michael Buesch489423c2006-02-13 00:11:07 +01003320 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -05003321 u16 value;
3322 u8 phy_version;
3323 u8 phy_type;
3324 u8 phy_rev;
3325 int phy_rev_ok = 1;
3326 void *p;
3327
3328 value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
3329
3330 phy_version = (value & 0xF000) >> 12;
3331 phy_type = (value & 0x0F00) >> 8;
3332 phy_rev = (value & 0x000F);
3333
3334 dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
3335 phy_version, phy_type, phy_rev);
3336
3337 switch (phy_type) {
3338 case BCM43xx_PHYTYPE_A:
3339 if (phy_rev >= 4)
3340 phy_rev_ok = 0;
3341 /*FIXME: We need to switch the ieee->modulation, etc.. flags,
3342 * if we switch 80211 cores after init is done.
3343 * As we do not implement on the fly switching between
3344 * wireless cores, I will leave this as a future task.
3345 */
3346 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION;
3347 bcm->ieee->mode = IEEE_A;
3348 bcm->ieee->freq_band = IEEE80211_52GHZ_BAND |
3349 IEEE80211_24GHZ_BAND;
3350 break;
3351 case BCM43xx_PHYTYPE_B:
3352 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7)
3353 phy_rev_ok = 0;
3354 bcm->ieee->modulation = IEEE80211_CCK_MODULATION;
3355 bcm->ieee->mode = IEEE_B;
3356 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3357 break;
3358 case BCM43xx_PHYTYPE_G:
3359 if (phy_rev > 7)
3360 phy_rev_ok = 0;
3361 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
3362 IEEE80211_CCK_MODULATION;
3363 bcm->ieee->mode = IEEE_G;
3364 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3365 break;
3366 default:
3367 printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n",
3368 phy_type);
3369 return -ENODEV;
3370 };
3371 if (!phy_rev_ok) {
3372 printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
3373 phy_rev);
3374 }
3375
Michael Buesch489423c2006-02-13 00:11:07 +01003376 phy->version = phy_version;
3377 phy->type = phy_type;
3378 phy->rev = phy_rev;
John W. Linvillef2223132006-01-23 16:59:58 -05003379 if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
3380 p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT,
3381 GFP_KERNEL);
3382 if (!p)
3383 return -ENOMEM;
Michael Buesch489423c2006-02-13 00:11:07 +01003384 phy->_lo_pairs = p;
John W. Linvillef2223132006-01-23 16:59:58 -05003385 }
3386
3387 return 0;
3388}
3389
3390static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
3391{
3392 struct pci_dev *pci_dev = bcm->pci_dev;
3393 struct net_device *net_dev = bcm->net_dev;
3394 int err;
3395 int i;
3396 void __iomem *ioaddr;
3397 unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
3398 int num_80211_cores;
3399 u32 coremask;
3400
3401 err = pci_enable_device(pci_dev);
3402 if (err) {
3403 printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
3404 err = -ENODEV;
3405 goto out;
3406 }
3407
3408 mmio_start = pci_resource_start(pci_dev, 0);
3409 mmio_end = pci_resource_end(pci_dev, 0);
3410 mmio_flags = pci_resource_flags(pci_dev, 0);
3411 mmio_len = pci_resource_len(pci_dev, 0);
3412
3413 /* make sure PCI base addr is MMIO */
3414 if (!(mmio_flags & IORESOURCE_MEM)) {
3415 printk(KERN_ERR PFX
3416 "%s, region #0 not an MMIO resource, aborting\n",
3417 pci_name(pci_dev));
3418 err = -ENODEV;
3419 goto err_pci_disable;
3420 }
3421//FIXME: Why is this check disabled for BCM947XX? What is the IO_SIZE there?
3422#ifndef CONFIG_BCM947XX
3423 if (mmio_len != BCM43xx_IO_SIZE) {
3424 printk(KERN_ERR PFX
3425 "%s: invalid PCI mem region size(s), aborting\n",
3426 pci_name(pci_dev));
3427 err = -ENODEV;
3428 goto err_pci_disable;
3429 }
3430#endif
3431
Michael Buesch65f3f192006-01-31 20:11:38 +01003432 err = pci_request_regions(pci_dev, KBUILD_MODNAME);
John W. Linvillef2223132006-01-23 16:59:58 -05003433 if (err) {
3434 printk(KERN_ERR PFX
3435 "could not access PCI resources (%i)\n", err);
3436 goto err_pci_disable;
3437 }
3438
3439 /* enable PCI bus-mastering */
3440 pci_set_master(pci_dev);
3441
3442 /* ioremap MMIO region */
3443 ioaddr = ioremap(mmio_start, mmio_len);
3444 if (!ioaddr) {
3445 printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
3446 pci_name(pci_dev));
3447 err = -EIO;
3448 goto err_pci_release;
3449 }
3450
3451 net_dev->base_addr = (unsigned long)ioaddr;
3452 bcm->mmio_addr = ioaddr;
3453 bcm->mmio_len = mmio_len;
3454
3455 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
3456 &bcm->board_vendor);
3457 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
3458 &bcm->board_type);
3459 bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
3460 &bcm->board_revision);
3461
3462 err = bcm43xx_chipset_attach(bcm);
3463 if (err)
3464 goto err_iounmap;
3465 err = bcm43xx_pctl_init(bcm);
3466 if (err)
3467 goto err_chipset_detach;
3468 err = bcm43xx_probe_cores(bcm);
3469 if (err)
3470 goto err_chipset_detach;
3471
3472 num_80211_cores = bcm43xx_num_80211_cores(bcm);
3473
3474 /* Attach all IO cores to the backplane. */
3475 coremask = 0;
3476 for (i = 0; i < num_80211_cores; i++)
3477 coremask |= (1 << bcm->core_80211[i].index);
3478 //FIXME: Also attach some non80211 cores?
3479 err = bcm43xx_setup_backplane_pci_connection(bcm, coremask);
3480 if (err) {
3481 printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
3482 goto err_chipset_detach;
3483 }
3484
Michael Bueschea0922b2006-02-19 14:09:20 +01003485 err = bcm43xx_sprom_extract(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003486 if (err)
3487 goto err_chipset_detach;
3488 err = bcm43xx_leds_init(bcm);
3489 if (err)
3490 goto err_chipset_detach;
3491
3492 for (i = 0; i < num_80211_cores; i++) {
3493 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3494 assert(err != -ENODEV);
3495 if (err)
3496 goto err_80211_unwind;
3497
3498 /* Enable the selected wireless core.
3499 * Connect PHY only on the first core.
3500 */
3501 bcm43xx_wireless_core_reset(bcm, (i == 0));
3502
3503 err = bcm43xx_read_phyinfo(bcm);
3504 if (err && (i == 0))
3505 goto err_80211_unwind;
3506
3507 err = bcm43xx_read_radioinfo(bcm);
3508 if (err && (i == 0))
3509 goto err_80211_unwind;
3510
3511 err = bcm43xx_validate_chip(bcm);
3512 if (err && (i == 0))
3513 goto err_80211_unwind;
3514
3515 bcm43xx_radio_turn_off(bcm);
3516 err = bcm43xx_phy_init_tssi2dbm_table(bcm);
3517 if (err)
3518 goto err_80211_unwind;
3519 bcm43xx_wireless_core_disable(bcm);
3520 }
3521 bcm43xx_pctl_set_crystal(bcm, 0);
3522
3523 /* Set the MAC address in the networking subsystem */
3524 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
3525 memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
3526 else
3527 memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
3528
3529 bcm43xx_geo_init(bcm);
3530
3531 snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
3532 "Broadcom %04X", bcm->chip_id);
3533
3534 assert(err == 0);
3535out:
3536 return err;
3537
3538err_80211_unwind:
3539 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3540 kfree(bcm->phy[i]._lo_pairs);
3541 if (bcm->phy[i].dyn_tssi_tbl)
3542 kfree(bcm->phy[i].tssi2dbm);
3543 }
3544err_chipset_detach:
3545 bcm43xx_chipset_detach(bcm);
3546err_iounmap:
3547 iounmap(bcm->mmio_addr);
3548err_pci_release:
3549 pci_release_regions(pci_dev);
3550err_pci_disable:
3551 pci_disable_device(pci_dev);
3552 goto out;
3553}
3554
John W. Linvillef2223132006-01-23 16:59:58 -05003555/* Do the Hardware IO operations to send the txb */
3556static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
3557 struct ieee80211_txb *txb)
3558{
3559 int err = -ENODEV;
3560
Michael Buesch77db31e2006-02-12 16:47:44 +01003561 if (bcm43xx_using_pio(bcm))
3562 err = bcm43xx_pio_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003563 else
Michael Bueschea72ab22006-01-27 17:26:20 +01003564 err = bcm43xx_dma_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003565
3566 return err;
3567}
3568
3569static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
3570 u8 channel)
3571{
3572 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3573 unsigned long flags;
3574
Michael Bueschefccb642006-03-11 13:39:14 +01003575 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003576 bcm43xx_mac_suspend(bcm);
3577 bcm43xx_radio_selectchannel(bcm, channel, 0);
3578 bcm43xx_mac_enable(bcm);
Michael Bueschefccb642006-03-11 13:39:14 +01003579 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003580}
3581
3582/* set_security() callback in struct ieee80211_device */
3583static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
3584 struct ieee80211_security *sec)
3585{
3586 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3587 struct ieee80211_security *secinfo = &bcm->ieee->sec;
3588 unsigned long flags;
3589 int keyidx;
3590
3591 dprintk(KERN_INFO PFX "set security called\n");
Michael Bueschefccb642006-03-11 13:39:14 +01003592
3593 bcm43xx_lock_mmio(bcm, flags);
3594
John W. Linvillef2223132006-01-23 16:59:58 -05003595 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
3596 if (sec->flags & (1<<keyidx)) {
3597 secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
3598 secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
3599 memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN);
3600 }
3601
3602 if (sec->flags & SEC_ACTIVE_KEY) {
3603 secinfo->active_key = sec->active_key;
3604 dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key);
3605 }
3606 if (sec->flags & SEC_UNICAST_GROUP) {
3607 secinfo->unicast_uses_group = sec->unicast_uses_group;
3608 dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group);
3609 }
3610 if (sec->flags & SEC_LEVEL) {
3611 secinfo->level = sec->level;
3612 dprintk(KERN_INFO PFX " .level = %d\n", sec->level);
3613 }
3614 if (sec->flags & SEC_ENABLED) {
3615 secinfo->enabled = sec->enabled;
3616 dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled);
3617 }
3618 if (sec->flags & SEC_ENCRYPT) {
3619 secinfo->encrypt = sec->encrypt;
3620 dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt);
3621 }
3622 if (bcm->initialized && !bcm->ieee->host_encrypt) {
3623 if (secinfo->enabled) {
3624 /* upload WEP keys to hardware */
3625 char null_address[6] = { 0 };
3626 u8 algorithm = 0;
3627 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
3628 if (!(sec->flags & (1<<keyidx)))
3629 continue;
3630 switch (sec->encode_alg[keyidx]) {
3631 case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
3632 case SEC_ALG_WEP:
3633 algorithm = BCM43xx_SEC_ALGO_WEP;
3634 if (secinfo->key_sizes[keyidx] == 13)
3635 algorithm = BCM43xx_SEC_ALGO_WEP104;
3636 break;
3637 case SEC_ALG_TKIP:
3638 FIXME();
3639 algorithm = BCM43xx_SEC_ALGO_TKIP;
3640 break;
3641 case SEC_ALG_CCMP:
3642 FIXME();
3643 algorithm = BCM43xx_SEC_ALGO_AES;
3644 break;
3645 default:
3646 assert(0);
3647 break;
3648 }
3649 bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
3650 bcm->key[keyidx].enabled = 1;
3651 bcm->key[keyidx].algorithm = algorithm;
3652 }
3653 } else
3654 bcm43xx_clear_keys(bcm);
3655 }
Michael Bueschefccb642006-03-11 13:39:14 +01003656 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003657}
3658
3659/* hard_start_xmit() callback in struct ieee80211_device */
3660static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
3661 struct net_device *net_dev,
3662 int pri)
3663{
3664 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3665 int err = -ENODEV;
3666 unsigned long flags;
3667
Michael Bueschefccb642006-03-11 13:39:14 +01003668 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003669 if (likely(bcm->initialized))
3670 err = bcm43xx_tx(bcm, txb);
Michael Bueschefccb642006-03-11 13:39:14 +01003671 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003672
3673 return err;
3674}
3675
3676static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
3677{
3678 return &(bcm43xx_priv(net_dev)->ieee->stats);
3679}
3680
3681static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
3682{
3683 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Bueschefccb642006-03-11 13:39:14 +01003684 unsigned long flags;
John W. Linvillef2223132006-01-23 16:59:58 -05003685
Michael Bueschefccb642006-03-11 13:39:14 +01003686 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003687 bcm43xx_controller_restart(bcm, "TX timeout");
Michael Bueschefccb642006-03-11 13:39:14 +01003688 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003689}
3690
3691#ifdef CONFIG_NET_POLL_CONTROLLER
3692static void bcm43xx_net_poll_controller(struct net_device *net_dev)
3693{
3694 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3695 unsigned long flags;
3696
3697 local_irq_save(flags);
3698 bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
3699 local_irq_restore(flags);
3700}
3701#endif /* CONFIG_NET_POLL_CONTROLLER */
3702
3703static int bcm43xx_net_open(struct net_device *net_dev)
3704{
3705 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3706
3707 return bcm43xx_init_board(bcm);
3708}
3709
3710static int bcm43xx_net_stop(struct net_device *net_dev)
3711{
3712 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3713
3714 ieee80211softmac_stop(net_dev);
3715 bcm43xx_disable_interrupts_sync(bcm, NULL);
3716 bcm43xx_free_board(bcm);
3717
3718 return 0;
3719}
3720
Michael Buesch77db31e2006-02-12 16:47:44 +01003721static int bcm43xx_init_private(struct bcm43xx_private *bcm,
3722 struct net_device *net_dev,
Michael Bueschab4977f2006-02-12 22:40:39 +01003723 struct pci_dev *pci_dev)
John W. Linvillef2223132006-01-23 16:59:58 -05003724{
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003725 int err;
3726
John W. Linvillef2223132006-01-23 16:59:58 -05003727 bcm->ieee = netdev_priv(net_dev);
3728 bcm->softmac = ieee80211_priv(net_dev);
3729 bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
John W. Linvillef2223132006-01-23 16:59:58 -05003730
3731#ifdef DEBUG_ENABLE_MMIO_PRINT
3732 bcm43xx_mmioprint_initial(bcm, 1);
3733#else
3734 bcm43xx_mmioprint_initial(bcm, 0);
3735#endif
3736#ifdef DEBUG_ENABLE_PCILOG
3737 bcm43xx_pciprint_initial(bcm, 1);
3738#else
3739 bcm43xx_pciprint_initial(bcm, 0);
3740#endif
3741
3742 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3743 bcm->pci_dev = pci_dev;
3744 bcm->net_dev = net_dev;
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003745 bcm->bad_frames_preempt = modparam_bad_frames_preempt;
Michael Bueschefccb642006-03-11 13:39:14 +01003746 spin_lock_init(&bcm->_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05003747 tasklet_init(&bcm->isr_tasklet,
3748 (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
3749 (unsigned long)bcm);
3750 tasklet_disable_nosync(&bcm->isr_tasklet);
3751 if (modparam_pio) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003752 bcm->__using_pio = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05003753 } else {
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003754 err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
3755 err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
3756 if (err) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003757#ifdef CONFIG_BCM43XX_PIO
John W. Linvillef2223132006-01-23 16:59:58 -05003758 printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
Michael Buesch77db31e2006-02-12 16:47:44 +01003759 bcm->__using_pio = 1;
3760#else
3761 printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
3762 "Recompile the driver with PIO support, please.\n");
3763 return -ENODEV;
3764#endif /* CONFIG_BCM43XX_PIO */
John W. Linvillef2223132006-01-23 16:59:58 -05003765 }
3766 }
3767 bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
3768
3769 /* default to sw encryption for now */
3770 bcm->ieee->host_build_iv = 0;
3771 bcm->ieee->host_encrypt = 1;
3772 bcm->ieee->host_decrypt = 1;
3773
3774 bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
3775 bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
3776 bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
3777 bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
Michael Buesch77db31e2006-02-12 16:47:44 +01003778
3779 return 0;
John W. Linvillef2223132006-01-23 16:59:58 -05003780}
3781
3782static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
3783 const struct pci_device_id *ent)
3784{
3785 struct net_device *net_dev;
3786 struct bcm43xx_private *bcm;
John W. Linvillef2223132006-01-23 16:59:58 -05003787 int err;
3788
3789#ifdef CONFIG_BCM947XX
3790 if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
3791 return -ENODEV;
3792#endif
3793
3794#ifdef DEBUG_SINGLE_DEVICE_ONLY
3795 if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
3796 return -ENODEV;
3797#endif
3798
3799 net_dev = alloc_ieee80211softmac(sizeof(*bcm));
3800 if (!net_dev) {
3801 printk(KERN_ERR PFX
3802 "could not allocate ieee80211 device %s\n",
3803 pci_name(pdev));
3804 err = -ENOMEM;
3805 goto out;
3806 }
3807 /* initialize the net_device struct */
3808 SET_MODULE_OWNER(net_dev);
3809 SET_NETDEV_DEV(net_dev, &pdev->dev);
3810
3811 net_dev->open = bcm43xx_net_open;
3812 net_dev->stop = bcm43xx_net_stop;
3813 net_dev->get_stats = bcm43xx_net_get_stats;
3814 net_dev->tx_timeout = bcm43xx_net_tx_timeout;
3815#ifdef CONFIG_NET_POLL_CONTROLLER
3816 net_dev->poll_controller = bcm43xx_net_poll_controller;
3817#endif
3818 net_dev->wireless_handlers = &bcm43xx_wx_handlers_def;
3819 net_dev->irq = pdev->irq;
Michael Buesch6465ce12006-02-02 19:11:08 +01003820 SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops);
John W. Linvillef2223132006-01-23 16:59:58 -05003821
3822 /* initialize the bcm43xx_private struct */
3823 bcm = bcm43xx_priv(net_dev);
3824 memset(bcm, 0, sizeof(*bcm));
Michael Bueschab4977f2006-02-12 22:40:39 +01003825 err = bcm43xx_init_private(bcm, net_dev, pdev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003826 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003827 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003828
3829 pci_set_drvdata(pdev, net_dev);
3830
3831 err = bcm43xx_attach_board(bcm);
3832 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003833 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003834
3835 err = register_netdev(net_dev);
3836 if (err) {
3837 printk(KERN_ERR PFX "Cannot register net device, "
3838 "aborting.\n");
3839 err = -ENOMEM;
3840 goto err_detach_board;
3841 }
3842
3843 bcm43xx_debugfs_add_device(bcm);
3844
3845 assert(err == 0);
3846out:
3847 return err;
3848
3849err_detach_board:
3850 bcm43xx_detach_board(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003851err_free_netdev:
3852 free_ieee80211softmac(net_dev);
3853 goto out;
3854}
3855
3856static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
3857{
3858 struct net_device *net_dev = pci_get_drvdata(pdev);
3859 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3860
3861 bcm43xx_debugfs_remove_device(bcm);
3862 unregister_netdev(net_dev);
3863 bcm43xx_detach_board(bcm);
3864 assert(bcm->ucode == NULL);
John W. Linvillef2223132006-01-23 16:59:58 -05003865 free_ieee80211softmac(net_dev);
3866}
3867
3868/* Hard-reset the chip. Do not call this directly.
3869 * Use bcm43xx_controller_restart()
3870 */
3871static void bcm43xx_chip_reset(void *_bcm)
3872{
3873 struct bcm43xx_private *bcm = _bcm;
3874 struct net_device *net_dev = bcm->net_dev;
3875 struct pci_dev *pci_dev = bcm->pci_dev;
John W. Linvillef2223132006-01-23 16:59:58 -05003876 int err;
3877 int was_initialized = bcm->initialized;
3878
3879 netif_stop_queue(bcm->net_dev);
3880 tasklet_disable(&bcm->isr_tasklet);
3881
3882 bcm->firmware_norelease = 1;
3883 if (was_initialized)
3884 bcm43xx_free_board(bcm);
3885 bcm->firmware_norelease = 0;
3886 bcm43xx_detach_board(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003887 err = bcm43xx_init_private(bcm, net_dev, pci_dev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003888 if (err)
3889 goto failure;
John W. Linvillef2223132006-01-23 16:59:58 -05003890 err = bcm43xx_attach_board(bcm);
3891 if (err)
3892 goto failure;
3893 if (was_initialized) {
3894 err = bcm43xx_init_board(bcm);
3895 if (err)
3896 goto failure;
3897 }
3898 netif_wake_queue(bcm->net_dev);
3899 printk(KERN_INFO PFX "Controller restarted\n");
3900
3901 return;
3902failure:
3903 printk(KERN_ERR PFX "Controller restart failed\n");
3904}
3905
3906/* Hard-reset the chip.
3907 * This can be called from interrupt or process context.
3908 * Make sure to _not_ re-enable device interrupts after this has been called.
3909*/
3910void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
3911{
3912 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3913 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
3914 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003915 schedule_work(&bcm->restart_work);
John W. Linvillef2223132006-01-23 16:59:58 -05003916}
3917
3918#ifdef CONFIG_PM
3919
3920static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
3921{
3922 struct net_device *net_dev = pci_get_drvdata(pdev);
3923 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3924 unsigned long flags;
3925 int try_to_shutdown = 0, err;
3926
3927 dprintk(KERN_INFO PFX "Suspending...\n");
3928
Michael Bueschefccb642006-03-11 13:39:14 +01003929 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003930 bcm->was_initialized = bcm->initialized;
3931 if (bcm->initialized)
3932 try_to_shutdown = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003933 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003934
3935 netif_device_detach(net_dev);
3936 if (try_to_shutdown) {
3937 ieee80211softmac_stop(net_dev);
3938 err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
3939 if (unlikely(err)) {
3940 dprintk(KERN_ERR PFX "Suspend failed.\n");
3941 return -EAGAIN;
3942 }
3943 bcm->firmware_norelease = 1;
3944 bcm43xx_free_board(bcm);
3945 bcm->firmware_norelease = 0;
3946 }
3947 bcm43xx_chipset_detach(bcm);
3948
3949 pci_save_state(pdev);
3950 pci_disable_device(pdev);
3951 pci_set_power_state(pdev, pci_choose_state(pdev, state));
3952
3953 dprintk(KERN_INFO PFX "Device suspended.\n");
3954
3955 return 0;
3956}
3957
3958static int bcm43xx_resume(struct pci_dev *pdev)
3959{
3960 struct net_device *net_dev = pci_get_drvdata(pdev);
3961 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3962 int err = 0;
3963
3964 dprintk(KERN_INFO PFX "Resuming...\n");
3965
3966 pci_set_power_state(pdev, 0);
3967 pci_enable_device(pdev);
3968 pci_restore_state(pdev);
3969
3970 bcm43xx_chipset_attach(bcm);
3971 if (bcm->was_initialized) {
3972 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3973 err = bcm43xx_init_board(bcm);
3974 }
3975 if (err) {
3976 printk(KERN_ERR PFX "Resume failed!\n");
3977 return err;
3978 }
3979
3980 netif_device_attach(net_dev);
3981
3982 /*FIXME: This should be handled by softmac instead. */
3983 schedule_work(&bcm->softmac->associnfo.work);
3984
3985 dprintk(KERN_INFO PFX "Device resumed.\n");
3986
3987 return 0;
3988}
3989
3990#endif /* CONFIG_PM */
3991
3992static struct pci_driver bcm43xx_pci_driver = {
Michael Buesch65f3f192006-01-31 20:11:38 +01003993 .name = KBUILD_MODNAME,
John W. Linvillef2223132006-01-23 16:59:58 -05003994 .id_table = bcm43xx_pci_tbl,
3995 .probe = bcm43xx_init_one,
3996 .remove = __devexit_p(bcm43xx_remove_one),
3997#ifdef CONFIG_PM
3998 .suspend = bcm43xx_suspend,
3999 .resume = bcm43xx_resume,
4000#endif /* CONFIG_PM */
4001};
4002
4003static int __init bcm43xx_init(void)
4004{
Michael Buesch65f3f192006-01-31 20:11:38 +01004005 printk(KERN_INFO KBUILD_MODNAME " driver\n");
John W. Linvillef2223132006-01-23 16:59:58 -05004006 bcm43xx_debugfs_init();
4007 return pci_register_driver(&bcm43xx_pci_driver);
4008}
4009
4010static void __exit bcm43xx_exit(void)
4011{
4012 pci_unregister_driver(&bcm43xx_pci_driver);
4013 bcm43xx_debugfs_exit();
4014}
4015
4016module_init(bcm43xx_init)
4017module_exit(bcm43xx_exit)
4018
4019/* vim: set ts=8 sw=8 sts=8: */