blob: f3cef345c8f9d72c2ce6bf559446adf187fffb18 [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
John W. Linvillef2223132006-01-23 16:59:58 -05002021 /* Upload Microcode. */
2022 data = (u32 *)(bcm->ucode->data);
2023 len = bcm->ucode->size / sizeof(u32);
2024 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
2025 for (i = 0; i < len; i++) {
2026 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2027 be32_to_cpu(data[i]));
2028 udelay(10);
2029 }
2030
2031 /* Upload PCM data. */
2032 data = (u32 *)(bcm->pcm->data);
2033 len = bcm->pcm->size / sizeof(u32);
2034 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
2035 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
2036 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
2037 for (i = 0; i < len; i++) {
2038 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2039 be32_to_cpu(data[i]));
2040 udelay(10);
2041 }
John W. Linvillef2223132006-01-23 16:59:58 -05002042}
2043
Michael Buescha4a600d2006-02-01 22:09:52 +01002044static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,
2045 const struct bcm43xx_initval *data,
2046 const unsigned int len)
John W. Linvillef2223132006-01-23 16:59:58 -05002047{
2048 u16 offset, size;
2049 u32 value;
2050 unsigned int i;
2051
2052 for (i = 0; i < len; i++) {
2053 offset = be16_to_cpu(data[i].offset);
2054 size = be16_to_cpu(data[i].size);
2055 value = be32_to_cpu(data[i].value);
2056
Michael Buescha4a600d2006-02-01 22:09:52 +01002057 if (unlikely(offset >= 0x1000))
2058 goto err_format;
2059 if (size == 2) {
2060 if (unlikely(value & 0xFFFF0000))
2061 goto err_format;
2062 bcm43xx_write16(bcm, offset, (u16)value);
2063 } else if (size == 4) {
John W. Linvillef2223132006-01-23 16:59:58 -05002064 bcm43xx_write32(bcm, offset, value);
Michael Buescha4a600d2006-02-01 22:09:52 +01002065 } else
2066 goto err_format;
John W. Linvillef2223132006-01-23 16:59:58 -05002067 }
Michael Buescha4a600d2006-02-01 22:09:52 +01002068
2069 return 0;
2070
2071err_format:
2072 printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. "
2073 "Please fix your bcm43xx firmware files.\n");
2074 return -EPROTO;
John W. Linvillef2223132006-01-23 16:59:58 -05002075}
2076
Michael Buescha4a600d2006-02-01 22:09:52 +01002077static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002078{
Michael Buescha4a600d2006-02-01 22:09:52 +01002079 int err;
2080
Michael Buescha4a600d2006-02-01 22:09:52 +01002081 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
2082 bcm->initvals0->size / sizeof(struct bcm43xx_initval));
2083 if (err)
2084 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002085 if (bcm->initvals1) {
Michael Buescha4a600d2006-02-01 22:09:52 +01002086 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
2087 bcm->initvals1->size / sizeof(struct bcm43xx_initval));
2088 if (err)
2089 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002090 }
Michael Buescha4a600d2006-02-01 22:09:52 +01002091out:
Michael Buescha4a600d2006-02-01 22:09:52 +01002092 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002093}
2094
2095static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
2096{
2097 int res;
2098 unsigned int i;
2099 u32 data;
2100
2101 bcm->irq = bcm->pci_dev->irq;
2102#ifdef CONFIG_BCM947XX
2103 if (bcm->pci_dev->bus->number == 0) {
2104 struct pci_dev *d = NULL;
2105 /* FIXME: we will probably need more device IDs here... */
2106 d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
2107 if (d != NULL) {
2108 bcm->irq = d->irq;
2109 }
2110 }
2111#endif
2112 res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
Michael Buesch65f3f192006-01-31 20:11:38 +01002113 SA_SHIRQ, KBUILD_MODNAME, bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002114 if (res) {
2115 printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
Michael Buesch489423c2006-02-13 00:11:07 +01002116 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002117 }
2118 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
2119 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
2120 i = 0;
2121 while (1) {
2122 data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2123 if (data == BCM43xx_IRQ_READY)
2124 break;
2125 i++;
2126 if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
2127 printk(KERN_ERR PFX "Card IRQ register not responding. "
2128 "Giving up.\n");
2129 free_irq(bcm->irq, bcm);
2130 return -ENODEV;
2131 }
2132 udelay(10);
2133 }
2134 // dummy read
2135 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2136
2137 return 0;
2138}
2139
2140/* Switch to the core used to write the GPIO register.
2141 * This is either the ChipCommon, or the PCI core.
2142 */
Michael Buesch489423c2006-02-13 00:11:07 +01002143static int switch_to_gpio_core(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002144{
2145 int err;
2146
2147 /* Where to find the GPIO register depends on the chipset.
2148 * If it has a ChipCommon, its register at offset 0x6c is the GPIO
2149 * control register. Otherwise the register at offset 0x6c in the
2150 * PCI core is the GPIO control register.
2151 */
2152 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
2153 if (err == -ENODEV) {
2154 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
Michael Buesch489423c2006-02-13 00:11:07 +01002155 if (unlikely(err == -ENODEV)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002156 printk(KERN_ERR PFX "gpio error: "
2157 "Neither ChipCommon nor PCI core available!\n");
2158 return -ENODEV;
Michael Buesch489423c2006-02-13 00:11:07 +01002159 } else if (unlikely(err != 0))
John W. Linvillef2223132006-01-23 16:59:58 -05002160 return -ENODEV;
Michael Buesch489423c2006-02-13 00:11:07 +01002161 } else if (unlikely(err != 0))
John W. Linvillef2223132006-01-23 16:59:58 -05002162 return -ENODEV;
2163
2164 return 0;
2165}
2166
2167/* Initialize the GPIOs
2168 * http://bcm-specs.sipsolutions.net/GPIO
2169 */
2170static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
2171{
2172 struct bcm43xx_coreinfo *old_core;
2173 int err;
2174 u32 mask, value;
2175
2176 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2177 value &= ~0xc000;
2178 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
2179
2180 mask = 0x0000001F;
2181 value = 0x0000000F;
2182 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL,
2183 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0);
2184 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2185 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
2186
2187 old_core = bcm->current_core;
2188
2189 err = switch_to_gpio_core(bcm);
2190 if (err)
2191 return err;
2192
2193 if (bcm->current_core->rev >= 2){
2194 mask |= 0x10;
2195 value |= 0x10;
2196 }
2197 if (bcm->chip_id == 0x4301) {
2198 mask |= 0x60;
2199 value |= 0x60;
2200 }
2201 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
2202 mask |= 0x200;
2203 value |= 0x200;
2204 }
2205
2206 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
2207 (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value);
2208
2209 err = bcm43xx_switch_core(bcm, old_core);
2210 assert(err == 0);
2211
2212 return 0;
2213}
2214
2215/* Turn off all GPIO stuff. Call this on module unload, for example. */
2216static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
2217{
2218 struct bcm43xx_coreinfo *old_core;
2219 int err;
2220
2221 old_core = bcm->current_core;
2222 err = switch_to_gpio_core(bcm);
2223 if (err)
2224 return err;
2225 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);
2226 err = bcm43xx_switch_core(bcm, old_core);
2227 assert(err == 0);
2228
2229 return 0;
2230}
2231
2232/* http://bcm-specs.sipsolutions.net/EnableMac */
2233void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
2234{
2235 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2236 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2237 | BCM43xx_SBF_MAC_ENABLED);
2238 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
2239 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
2240 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2241 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
2242}
2243
2244/* http://bcm-specs.sipsolutions.net/SuspendMAC */
2245void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
2246{
2247 int i;
2248 u32 tmp;
2249
2250 bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
2251 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2252 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2253 & ~BCM43xx_SBF_MAC_ENABLED);
2254 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
Michael Buesch921e4852006-02-08 17:55:55 +01002255 for (i = 100000; i; i--) {
John W. Linvillef2223132006-01-23 16:59:58 -05002256 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch921e4852006-02-08 17:55:55 +01002257 if (tmp & BCM43xx_IRQ_READY)
2258 return;
John W. Linvillef2223132006-01-23 16:59:58 -05002259 udelay(10);
2260 }
Michael Buesch921e4852006-02-08 17:55:55 +01002261 printkl(KERN_ERR PFX "MAC suspend failed\n");
John W. Linvillef2223132006-01-23 16:59:58 -05002262}
2263
2264void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
2265 int iw_mode)
2266{
2267 unsigned long flags;
2268 u32 status;
2269
2270 spin_lock_irqsave(&bcm->ieee->lock, flags);
2271 bcm->ieee->iw_mode = iw_mode;
2272 spin_unlock_irqrestore(&bcm->ieee->lock, flags);
2273 if (iw_mode == IW_MODE_MONITOR)
2274 bcm->net_dev->type = ARPHRD_IEEE80211;
2275 else
2276 bcm->net_dev->type = ARPHRD_ETHER;
2277
2278 if (!bcm->initialized)
2279 return;
2280
2281 bcm43xx_mac_suspend(bcm);
2282 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2283 /* Reset status to infrastructured mode */
2284 status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
2285 /*FIXME: We actually set promiscuous mode as well, until we don't
2286 * get the HW mac filter working */
2287 status |= BCM43xx_SBF_MODE_NOTADHOC | BCM43xx_SBF_MODE_PROMISC;
2288
2289 switch (iw_mode) {
2290 case IW_MODE_MONITOR:
2291 status |= (BCM43xx_SBF_MODE_PROMISC |
2292 BCM43xx_SBF_MODE_MONITOR);
2293 break;
2294 case IW_MODE_ADHOC:
2295 status &= ~BCM43xx_SBF_MODE_NOTADHOC;
2296 break;
2297 case IW_MODE_MASTER:
2298 case IW_MODE_SECOND:
2299 case IW_MODE_REPEAT:
2300 /* TODO: No AP/Repeater mode for now :-/ */
2301 TODO();
2302 break;
2303 case IW_MODE_INFRA:
2304 /* nothing to be done here... */
2305 break;
2306 default:
2307 printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode);
2308 }
2309
2310 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
2311 bcm43xx_mac_enable(bcm);
2312}
2313
2314/* This is the opposite of bcm43xx_chip_init() */
2315static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
2316{
2317 bcm43xx_radio_turn_off(bcm);
2318 if (!modparam_noleds)
2319 bcm43xx_leds_exit(bcm);
2320 bcm43xx_gpio_cleanup(bcm);
2321 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002322 bcm43xx_release_firmware(bcm, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05002323}
2324
2325/* Initialize the chip
2326 * http://bcm-specs.sipsolutions.net/ChipInit
2327 */
2328static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
2329{
2330 int err;
2331 int iw_mode = bcm->ieee->iw_mode;
2332 int tmp;
2333 u32 value32;
2334 u16 value16;
2335
2336 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2337 BCM43xx_SBF_CORE_READY
2338 | BCM43xx_SBF_400);
2339
2340 err = bcm43xx_request_firmware(bcm);
2341 if (err)
2342 goto out;
2343 bcm43xx_upload_microcode(bcm);
2344
2345 err = bcm43xx_initialize_irq(bcm);
2346 if (err)
Michael Buescha4a600d2006-02-01 22:09:52 +01002347 goto err_release_fw;
John W. Linvillef2223132006-01-23 16:59:58 -05002348
2349 err = bcm43xx_gpio_init(bcm);
2350 if (err)
2351 goto err_free_irq;
2352
Michael Buescha4a600d2006-02-01 22:09:52 +01002353 err = bcm43xx_upload_initvals(bcm);
2354 if (err)
2355 goto err_gpio_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002356 bcm43xx_radio_turn_on(bcm);
2357
2358 if (modparam_noleds)
2359 bcm43xx_leds_turn_off(bcm);
2360 else
2361 bcm43xx_leds_update(bcm, 0);
2362
2363 bcm43xx_write16(bcm, 0x03E6, 0x0000);
2364 err = bcm43xx_phy_init(bcm);
2365 if (err)
2366 goto err_radio_off;
2367
2368 /* Select initial Interference Mitigation. */
2369 tmp = bcm->current_core->radio->interfmode;
2370 bcm->current_core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
2371 bcm43xx_radio_set_interference_mitigation(bcm, tmp);
2372
2373 bcm43xx_phy_set_antenna_diversity(bcm);
2374 bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT);
2375 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) {
2376 value16 = bcm43xx_read16(bcm, 0x005E);
2377 value16 |= 0x0004;
2378 bcm43xx_write16(bcm, 0x005E, value16);
2379 }
2380 bcm43xx_write32(bcm, 0x0100, 0x01000000);
2381 if (bcm->current_core->rev < 5)
2382 bcm43xx_write32(bcm, 0x010C, 0x01000000);
2383
2384 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2385 value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC;
2386 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2387 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2388 value32 |= BCM43xx_SBF_MODE_NOTADHOC;
2389 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2390 /*FIXME: For now, use promiscuous mode at all times; otherwise we don't
2391 get broadcast or multicast packets */
2392 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2393 value32 |= BCM43xx_SBF_MODE_PROMISC;
2394 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2395
2396 if (iw_mode == IW_MODE_MONITOR) {
2397 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2398 value32 |= BCM43xx_SBF_MODE_PROMISC;
2399 value32 |= BCM43xx_SBF_MODE_MONITOR;
2400 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2401 }
2402 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2403 value32 |= 0x100000; //FIXME: What's this? Is this correct?
2404 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2405
Michael Buesch77db31e2006-02-12 16:47:44 +01002406 if (bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002407 bcm43xx_write32(bcm, 0x0210, 0x00000100);
2408 bcm43xx_write32(bcm, 0x0230, 0x00000100);
2409 bcm43xx_write32(bcm, 0x0250, 0x00000100);
2410 bcm43xx_write32(bcm, 0x0270, 0x00000100);
2411 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000);
2412 }
2413
2414 /* Probe Response Timeout value */
2415 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2416 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
2417
2418 if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
2419 if ((bcm->chip_id == 0x4306) && (bcm->chip_rev == 3))
2420 bcm43xx_write16(bcm, 0x0612, 0x0064);
2421 else
2422 bcm43xx_write16(bcm, 0x0612, 0x0032);
2423 } else
2424 bcm43xx_write16(bcm, 0x0612, 0x0002);
2425
2426 if (bcm->current_core->rev < 3) {
2427 bcm43xx_write16(bcm, 0x060E, 0x0000);
2428 bcm43xx_write16(bcm, 0x0610, 0x8000);
2429 bcm43xx_write16(bcm, 0x0604, 0x0000);
2430 bcm43xx_write16(bcm, 0x0606, 0x0200);
2431 } else {
2432 bcm43xx_write32(bcm, 0x0188, 0x80000000);
2433 bcm43xx_write32(bcm, 0x018C, 0x02000000);
2434 }
2435 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
2436 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
2437 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2438 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
2439 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
2440
2441 value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
2442 value32 |= 0x00100000;
2443 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
2444
2445 bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
2446
2447 assert(err == 0);
2448 dprintk(KERN_INFO PFX "Chip initialized\n");
2449out:
2450 return err;
2451
2452err_radio_off:
2453 bcm43xx_radio_turn_off(bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002454err_gpio_cleanup:
John W. Linvillef2223132006-01-23 16:59:58 -05002455 bcm43xx_gpio_cleanup(bcm);
2456err_free_irq:
2457 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002458err_release_fw:
2459 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002460 goto out;
2461}
2462
2463/* Validate chip access
2464 * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
2465static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
2466{
John W. Linvillef2223132006-01-23 16:59:58 -05002467 u32 value;
2468 u32 shm_backup;
2469
2470 shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000);
2471 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA);
Michael Buesch489423c2006-02-13 00:11:07 +01002472 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA)
2473 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002474 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
Michael Buesch489423c2006-02-13 00:11:07 +01002475 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55)
2476 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002477 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup);
2478
2479 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
Michael Buesch489423c2006-02-13 00:11:07 +01002480 if ((value | 0x80000000) != 0x80000400)
2481 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002482
2483 value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch489423c2006-02-13 00:11:07 +01002484 if (value != 0x00000000)
2485 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002486
Michael Buesch489423c2006-02-13 00:11:07 +01002487 return 0;
2488error:
2489 printk(KERN_ERR PFX "Failed to validate the chipaccess\n");
2490 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002491}
2492
2493static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
2494{
2495 int err, i;
2496 int current_core;
2497 u32 core_vendor, core_id, core_rev;
2498 u32 sb_id_hi, chip_id_32 = 0;
2499 u16 pci_device, chip_id_16;
2500 u8 core_count;
2501
2502 memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo));
2503 memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo));
2504 memset(&bcm->core_v90, 0, sizeof(struct bcm43xx_coreinfo));
2505 memset(&bcm->core_pcmcia, 0, sizeof(struct bcm43xx_coreinfo));
2506 memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo)
2507 * BCM43xx_MAX_80211_CORES);
2508
2509 memset(&bcm->phy, 0, sizeof(struct bcm43xx_phyinfo)
2510 * BCM43xx_MAX_80211_CORES);
2511 memset(&bcm->radio, 0, sizeof(struct bcm43xx_radioinfo)
2512 * BCM43xx_MAX_80211_CORES);
2513
2514 /* map core 0 */
2515 err = _switch_core(bcm, 0);
2516 if (err)
2517 goto out;
2518
2519 /* fetch sb_id_hi from core information registers */
2520 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2521
2522 core_id = (sb_id_hi & 0xFFF0) >> 4;
2523 core_rev = (sb_id_hi & 0xF);
2524 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2525
2526 /* if present, chipcommon is always core 0; read the chipid from it */
2527 if (core_id == BCM43xx_COREID_CHIPCOMMON) {
2528 chip_id_32 = bcm43xx_read32(bcm, 0);
2529 chip_id_16 = chip_id_32 & 0xFFFF;
2530 bcm->core_chipcommon.flags |= BCM43xx_COREFLAG_AVAILABLE;
2531 bcm->core_chipcommon.id = core_id;
2532 bcm->core_chipcommon.rev = core_rev;
2533 bcm->core_chipcommon.index = 0;
2534 /* While we are at it, also read the capabilities. */
2535 bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES);
2536 } else {
2537 /* without a chipCommon, use a hard coded table. */
2538 pci_device = bcm->pci_dev->device;
2539 if (pci_device == 0x4301)
2540 chip_id_16 = 0x4301;
2541 else if ((pci_device >= 0x4305) && (pci_device <= 0x4307))
2542 chip_id_16 = 0x4307;
2543 else if ((pci_device >= 0x4402) && (pci_device <= 0x4403))
2544 chip_id_16 = 0x4402;
2545 else if ((pci_device >= 0x4610) && (pci_device <= 0x4615))
2546 chip_id_16 = 0x4610;
2547 else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
2548 chip_id_16 = 0x4710;
2549#ifdef CONFIG_BCM947XX
2550 else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
2551 chip_id_16 = 0x4309;
2552#endif
2553 else {
2554 printk(KERN_ERR PFX "Could not determine Chip ID\n");
2555 return -ENODEV;
2556 }
2557 }
2558
2559 /* ChipCommon with Core Rev >=4 encodes number of cores,
2560 * otherwise consult hardcoded table */
2561 if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) {
2562 core_count = (chip_id_32 & 0x0F000000) >> 24;
2563 } else {
2564 switch (chip_id_16) {
2565 case 0x4610:
2566 case 0x4704:
2567 case 0x4710:
2568 core_count = 9;
2569 break;
2570 case 0x4310:
2571 core_count = 8;
2572 break;
2573 case 0x5365:
2574 core_count = 7;
2575 break;
2576 case 0x4306:
2577 core_count = 6;
2578 break;
2579 case 0x4301:
2580 case 0x4307:
2581 core_count = 5;
2582 break;
2583 case 0x4402:
2584 core_count = 3;
2585 break;
2586 default:
2587 /* SOL if we get here */
2588 assert(0);
2589 core_count = 1;
2590 }
2591 }
2592
2593 bcm->chip_id = chip_id_16;
2594 bcm->chip_rev = (chip_id_32 & 0x000f0000) >> 16;
2595
2596 dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
2597 bcm->chip_id, bcm->chip_rev);
2598 dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
2599 if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) {
2600 dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2601 core_id, core_rev, core_vendor,
2602 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
2603 }
2604
2605 if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE)
2606 current_core = 1;
2607 else
2608 current_core = 0;
2609 for ( ; current_core < core_count; current_core++) {
2610 struct bcm43xx_coreinfo *core;
2611
2612 err = _switch_core(bcm, current_core);
2613 if (err)
2614 goto out;
2615 /* Gather information */
2616 /* fetch sb_id_hi from core information registers */
2617 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2618
2619 /* extract core_id, core_rev, core_vendor */
2620 core_id = (sb_id_hi & 0xFFF0) >> 4;
2621 core_rev = (sb_id_hi & 0xF);
2622 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2623
2624 dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2625 current_core, core_id, core_rev, core_vendor,
2626 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
2627
2628 core = NULL;
2629 switch (core_id) {
2630 case BCM43xx_COREID_PCI:
2631 core = &bcm->core_pci;
2632 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2633 printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
2634 continue;
2635 }
2636 break;
2637 case BCM43xx_COREID_V90:
2638 core = &bcm->core_v90;
2639 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2640 printk(KERN_WARNING PFX "Multiple V90 cores found.\n");
2641 continue;
2642 }
2643 break;
2644 case BCM43xx_COREID_PCMCIA:
2645 core = &bcm->core_pcmcia;
2646 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2647 printk(KERN_WARNING PFX "Multiple PCMCIA cores found.\n");
2648 continue;
2649 }
2650 break;
2651 case BCM43xx_COREID_ETHERNET:
2652 core = &bcm->core_ethernet;
2653 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2654 printk(KERN_WARNING PFX "Multiple Ethernet cores found.\n");
2655 continue;
2656 }
2657 break;
2658 case BCM43xx_COREID_80211:
2659 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
2660 core = &(bcm->core_80211[i]);
2661 if (!(core->flags & BCM43xx_COREFLAG_AVAILABLE))
2662 break;
2663 core = NULL;
2664 }
2665 if (!core) {
2666 printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n",
2667 BCM43xx_MAX_80211_CORES);
2668 continue;
2669 }
2670 if (i != 0) {
2671 /* More than one 80211 core is only supported
2672 * by special chips.
2673 * There are chips with two 80211 cores, but with
2674 * dangling pins on the second core. Be careful
2675 * and ignore these cores here.
2676 */
2677 if (bcm->pci_dev->device != 0x4324) {
2678 dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
2679 continue;
2680 }
2681 }
2682 switch (core_rev) {
2683 case 2:
2684 case 4:
2685 case 5:
2686 case 6:
2687 case 7:
2688 case 9:
2689 break;
2690 default:
2691 printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
2692 core_rev);
2693 err = -ENODEV;
2694 goto out;
2695 }
2696 core->phy = &bcm->phy[i];
2697 core->phy->antenna_diversity = 0xffff;
2698 core->phy->savedpctlreg = 0xFFFF;
2699 core->phy->minlowsig[0] = 0xFFFF;
2700 core->phy->minlowsig[1] = 0xFFFF;
2701 core->phy->minlowsigpos[0] = 0;
2702 core->phy->minlowsigpos[1] = 0;
2703 spin_lock_init(&core->phy->lock);
2704 core->radio = &bcm->radio[i];
Michael Bueschab4977f2006-02-12 22:40:39 +01002705 core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
John W. Linvillef2223132006-01-23 16:59:58 -05002706 core->radio->channel = 0xFF;
2707 core->radio->initial_channel = 0xFF;
2708 core->radio->lofcal = 0xFFFF;
2709 core->radio->initval = 0xFFFF;
2710 core->radio->nrssi[0] = -1000;
2711 core->radio->nrssi[1] = -1000;
2712 core->dma = &bcm->dma[i];
2713 core->pio = &bcm->pio[i];
2714 break;
2715 case BCM43xx_COREID_CHIPCOMMON:
2716 printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
2717 break;
2718 default:
2719 printk(KERN_WARNING PFX "Unknown core found (ID 0x%x)\n", core_id);
2720 }
2721 if (core) {
2722 core->flags |= BCM43xx_COREFLAG_AVAILABLE;
2723 core->id = core_id;
2724 core->rev = core_rev;
2725 core->index = current_core;
2726 }
2727 }
2728
2729 if (!(bcm->core_80211[0].flags & BCM43xx_COREFLAG_AVAILABLE)) {
2730 printk(KERN_ERR PFX "Error: No 80211 core found!\n");
2731 err = -ENODEV;
2732 goto out;
2733 }
2734
2735 err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
2736
2737 assert(err == 0);
2738out:
2739 return err;
2740}
2741
2742static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm)
2743{
2744 const u8 *mac = (const u8*)(bcm->net_dev->dev_addr);
2745 u8 *bssid = bcm->ieee->bssid;
2746
2747 switch (bcm->ieee->iw_mode) {
2748 case IW_MODE_ADHOC:
2749 random_ether_addr(bssid);
2750 break;
2751 case IW_MODE_MASTER:
2752 case IW_MODE_INFRA:
2753 case IW_MODE_REPEAT:
2754 case IW_MODE_SECOND:
2755 case IW_MODE_MONITOR:
2756 memcpy(bssid, mac, ETH_ALEN);
2757 break;
2758 default:
2759 assert(0);
2760 }
2761}
2762
2763static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm,
2764 u16 rate,
2765 int is_ofdm)
2766{
2767 u16 offset;
2768
2769 if (is_ofdm) {
2770 offset = 0x480;
2771 offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
2772 }
2773 else {
2774 offset = 0x4C0;
2775 offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
2776 }
2777 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20,
2778 bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset));
2779}
2780
2781static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm)
2782{
2783 switch (bcm->current_core->phy->type) {
2784 case BCM43xx_PHYTYPE_A:
2785 case BCM43xx_PHYTYPE_G:
2786 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1);
2787 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1);
2788 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1);
2789 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1);
2790 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1);
2791 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1);
2792 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1);
2793 case BCM43xx_PHYTYPE_B:
2794 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0);
2795 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0);
2796 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0);
2797 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0);
2798 break;
2799 default:
2800 assert(0);
2801 }
2802}
2803
2804static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
2805{
2806 bcm43xx_chip_cleanup(bcm);
2807 bcm43xx_pio_free(bcm);
2808 bcm43xx_dma_free(bcm);
2809
2810 bcm->current_core->flags &= ~ BCM43xx_COREFLAG_INITIALIZED;
2811}
2812
2813/* http://bcm-specs.sipsolutions.net/80211Init */
2814static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
2815{
2816 u32 ucodeflags;
2817 int err;
2818 u32 sbimconfiglow;
2819 u8 limit;
2820
2821 if (bcm->chip_rev < 5) {
2822 sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
2823 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
2824 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
2825 if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
2826 sbimconfiglow |= 0x32;
2827 else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
2828 sbimconfiglow |= 0x53;
2829 else
2830 assert(0);
2831 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
2832 }
2833
2834 bcm43xx_phy_calibrate(bcm);
2835 err = bcm43xx_chip_init(bcm);
2836 if (err)
2837 goto out;
2838
2839 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
2840 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
2841
2842 if (0 /*FIXME: which condition has to be used here? */)
2843 ucodeflags |= 0x00000010;
2844
2845 /* HW decryption needs to be set now */
2846 ucodeflags |= 0x40000000;
2847
2848 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
2849 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
2850 if (bcm->current_core->phy->rev == 1)
2851 ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
2852 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
2853 ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
2854 } else if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) {
2855 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
2856 if ((bcm->current_core->phy->rev >= 2) &&
2857 (bcm->current_core->radio->version == 0x2050))
2858 ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY;
2859 }
2860
2861 if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
2862 BCM43xx_UCODEFLAGS_OFFSET)) {
2863 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
2864 BCM43xx_UCODEFLAGS_OFFSET, ucodeflags);
2865 }
2866
2867 /* Short/Long Retry Limit.
2868 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
2869 * the chip-internal counter.
2870 */
2871 limit = limit_value(modparam_short_retry, 0, 0xF);
2872 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit);
2873 limit = limit_value(modparam_long_retry, 0, 0xF);
2874 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit);
2875
2876 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3);
2877 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2);
2878
2879 bcm43xx_rate_memory_init(bcm);
2880
2881 /* Minimum Contention Window */
2882 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B)
2883 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f);
2884 else
2885 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f);
2886 /* Maximum Contention Window */
2887 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
2888
2889 bcm43xx_gen_bssid(bcm);
2890 bcm43xx_write_mac_bssid_templates(bcm);
2891
2892 if (bcm->current_core->rev >= 5)
2893 bcm43xx_write16(bcm, 0x043C, 0x000C);
2894
Michael Buesch77db31e2006-02-12 16:47:44 +01002895 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05002896 err = bcm43xx_pio_init(bcm);
Michael Buesch77db31e2006-02-12 16:47:44 +01002897 else
2898 err = bcm43xx_dma_init(bcm);
2899 if (err)
2900 goto err_chip_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002901 bcm43xx_write16(bcm, 0x0612, 0x0050);
2902 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
2903 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
2904
2905 bcm43xx_mac_enable(bcm);
2906 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
2907
2908 bcm->current_core->flags |= BCM43xx_COREFLAG_INITIALIZED;
2909out:
2910 return err;
2911
2912err_chip_cleanup:
2913 bcm43xx_chip_cleanup(bcm);
2914 goto out;
2915}
2916
2917static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
2918{
2919 int err;
2920 u16 pci_status;
2921
2922 err = bcm43xx_pctl_set_crystal(bcm, 1);
2923 if (err)
2924 goto out;
2925 bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
2926 bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
2927
2928out:
2929 return err;
2930}
2931
2932static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm)
2933{
2934 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
2935 bcm43xx_pctl_set_crystal(bcm, 0);
2936}
2937
Michael Buesch489423c2006-02-13 00:11:07 +01002938static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
2939 u32 address,
2940 u32 data)
John W. Linvillef2223132006-01-23 16:59:58 -05002941{
2942 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address);
2943 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data);
2944}
2945
2946static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
2947{
2948 int err;
2949 struct bcm43xx_coreinfo *old_core;
2950
2951 old_core = bcm->current_core;
2952 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2953 if (err)
2954 goto out;
2955
2956 bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
2957
2958 bcm43xx_switch_core(bcm, old_core);
2959 assert(err == 0);
2960out:
2961 return err;
2962}
2963
2964/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
2965 * To enable core 0, pass a core_mask of 1<<0
2966 */
2967static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
2968 u32 core_mask)
2969{
2970 u32 backplane_flag_nr;
2971 u32 value;
2972 struct bcm43xx_coreinfo *old_core;
2973 int err = 0;
2974
2975 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG);
2976 backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK;
2977
2978 old_core = bcm->current_core;
2979 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2980 if (err)
2981 goto out;
2982
2983 if (bcm->core_pci.rev < 6) {
2984 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
2985 value |= (1 << backplane_flag_nr);
2986 bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
2987 } else {
2988 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value);
2989 if (err) {
2990 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
2991 goto out_switch_back;
2992 }
2993 value |= core_mask << 8;
2994 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value);
2995 if (err) {
2996 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
2997 goto out_switch_back;
2998 }
2999 }
3000
3001 value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
3002 value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
3003 bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
3004
3005 if (bcm->core_pci.rev < 5) {
3006 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
3007 value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
3008 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
3009 value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
3010 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
3011 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
3012 err = bcm43xx_pcicore_commit_settings(bcm);
3013 assert(err == 0);
3014 }
3015
3016out_switch_back:
3017 err = bcm43xx_switch_core(bcm, old_core);
3018out:
3019 return err;
3020}
3021
3022static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
3023{
3024 ieee80211softmac_start(bcm->net_dev);
3025}
3026
Michael Bueschab4977f2006-02-12 22:40:39 +01003027static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003028{
Michael Bueschab4977f2006-02-12 22:40:39 +01003029 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -05003030
Michael Bueschab4977f2006-02-12 22:40:39 +01003031 if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2)
3032 return;
John W. Linvillef2223132006-01-23 16:59:58 -05003033
Michael Bueschab4977f2006-02-12 22:40:39 +01003034 bcm43xx_mac_suspend(bcm);
3035 bcm43xx_phy_lo_g_measure(bcm);
3036 bcm43xx_mac_enable(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003037}
3038
Michael Bueschab4977f2006-02-12 22:40:39 +01003039static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003040{
John W. Linvillef2223132006-01-23 16:59:58 -05003041 bcm43xx_phy_lo_mark_all_unused(bcm);
3042 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3043 bcm43xx_mac_suspend(bcm);
3044 bcm43xx_calc_nrssi_slope(bcm);
3045 bcm43xx_mac_enable(bcm);
3046 }
John W. Linvillef2223132006-01-23 16:59:58 -05003047}
3048
Michael Bueschab4977f2006-02-12 22:40:39 +01003049static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003050{
John W. Linvillef2223132006-01-23 16:59:58 -05003051 /* Update device statistics. */
3052 bcm43xx_calculate_link_quality(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003053}
John W. Linvillef2223132006-01-23 16:59:58 -05003054
Michael Bueschab4977f2006-02-12 22:40:39 +01003055static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
3056{
3057 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
3058 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
3059
3060 if (phy->type == BCM43xx_PHYTYPE_G) {
3061 //TODO: update_aci_moving_average
3062 if (radio->aci_enable && radio->aci_wlan_automatic) {
3063 bcm43xx_mac_suspend(bcm);
3064 if (!radio->aci_enable && 1 /*TODO: not scanning? */) {
3065 if (0 /*TODO: bunch of conditions*/) {
3066 bcm43xx_radio_set_interference_mitigation(bcm,
3067 BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
3068 }
3069 } else if (1/*TODO*/) {
3070 /*
3071 if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) {
3072 bcm43xx_radio_set_interference_mitigation(bcm,
3073 BCM43xx_RADIO_INTERFMODE_NONE);
3074 }
3075 */
3076 }
3077 bcm43xx_mac_enable(bcm);
3078 } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN &&
3079 phy->rev == 1) {
3080 //TODO: implement rev1 workaround
3081 }
John W. Linvillef2223132006-01-23 16:59:58 -05003082 }
Michael Bueschab4977f2006-02-12 22:40:39 +01003083 bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
3084 //TODO for APHY (temperature?)
3085}
3086
3087static void bcm43xx_periodic_task_handler(unsigned long d)
3088{
3089 struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
3090 unsigned long flags;
3091 unsigned int state;
3092
Michael Bueschefccb642006-03-11 13:39:14 +01003093 bcm43xx_lock_mmio(bcm, flags);
Michael Bueschab4977f2006-02-12 22:40:39 +01003094
3095 assert(bcm->initialized);
3096 state = bcm->periodic_state;
3097 if (state % 8 == 0)
3098 bcm43xx_periodic_every120sec(bcm);
3099 if (state % 4 == 0)
3100 bcm43xx_periodic_every60sec(bcm);
3101 if (state % 2 == 0)
3102 bcm43xx_periodic_every30sec(bcm);
3103 bcm43xx_periodic_every15sec(bcm);
3104 bcm->periodic_state = state + 1;
3105
3106 mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
3107
Michael Bueschefccb642006-03-11 13:39:14 +01003108 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003109}
3110
John W. Linvillef2223132006-01-23 16:59:58 -05003111static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
3112{
Michael Bueschab4977f2006-02-12 22:40:39 +01003113 del_timer_sync(&bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003114}
3115
John W. Linvillef2223132006-01-23 16:59:58 -05003116static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
3117{
Michael Bueschab4977f2006-02-12 22:40:39 +01003118 struct timer_list *timer = &(bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003119
Michael Buesch1d1a73c2006-02-21 18:19:59 +01003120 assert(bcm->initialized);
Michael Bueschab4977f2006-02-12 22:40:39 +01003121 setup_timer(timer,
3122 bcm43xx_periodic_task_handler,
3123 (unsigned long)bcm);
3124 timer->expires = jiffies;
3125 add_timer(timer);
John W. Linvillef2223132006-01-23 16:59:58 -05003126}
3127
3128static void bcm43xx_security_init(struct bcm43xx_private *bcm)
3129{
3130 bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
3131 0x0056) * 2;
3132 bcm43xx_clear_keys(bcm);
3133}
3134
3135/* This is the opposite of bcm43xx_init_board() */
3136static void bcm43xx_free_board(struct bcm43xx_private *bcm)
3137{
3138 int i, err;
3139 unsigned long flags;
3140
Michael Buesch367f8992006-02-28 15:32:19 +01003141 bcm43xx_sysfs_unregister(bcm);
3142
Michael Bueschab4977f2006-02-12 22:40:39 +01003143 bcm43xx_periodic_tasks_delete(bcm);
3144
Michael Bueschefccb642006-03-11 13:39:14 +01003145 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003146 bcm->initialized = 0;
3147 bcm->shutting_down = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003148 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003149
John W. Linvillef2223132006-01-23 16:59:58 -05003150 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3151 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE))
3152 continue;
3153 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED))
3154 continue;
3155
3156 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3157 assert(err == 0);
3158 bcm43xx_wireless_core_cleanup(bcm);
3159 }
3160
3161 bcm43xx_pctl_set_crystal(bcm, 0);
3162
Michael Bueschefccb642006-03-11 13:39:14 +01003163 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003164 bcm->shutting_down = 0;
Michael Bueschefccb642006-03-11 13:39:14 +01003165 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003166}
3167
3168static int bcm43xx_init_board(struct bcm43xx_private *bcm)
3169{
3170 int i, err;
3171 int num_80211_cores;
3172 int connect_phy;
3173 unsigned long flags;
3174
3175 might_sleep();
3176
Michael Bueschefccb642006-03-11 13:39:14 +01003177 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003178 bcm->initialized = 0;
3179 bcm->shutting_down = 0;
Michael Bueschefccb642006-03-11 13:39:14 +01003180 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003181
3182 err = bcm43xx_pctl_set_crystal(bcm, 1);
3183 if (err)
3184 goto out;
3185 err = bcm43xx_pctl_init(bcm);
3186 if (err)
3187 goto err_crystal_off;
3188 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
3189 if (err)
3190 goto err_crystal_off;
3191
3192 tasklet_enable(&bcm->isr_tasklet);
3193 num_80211_cores = bcm43xx_num_80211_cores(bcm);
3194 for (i = 0; i < num_80211_cores; i++) {
3195 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3196 assert(err != -ENODEV);
3197 if (err)
3198 goto err_80211_unwind;
3199
3200 /* Enable the selected wireless core.
3201 * Connect PHY only on the first core.
3202 */
3203 if (!bcm43xx_core_enabled(bcm)) {
3204 if (num_80211_cores == 1) {
3205 connect_phy = bcm->current_core->phy->connected;
3206 } else {
3207 if (i == 0)
3208 connect_phy = 1;
3209 else
3210 connect_phy = 0;
3211 }
3212 bcm43xx_wireless_core_reset(bcm, connect_phy);
3213 }
3214
3215 if (i != 0)
3216 bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
3217
3218 err = bcm43xx_wireless_core_init(bcm);
3219 if (err)
3220 goto err_80211_unwind;
3221
3222 if (i != 0) {
3223 bcm43xx_mac_suspend(bcm);
3224 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3225 bcm43xx_radio_turn_off(bcm);
3226 }
3227 }
3228 bcm->active_80211_core = &bcm->core_80211[0];
3229 if (num_80211_cores >= 2) {
3230 bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
3231 bcm43xx_mac_enable(bcm);
3232 }
3233 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
3234 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
3235 dprintk(KERN_INFO PFX "80211 cores initialized\n");
3236 bcm43xx_security_init(bcm);
3237 bcm43xx_softmac_init(bcm);
3238
3239 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
3240
John W. Linvillef2223132006-01-23 16:59:58 -05003241 if (bcm->current_core->radio->initial_channel != 0xFF) {
3242 bcm43xx_mac_suspend(bcm);
3243 bcm43xx_radio_selectchannel(bcm, bcm->current_core->radio->initial_channel, 0);
3244 bcm43xx_mac_enable(bcm);
3245 }
Michael Bueschcad2b312006-02-21 18:08:55 +01003246
3247 /* Initialization of the board is done. Flag it as such. */
Michael Bueschefccb642006-03-11 13:39:14 +01003248 bcm43xx_lock(bcm, flags);
Michael Bueschcad2b312006-02-21 18:08:55 +01003249 bcm->initialized = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003250 bcm43xx_unlock(bcm, flags);
Michael Bueschcad2b312006-02-21 18:08:55 +01003251
John W. Linvillef2223132006-01-23 16:59:58 -05003252 bcm43xx_periodic_tasks_setup(bcm);
Michael Buesch367f8992006-02-28 15:32:19 +01003253 bcm43xx_sysfs_register(bcm);
3254 //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
John W. Linvillef2223132006-01-23 16:59:58 -05003255
3256 assert(err == 0);
3257out:
3258 return err;
3259
3260err_80211_unwind:
3261 tasklet_disable(&bcm->isr_tasklet);
3262 /* unwind all 80211 initialization */
3263 for (i = 0; i < num_80211_cores; i++) {
3264 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED))
3265 continue;
3266 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3267 bcm43xx_wireless_core_cleanup(bcm);
3268 }
3269err_crystal_off:
3270 bcm43xx_pctl_set_crystal(bcm, 0);
3271 goto out;
3272}
3273
3274static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
3275{
3276 struct pci_dev *pci_dev = bcm->pci_dev;
3277 int i;
3278
3279 bcm43xx_chipset_detach(bcm);
3280 /* Do _not_ access the chip, after it is detached. */
3281 iounmap(bcm->mmio_addr);
3282
3283 pci_release_regions(pci_dev);
3284 pci_disable_device(pci_dev);
3285
3286 /* Free allocated structures/fields */
3287 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3288 kfree(bcm->phy[i]._lo_pairs);
3289 if (bcm->phy[i].dyn_tssi_tbl)
3290 kfree(bcm->phy[i].tssi2dbm);
3291 }
3292}
3293
3294static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
3295{
Michael Buesch489423c2006-02-13 00:11:07 +01003296 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -05003297 u16 value;
3298 u8 phy_version;
3299 u8 phy_type;
3300 u8 phy_rev;
3301 int phy_rev_ok = 1;
3302 void *p;
3303
3304 value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
3305
3306 phy_version = (value & 0xF000) >> 12;
3307 phy_type = (value & 0x0F00) >> 8;
3308 phy_rev = (value & 0x000F);
3309
3310 dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
3311 phy_version, phy_type, phy_rev);
3312
3313 switch (phy_type) {
3314 case BCM43xx_PHYTYPE_A:
3315 if (phy_rev >= 4)
3316 phy_rev_ok = 0;
3317 /*FIXME: We need to switch the ieee->modulation, etc.. flags,
3318 * if we switch 80211 cores after init is done.
3319 * As we do not implement on the fly switching between
3320 * wireless cores, I will leave this as a future task.
3321 */
3322 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION;
3323 bcm->ieee->mode = IEEE_A;
3324 bcm->ieee->freq_band = IEEE80211_52GHZ_BAND |
3325 IEEE80211_24GHZ_BAND;
3326 break;
3327 case BCM43xx_PHYTYPE_B:
3328 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7)
3329 phy_rev_ok = 0;
3330 bcm->ieee->modulation = IEEE80211_CCK_MODULATION;
3331 bcm->ieee->mode = IEEE_B;
3332 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3333 break;
3334 case BCM43xx_PHYTYPE_G:
3335 if (phy_rev > 7)
3336 phy_rev_ok = 0;
3337 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
3338 IEEE80211_CCK_MODULATION;
3339 bcm->ieee->mode = IEEE_G;
3340 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3341 break;
3342 default:
3343 printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n",
3344 phy_type);
3345 return -ENODEV;
3346 };
3347 if (!phy_rev_ok) {
3348 printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
3349 phy_rev);
3350 }
3351
Michael Buesch489423c2006-02-13 00:11:07 +01003352 phy->version = phy_version;
3353 phy->type = phy_type;
3354 phy->rev = phy_rev;
John W. Linvillef2223132006-01-23 16:59:58 -05003355 if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
3356 p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT,
3357 GFP_KERNEL);
3358 if (!p)
3359 return -ENOMEM;
Michael Buesch489423c2006-02-13 00:11:07 +01003360 phy->_lo_pairs = p;
John W. Linvillef2223132006-01-23 16:59:58 -05003361 }
3362
3363 return 0;
3364}
3365
3366static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
3367{
3368 struct pci_dev *pci_dev = bcm->pci_dev;
3369 struct net_device *net_dev = bcm->net_dev;
3370 int err;
3371 int i;
3372 void __iomem *ioaddr;
3373 unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
3374 int num_80211_cores;
3375 u32 coremask;
3376
3377 err = pci_enable_device(pci_dev);
3378 if (err) {
3379 printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
3380 err = -ENODEV;
3381 goto out;
3382 }
3383
3384 mmio_start = pci_resource_start(pci_dev, 0);
3385 mmio_end = pci_resource_end(pci_dev, 0);
3386 mmio_flags = pci_resource_flags(pci_dev, 0);
3387 mmio_len = pci_resource_len(pci_dev, 0);
3388
3389 /* make sure PCI base addr is MMIO */
3390 if (!(mmio_flags & IORESOURCE_MEM)) {
3391 printk(KERN_ERR PFX
3392 "%s, region #0 not an MMIO resource, aborting\n",
3393 pci_name(pci_dev));
3394 err = -ENODEV;
3395 goto err_pci_disable;
3396 }
3397//FIXME: Why is this check disabled for BCM947XX? What is the IO_SIZE there?
3398#ifndef CONFIG_BCM947XX
3399 if (mmio_len != BCM43xx_IO_SIZE) {
3400 printk(KERN_ERR PFX
3401 "%s: invalid PCI mem region size(s), aborting\n",
3402 pci_name(pci_dev));
3403 err = -ENODEV;
3404 goto err_pci_disable;
3405 }
3406#endif
3407
Michael Buesch65f3f192006-01-31 20:11:38 +01003408 err = pci_request_regions(pci_dev, KBUILD_MODNAME);
John W. Linvillef2223132006-01-23 16:59:58 -05003409 if (err) {
3410 printk(KERN_ERR PFX
3411 "could not access PCI resources (%i)\n", err);
3412 goto err_pci_disable;
3413 }
3414
3415 /* enable PCI bus-mastering */
3416 pci_set_master(pci_dev);
3417
3418 /* ioremap MMIO region */
3419 ioaddr = ioremap(mmio_start, mmio_len);
3420 if (!ioaddr) {
3421 printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
3422 pci_name(pci_dev));
3423 err = -EIO;
3424 goto err_pci_release;
3425 }
3426
3427 net_dev->base_addr = (unsigned long)ioaddr;
3428 bcm->mmio_addr = ioaddr;
3429 bcm->mmio_len = mmio_len;
3430
3431 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
3432 &bcm->board_vendor);
3433 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
3434 &bcm->board_type);
3435 bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
3436 &bcm->board_revision);
3437
3438 err = bcm43xx_chipset_attach(bcm);
3439 if (err)
3440 goto err_iounmap;
3441 err = bcm43xx_pctl_init(bcm);
3442 if (err)
3443 goto err_chipset_detach;
3444 err = bcm43xx_probe_cores(bcm);
3445 if (err)
3446 goto err_chipset_detach;
3447
3448 num_80211_cores = bcm43xx_num_80211_cores(bcm);
3449
3450 /* Attach all IO cores to the backplane. */
3451 coremask = 0;
3452 for (i = 0; i < num_80211_cores; i++)
3453 coremask |= (1 << bcm->core_80211[i].index);
3454 //FIXME: Also attach some non80211 cores?
3455 err = bcm43xx_setup_backplane_pci_connection(bcm, coremask);
3456 if (err) {
3457 printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
3458 goto err_chipset_detach;
3459 }
3460
Michael Bueschea0922b2006-02-19 14:09:20 +01003461 err = bcm43xx_sprom_extract(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003462 if (err)
3463 goto err_chipset_detach;
3464 err = bcm43xx_leds_init(bcm);
3465 if (err)
3466 goto err_chipset_detach;
3467
3468 for (i = 0; i < num_80211_cores; i++) {
3469 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3470 assert(err != -ENODEV);
3471 if (err)
3472 goto err_80211_unwind;
3473
3474 /* Enable the selected wireless core.
3475 * Connect PHY only on the first core.
3476 */
3477 bcm43xx_wireless_core_reset(bcm, (i == 0));
3478
3479 err = bcm43xx_read_phyinfo(bcm);
3480 if (err && (i == 0))
3481 goto err_80211_unwind;
3482
3483 err = bcm43xx_read_radioinfo(bcm);
3484 if (err && (i == 0))
3485 goto err_80211_unwind;
3486
3487 err = bcm43xx_validate_chip(bcm);
3488 if (err && (i == 0))
3489 goto err_80211_unwind;
3490
3491 bcm43xx_radio_turn_off(bcm);
3492 err = bcm43xx_phy_init_tssi2dbm_table(bcm);
3493 if (err)
3494 goto err_80211_unwind;
3495 bcm43xx_wireless_core_disable(bcm);
3496 }
3497 bcm43xx_pctl_set_crystal(bcm, 0);
3498
3499 /* Set the MAC address in the networking subsystem */
3500 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
3501 memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
3502 else
3503 memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
3504
3505 bcm43xx_geo_init(bcm);
3506
3507 snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
3508 "Broadcom %04X", bcm->chip_id);
3509
3510 assert(err == 0);
3511out:
3512 return err;
3513
3514err_80211_unwind:
3515 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3516 kfree(bcm->phy[i]._lo_pairs);
3517 if (bcm->phy[i].dyn_tssi_tbl)
3518 kfree(bcm->phy[i].tssi2dbm);
3519 }
3520err_chipset_detach:
3521 bcm43xx_chipset_detach(bcm);
3522err_iounmap:
3523 iounmap(bcm->mmio_addr);
3524err_pci_release:
3525 pci_release_regions(pci_dev);
3526err_pci_disable:
3527 pci_disable_device(pci_dev);
3528 goto out;
3529}
3530
John W. Linvillef2223132006-01-23 16:59:58 -05003531/* Do the Hardware IO operations to send the txb */
3532static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
3533 struct ieee80211_txb *txb)
3534{
3535 int err = -ENODEV;
3536
Michael Buesch77db31e2006-02-12 16:47:44 +01003537 if (bcm43xx_using_pio(bcm))
3538 err = bcm43xx_pio_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003539 else
Michael Bueschea72ab22006-01-27 17:26:20 +01003540 err = bcm43xx_dma_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003541
3542 return err;
3543}
3544
3545static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
3546 u8 channel)
3547{
3548 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3549 unsigned long flags;
3550
Michael Bueschefccb642006-03-11 13:39:14 +01003551 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003552 bcm43xx_mac_suspend(bcm);
3553 bcm43xx_radio_selectchannel(bcm, channel, 0);
3554 bcm43xx_mac_enable(bcm);
Michael Bueschefccb642006-03-11 13:39:14 +01003555 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003556}
3557
3558/* set_security() callback in struct ieee80211_device */
3559static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
3560 struct ieee80211_security *sec)
3561{
3562 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3563 struct ieee80211_security *secinfo = &bcm->ieee->sec;
3564 unsigned long flags;
3565 int keyidx;
3566
3567 dprintk(KERN_INFO PFX "set security called\n");
Michael Bueschefccb642006-03-11 13:39:14 +01003568
3569 bcm43xx_lock_mmio(bcm, flags);
3570
John W. Linvillef2223132006-01-23 16:59:58 -05003571 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
3572 if (sec->flags & (1<<keyidx)) {
3573 secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
3574 secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
3575 memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN);
3576 }
3577
3578 if (sec->flags & SEC_ACTIVE_KEY) {
3579 secinfo->active_key = sec->active_key;
3580 dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key);
3581 }
3582 if (sec->flags & SEC_UNICAST_GROUP) {
3583 secinfo->unicast_uses_group = sec->unicast_uses_group;
3584 dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group);
3585 }
3586 if (sec->flags & SEC_LEVEL) {
3587 secinfo->level = sec->level;
3588 dprintk(KERN_INFO PFX " .level = %d\n", sec->level);
3589 }
3590 if (sec->flags & SEC_ENABLED) {
3591 secinfo->enabled = sec->enabled;
3592 dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled);
3593 }
3594 if (sec->flags & SEC_ENCRYPT) {
3595 secinfo->encrypt = sec->encrypt;
3596 dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt);
3597 }
3598 if (bcm->initialized && !bcm->ieee->host_encrypt) {
3599 if (secinfo->enabled) {
3600 /* upload WEP keys to hardware */
3601 char null_address[6] = { 0 };
3602 u8 algorithm = 0;
3603 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
3604 if (!(sec->flags & (1<<keyidx)))
3605 continue;
3606 switch (sec->encode_alg[keyidx]) {
3607 case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
3608 case SEC_ALG_WEP:
3609 algorithm = BCM43xx_SEC_ALGO_WEP;
3610 if (secinfo->key_sizes[keyidx] == 13)
3611 algorithm = BCM43xx_SEC_ALGO_WEP104;
3612 break;
3613 case SEC_ALG_TKIP:
3614 FIXME();
3615 algorithm = BCM43xx_SEC_ALGO_TKIP;
3616 break;
3617 case SEC_ALG_CCMP:
3618 FIXME();
3619 algorithm = BCM43xx_SEC_ALGO_AES;
3620 break;
3621 default:
3622 assert(0);
3623 break;
3624 }
3625 bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
3626 bcm->key[keyidx].enabled = 1;
3627 bcm->key[keyidx].algorithm = algorithm;
3628 }
3629 } else
3630 bcm43xx_clear_keys(bcm);
3631 }
Michael Bueschefccb642006-03-11 13:39:14 +01003632 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003633}
3634
3635/* hard_start_xmit() callback in struct ieee80211_device */
3636static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
3637 struct net_device *net_dev,
3638 int pri)
3639{
3640 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3641 int err = -ENODEV;
3642 unsigned long flags;
3643
Michael Bueschefccb642006-03-11 13:39:14 +01003644 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003645 if (likely(bcm->initialized))
3646 err = bcm43xx_tx(bcm, txb);
Michael Bueschefccb642006-03-11 13:39:14 +01003647 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003648
3649 return err;
3650}
3651
3652static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
3653{
3654 return &(bcm43xx_priv(net_dev)->ieee->stats);
3655}
3656
3657static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
3658{
3659 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Bueschefccb642006-03-11 13:39:14 +01003660 unsigned long flags;
John W. Linvillef2223132006-01-23 16:59:58 -05003661
Michael Bueschefccb642006-03-11 13:39:14 +01003662 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003663 bcm43xx_controller_restart(bcm, "TX timeout");
Michael Bueschefccb642006-03-11 13:39:14 +01003664 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003665}
3666
3667#ifdef CONFIG_NET_POLL_CONTROLLER
3668static void bcm43xx_net_poll_controller(struct net_device *net_dev)
3669{
3670 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3671 unsigned long flags;
3672
3673 local_irq_save(flags);
3674 bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
3675 local_irq_restore(flags);
3676}
3677#endif /* CONFIG_NET_POLL_CONTROLLER */
3678
3679static int bcm43xx_net_open(struct net_device *net_dev)
3680{
3681 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3682
3683 return bcm43xx_init_board(bcm);
3684}
3685
3686static int bcm43xx_net_stop(struct net_device *net_dev)
3687{
3688 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3689
3690 ieee80211softmac_stop(net_dev);
3691 bcm43xx_disable_interrupts_sync(bcm, NULL);
3692 bcm43xx_free_board(bcm);
3693
3694 return 0;
3695}
3696
Michael Buesch77db31e2006-02-12 16:47:44 +01003697static int bcm43xx_init_private(struct bcm43xx_private *bcm,
3698 struct net_device *net_dev,
Michael Bueschab4977f2006-02-12 22:40:39 +01003699 struct pci_dev *pci_dev)
John W. Linvillef2223132006-01-23 16:59:58 -05003700{
Michael Buesch4d5a9e02006-03-11 13:15:02 +01003701 int err;
3702
John W. Linvillef2223132006-01-23 16:59:58 -05003703 bcm->ieee = netdev_priv(net_dev);
3704 bcm->softmac = ieee80211_priv(net_dev);
3705 bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
John W. Linvillef2223132006-01-23 16:59:58 -05003706
John W. Linvillef2223132006-01-23 16:59:58 -05003707 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3708 bcm->pci_dev = pci_dev;
3709 bcm->net_dev = net_dev;
Michael Buesch4d5a9e02006-03-11 13:15:02 +01003710 bcm->bad_frames_preempt = modparam_bad_frames_preempt;
Michael Bueschefccb642006-03-11 13:39:14 +01003711 spin_lock_init(&bcm->_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05003712 tasklet_init(&bcm->isr_tasklet,
3713 (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
3714 (unsigned long)bcm);
3715 tasklet_disable_nosync(&bcm->isr_tasklet);
3716 if (modparam_pio) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003717 bcm->__using_pio = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05003718 } else {
Michael Buesch4d5a9e02006-03-11 13:15:02 +01003719 err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
3720 err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
3721 if (err) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003722#ifdef CONFIG_BCM43XX_PIO
John W. Linvillef2223132006-01-23 16:59:58 -05003723 printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
Michael Buesch77db31e2006-02-12 16:47:44 +01003724 bcm->__using_pio = 1;
3725#else
3726 printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
3727 "Recompile the driver with PIO support, please.\n");
3728 return -ENODEV;
3729#endif /* CONFIG_BCM43XX_PIO */
John W. Linvillef2223132006-01-23 16:59:58 -05003730 }
3731 }
3732 bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
3733
3734 /* default to sw encryption for now */
3735 bcm->ieee->host_build_iv = 0;
3736 bcm->ieee->host_encrypt = 1;
3737 bcm->ieee->host_decrypt = 1;
3738
3739 bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
3740 bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
3741 bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
3742 bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
Michael Buesch77db31e2006-02-12 16:47:44 +01003743
3744 return 0;
John W. Linvillef2223132006-01-23 16:59:58 -05003745}
3746
3747static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
3748 const struct pci_device_id *ent)
3749{
3750 struct net_device *net_dev;
3751 struct bcm43xx_private *bcm;
John W. Linvillef2223132006-01-23 16:59:58 -05003752 int err;
3753
3754#ifdef CONFIG_BCM947XX
3755 if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
3756 return -ENODEV;
3757#endif
3758
3759#ifdef DEBUG_SINGLE_DEVICE_ONLY
3760 if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
3761 return -ENODEV;
3762#endif
3763
3764 net_dev = alloc_ieee80211softmac(sizeof(*bcm));
3765 if (!net_dev) {
3766 printk(KERN_ERR PFX
3767 "could not allocate ieee80211 device %s\n",
3768 pci_name(pdev));
3769 err = -ENOMEM;
3770 goto out;
3771 }
3772 /* initialize the net_device struct */
3773 SET_MODULE_OWNER(net_dev);
3774 SET_NETDEV_DEV(net_dev, &pdev->dev);
3775
3776 net_dev->open = bcm43xx_net_open;
3777 net_dev->stop = bcm43xx_net_stop;
3778 net_dev->get_stats = bcm43xx_net_get_stats;
3779 net_dev->tx_timeout = bcm43xx_net_tx_timeout;
3780#ifdef CONFIG_NET_POLL_CONTROLLER
3781 net_dev->poll_controller = bcm43xx_net_poll_controller;
3782#endif
3783 net_dev->wireless_handlers = &bcm43xx_wx_handlers_def;
3784 net_dev->irq = pdev->irq;
Michael Buesch6465ce12006-02-02 19:11:08 +01003785 SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops);
John W. Linvillef2223132006-01-23 16:59:58 -05003786
3787 /* initialize the bcm43xx_private struct */
3788 bcm = bcm43xx_priv(net_dev);
3789 memset(bcm, 0, sizeof(*bcm));
Michael Bueschab4977f2006-02-12 22:40:39 +01003790 err = bcm43xx_init_private(bcm, net_dev, pdev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003791 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003792 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003793
3794 pci_set_drvdata(pdev, net_dev);
3795
3796 err = bcm43xx_attach_board(bcm);
3797 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003798 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003799
3800 err = register_netdev(net_dev);
3801 if (err) {
3802 printk(KERN_ERR PFX "Cannot register net device, "
3803 "aborting.\n");
3804 err = -ENOMEM;
3805 goto err_detach_board;
3806 }
3807
3808 bcm43xx_debugfs_add_device(bcm);
3809
3810 assert(err == 0);
3811out:
3812 return err;
3813
3814err_detach_board:
3815 bcm43xx_detach_board(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003816err_free_netdev:
3817 free_ieee80211softmac(net_dev);
3818 goto out;
3819}
3820
3821static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
3822{
3823 struct net_device *net_dev = pci_get_drvdata(pdev);
3824 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3825
3826 bcm43xx_debugfs_remove_device(bcm);
3827 unregister_netdev(net_dev);
3828 bcm43xx_detach_board(bcm);
3829 assert(bcm->ucode == NULL);
John W. Linvillef2223132006-01-23 16:59:58 -05003830 free_ieee80211softmac(net_dev);
3831}
3832
3833/* Hard-reset the chip. Do not call this directly.
3834 * Use bcm43xx_controller_restart()
3835 */
3836static void bcm43xx_chip_reset(void *_bcm)
3837{
3838 struct bcm43xx_private *bcm = _bcm;
3839 struct net_device *net_dev = bcm->net_dev;
3840 struct pci_dev *pci_dev = bcm->pci_dev;
John W. Linvillef2223132006-01-23 16:59:58 -05003841 int err;
3842 int was_initialized = bcm->initialized;
3843
3844 netif_stop_queue(bcm->net_dev);
3845 tasklet_disable(&bcm->isr_tasklet);
3846
3847 bcm->firmware_norelease = 1;
3848 if (was_initialized)
3849 bcm43xx_free_board(bcm);
3850 bcm->firmware_norelease = 0;
3851 bcm43xx_detach_board(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003852 err = bcm43xx_init_private(bcm, net_dev, pci_dev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003853 if (err)
3854 goto failure;
John W. Linvillef2223132006-01-23 16:59:58 -05003855 err = bcm43xx_attach_board(bcm);
3856 if (err)
3857 goto failure;
3858 if (was_initialized) {
3859 err = bcm43xx_init_board(bcm);
3860 if (err)
3861 goto failure;
3862 }
3863 netif_wake_queue(bcm->net_dev);
3864 printk(KERN_INFO PFX "Controller restarted\n");
3865
3866 return;
3867failure:
3868 printk(KERN_ERR PFX "Controller restart failed\n");
3869}
3870
3871/* Hard-reset the chip.
3872 * This can be called from interrupt or process context.
3873 * Make sure to _not_ re-enable device interrupts after this has been called.
3874*/
3875void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
3876{
3877 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3878 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
3879 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003880 schedule_work(&bcm->restart_work);
John W. Linvillef2223132006-01-23 16:59:58 -05003881}
3882
3883#ifdef CONFIG_PM
3884
3885static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
3886{
3887 struct net_device *net_dev = pci_get_drvdata(pdev);
3888 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3889 unsigned long flags;
3890 int try_to_shutdown = 0, err;
3891
3892 dprintk(KERN_INFO PFX "Suspending...\n");
3893
Michael Bueschefccb642006-03-11 13:39:14 +01003894 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003895 bcm->was_initialized = bcm->initialized;
3896 if (bcm->initialized)
3897 try_to_shutdown = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003898 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003899
3900 netif_device_detach(net_dev);
3901 if (try_to_shutdown) {
3902 ieee80211softmac_stop(net_dev);
3903 err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
3904 if (unlikely(err)) {
3905 dprintk(KERN_ERR PFX "Suspend failed.\n");
3906 return -EAGAIN;
3907 }
3908 bcm->firmware_norelease = 1;
3909 bcm43xx_free_board(bcm);
3910 bcm->firmware_norelease = 0;
3911 }
3912 bcm43xx_chipset_detach(bcm);
3913
3914 pci_save_state(pdev);
3915 pci_disable_device(pdev);
3916 pci_set_power_state(pdev, pci_choose_state(pdev, state));
3917
3918 dprintk(KERN_INFO PFX "Device suspended.\n");
3919
3920 return 0;
3921}
3922
3923static int bcm43xx_resume(struct pci_dev *pdev)
3924{
3925 struct net_device *net_dev = pci_get_drvdata(pdev);
3926 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3927 int err = 0;
3928
3929 dprintk(KERN_INFO PFX "Resuming...\n");
3930
3931 pci_set_power_state(pdev, 0);
3932 pci_enable_device(pdev);
3933 pci_restore_state(pdev);
3934
3935 bcm43xx_chipset_attach(bcm);
3936 if (bcm->was_initialized) {
3937 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3938 err = bcm43xx_init_board(bcm);
3939 }
3940 if (err) {
3941 printk(KERN_ERR PFX "Resume failed!\n");
3942 return err;
3943 }
3944
3945 netif_device_attach(net_dev);
3946
3947 /*FIXME: This should be handled by softmac instead. */
3948 schedule_work(&bcm->softmac->associnfo.work);
3949
3950 dprintk(KERN_INFO PFX "Device resumed.\n");
3951
3952 return 0;
3953}
3954
3955#endif /* CONFIG_PM */
3956
3957static struct pci_driver bcm43xx_pci_driver = {
Michael Buesch65f3f192006-01-31 20:11:38 +01003958 .name = KBUILD_MODNAME,
John W. Linvillef2223132006-01-23 16:59:58 -05003959 .id_table = bcm43xx_pci_tbl,
3960 .probe = bcm43xx_init_one,
3961 .remove = __devexit_p(bcm43xx_remove_one),
3962#ifdef CONFIG_PM
3963 .suspend = bcm43xx_suspend,
3964 .resume = bcm43xx_resume,
3965#endif /* CONFIG_PM */
3966};
3967
3968static int __init bcm43xx_init(void)
3969{
Michael Buesch65f3f192006-01-31 20:11:38 +01003970 printk(KERN_INFO KBUILD_MODNAME " driver\n");
John W. Linvillef2223132006-01-23 16:59:58 -05003971 bcm43xx_debugfs_init();
3972 return pci_register_driver(&bcm43xx_pci_driver);
3973}
3974
3975static void __exit bcm43xx_exit(void)
3976{
3977 pci_unregister_driver(&bcm43xx_pci_driver);
3978 bcm43xx_debugfs_exit();
3979}
3980
3981module_init(bcm43xx_init)
3982module_exit(bcm43xx_exit)
3983
3984/* vim: set ts=8 sw=8 sts=8: */