blob: 6da0beb0a9339daf4cab269bbbd8337367c3bc8c [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
485 spin_lock_irqsave(&bcm->lock, flags);
486 if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
487 spin_unlock_irqrestore(&bcm->lock, flags);
488 return -EBUSY;
489 }
490 old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
491 tasklet_disable(&bcm->isr_tasklet);
492 spin_unlock_irqrestore(&bcm->lock, flags);
493 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]);
749 mdelay(20);
750 }
751 spromctl &= ~0x10; /* SPROM WRITE enable. */
752 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
753 if (err)
754 goto err_ctlreg;
755 mdelay(500);
756 printk("100%% ]\n");
757 printk(KERN_INFO PFX "SPROM written.\n");
758 bcm43xx_controller_restart(bcm, "SPROM update");
759
760 return 0;
761err_ctlreg:
762 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
763 return -ENODEV;
764}
765
766static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
767{
John W. Linvillef2223132006-01-23 16:59:58 -0500768 u16 value;
769 u16 *sprom;
John W. Linvillef2223132006-01-23 16:59:58 -0500770#ifdef CONFIG_BCM947XX
771 char *c;
772#endif
773
774 sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
775 GFP_KERNEL);
776 if (!sprom) {
Michael Bueschea0922b2006-02-19 14:09:20 +0100777 printk(KERN_ERR PFX "sprom_extract OOM\n");
John W. Linvillef2223132006-01-23 16:59:58 -0500778 return -ENOMEM;
779 }
780#ifdef CONFIG_BCM947XX
781 sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
782 sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
783
784 if ((c = nvram_get("il0macaddr")) != NULL)
785 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
786
787 if ((c = nvram_get("et1macaddr")) != NULL)
788 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
789
790 sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
791 sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
792 sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
793
794 sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
795 sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
796 sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
797
798 sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
799#else
Michael Bueschea0922b2006-02-19 14:09:20 +0100800 bcm43xx_sprom_read(bcm, sprom);
John W. Linvillef2223132006-01-23 16:59:58 -0500801#endif
802
803 /* boardflags2 */
804 value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
805 bcm->sprom.boardflags2 = value;
806
807 /* il0macaddr */
808 value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
809 *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
810 value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
811 *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
812 value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
813 *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
814
815 /* et0macaddr */
816 value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
817 *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
818 value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
819 *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
820 value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
821 *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
822
823 /* et1macaddr */
824 value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
825 *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
826 value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
827 *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
828 value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
829 *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
830
831 /* ethernet phy settings */
832 value = sprom[BCM43xx_SPROM_ETHPHY];
833 bcm->sprom.et0phyaddr = (value & 0x001F);
834 bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;
835 bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;
836 bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;
837
838 /* boardrev, antennas, locale */
839 value = sprom[BCM43xx_SPROM_BOARDREV];
840 bcm->sprom.boardrev = (value & 0x00FF);
841 bcm->sprom.locale = (value & 0x0F00) >> 8;
842 bcm->sprom.antennas_aphy = (value & 0x3000) >> 12;
843 bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14;
844 if (modparam_locale != -1) {
845 if (modparam_locale >= 0 && modparam_locale <= 11) {
846 bcm->sprom.locale = modparam_locale;
847 printk(KERN_WARNING PFX "Operating with modified "
848 "LocaleCode %u (%s)\n",
849 bcm->sprom.locale,
850 bcm43xx_locale_string(bcm->sprom.locale));
851 } else {
852 printk(KERN_WARNING PFX "Module parameter \"locale\" "
853 "invalid value. (0 - 11)\n");
854 }
855 }
856
857 /* pa0b* */
858 value = sprom[BCM43xx_SPROM_PA0B0];
859 bcm->sprom.pa0b0 = value;
860 value = sprom[BCM43xx_SPROM_PA0B1];
861 bcm->sprom.pa0b1 = value;
862 value = sprom[BCM43xx_SPROM_PA0B2];
863 bcm->sprom.pa0b2 = value;
864
865 /* wl0gpio* */
866 value = sprom[BCM43xx_SPROM_WL0GPIO0];
867 if (value == 0x0000)
868 value = 0xFFFF;
869 bcm->sprom.wl0gpio0 = value & 0x00FF;
870 bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8;
871 value = sprom[BCM43xx_SPROM_WL0GPIO2];
872 if (value == 0x0000)
873 value = 0xFFFF;
874 bcm->sprom.wl0gpio2 = value & 0x00FF;
875 bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8;
876
877 /* maxpower */
878 value = sprom[BCM43xx_SPROM_MAXPWR];
879 bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8;
880 bcm->sprom.maxpower_bgphy = value & 0x00FF;
881
882 /* pa1b* */
883 value = sprom[BCM43xx_SPROM_PA1B0];
884 bcm->sprom.pa1b0 = value;
885 value = sprom[BCM43xx_SPROM_PA1B1];
886 bcm->sprom.pa1b1 = value;
887 value = sprom[BCM43xx_SPROM_PA1B2];
888 bcm->sprom.pa1b2 = value;
889
890 /* idle tssi target */
891 value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT];
892 bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF;
893 bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8;
894
895 /* boardflags */
896 value = sprom[BCM43xx_SPROM_BOARDFLAGS];
897 if (value == 0xFFFF)
898 value = 0x0000;
899 bcm->sprom.boardflags = value;
900
901 /* antenna gain */
902 value = sprom[BCM43xx_SPROM_ANTENNA_GAIN];
903 if (value == 0x0000 || value == 0xFFFF)
904 value = 0x0202;
905 /* convert values to Q5.2 */
906 bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4;
907 bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4;
908
909 kfree(sprom);
910
911 return 0;
912}
913
John W. Linvillef2223132006-01-23 16:59:58 -0500914static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
915{
916 struct ieee80211_geo geo;
917 struct ieee80211_channel *chan;
918 int have_a = 0, have_bg = 0;
919 int i, num80211;
Michael Buesch9e4a3752006-02-02 18:43:25 +0100920 u8 channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500921 struct bcm43xx_phyinfo *phy;
922 const char *iso_country;
923
924 memset(&geo, 0, sizeof(geo));
925 num80211 = bcm43xx_num_80211_cores(bcm);
926 for (i = 0; i < num80211; i++) {
927 phy = bcm->phy + i;
928 switch (phy->type) {
929 case BCM43xx_PHYTYPE_B:
930 case BCM43xx_PHYTYPE_G:
931 have_bg = 1;
932 break;
933 case BCM43xx_PHYTYPE_A:
934 have_a = 1;
935 break;
936 default:
937 assert(0);
938 }
939 }
940 iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
941
942 if (have_a) {
943 for (i = 0, channel = 0; channel < 201; channel++) {
John W. Linvillef2223132006-01-23 16:59:58 -0500944 chan = &geo.a[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +0100945 chan->freq = bcm43xx_channel_to_freq_a(channel);
John W. Linvillef2223132006-01-23 16:59:58 -0500946 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500947 }
948 geo.a_channels = i;
949 }
950 if (have_bg) {
951 for (i = 0, channel = 1; channel < 15; channel++) {
John W. Linvillef2223132006-01-23 16:59:58 -0500952 chan = &geo.bg[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +0100953 chan->freq = bcm43xx_channel_to_freq_bg(channel);
John W. Linvillef2223132006-01-23 16:59:58 -0500954 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500955 }
956 geo.bg_channels = i;
957 }
958 memcpy(geo.name, iso_country, 2);
959 if (0 /*TODO: Outdoor use only */)
960 geo.name[2] = 'O';
961 else if (0 /*TODO: Indoor use only */)
962 geo.name[2] = 'I';
963 else
964 geo.name[2] = ' ';
965 geo.name[3] = '\0';
966
967 ieee80211_set_geo(bcm->ieee, &geo);
968}
969
970/* DummyTransmission function, as documented on
971 * http://bcm-specs.sipsolutions.net/DummyTransmission
972 */
973void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
974{
Michael Buesch489423c2006-02-13 00:11:07 +0100975 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -0500976 unsigned int i, max_loop;
977 u16 value = 0;
978 u32 buffer[5] = {
979 0x00000000,
980 0x0000D400,
981 0x00000000,
982 0x00000001,
983 0x00000000,
984 };
985
Michael Buesch489423c2006-02-13 00:11:07 +0100986 switch (phy->type) {
John W. Linvillef2223132006-01-23 16:59:58 -0500987 case BCM43xx_PHYTYPE_A:
988 max_loop = 0x1E;
989 buffer[0] = 0xCC010200;
990 break;
991 case BCM43xx_PHYTYPE_B:
992 case BCM43xx_PHYTYPE_G:
993 max_loop = 0xFA;
994 buffer[0] = 0x6E840B00;
995 break;
996 default:
997 assert(0);
998 return;
999 }
1000
1001 for (i = 0; i < 5; i++)
1002 bcm43xx_ram_write(bcm, i * 4, buffer[i]);
1003
1004 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
1005
1006 bcm43xx_write16(bcm, 0x0568, 0x0000);
1007 bcm43xx_write16(bcm, 0x07C0, 0x0000);
Michael Buesch489423c2006-02-13 00:11:07 +01001008 bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0));
John W. Linvillef2223132006-01-23 16:59:58 -05001009 bcm43xx_write16(bcm, 0x0508, 0x0000);
1010 bcm43xx_write16(bcm, 0x050A, 0x0000);
1011 bcm43xx_write16(bcm, 0x054C, 0x0000);
1012 bcm43xx_write16(bcm, 0x056A, 0x0014);
1013 bcm43xx_write16(bcm, 0x0568, 0x0826);
1014 bcm43xx_write16(bcm, 0x0500, 0x0000);
1015 bcm43xx_write16(bcm, 0x0502, 0x0030);
1016
1017 for (i = 0x00; i < max_loop; i++) {
1018 value = bcm43xx_read16(bcm, 0x050E);
1019 if ((value & 0x0080) != 0)
1020 break;
1021 udelay(10);
1022 }
1023 for (i = 0x00; i < 0x0A; i++) {
1024 value = bcm43xx_read16(bcm, 0x050E);
1025 if ((value & 0x0400) != 0)
1026 break;
1027 udelay(10);
1028 }
1029 for (i = 0x00; i < 0x0A; i++) {
1030 value = bcm43xx_read16(bcm, 0x0690);
1031 if ((value & 0x0100) == 0)
1032 break;
1033 udelay(10);
1034 }
1035}
1036
1037static void key_write(struct bcm43xx_private *bcm,
1038 u8 index, u8 algorithm, const u16 *key)
1039{
1040 unsigned int i, basic_wep = 0;
1041 u32 offset;
1042 u16 value;
1043
1044 /* Write associated key information */
1045 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2),
1046 ((index << 4) | (algorithm & 0x0F)));
1047
1048 /* The first 4 WEP keys need extra love */
1049 if (((algorithm == BCM43xx_SEC_ALGO_WEP) ||
1050 (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4))
1051 basic_wep = 1;
1052
1053 /* Write key payload, 8 little endian words */
1054 offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE);
1055 for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) {
1056 value = cpu_to_le16(key[i]);
1057 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1058 offset + (i * 2), value);
1059
1060 if (!basic_wep)
1061 continue;
1062
1063 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1064 offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE,
1065 value);
1066 }
1067}
1068
1069static void keymac_write(struct bcm43xx_private *bcm,
1070 u8 index, const u32 *addr)
1071{
1072 /* for keys 0-3 there is no associated mac address */
1073 if (index < 4)
1074 return;
1075
1076 index -= 4;
1077 if (bcm->current_core->rev >= 5) {
1078 bcm43xx_shm_write32(bcm,
1079 BCM43xx_SHM_HWMAC,
1080 index * 2,
1081 cpu_to_be32(*addr));
1082 bcm43xx_shm_write16(bcm,
1083 BCM43xx_SHM_HWMAC,
1084 (index * 2) + 1,
1085 cpu_to_be16(*((u16 *)(addr + 1))));
1086 } else {
1087 if (index < 8) {
1088 TODO(); /* Put them in the macaddress filter */
1089 } else {
1090 TODO();
1091 /* Put them BCM43xx_SHM_SHARED, stating index 0x0120.
1092 Keep in mind to update the count of keymacs in 0x003E as well! */
1093 }
1094 }
1095}
1096
1097static int bcm43xx_key_write(struct bcm43xx_private *bcm,
1098 u8 index, u8 algorithm,
1099 const u8 *_key, int key_len,
1100 const u8 *mac_addr)
1101{
1102 u8 key[BCM43xx_SEC_KEYSIZE] = { 0 };
1103
1104 if (index >= ARRAY_SIZE(bcm->key))
1105 return -EINVAL;
1106 if (key_len > ARRAY_SIZE(key))
1107 return -EINVAL;
1108 if (algorithm < 1 || algorithm > 5)
1109 return -EINVAL;
1110
1111 memcpy(key, _key, key_len);
1112 key_write(bcm, index, algorithm, (const u16 *)key);
1113 keymac_write(bcm, index, (const u32 *)mac_addr);
1114
1115 bcm->key[index].algorithm = algorithm;
1116
1117 return 0;
1118}
1119
1120static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
1121{
1122 static const u32 zero_mac[2] = { 0 };
1123 unsigned int i,j, nr_keys = 54;
1124 u16 offset;
1125
1126 if (bcm->current_core->rev < 5)
1127 nr_keys = 16;
1128 assert(nr_keys <= ARRAY_SIZE(bcm->key));
1129
1130 for (i = 0; i < nr_keys; i++) {
1131 bcm->key[i].enabled = 0;
1132 /* returns for i < 4 immediately */
1133 keymac_write(bcm, i, zero_mac);
1134 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1135 0x100 + (i * 2), 0x0000);
1136 for (j = 0; j < 8; j++) {
1137 offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE);
1138 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1139 offset, 0x0000);
1140 }
1141 }
1142 dprintk(KERN_INFO PFX "Keys cleared\n");
1143}
1144
John W. Linvillef2223132006-01-23 16:59:58 -05001145/* Lowlevel core-switch function. This is only to be used in
1146 * bcm43xx_switch_core() and bcm43xx_probe_cores()
1147 */
1148static int _switch_core(struct bcm43xx_private *bcm, int core)
1149{
1150 int err;
1151 int attempts = 0;
Michael Buesch489423c2006-02-13 00:11:07 +01001152 u32 current_core;
John W. Linvillef2223132006-01-23 16:59:58 -05001153
1154 assert(core >= 0);
Michael Buesch489423c2006-02-13 00:11:07 +01001155 while (1) {
1156 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
John W. Linvillef2223132006-01-23 16:59:58 -05001157 (core * 0x1000) + 0x18000000);
Michael Buesch489423c2006-02-13 00:11:07 +01001158 if (unlikely(err))
1159 goto error;
1160 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
1161 &current_core);
1162 if (unlikely(err))
1163 goto error;
1164 current_core = (current_core - 0x18000000) / 0x1000;
1165 if (current_core == core)
1166 break;
John W. Linvillef2223132006-01-23 16:59:58 -05001167
Michael Buesch489423c2006-02-13 00:11:07 +01001168 if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES))
1169 goto error;
1170 udelay(10);
1171 }
1172#ifdef CONFIG_BCM947XX
1173 if (bcm->pci_dev->bus->number == 0)
1174 bcm->current_core_offset = 0x1000 * core;
1175 else
1176 bcm->current_core_offset = 0;
1177#endif
1178
1179 return 0;
1180error:
1181 printk(KERN_ERR PFX "Failed to switch to core %d\n", core);
1182 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05001183}
1184
1185int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core)
1186{
1187 int err;
1188
Michael Buesch489423c2006-02-13 00:11:07 +01001189 if (unlikely(!new_core))
John W. Linvillef2223132006-01-23 16:59:58 -05001190 return 0;
John W. Linvillef2223132006-01-23 16:59:58 -05001191 if (!(new_core->flags & BCM43xx_COREFLAG_AVAILABLE))
1192 return -ENODEV;
1193 if (bcm->current_core == new_core)
1194 return 0;
1195 err = _switch_core(bcm, new_core->index);
Michael Buesch489423c2006-02-13 00:11:07 +01001196 if (likely(!err))
John W. Linvillef2223132006-01-23 16:59:58 -05001197 bcm->current_core = new_core;
1198
1199 return err;
1200}
1201
Michael Buesch489423c2006-02-13 00:11:07 +01001202static int bcm43xx_core_enabled(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001203{
1204 u32 value;
1205
1206 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1207 value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET
1208 | BCM43xx_SBTMSTATELOW_REJECT;
1209
1210 return (value == BCM43xx_SBTMSTATELOW_CLOCK);
1211}
1212
1213/* disable current core */
1214static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags)
1215{
1216 u32 sbtmstatelow;
1217 u32 sbtmstatehigh;
1218 int i;
1219
1220 /* fetch sbtmstatelow from core information registers */
1221 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1222
1223 /* core is already in reset */
1224 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET)
1225 goto out;
1226
1227 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) {
1228 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1229 BCM43xx_SBTMSTATELOW_REJECT;
1230 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1231
1232 for (i = 0; i < 1000; i++) {
1233 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1234 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) {
1235 i = -1;
1236 break;
1237 }
1238 udelay(10);
1239 }
1240 if (i != -1) {
1241 printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n");
1242 return -EBUSY;
1243 }
1244
1245 for (i = 0; i < 1000; i++) {
1246 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1247 if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) {
1248 i = -1;
1249 break;
1250 }
1251 udelay(10);
1252 }
1253 if (i != -1) {
1254 printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n");
1255 return -EBUSY;
1256 }
1257
1258 sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1259 BCM43xx_SBTMSTATELOW_REJECT |
1260 BCM43xx_SBTMSTATELOW_RESET |
1261 BCM43xx_SBTMSTATELOW_CLOCK |
1262 core_flags;
1263 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1264 udelay(10);
1265 }
1266
1267 sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET |
1268 BCM43xx_SBTMSTATELOW_REJECT |
1269 core_flags;
1270 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1271
1272out:
1273 bcm->current_core->flags &= ~ BCM43xx_COREFLAG_ENABLED;
1274 return 0;
1275}
1276
1277/* enable (reset) current core */
1278static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags)
1279{
1280 u32 sbtmstatelow;
1281 u32 sbtmstatehigh;
1282 u32 sbimstate;
1283 int err;
1284
1285 err = bcm43xx_core_disable(bcm, core_flags);
1286 if (err)
1287 goto out;
1288
1289 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1290 BCM43xx_SBTMSTATELOW_RESET |
1291 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1292 core_flags;
1293 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1294 udelay(1);
1295
1296 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1297 if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) {
1298 sbtmstatehigh = 0x00000000;
1299 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh);
1300 }
1301
1302 sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE);
1303 if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) {
1304 sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT);
1305 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate);
1306 }
1307
1308 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1309 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1310 core_flags;
1311 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1312 udelay(1);
1313
1314 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags;
1315 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1316 udelay(1);
1317
1318 bcm->current_core->flags |= BCM43xx_COREFLAG_ENABLED;
1319 assert(err == 0);
1320out:
1321 return err;
1322}
1323
1324/* http://bcm-specs.sipsolutions.net/80211CoreReset */
1325void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
1326{
1327 u32 flags = 0x00040000;
1328
Michael Buesch77db31e2006-02-12 16:47:44 +01001329 if ((bcm43xx_core_enabled(bcm)) &&
1330 !bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05001331//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
1332#ifndef CONFIG_BCM947XX
1333 /* reset all used DMA controllers. */
1334 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1335 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
1336 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
1337 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1338 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1339 if (bcm->current_core->rev < 5)
1340 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1341#endif
1342 }
1343 if (bcm->shutting_down) {
1344 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1345 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1346 & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
1347 } else {
1348 if (connect_phy)
1349 flags |= 0x20000000;
1350 bcm43xx_phy_connect(bcm, connect_phy);
1351 bcm43xx_core_enable(bcm, flags);
1352 bcm43xx_write16(bcm, 0x03E6, 0x0000);
1353 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1354 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1355 | BCM43xx_SBF_400);
1356 }
1357}
1358
1359static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
1360{
1361 bcm43xx_radio_turn_off(bcm);
1362 bcm43xx_write16(bcm, 0x03E6, 0x00F4);
1363 bcm43xx_core_disable(bcm, 0);
1364}
1365
1366/* Mark the current 80211 core inactive.
1367 * "active_80211_core" is the other 80211 core, which is used.
1368 */
1369static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
1370 struct bcm43xx_coreinfo *active_80211_core)
1371{
1372 u32 sbtmstatelow;
1373 struct bcm43xx_coreinfo *old_core;
1374 int err = 0;
1375
1376 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1377 bcm43xx_radio_turn_off(bcm);
1378 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1379 sbtmstatelow &= ~0x200a0000;
1380 sbtmstatelow |= 0xa0000;
1381 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1382 udelay(1);
1383 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1384 sbtmstatelow &= ~0xa0000;
1385 sbtmstatelow |= 0x80000;
1386 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1387 udelay(1);
1388
1389 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
1390 old_core = bcm->current_core;
1391 err = bcm43xx_switch_core(bcm, active_80211_core);
1392 if (err)
1393 goto out;
1394 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1395 sbtmstatelow &= ~0x20000000;
1396 sbtmstatelow |= 0x20000000;
1397 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1398 err = bcm43xx_switch_core(bcm, old_core);
1399 }
1400
1401out:
1402 return err;
1403}
1404
Michael Buesch489423c2006-02-13 00:11:07 +01001405static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001406{
1407 u32 v0, v1;
1408 u16 tmp;
1409 struct bcm43xx_xmitstatus stat;
1410
1411 assert(bcm->current_core->id == BCM43xx_COREID_80211);
1412 assert(bcm->current_core->rev >= 5);
1413
1414 while (1) {
1415 v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
1416 if (!v0)
1417 break;
1418 v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
1419
1420 stat.cookie = (v0 >> 16) & 0x0000FFFF;
1421 tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1));
1422 stat.flags = tmp & 0xFF;
1423 stat.cnt1 = (tmp & 0x0F00) >> 8;
1424 stat.cnt2 = (tmp & 0xF000) >> 12;
1425 stat.seq = (u16)(v1 & 0xFFFF);
1426 stat.unknown = (u16)((v1 >> 16) & 0xFF);
1427
1428 bcm43xx_debugfs_log_txstat(bcm, &stat);
1429
1430 if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE)
1431 continue;
1432 if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) {
1433 //TODO: packet was not acked (was lost)
1434 }
1435 //TODO: There are more (unknown) flags to test. see bcm43xx_main.h
1436
Michael Buesch77db31e2006-02-12 16:47:44 +01001437 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001438 bcm43xx_pio_handle_xmitstatus(bcm, &stat);
1439 else
1440 bcm43xx_dma_handle_xmitstatus(bcm, &stat);
1441 }
1442}
1443
Michael Buesch489423c2006-02-13 00:11:07 +01001444static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001445{
1446 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
1447 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F);
1448 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1449 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4));
1450 assert(bcm->noisecalc.core_at_start == bcm->current_core);
1451 assert(bcm->noisecalc.channel_at_start == bcm->current_core->radio->channel);
1452}
1453
1454static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm)
1455{
1456 /* Top half of Link Quality calculation. */
1457
1458 if (bcm->noisecalc.calculation_running)
1459 return;
1460 bcm->noisecalc.core_at_start = bcm->current_core;
1461 bcm->noisecalc.channel_at_start = bcm->current_core->radio->channel;
1462 bcm->noisecalc.calculation_running = 1;
1463 bcm->noisecalc.nr_samples = 0;
1464
1465 bcm43xx_generate_noise_sample(bcm);
1466}
1467
Michael Buesch489423c2006-02-13 00:11:07 +01001468static void handle_irq_noise(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001469{
1470 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1471 u16 tmp;
1472 u8 noise[4];
1473 u8 i, j;
1474 s32 average;
1475
1476 /* Bottom half of Link Quality calculation. */
1477
1478 assert(bcm->noisecalc.calculation_running);
1479 if (bcm->noisecalc.core_at_start != bcm->current_core ||
1480 bcm->noisecalc.channel_at_start != radio->channel)
1481 goto drop_calculation;
1482 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);
1483 noise[0] = (tmp & 0x00FF);
1484 noise[1] = (tmp & 0xFF00) >> 8;
1485 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A);
1486 noise[2] = (tmp & 0x00FF);
1487 noise[3] = (tmp & 0xFF00) >> 8;
1488 if (noise[0] == 0x7F || noise[1] == 0x7F ||
1489 noise[2] == 0x7F || noise[3] == 0x7F)
1490 goto generate_new;
1491
1492 /* Get the noise samples. */
1493 assert(bcm->noisecalc.nr_samples <= 8);
1494 i = bcm->noisecalc.nr_samples;
1495 noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1496 noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1497 noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1498 noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1499 bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]];
1500 bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]];
1501 bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]];
1502 bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]];
1503 bcm->noisecalc.nr_samples++;
1504 if (bcm->noisecalc.nr_samples == 8) {
1505 /* Calculate the Link Quality by the noise samples. */
1506 average = 0;
1507 for (i = 0; i < 8; i++) {
1508 for (j = 0; j < 4; j++)
1509 average += bcm->noisecalc.samples[i][j];
1510 }
1511 average /= (8 * 4);
1512 average *= 125;
1513 average += 64;
1514 average /= 128;
1515 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
1516 tmp = (tmp / 128) & 0x1F;
1517 if (tmp >= 8)
1518 average += 2;
1519 else
1520 average -= 25;
1521 if (tmp == 8)
1522 average -= 72;
1523 else
1524 average -= 48;
1525
1526 if (average > -65)
1527 bcm->stats.link_quality = 0;
1528 else if (average > -75)
1529 bcm->stats.link_quality = 1;
1530 else if (average > -85)
1531 bcm->stats.link_quality = 2;
1532 else
1533 bcm->stats.link_quality = 3;
1534// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
1535drop_calculation:
1536 bcm->noisecalc.calculation_running = 0;
1537 return;
1538 }
1539generate_new:
1540 bcm43xx_generate_noise_sample(bcm);
1541}
1542
Michael Buesch489423c2006-02-13 00:11:07 +01001543static void handle_irq_ps(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001544{
1545 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
1546 ///TODO: PS TBTT
1547 } else {
1548 if (1/*FIXME: the last PSpoll frame was sent successfully */)
1549 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
1550 }
1551 if (bcm->ieee->iw_mode == IW_MODE_ADHOC)
1552 bcm->reg124_set_0x4 = 1;
1553 //FIXME else set to false?
1554}
1555
Michael Buesch489423c2006-02-13 00:11:07 +01001556static void handle_irq_reg124(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001557{
1558 if (!bcm->reg124_set_0x4)
1559 return;
1560 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1561 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD)
1562 | 0x4);
1563 //FIXME: reset reg124_set_0x4 to false?
1564}
1565
Michael Buesch489423c2006-02-13 00:11:07 +01001566static void handle_irq_pmq(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001567{
1568 u32 tmp;
1569
1570 //TODO: AP mode.
1571
1572 while (1) {
1573 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS);
1574 if (!(tmp & 0x00000008))
1575 break;
1576 }
1577 /* 16bit write is odd, but correct. */
1578 bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);
1579}
1580
1581static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm,
1582 u16 ram_offset, u16 shm_size_offset)
1583{
1584 u32 value;
1585 u16 size = 0;
1586
1587 /* Timestamp. */
1588 //FIXME: assumption: The chip sets the timestamp
1589 value = 0;
1590 bcm43xx_ram_write(bcm, ram_offset++, value);
1591 bcm43xx_ram_write(bcm, ram_offset++, value);
1592 size += 8;
1593
1594 /* Beacon Interval / Capability Information */
1595 value = 0x0000;//FIXME: Which interval?
1596 value |= (1 << 0) << 16; /* ESS */
1597 value |= (1 << 2) << 16; /* CF Pollable */ //FIXME?
1598 value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME?
1599 if (!bcm->ieee->open_wep)
1600 value |= (1 << 4) << 16; /* Privacy */
1601 bcm43xx_ram_write(bcm, ram_offset++, value);
1602 size += 4;
1603
1604 /* SSID */
1605 //TODO
1606
1607 /* FH Parameter Set */
1608 //TODO
1609
1610 /* DS Parameter Set */
1611 //TODO
1612
1613 /* CF Parameter Set */
1614 //TODO
1615
1616 /* TIM */
1617 //TODO
1618
1619 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);
1620}
1621
Michael Buesch489423c2006-02-13 00:11:07 +01001622static void handle_irq_beacon(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001623{
1624 u32 status;
1625
1626 bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
1627 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
1628
1629 if ((status & 0x1) && (status & 0x2)) {
1630 /* ACK beacon IRQ. */
1631 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
1632 BCM43xx_IRQ_BEACON);
1633 bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;
1634 return;
1635 }
1636 if (!(status & 0x1)) {
1637 bcm43xx_generate_beacon_template(bcm, 0x68, 0x18);
1638 status |= 0x1;
1639 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1640 }
1641 if (!(status & 0x2)) {
1642 bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A);
1643 status |= 0x2;
1644 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1645 }
1646}
1647
1648/* Debug helper for irq bottom-half to print all reason registers. */
1649#define bcmirq_print_reasons(description) \
1650 do { \
1651 dprintkl(KERN_ERR PFX description "\n" \
1652 KERN_ERR PFX " Generic Reason: 0x%08x\n" \
1653 KERN_ERR PFX " DMA reasons: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n" \
1654 KERN_ERR PFX " DMA TX status: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", \
1655 reason, \
1656 dma_reason[0], dma_reason[1], \
1657 dma_reason[2], dma_reason[3], \
1658 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_BASE + BCM43xx_DMA_TX_STATUS), \
1659 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_BASE + BCM43xx_DMA_TX_STATUS), \
1660 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_BASE + BCM43xx_DMA_TX_STATUS), \
1661 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_BASE + BCM43xx_DMA_TX_STATUS)); \
1662 } while (0)
1663
1664/* Interrupt handler bottom-half */
1665static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
1666{
1667 u32 reason;
1668 u32 dma_reason[4];
1669 int activity = 0;
1670 unsigned long flags;
1671
1672#ifdef CONFIG_BCM43XX_DEBUG
1673 u32 _handled = 0x00000000;
1674# define bcmirq_handled(irq) do { _handled |= (irq); } while (0)
1675#else
1676# define bcmirq_handled(irq) do { /* nothing */ } while (0)
1677#endif /* CONFIG_BCM43XX_DEBUG*/
1678
1679 spin_lock_irqsave(&bcm->lock, flags);
1680 reason = bcm->irq_reason;
1681 dma_reason[0] = bcm->dma_reason[0];
1682 dma_reason[1] = bcm->dma_reason[1];
1683 dma_reason[2] = bcm->dma_reason[2];
1684 dma_reason[3] = bcm->dma_reason[3];
1685
1686 if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
1687 /* TX error. We get this when Template Ram is written in wrong endianess
1688 * in dummy_tx(). We also get this if something is wrong with the TX header
1689 * on DMA or PIO queues.
1690 * Maybe we get this in other error conditions, too.
1691 */
1692 bcmirq_print_reasons("XMIT ERROR");
1693 bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
1694 }
1695
1696 if (reason & BCM43xx_IRQ_PS) {
1697 handle_irq_ps(bcm);
1698 bcmirq_handled(BCM43xx_IRQ_PS);
1699 }
1700
1701 if (reason & BCM43xx_IRQ_REG124) {
1702 handle_irq_reg124(bcm);
1703 bcmirq_handled(BCM43xx_IRQ_REG124);
1704 }
1705
1706 if (reason & BCM43xx_IRQ_BEACON) {
1707 if (bcm->ieee->iw_mode == IW_MODE_MASTER)
1708 handle_irq_beacon(bcm);
1709 bcmirq_handled(BCM43xx_IRQ_BEACON);
1710 }
1711
1712 if (reason & BCM43xx_IRQ_PMQ) {
1713 handle_irq_pmq(bcm);
1714 bcmirq_handled(BCM43xx_IRQ_PMQ);
1715 }
1716
1717 if (reason & BCM43xx_IRQ_SCAN) {
1718 /*TODO*/
1719 //bcmirq_handled(BCM43xx_IRQ_SCAN);
1720 }
1721
1722 if (reason & BCM43xx_IRQ_NOISE) {
1723 handle_irq_noise(bcm);
1724 bcmirq_handled(BCM43xx_IRQ_NOISE);
1725 }
1726
1727 /* Check the DMA reason registers for received data. */
1728 assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
1729 assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
1730 if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
Michael Buesch77db31e2006-02-12 16:47:44 +01001731 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001732 bcm43xx_pio_rx(bcm->current_core->pio->queue0);
1733 else
1734 bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0);
Michael Bueschdcfd7202006-02-12 20:25:55 +01001735 /* We intentionally don't set "activity" to 1, here. */
John W. Linvillef2223132006-01-23 16:59:58 -05001736 }
1737 if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
1738 if (likely(bcm->current_core->rev < 5)) {
Michael Buesch77db31e2006-02-12 16:47:44 +01001739 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001740 bcm43xx_pio_rx(bcm->current_core->pio->queue3);
1741 else
1742 bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1);
1743 activity = 1;
1744 } else
1745 assert(0);
1746 }
1747 bcmirq_handled(BCM43xx_IRQ_RX);
1748
1749 if (reason & BCM43xx_IRQ_XMIT_STATUS) {
1750 if (bcm->current_core->rev >= 5) {
1751 handle_irq_transmit_status(bcm);
1752 activity = 1;
1753 }
1754 //TODO: In AP mode, this also causes sending of powersave responses.
1755 bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
1756 }
1757
1758 /* We get spurious IRQs, althought they are masked.
1759 * Assume they are void and ignore them.
1760 */
1761 bcmirq_handled(~(bcm->irq_savedstate));
1762 /* IRQ_PIO_WORKAROUND is handled in the top-half. */
1763 bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);
1764#ifdef CONFIG_BCM43XX_DEBUG
1765 if (unlikely(reason & ~_handled)) {
1766 printkl(KERN_WARNING PFX
1767 "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, "
1768 "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1769 reason, (reason & ~_handled),
1770 dma_reason[0], dma_reason[1],
1771 dma_reason[2], dma_reason[3]);
1772 }
1773#endif
1774#undef bcmirq_handled
1775
1776 if (!modparam_noleds)
1777 bcm43xx_leds_update(bcm, activity);
1778 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
1779 spin_unlock_irqrestore(&bcm->lock, flags);
1780}
1781
1782#undef bcmirq_print_reasons
1783
Michael Buesch489423c2006-02-13 00:11:07 +01001784static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm,
1785 u32 reason, u32 mask)
John W. Linvillef2223132006-01-23 16:59:58 -05001786{
1787 bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
1788 & 0x0001dc00;
1789 bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
1790 & 0x0000dc00;
1791 bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
1792 & 0x0000dc00;
1793 bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
1794 & 0x0001dc00;
1795
Michael Buesch77db31e2006-02-12 16:47:44 +01001796 if (bcm43xx_using_pio(bcm) &&
John W. Linvillef2223132006-01-23 16:59:58 -05001797 (bcm->current_core->rev < 3) &&
1798 (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
1799 /* Apply a PIO specific workaround to the dma_reasons */
1800
1801#define apply_pio_workaround(BASE, QNUM) \
1802 do { \
1803 if (bcm43xx_read16(bcm, BASE + BCM43xx_PIO_RXCTL) & BCM43xx_PIO_RXCTL_DATAAVAILABLE) \
1804 bcm->dma_reason[QNUM] |= 0x00010000; \
1805 else \
1806 bcm->dma_reason[QNUM] &= ~0x00010000; \
1807 } while (0)
1808
1809 apply_pio_workaround(BCM43xx_MMIO_PIO1_BASE, 0);
1810 apply_pio_workaround(BCM43xx_MMIO_PIO2_BASE, 1);
1811 apply_pio_workaround(BCM43xx_MMIO_PIO3_BASE, 2);
1812 apply_pio_workaround(BCM43xx_MMIO_PIO4_BASE, 3);
1813
1814#undef apply_pio_workaround
1815 }
1816
1817 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
1818 reason & mask);
1819
1820 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
1821 bcm->dma_reason[0]);
1822 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
1823 bcm->dma_reason[1]);
1824 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
1825 bcm->dma_reason[2]);
1826 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
1827 bcm->dma_reason[3]);
1828}
1829
1830/* Interrupt handler top-half */
1831static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
1832{
1833 struct bcm43xx_private *bcm = dev_id;
1834 u32 reason, mask;
1835
1836 if (!bcm)
1837 return IRQ_NONE;
1838
1839 spin_lock(&bcm->lock);
1840
1841 reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
1842 if (reason == 0xffffffff) {
1843 /* irq not for us (shared irq) */
1844 spin_unlock(&bcm->lock);
1845 return IRQ_NONE;
1846 }
1847 mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
1848 if (!(reason & mask)) {
1849 spin_unlock(&bcm->lock);
1850 return IRQ_HANDLED;
1851 }
1852
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
1869 spin_unlock(&bcm->lock);
1870
1871 return IRQ_HANDLED;
1872}
1873
Michael Buescha4a600d2006-02-01 22:09:52 +01001874static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
John W. Linvillef2223132006-01-23 16:59:58 -05001875{
Michael Buescha4a600d2006-02-01 22:09:52 +01001876 if (bcm->firmware_norelease && !force)
John W. Linvillef2223132006-01-23 16:59:58 -05001877 return; /* Suspending or controller reset. */
1878 release_firmware(bcm->ucode);
1879 bcm->ucode = NULL;
1880 release_firmware(bcm->pcm);
1881 bcm->pcm = NULL;
1882 release_firmware(bcm->initvals0);
1883 bcm->initvals0 = NULL;
1884 release_firmware(bcm->initvals1);
1885 bcm->initvals1 = NULL;
1886}
1887
1888static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
1889{
1890 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1891 u8 rev = bcm->current_core->rev;
1892 int err = 0;
1893 int nr;
1894 char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
1895
1896 if (!bcm->ucode) {
1897 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
1898 (rev >= 5 ? 5 : rev),
1899 modparam_fwpostfix);
1900 err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
1901 if (err) {
1902 printk(KERN_ERR PFX
1903 "Error: Microcode \"%s\" not available or load failed.\n",
1904 buf);
1905 goto error;
1906 }
1907 }
1908
1909 if (!bcm->pcm) {
1910 snprintf(buf, ARRAY_SIZE(buf),
1911 "bcm43xx_pcm%d%s.fw",
1912 (rev < 5 ? 4 : 5),
1913 modparam_fwpostfix);
1914 err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
1915 if (err) {
1916 printk(KERN_ERR PFX
1917 "Error: PCM \"%s\" not available or load failed.\n",
1918 buf);
1919 goto error;
1920 }
1921 }
1922
1923 if (!bcm->initvals0) {
1924 if (rev == 2 || rev == 4) {
1925 switch (phy->type) {
1926 case BCM43xx_PHYTYPE_A:
1927 nr = 3;
1928 break;
1929 case BCM43xx_PHYTYPE_B:
1930 case BCM43xx_PHYTYPE_G:
1931 nr = 1;
1932 break;
1933 default:
1934 goto err_noinitval;
1935 }
1936
1937 } else if (rev >= 5) {
1938 switch (phy->type) {
1939 case BCM43xx_PHYTYPE_A:
1940 nr = 7;
1941 break;
1942 case BCM43xx_PHYTYPE_B:
1943 case BCM43xx_PHYTYPE_G:
1944 nr = 5;
1945 break;
1946 default:
1947 goto err_noinitval;
1948 }
1949 } else
1950 goto err_noinitval;
1951 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
1952 nr, modparam_fwpostfix);
1953
1954 err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
1955 if (err) {
1956 printk(KERN_ERR PFX
1957 "Error: InitVals \"%s\" not available or load failed.\n",
1958 buf);
1959 goto error;
1960 }
1961 if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
1962 printk(KERN_ERR PFX "InitVals fileformat error.\n");
1963 goto error;
1964 }
1965 }
1966
1967 if (!bcm->initvals1) {
1968 if (rev >= 5) {
1969 u32 sbtmstatehigh;
1970
1971 switch (phy->type) {
1972 case BCM43xx_PHYTYPE_A:
1973 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1974 if (sbtmstatehigh & 0x00010000)
1975 nr = 9;
1976 else
1977 nr = 10;
1978 break;
1979 case BCM43xx_PHYTYPE_B:
1980 case BCM43xx_PHYTYPE_G:
1981 nr = 6;
1982 break;
1983 default:
1984 goto err_noinitval;
1985 }
1986 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
1987 nr, modparam_fwpostfix);
1988
1989 err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
1990 if (err) {
1991 printk(KERN_ERR PFX
1992 "Error: InitVals \"%s\" not available or load failed.\n",
1993 buf);
1994 goto error;
1995 }
1996 if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
1997 printk(KERN_ERR PFX "InitVals fileformat error.\n");
1998 goto error;
1999 }
2000 }
2001 }
2002
2003out:
2004 return err;
2005error:
Michael Buescha4a600d2006-02-01 22:09:52 +01002006 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002007 goto out;
2008err_noinitval:
2009 printk(KERN_ERR PFX "Error: No InitVals available!\n");
2010 err = -ENOENT;
2011 goto error;
2012}
2013
2014static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
2015{
2016 const u32 *data;
2017 unsigned int i, len;
2018
2019#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2020 bcm43xx_mmioprint_enable(bcm);
2021#else
2022 bcm43xx_mmioprint_disable(bcm);
2023#endif
2024
2025 /* Upload Microcode. */
2026 data = (u32 *)(bcm->ucode->data);
2027 len = bcm->ucode->size / sizeof(u32);
2028 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
2029 for (i = 0; i < len; i++) {
2030 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2031 be32_to_cpu(data[i]));
2032 udelay(10);
2033 }
2034
2035 /* Upload PCM data. */
2036 data = (u32 *)(bcm->pcm->data);
2037 len = bcm->pcm->size / sizeof(u32);
2038 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
2039 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
2040 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
2041 for (i = 0; i < len; i++) {
2042 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2043 be32_to_cpu(data[i]));
2044 udelay(10);
2045 }
2046
2047#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2048 bcm43xx_mmioprint_disable(bcm);
2049#else
2050 bcm43xx_mmioprint_enable(bcm);
2051#endif
2052}
2053
Michael Buescha4a600d2006-02-01 22:09:52 +01002054static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,
2055 const struct bcm43xx_initval *data,
2056 const unsigned int len)
John W. Linvillef2223132006-01-23 16:59:58 -05002057{
2058 u16 offset, size;
2059 u32 value;
2060 unsigned int i;
2061
2062 for (i = 0; i < len; i++) {
2063 offset = be16_to_cpu(data[i].offset);
2064 size = be16_to_cpu(data[i].size);
2065 value = be32_to_cpu(data[i].value);
2066
Michael Buescha4a600d2006-02-01 22:09:52 +01002067 if (unlikely(offset >= 0x1000))
2068 goto err_format;
2069 if (size == 2) {
2070 if (unlikely(value & 0xFFFF0000))
2071 goto err_format;
2072 bcm43xx_write16(bcm, offset, (u16)value);
2073 } else if (size == 4) {
John W. Linvillef2223132006-01-23 16:59:58 -05002074 bcm43xx_write32(bcm, offset, value);
Michael Buescha4a600d2006-02-01 22:09:52 +01002075 } else
2076 goto err_format;
John W. Linvillef2223132006-01-23 16:59:58 -05002077 }
Michael Buescha4a600d2006-02-01 22:09:52 +01002078
2079 return 0;
2080
2081err_format:
2082 printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. "
2083 "Please fix your bcm43xx firmware files.\n");
2084 return -EPROTO;
John W. Linvillef2223132006-01-23 16:59:58 -05002085}
2086
Michael Buescha4a600d2006-02-01 22:09:52 +01002087static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002088{
Michael Buescha4a600d2006-02-01 22:09:52 +01002089 int err;
2090
John W. Linvillef2223132006-01-23 16:59:58 -05002091#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2092 bcm43xx_mmioprint_enable(bcm);
2093#else
2094 bcm43xx_mmioprint_disable(bcm);
2095#endif
2096
Michael Buescha4a600d2006-02-01 22:09:52 +01002097 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
2098 bcm->initvals0->size / sizeof(struct bcm43xx_initval));
2099 if (err)
2100 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002101 if (bcm->initvals1) {
Michael Buescha4a600d2006-02-01 22:09:52 +01002102 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
2103 bcm->initvals1->size / sizeof(struct bcm43xx_initval));
2104 if (err)
2105 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002106 }
2107
Michael Buescha4a600d2006-02-01 22:09:52 +01002108out:
John W. Linvillef2223132006-01-23 16:59:58 -05002109#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2110 bcm43xx_mmioprint_disable(bcm);
2111#else
2112 bcm43xx_mmioprint_enable(bcm);
2113#endif
Michael Buescha4a600d2006-02-01 22:09:52 +01002114 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002115}
2116
2117static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
2118{
2119 int res;
2120 unsigned int i;
2121 u32 data;
2122
2123 bcm->irq = bcm->pci_dev->irq;
2124#ifdef CONFIG_BCM947XX
2125 if (bcm->pci_dev->bus->number == 0) {
2126 struct pci_dev *d = NULL;
2127 /* FIXME: we will probably need more device IDs here... */
2128 d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
2129 if (d != NULL) {
2130 bcm->irq = d->irq;
2131 }
2132 }
2133#endif
2134 res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
Michael Buesch65f3f192006-01-31 20:11:38 +01002135 SA_SHIRQ, KBUILD_MODNAME, bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002136 if (res) {
2137 printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
Michael Buesch489423c2006-02-13 00:11:07 +01002138 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002139 }
2140 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
2141 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
2142 i = 0;
2143 while (1) {
2144 data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2145 if (data == BCM43xx_IRQ_READY)
2146 break;
2147 i++;
2148 if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
2149 printk(KERN_ERR PFX "Card IRQ register not responding. "
2150 "Giving up.\n");
2151 free_irq(bcm->irq, bcm);
2152 return -ENODEV;
2153 }
2154 udelay(10);
2155 }
2156 // dummy read
2157 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2158
2159 return 0;
2160}
2161
2162/* Switch to the core used to write the GPIO register.
2163 * This is either the ChipCommon, or the PCI core.
2164 */
Michael Buesch489423c2006-02-13 00:11:07 +01002165static int switch_to_gpio_core(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002166{
2167 int err;
2168
2169 /* Where to find the GPIO register depends on the chipset.
2170 * If it has a ChipCommon, its register at offset 0x6c is the GPIO
2171 * control register. Otherwise the register at offset 0x6c in the
2172 * PCI core is the GPIO control register.
2173 */
2174 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
2175 if (err == -ENODEV) {
2176 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
Michael Buesch489423c2006-02-13 00:11:07 +01002177 if (unlikely(err == -ENODEV)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002178 printk(KERN_ERR PFX "gpio error: "
2179 "Neither ChipCommon nor PCI core available!\n");
2180 return -ENODEV;
Michael Buesch489423c2006-02-13 00:11:07 +01002181 } else if (unlikely(err != 0))
John W. Linvillef2223132006-01-23 16:59:58 -05002182 return -ENODEV;
Michael Buesch489423c2006-02-13 00:11:07 +01002183 } else if (unlikely(err != 0))
John W. Linvillef2223132006-01-23 16:59:58 -05002184 return -ENODEV;
2185
2186 return 0;
2187}
2188
2189/* Initialize the GPIOs
2190 * http://bcm-specs.sipsolutions.net/GPIO
2191 */
2192static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
2193{
2194 struct bcm43xx_coreinfo *old_core;
2195 int err;
2196 u32 mask, value;
2197
2198 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2199 value &= ~0xc000;
2200 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
2201
2202 mask = 0x0000001F;
2203 value = 0x0000000F;
2204 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL,
2205 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0);
2206 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2207 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
2208
2209 old_core = bcm->current_core;
2210
2211 err = switch_to_gpio_core(bcm);
2212 if (err)
2213 return err;
2214
2215 if (bcm->current_core->rev >= 2){
2216 mask |= 0x10;
2217 value |= 0x10;
2218 }
2219 if (bcm->chip_id == 0x4301) {
2220 mask |= 0x60;
2221 value |= 0x60;
2222 }
2223 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
2224 mask |= 0x200;
2225 value |= 0x200;
2226 }
2227
2228 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
2229 (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value);
2230
2231 err = bcm43xx_switch_core(bcm, old_core);
2232 assert(err == 0);
2233
2234 return 0;
2235}
2236
2237/* Turn off all GPIO stuff. Call this on module unload, for example. */
2238static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
2239{
2240 struct bcm43xx_coreinfo *old_core;
2241 int err;
2242
2243 old_core = bcm->current_core;
2244 err = switch_to_gpio_core(bcm);
2245 if (err)
2246 return err;
2247 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);
2248 err = bcm43xx_switch_core(bcm, old_core);
2249 assert(err == 0);
2250
2251 return 0;
2252}
2253
2254/* http://bcm-specs.sipsolutions.net/EnableMac */
2255void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
2256{
2257 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2258 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2259 | BCM43xx_SBF_MAC_ENABLED);
2260 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
2261 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
2262 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2263 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
2264}
2265
2266/* http://bcm-specs.sipsolutions.net/SuspendMAC */
2267void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
2268{
2269 int i;
2270 u32 tmp;
2271
2272 bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
2273 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2274 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2275 & ~BCM43xx_SBF_MAC_ENABLED);
2276 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
Michael Buesch921e4852006-02-08 17:55:55 +01002277 for (i = 100000; i; i--) {
John W. Linvillef2223132006-01-23 16:59:58 -05002278 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch921e4852006-02-08 17:55:55 +01002279 if (tmp & BCM43xx_IRQ_READY)
2280 return;
John W. Linvillef2223132006-01-23 16:59:58 -05002281 udelay(10);
2282 }
Michael Buesch921e4852006-02-08 17:55:55 +01002283 printkl(KERN_ERR PFX "MAC suspend failed\n");
John W. Linvillef2223132006-01-23 16:59:58 -05002284}
2285
2286void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
2287 int iw_mode)
2288{
2289 unsigned long flags;
2290 u32 status;
2291
2292 spin_lock_irqsave(&bcm->ieee->lock, flags);
2293 bcm->ieee->iw_mode = iw_mode;
2294 spin_unlock_irqrestore(&bcm->ieee->lock, flags);
2295 if (iw_mode == IW_MODE_MONITOR)
2296 bcm->net_dev->type = ARPHRD_IEEE80211;
2297 else
2298 bcm->net_dev->type = ARPHRD_ETHER;
2299
2300 if (!bcm->initialized)
2301 return;
2302
2303 bcm43xx_mac_suspend(bcm);
2304 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2305 /* Reset status to infrastructured mode */
2306 status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
2307 /*FIXME: We actually set promiscuous mode as well, until we don't
2308 * get the HW mac filter working */
2309 status |= BCM43xx_SBF_MODE_NOTADHOC | BCM43xx_SBF_MODE_PROMISC;
2310
2311 switch (iw_mode) {
2312 case IW_MODE_MONITOR:
2313 status |= (BCM43xx_SBF_MODE_PROMISC |
2314 BCM43xx_SBF_MODE_MONITOR);
2315 break;
2316 case IW_MODE_ADHOC:
2317 status &= ~BCM43xx_SBF_MODE_NOTADHOC;
2318 break;
2319 case IW_MODE_MASTER:
2320 case IW_MODE_SECOND:
2321 case IW_MODE_REPEAT:
2322 /* TODO: No AP/Repeater mode for now :-/ */
2323 TODO();
2324 break;
2325 case IW_MODE_INFRA:
2326 /* nothing to be done here... */
2327 break;
2328 default:
2329 printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode);
2330 }
2331
2332 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
2333 bcm43xx_mac_enable(bcm);
2334}
2335
2336/* This is the opposite of bcm43xx_chip_init() */
2337static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
2338{
2339 bcm43xx_radio_turn_off(bcm);
2340 if (!modparam_noleds)
2341 bcm43xx_leds_exit(bcm);
2342 bcm43xx_gpio_cleanup(bcm);
2343 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002344 bcm43xx_release_firmware(bcm, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05002345}
2346
2347/* Initialize the chip
2348 * http://bcm-specs.sipsolutions.net/ChipInit
2349 */
2350static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
2351{
2352 int err;
2353 int iw_mode = bcm->ieee->iw_mode;
2354 int tmp;
2355 u32 value32;
2356 u16 value16;
2357
2358 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2359 BCM43xx_SBF_CORE_READY
2360 | BCM43xx_SBF_400);
2361
2362 err = bcm43xx_request_firmware(bcm);
2363 if (err)
2364 goto out;
2365 bcm43xx_upload_microcode(bcm);
2366
2367 err = bcm43xx_initialize_irq(bcm);
2368 if (err)
Michael Buescha4a600d2006-02-01 22:09:52 +01002369 goto err_release_fw;
John W. Linvillef2223132006-01-23 16:59:58 -05002370
2371 err = bcm43xx_gpio_init(bcm);
2372 if (err)
2373 goto err_free_irq;
2374
Michael Buescha4a600d2006-02-01 22:09:52 +01002375 err = bcm43xx_upload_initvals(bcm);
2376 if (err)
2377 goto err_gpio_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002378 bcm43xx_radio_turn_on(bcm);
2379
2380 if (modparam_noleds)
2381 bcm43xx_leds_turn_off(bcm);
2382 else
2383 bcm43xx_leds_update(bcm, 0);
2384
2385 bcm43xx_write16(bcm, 0x03E6, 0x0000);
2386 err = bcm43xx_phy_init(bcm);
2387 if (err)
2388 goto err_radio_off;
2389
2390 /* Select initial Interference Mitigation. */
2391 tmp = bcm->current_core->radio->interfmode;
2392 bcm->current_core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
2393 bcm43xx_radio_set_interference_mitigation(bcm, tmp);
2394
2395 bcm43xx_phy_set_antenna_diversity(bcm);
2396 bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT);
2397 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) {
2398 value16 = bcm43xx_read16(bcm, 0x005E);
2399 value16 |= 0x0004;
2400 bcm43xx_write16(bcm, 0x005E, value16);
2401 }
2402 bcm43xx_write32(bcm, 0x0100, 0x01000000);
2403 if (bcm->current_core->rev < 5)
2404 bcm43xx_write32(bcm, 0x010C, 0x01000000);
2405
2406 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2407 value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC;
2408 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2409 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2410 value32 |= BCM43xx_SBF_MODE_NOTADHOC;
2411 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2412 /*FIXME: For now, use promiscuous mode at all times; otherwise we don't
2413 get broadcast or multicast packets */
2414 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2415 value32 |= BCM43xx_SBF_MODE_PROMISC;
2416 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2417
2418 if (iw_mode == IW_MODE_MONITOR) {
2419 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2420 value32 |= BCM43xx_SBF_MODE_PROMISC;
2421 value32 |= BCM43xx_SBF_MODE_MONITOR;
2422 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2423 }
2424 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2425 value32 |= 0x100000; //FIXME: What's this? Is this correct?
2426 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2427
Michael Buesch77db31e2006-02-12 16:47:44 +01002428 if (bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002429 bcm43xx_write32(bcm, 0x0210, 0x00000100);
2430 bcm43xx_write32(bcm, 0x0230, 0x00000100);
2431 bcm43xx_write32(bcm, 0x0250, 0x00000100);
2432 bcm43xx_write32(bcm, 0x0270, 0x00000100);
2433 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000);
2434 }
2435
2436 /* Probe Response Timeout value */
2437 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2438 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
2439
2440 if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
2441 if ((bcm->chip_id == 0x4306) && (bcm->chip_rev == 3))
2442 bcm43xx_write16(bcm, 0x0612, 0x0064);
2443 else
2444 bcm43xx_write16(bcm, 0x0612, 0x0032);
2445 } else
2446 bcm43xx_write16(bcm, 0x0612, 0x0002);
2447
2448 if (bcm->current_core->rev < 3) {
2449 bcm43xx_write16(bcm, 0x060E, 0x0000);
2450 bcm43xx_write16(bcm, 0x0610, 0x8000);
2451 bcm43xx_write16(bcm, 0x0604, 0x0000);
2452 bcm43xx_write16(bcm, 0x0606, 0x0200);
2453 } else {
2454 bcm43xx_write32(bcm, 0x0188, 0x80000000);
2455 bcm43xx_write32(bcm, 0x018C, 0x02000000);
2456 }
2457 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
2458 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
2459 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2460 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
2461 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
2462
2463 value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
2464 value32 |= 0x00100000;
2465 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
2466
2467 bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
2468
2469 assert(err == 0);
2470 dprintk(KERN_INFO PFX "Chip initialized\n");
2471out:
2472 return err;
2473
2474err_radio_off:
2475 bcm43xx_radio_turn_off(bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002476err_gpio_cleanup:
John W. Linvillef2223132006-01-23 16:59:58 -05002477 bcm43xx_gpio_cleanup(bcm);
2478err_free_irq:
2479 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002480err_release_fw:
2481 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002482 goto out;
2483}
2484
2485/* Validate chip access
2486 * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
2487static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
2488{
John W. Linvillef2223132006-01-23 16:59:58 -05002489 u32 value;
2490 u32 shm_backup;
2491
2492 shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000);
2493 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA);
Michael Buesch489423c2006-02-13 00:11:07 +01002494 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA)
2495 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002496 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
Michael Buesch489423c2006-02-13 00:11:07 +01002497 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55)
2498 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002499 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup);
2500
2501 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
Michael Buesch489423c2006-02-13 00:11:07 +01002502 if ((value | 0x80000000) != 0x80000400)
2503 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002504
2505 value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch489423c2006-02-13 00:11:07 +01002506 if (value != 0x00000000)
2507 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002508
Michael Buesch489423c2006-02-13 00:11:07 +01002509 return 0;
2510error:
2511 printk(KERN_ERR PFX "Failed to validate the chipaccess\n");
2512 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002513}
2514
2515static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
2516{
2517 int err, i;
2518 int current_core;
2519 u32 core_vendor, core_id, core_rev;
2520 u32 sb_id_hi, chip_id_32 = 0;
2521 u16 pci_device, chip_id_16;
2522 u8 core_count;
2523
2524 memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo));
2525 memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo));
2526 memset(&bcm->core_v90, 0, sizeof(struct bcm43xx_coreinfo));
2527 memset(&bcm->core_pcmcia, 0, sizeof(struct bcm43xx_coreinfo));
2528 memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo)
2529 * BCM43xx_MAX_80211_CORES);
2530
2531 memset(&bcm->phy, 0, sizeof(struct bcm43xx_phyinfo)
2532 * BCM43xx_MAX_80211_CORES);
2533 memset(&bcm->radio, 0, sizeof(struct bcm43xx_radioinfo)
2534 * BCM43xx_MAX_80211_CORES);
2535
2536 /* map core 0 */
2537 err = _switch_core(bcm, 0);
2538 if (err)
2539 goto out;
2540
2541 /* fetch sb_id_hi from core information registers */
2542 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2543
2544 core_id = (sb_id_hi & 0xFFF0) >> 4;
2545 core_rev = (sb_id_hi & 0xF);
2546 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2547
2548 /* if present, chipcommon is always core 0; read the chipid from it */
2549 if (core_id == BCM43xx_COREID_CHIPCOMMON) {
2550 chip_id_32 = bcm43xx_read32(bcm, 0);
2551 chip_id_16 = chip_id_32 & 0xFFFF;
2552 bcm->core_chipcommon.flags |= BCM43xx_COREFLAG_AVAILABLE;
2553 bcm->core_chipcommon.id = core_id;
2554 bcm->core_chipcommon.rev = core_rev;
2555 bcm->core_chipcommon.index = 0;
2556 /* While we are at it, also read the capabilities. */
2557 bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES);
2558 } else {
2559 /* without a chipCommon, use a hard coded table. */
2560 pci_device = bcm->pci_dev->device;
2561 if (pci_device == 0x4301)
2562 chip_id_16 = 0x4301;
2563 else if ((pci_device >= 0x4305) && (pci_device <= 0x4307))
2564 chip_id_16 = 0x4307;
2565 else if ((pci_device >= 0x4402) && (pci_device <= 0x4403))
2566 chip_id_16 = 0x4402;
2567 else if ((pci_device >= 0x4610) && (pci_device <= 0x4615))
2568 chip_id_16 = 0x4610;
2569 else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
2570 chip_id_16 = 0x4710;
2571#ifdef CONFIG_BCM947XX
2572 else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
2573 chip_id_16 = 0x4309;
2574#endif
2575 else {
2576 printk(KERN_ERR PFX "Could not determine Chip ID\n");
2577 return -ENODEV;
2578 }
2579 }
2580
2581 /* ChipCommon with Core Rev >=4 encodes number of cores,
2582 * otherwise consult hardcoded table */
2583 if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) {
2584 core_count = (chip_id_32 & 0x0F000000) >> 24;
2585 } else {
2586 switch (chip_id_16) {
2587 case 0x4610:
2588 case 0x4704:
2589 case 0x4710:
2590 core_count = 9;
2591 break;
2592 case 0x4310:
2593 core_count = 8;
2594 break;
2595 case 0x5365:
2596 core_count = 7;
2597 break;
2598 case 0x4306:
2599 core_count = 6;
2600 break;
2601 case 0x4301:
2602 case 0x4307:
2603 core_count = 5;
2604 break;
2605 case 0x4402:
2606 core_count = 3;
2607 break;
2608 default:
2609 /* SOL if we get here */
2610 assert(0);
2611 core_count = 1;
2612 }
2613 }
2614
2615 bcm->chip_id = chip_id_16;
2616 bcm->chip_rev = (chip_id_32 & 0x000f0000) >> 16;
2617
2618 dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
2619 bcm->chip_id, bcm->chip_rev);
2620 dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
2621 if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) {
2622 dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2623 core_id, core_rev, core_vendor,
2624 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
2625 }
2626
2627 if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE)
2628 current_core = 1;
2629 else
2630 current_core = 0;
2631 for ( ; current_core < core_count; current_core++) {
2632 struct bcm43xx_coreinfo *core;
2633
2634 err = _switch_core(bcm, current_core);
2635 if (err)
2636 goto out;
2637 /* Gather information */
2638 /* fetch sb_id_hi from core information registers */
2639 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2640
2641 /* extract core_id, core_rev, core_vendor */
2642 core_id = (sb_id_hi & 0xFFF0) >> 4;
2643 core_rev = (sb_id_hi & 0xF);
2644 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2645
2646 dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2647 current_core, core_id, core_rev, core_vendor,
2648 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
2649
2650 core = NULL;
2651 switch (core_id) {
2652 case BCM43xx_COREID_PCI:
2653 core = &bcm->core_pci;
2654 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2655 printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
2656 continue;
2657 }
2658 break;
2659 case BCM43xx_COREID_V90:
2660 core = &bcm->core_v90;
2661 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2662 printk(KERN_WARNING PFX "Multiple V90 cores found.\n");
2663 continue;
2664 }
2665 break;
2666 case BCM43xx_COREID_PCMCIA:
2667 core = &bcm->core_pcmcia;
2668 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2669 printk(KERN_WARNING PFX "Multiple PCMCIA cores found.\n");
2670 continue;
2671 }
2672 break;
2673 case BCM43xx_COREID_ETHERNET:
2674 core = &bcm->core_ethernet;
2675 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2676 printk(KERN_WARNING PFX "Multiple Ethernet cores found.\n");
2677 continue;
2678 }
2679 break;
2680 case BCM43xx_COREID_80211:
2681 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
2682 core = &(bcm->core_80211[i]);
2683 if (!(core->flags & BCM43xx_COREFLAG_AVAILABLE))
2684 break;
2685 core = NULL;
2686 }
2687 if (!core) {
2688 printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n",
2689 BCM43xx_MAX_80211_CORES);
2690 continue;
2691 }
2692 if (i != 0) {
2693 /* More than one 80211 core is only supported
2694 * by special chips.
2695 * There are chips with two 80211 cores, but with
2696 * dangling pins on the second core. Be careful
2697 * and ignore these cores here.
2698 */
2699 if (bcm->pci_dev->device != 0x4324) {
2700 dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
2701 continue;
2702 }
2703 }
2704 switch (core_rev) {
2705 case 2:
2706 case 4:
2707 case 5:
2708 case 6:
2709 case 7:
2710 case 9:
2711 break;
2712 default:
2713 printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
2714 core_rev);
2715 err = -ENODEV;
2716 goto out;
2717 }
2718 core->phy = &bcm->phy[i];
2719 core->phy->antenna_diversity = 0xffff;
2720 core->phy->savedpctlreg = 0xFFFF;
2721 core->phy->minlowsig[0] = 0xFFFF;
2722 core->phy->minlowsig[1] = 0xFFFF;
2723 core->phy->minlowsigpos[0] = 0;
2724 core->phy->minlowsigpos[1] = 0;
2725 spin_lock_init(&core->phy->lock);
2726 core->radio = &bcm->radio[i];
Michael Bueschab4977f2006-02-12 22:40:39 +01002727 core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
John W. Linvillef2223132006-01-23 16:59:58 -05002728 core->radio->channel = 0xFF;
2729 core->radio->initial_channel = 0xFF;
2730 core->radio->lofcal = 0xFFFF;
2731 core->radio->initval = 0xFFFF;
2732 core->radio->nrssi[0] = -1000;
2733 core->radio->nrssi[1] = -1000;
2734 core->dma = &bcm->dma[i];
2735 core->pio = &bcm->pio[i];
2736 break;
2737 case BCM43xx_COREID_CHIPCOMMON:
2738 printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
2739 break;
2740 default:
2741 printk(KERN_WARNING PFX "Unknown core found (ID 0x%x)\n", core_id);
2742 }
2743 if (core) {
2744 core->flags |= BCM43xx_COREFLAG_AVAILABLE;
2745 core->id = core_id;
2746 core->rev = core_rev;
2747 core->index = current_core;
2748 }
2749 }
2750
2751 if (!(bcm->core_80211[0].flags & BCM43xx_COREFLAG_AVAILABLE)) {
2752 printk(KERN_ERR PFX "Error: No 80211 core found!\n");
2753 err = -ENODEV;
2754 goto out;
2755 }
2756
2757 err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
2758
2759 assert(err == 0);
2760out:
2761 return err;
2762}
2763
2764static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm)
2765{
2766 const u8 *mac = (const u8*)(bcm->net_dev->dev_addr);
2767 u8 *bssid = bcm->ieee->bssid;
2768
2769 switch (bcm->ieee->iw_mode) {
2770 case IW_MODE_ADHOC:
2771 random_ether_addr(bssid);
2772 break;
2773 case IW_MODE_MASTER:
2774 case IW_MODE_INFRA:
2775 case IW_MODE_REPEAT:
2776 case IW_MODE_SECOND:
2777 case IW_MODE_MONITOR:
2778 memcpy(bssid, mac, ETH_ALEN);
2779 break;
2780 default:
2781 assert(0);
2782 }
2783}
2784
2785static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm,
2786 u16 rate,
2787 int is_ofdm)
2788{
2789 u16 offset;
2790
2791 if (is_ofdm) {
2792 offset = 0x480;
2793 offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
2794 }
2795 else {
2796 offset = 0x4C0;
2797 offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
2798 }
2799 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20,
2800 bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset));
2801}
2802
2803static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm)
2804{
2805 switch (bcm->current_core->phy->type) {
2806 case BCM43xx_PHYTYPE_A:
2807 case BCM43xx_PHYTYPE_G:
2808 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1);
2809 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1);
2810 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1);
2811 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1);
2812 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1);
2813 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1);
2814 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1);
2815 case BCM43xx_PHYTYPE_B:
2816 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0);
2817 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0);
2818 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0);
2819 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0);
2820 break;
2821 default:
2822 assert(0);
2823 }
2824}
2825
2826static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
2827{
2828 bcm43xx_chip_cleanup(bcm);
2829 bcm43xx_pio_free(bcm);
2830 bcm43xx_dma_free(bcm);
2831
2832 bcm->current_core->flags &= ~ BCM43xx_COREFLAG_INITIALIZED;
2833}
2834
2835/* http://bcm-specs.sipsolutions.net/80211Init */
2836static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
2837{
2838 u32 ucodeflags;
2839 int err;
2840 u32 sbimconfiglow;
2841 u8 limit;
2842
2843 if (bcm->chip_rev < 5) {
2844 sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
2845 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
2846 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
2847 if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
2848 sbimconfiglow |= 0x32;
2849 else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
2850 sbimconfiglow |= 0x53;
2851 else
2852 assert(0);
2853 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
2854 }
2855
2856 bcm43xx_phy_calibrate(bcm);
2857 err = bcm43xx_chip_init(bcm);
2858 if (err)
2859 goto out;
2860
2861 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
2862 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
2863
2864 if (0 /*FIXME: which condition has to be used here? */)
2865 ucodeflags |= 0x00000010;
2866
2867 /* HW decryption needs to be set now */
2868 ucodeflags |= 0x40000000;
2869
2870 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
2871 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
2872 if (bcm->current_core->phy->rev == 1)
2873 ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
2874 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
2875 ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
2876 } else if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) {
2877 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
2878 if ((bcm->current_core->phy->rev >= 2) &&
2879 (bcm->current_core->radio->version == 0x2050))
2880 ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY;
2881 }
2882
2883 if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
2884 BCM43xx_UCODEFLAGS_OFFSET)) {
2885 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
2886 BCM43xx_UCODEFLAGS_OFFSET, ucodeflags);
2887 }
2888
2889 /* Short/Long Retry Limit.
2890 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
2891 * the chip-internal counter.
2892 */
2893 limit = limit_value(modparam_short_retry, 0, 0xF);
2894 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit);
2895 limit = limit_value(modparam_long_retry, 0, 0xF);
2896 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit);
2897
2898 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3);
2899 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2);
2900
2901 bcm43xx_rate_memory_init(bcm);
2902
2903 /* Minimum Contention Window */
2904 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B)
2905 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f);
2906 else
2907 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f);
2908 /* Maximum Contention Window */
2909 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
2910
2911 bcm43xx_gen_bssid(bcm);
2912 bcm43xx_write_mac_bssid_templates(bcm);
2913
2914 if (bcm->current_core->rev >= 5)
2915 bcm43xx_write16(bcm, 0x043C, 0x000C);
2916
Michael Buesch77db31e2006-02-12 16:47:44 +01002917 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05002918 err = bcm43xx_pio_init(bcm);
Michael Buesch77db31e2006-02-12 16:47:44 +01002919 else
2920 err = bcm43xx_dma_init(bcm);
2921 if (err)
2922 goto err_chip_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002923 bcm43xx_write16(bcm, 0x0612, 0x0050);
2924 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
2925 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
2926
2927 bcm43xx_mac_enable(bcm);
2928 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
2929
2930 bcm->current_core->flags |= BCM43xx_COREFLAG_INITIALIZED;
2931out:
2932 return err;
2933
2934err_chip_cleanup:
2935 bcm43xx_chip_cleanup(bcm);
2936 goto out;
2937}
2938
2939static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
2940{
2941 int err;
2942 u16 pci_status;
2943
2944 err = bcm43xx_pctl_set_crystal(bcm, 1);
2945 if (err)
2946 goto out;
2947 bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
2948 bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
2949
2950out:
2951 return err;
2952}
2953
2954static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm)
2955{
2956 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
2957 bcm43xx_pctl_set_crystal(bcm, 0);
2958}
2959
Michael Buesch489423c2006-02-13 00:11:07 +01002960static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
2961 u32 address,
2962 u32 data)
John W. Linvillef2223132006-01-23 16:59:58 -05002963{
2964 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address);
2965 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data);
2966}
2967
2968static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
2969{
2970 int err;
2971 struct bcm43xx_coreinfo *old_core;
2972
2973 old_core = bcm->current_core;
2974 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2975 if (err)
2976 goto out;
2977
2978 bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
2979
2980 bcm43xx_switch_core(bcm, old_core);
2981 assert(err == 0);
2982out:
2983 return err;
2984}
2985
2986/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
2987 * To enable core 0, pass a core_mask of 1<<0
2988 */
2989static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
2990 u32 core_mask)
2991{
2992 u32 backplane_flag_nr;
2993 u32 value;
2994 struct bcm43xx_coreinfo *old_core;
2995 int err = 0;
2996
2997 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG);
2998 backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK;
2999
3000 old_core = bcm->current_core;
3001 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
3002 if (err)
3003 goto out;
3004
3005 if (bcm->core_pci.rev < 6) {
3006 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
3007 value |= (1 << backplane_flag_nr);
3008 bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
3009 } else {
3010 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value);
3011 if (err) {
3012 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3013 goto out_switch_back;
3014 }
3015 value |= core_mask << 8;
3016 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value);
3017 if (err) {
3018 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3019 goto out_switch_back;
3020 }
3021 }
3022
3023 value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
3024 value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
3025 bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
3026
3027 if (bcm->core_pci.rev < 5) {
3028 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
3029 value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
3030 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
3031 value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
3032 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
3033 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
3034 err = bcm43xx_pcicore_commit_settings(bcm);
3035 assert(err == 0);
3036 }
3037
3038out_switch_back:
3039 err = bcm43xx_switch_core(bcm, old_core);
3040out:
3041 return err;
3042}
3043
3044static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
3045{
3046 ieee80211softmac_start(bcm->net_dev);
3047}
3048
Michael Bueschab4977f2006-02-12 22:40:39 +01003049static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003050{
Michael Bueschab4977f2006-02-12 22:40:39 +01003051 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -05003052
Michael Bueschab4977f2006-02-12 22:40:39 +01003053 if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2)
3054 return;
John W. Linvillef2223132006-01-23 16:59:58 -05003055
Michael Bueschab4977f2006-02-12 22:40:39 +01003056 bcm43xx_mac_suspend(bcm);
3057 bcm43xx_phy_lo_g_measure(bcm);
3058 bcm43xx_mac_enable(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003059}
3060
Michael Bueschab4977f2006-02-12 22:40:39 +01003061static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003062{
John W. Linvillef2223132006-01-23 16:59:58 -05003063 bcm43xx_phy_lo_mark_all_unused(bcm);
3064 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3065 bcm43xx_mac_suspend(bcm);
3066 bcm43xx_calc_nrssi_slope(bcm);
3067 bcm43xx_mac_enable(bcm);
3068 }
John W. Linvillef2223132006-01-23 16:59:58 -05003069}
3070
Michael Bueschab4977f2006-02-12 22:40:39 +01003071static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003072{
John W. Linvillef2223132006-01-23 16:59:58 -05003073 /* Update device statistics. */
3074 bcm43xx_calculate_link_quality(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003075}
John W. Linvillef2223132006-01-23 16:59:58 -05003076
Michael Bueschab4977f2006-02-12 22:40:39 +01003077static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
3078{
3079 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
3080 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
3081
3082 if (phy->type == BCM43xx_PHYTYPE_G) {
3083 //TODO: update_aci_moving_average
3084 if (radio->aci_enable && radio->aci_wlan_automatic) {
3085 bcm43xx_mac_suspend(bcm);
3086 if (!radio->aci_enable && 1 /*TODO: not scanning? */) {
3087 if (0 /*TODO: bunch of conditions*/) {
3088 bcm43xx_radio_set_interference_mitigation(bcm,
3089 BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
3090 }
3091 } else if (1/*TODO*/) {
3092 /*
3093 if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) {
3094 bcm43xx_radio_set_interference_mitigation(bcm,
3095 BCM43xx_RADIO_INTERFMODE_NONE);
3096 }
3097 */
3098 }
3099 bcm43xx_mac_enable(bcm);
3100 } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN &&
3101 phy->rev == 1) {
3102 //TODO: implement rev1 workaround
3103 }
John W. Linvillef2223132006-01-23 16:59:58 -05003104 }
Michael Bueschab4977f2006-02-12 22:40:39 +01003105 bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
3106 //TODO for APHY (temperature?)
3107}
3108
3109static void bcm43xx_periodic_task_handler(unsigned long d)
3110{
3111 struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
3112 unsigned long flags;
3113 unsigned int state;
3114
3115 spin_lock_irqsave(&bcm->lock, flags);
3116
3117 assert(bcm->initialized);
3118 state = bcm->periodic_state;
3119 if (state % 8 == 0)
3120 bcm43xx_periodic_every120sec(bcm);
3121 if (state % 4 == 0)
3122 bcm43xx_periodic_every60sec(bcm);
3123 if (state % 2 == 0)
3124 bcm43xx_periodic_every30sec(bcm);
3125 bcm43xx_periodic_every15sec(bcm);
3126 bcm->periodic_state = state + 1;
3127
3128 mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
3129
John W. Linvillef2223132006-01-23 16:59:58 -05003130 spin_unlock_irqrestore(&bcm->lock, flags);
3131}
3132
John W. Linvillef2223132006-01-23 16:59:58 -05003133static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
3134{
Michael Bueschab4977f2006-02-12 22:40:39 +01003135 del_timer_sync(&bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003136}
3137
John W. Linvillef2223132006-01-23 16:59:58 -05003138static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
3139{
Michael Bueschab4977f2006-02-12 22:40:39 +01003140 struct timer_list *timer = &(bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003141
Michael Buesch1d1a73c2006-02-21 18:19:59 +01003142 assert(bcm->initialized);
Michael Bueschab4977f2006-02-12 22:40:39 +01003143 setup_timer(timer,
3144 bcm43xx_periodic_task_handler,
3145 (unsigned long)bcm);
3146 timer->expires = jiffies;
3147 add_timer(timer);
John W. Linvillef2223132006-01-23 16:59:58 -05003148}
3149
3150static void bcm43xx_security_init(struct bcm43xx_private *bcm)
3151{
3152 bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
3153 0x0056) * 2;
3154 bcm43xx_clear_keys(bcm);
3155}
3156
3157/* This is the opposite of bcm43xx_init_board() */
3158static void bcm43xx_free_board(struct bcm43xx_private *bcm)
3159{
3160 int i, err;
3161 unsigned long flags;
3162
Michael Buesch367f8992006-02-28 15:32:19 +01003163 bcm43xx_sysfs_unregister(bcm);
3164
Michael Bueschab4977f2006-02-12 22:40:39 +01003165 bcm43xx_periodic_tasks_delete(bcm);
3166
John W. Linvillef2223132006-01-23 16:59:58 -05003167 spin_lock_irqsave(&bcm->lock, flags);
3168 bcm->initialized = 0;
3169 bcm->shutting_down = 1;
3170 spin_unlock_irqrestore(&bcm->lock, flags);
3171
John W. Linvillef2223132006-01-23 16:59:58 -05003172 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3173 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE))
3174 continue;
3175 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED))
3176 continue;
3177
3178 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3179 assert(err == 0);
3180 bcm43xx_wireless_core_cleanup(bcm);
3181 }
3182
3183 bcm43xx_pctl_set_crystal(bcm, 0);
3184
3185 spin_lock_irqsave(&bcm->lock, flags);
3186 bcm->shutting_down = 0;
3187 spin_unlock_irqrestore(&bcm->lock, flags);
3188}
3189
3190static int bcm43xx_init_board(struct bcm43xx_private *bcm)
3191{
3192 int i, err;
3193 int num_80211_cores;
3194 int connect_phy;
3195 unsigned long flags;
3196
3197 might_sleep();
3198
3199 spin_lock_irqsave(&bcm->lock, flags);
3200 bcm->initialized = 0;
3201 bcm->shutting_down = 0;
3202 spin_unlock_irqrestore(&bcm->lock, flags);
3203
3204 err = bcm43xx_pctl_set_crystal(bcm, 1);
3205 if (err)
3206 goto out;
3207 err = bcm43xx_pctl_init(bcm);
3208 if (err)
3209 goto err_crystal_off;
3210 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
3211 if (err)
3212 goto err_crystal_off;
3213
3214 tasklet_enable(&bcm->isr_tasklet);
3215 num_80211_cores = bcm43xx_num_80211_cores(bcm);
3216 for (i = 0; i < num_80211_cores; i++) {
3217 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3218 assert(err != -ENODEV);
3219 if (err)
3220 goto err_80211_unwind;
3221
3222 /* Enable the selected wireless core.
3223 * Connect PHY only on the first core.
3224 */
3225 if (!bcm43xx_core_enabled(bcm)) {
3226 if (num_80211_cores == 1) {
3227 connect_phy = bcm->current_core->phy->connected;
3228 } else {
3229 if (i == 0)
3230 connect_phy = 1;
3231 else
3232 connect_phy = 0;
3233 }
3234 bcm43xx_wireless_core_reset(bcm, connect_phy);
3235 }
3236
3237 if (i != 0)
3238 bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
3239
3240 err = bcm43xx_wireless_core_init(bcm);
3241 if (err)
3242 goto err_80211_unwind;
3243
3244 if (i != 0) {
3245 bcm43xx_mac_suspend(bcm);
3246 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3247 bcm43xx_radio_turn_off(bcm);
3248 }
3249 }
3250 bcm->active_80211_core = &bcm->core_80211[0];
3251 if (num_80211_cores >= 2) {
3252 bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
3253 bcm43xx_mac_enable(bcm);
3254 }
3255 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
3256 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
3257 dprintk(KERN_INFO PFX "80211 cores initialized\n");
3258 bcm43xx_security_init(bcm);
3259 bcm43xx_softmac_init(bcm);
3260
3261 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
3262
John W. Linvillef2223132006-01-23 16:59:58 -05003263 if (bcm->current_core->radio->initial_channel != 0xFF) {
3264 bcm43xx_mac_suspend(bcm);
3265 bcm43xx_radio_selectchannel(bcm, bcm->current_core->radio->initial_channel, 0);
3266 bcm43xx_mac_enable(bcm);
3267 }
Michael Bueschcad2b312006-02-21 18:08:55 +01003268
3269 /* Initialization of the board is done. Flag it as such. */
3270 spin_lock_irqsave(&bcm->lock, flags);
3271 bcm->initialized = 1;
3272 spin_unlock_irqrestore(&bcm->lock, flags);
3273
John W. Linvillef2223132006-01-23 16:59:58 -05003274 bcm43xx_periodic_tasks_setup(bcm);
Michael Buesch367f8992006-02-28 15:32:19 +01003275 bcm43xx_sysfs_register(bcm);
3276 //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
John W. Linvillef2223132006-01-23 16:59:58 -05003277
3278 assert(err == 0);
3279out:
3280 return err;
3281
3282err_80211_unwind:
3283 tasklet_disable(&bcm->isr_tasklet);
3284 /* unwind all 80211 initialization */
3285 for (i = 0; i < num_80211_cores; i++) {
3286 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED))
3287 continue;
3288 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3289 bcm43xx_wireless_core_cleanup(bcm);
3290 }
3291err_crystal_off:
3292 bcm43xx_pctl_set_crystal(bcm, 0);
3293 goto out;
3294}
3295
3296static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
3297{
3298 struct pci_dev *pci_dev = bcm->pci_dev;
3299 int i;
3300
3301 bcm43xx_chipset_detach(bcm);
3302 /* Do _not_ access the chip, after it is detached. */
3303 iounmap(bcm->mmio_addr);
3304
3305 pci_release_regions(pci_dev);
3306 pci_disable_device(pci_dev);
3307
3308 /* Free allocated structures/fields */
3309 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3310 kfree(bcm->phy[i]._lo_pairs);
3311 if (bcm->phy[i].dyn_tssi_tbl)
3312 kfree(bcm->phy[i].tssi2dbm);
3313 }
3314}
3315
3316static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
3317{
Michael Buesch489423c2006-02-13 00:11:07 +01003318 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -05003319 u16 value;
3320 u8 phy_version;
3321 u8 phy_type;
3322 u8 phy_rev;
3323 int phy_rev_ok = 1;
3324 void *p;
3325
3326 value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
3327
3328 phy_version = (value & 0xF000) >> 12;
3329 phy_type = (value & 0x0F00) >> 8;
3330 phy_rev = (value & 0x000F);
3331
3332 dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
3333 phy_version, phy_type, phy_rev);
3334
3335 switch (phy_type) {
3336 case BCM43xx_PHYTYPE_A:
3337 if (phy_rev >= 4)
3338 phy_rev_ok = 0;
3339 /*FIXME: We need to switch the ieee->modulation, etc.. flags,
3340 * if we switch 80211 cores after init is done.
3341 * As we do not implement on the fly switching between
3342 * wireless cores, I will leave this as a future task.
3343 */
3344 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION;
3345 bcm->ieee->mode = IEEE_A;
3346 bcm->ieee->freq_band = IEEE80211_52GHZ_BAND |
3347 IEEE80211_24GHZ_BAND;
3348 break;
3349 case BCM43xx_PHYTYPE_B:
3350 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7)
3351 phy_rev_ok = 0;
3352 bcm->ieee->modulation = IEEE80211_CCK_MODULATION;
3353 bcm->ieee->mode = IEEE_B;
3354 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3355 break;
3356 case BCM43xx_PHYTYPE_G:
3357 if (phy_rev > 7)
3358 phy_rev_ok = 0;
3359 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
3360 IEEE80211_CCK_MODULATION;
3361 bcm->ieee->mode = IEEE_G;
3362 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3363 break;
3364 default:
3365 printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n",
3366 phy_type);
3367 return -ENODEV;
3368 };
3369 if (!phy_rev_ok) {
3370 printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
3371 phy_rev);
3372 }
3373
Michael Buesch489423c2006-02-13 00:11:07 +01003374 phy->version = phy_version;
3375 phy->type = phy_type;
3376 phy->rev = phy_rev;
John W. Linvillef2223132006-01-23 16:59:58 -05003377 if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
3378 p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT,
3379 GFP_KERNEL);
3380 if (!p)
3381 return -ENOMEM;
Michael Buesch489423c2006-02-13 00:11:07 +01003382 phy->_lo_pairs = p;
John W. Linvillef2223132006-01-23 16:59:58 -05003383 }
3384
3385 return 0;
3386}
3387
3388static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
3389{
3390 struct pci_dev *pci_dev = bcm->pci_dev;
3391 struct net_device *net_dev = bcm->net_dev;
3392 int err;
3393 int i;
3394 void __iomem *ioaddr;
3395 unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
3396 int num_80211_cores;
3397 u32 coremask;
3398
3399 err = pci_enable_device(pci_dev);
3400 if (err) {
3401 printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
3402 err = -ENODEV;
3403 goto out;
3404 }
3405
3406 mmio_start = pci_resource_start(pci_dev, 0);
3407 mmio_end = pci_resource_end(pci_dev, 0);
3408 mmio_flags = pci_resource_flags(pci_dev, 0);
3409 mmio_len = pci_resource_len(pci_dev, 0);
3410
3411 /* make sure PCI base addr is MMIO */
3412 if (!(mmio_flags & IORESOURCE_MEM)) {
3413 printk(KERN_ERR PFX
3414 "%s, region #0 not an MMIO resource, aborting\n",
3415 pci_name(pci_dev));
3416 err = -ENODEV;
3417 goto err_pci_disable;
3418 }
3419//FIXME: Why is this check disabled for BCM947XX? What is the IO_SIZE there?
3420#ifndef CONFIG_BCM947XX
3421 if (mmio_len != BCM43xx_IO_SIZE) {
3422 printk(KERN_ERR PFX
3423 "%s: invalid PCI mem region size(s), aborting\n",
3424 pci_name(pci_dev));
3425 err = -ENODEV;
3426 goto err_pci_disable;
3427 }
3428#endif
3429
Michael Buesch65f3f192006-01-31 20:11:38 +01003430 err = pci_request_regions(pci_dev, KBUILD_MODNAME);
John W. Linvillef2223132006-01-23 16:59:58 -05003431 if (err) {
3432 printk(KERN_ERR PFX
3433 "could not access PCI resources (%i)\n", err);
3434 goto err_pci_disable;
3435 }
3436
3437 /* enable PCI bus-mastering */
3438 pci_set_master(pci_dev);
3439
3440 /* ioremap MMIO region */
3441 ioaddr = ioremap(mmio_start, mmio_len);
3442 if (!ioaddr) {
3443 printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
3444 pci_name(pci_dev));
3445 err = -EIO;
3446 goto err_pci_release;
3447 }
3448
3449 net_dev->base_addr = (unsigned long)ioaddr;
3450 bcm->mmio_addr = ioaddr;
3451 bcm->mmio_len = mmio_len;
3452
3453 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
3454 &bcm->board_vendor);
3455 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
3456 &bcm->board_type);
3457 bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
3458 &bcm->board_revision);
3459
3460 err = bcm43xx_chipset_attach(bcm);
3461 if (err)
3462 goto err_iounmap;
3463 err = bcm43xx_pctl_init(bcm);
3464 if (err)
3465 goto err_chipset_detach;
3466 err = bcm43xx_probe_cores(bcm);
3467 if (err)
3468 goto err_chipset_detach;
3469
3470 num_80211_cores = bcm43xx_num_80211_cores(bcm);
3471
3472 /* Attach all IO cores to the backplane. */
3473 coremask = 0;
3474 for (i = 0; i < num_80211_cores; i++)
3475 coremask |= (1 << bcm->core_80211[i].index);
3476 //FIXME: Also attach some non80211 cores?
3477 err = bcm43xx_setup_backplane_pci_connection(bcm, coremask);
3478 if (err) {
3479 printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
3480 goto err_chipset_detach;
3481 }
3482
Michael Bueschea0922b2006-02-19 14:09:20 +01003483 err = bcm43xx_sprom_extract(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003484 if (err)
3485 goto err_chipset_detach;
3486 err = bcm43xx_leds_init(bcm);
3487 if (err)
3488 goto err_chipset_detach;
3489
3490 for (i = 0; i < num_80211_cores; i++) {
3491 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3492 assert(err != -ENODEV);
3493 if (err)
3494 goto err_80211_unwind;
3495
3496 /* Enable the selected wireless core.
3497 * Connect PHY only on the first core.
3498 */
3499 bcm43xx_wireless_core_reset(bcm, (i == 0));
3500
3501 err = bcm43xx_read_phyinfo(bcm);
3502 if (err && (i == 0))
3503 goto err_80211_unwind;
3504
3505 err = bcm43xx_read_radioinfo(bcm);
3506 if (err && (i == 0))
3507 goto err_80211_unwind;
3508
3509 err = bcm43xx_validate_chip(bcm);
3510 if (err && (i == 0))
3511 goto err_80211_unwind;
3512
3513 bcm43xx_radio_turn_off(bcm);
3514 err = bcm43xx_phy_init_tssi2dbm_table(bcm);
3515 if (err)
3516 goto err_80211_unwind;
3517 bcm43xx_wireless_core_disable(bcm);
3518 }
3519 bcm43xx_pctl_set_crystal(bcm, 0);
3520
3521 /* Set the MAC address in the networking subsystem */
3522 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
3523 memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
3524 else
3525 memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
3526
3527 bcm43xx_geo_init(bcm);
3528
3529 snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
3530 "Broadcom %04X", bcm->chip_id);
3531
3532 assert(err == 0);
3533out:
3534 return err;
3535
3536err_80211_unwind:
3537 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3538 kfree(bcm->phy[i]._lo_pairs);
3539 if (bcm->phy[i].dyn_tssi_tbl)
3540 kfree(bcm->phy[i].tssi2dbm);
3541 }
3542err_chipset_detach:
3543 bcm43xx_chipset_detach(bcm);
3544err_iounmap:
3545 iounmap(bcm->mmio_addr);
3546err_pci_release:
3547 pci_release_regions(pci_dev);
3548err_pci_disable:
3549 pci_disable_device(pci_dev);
3550 goto out;
3551}
3552
John W. Linvillef2223132006-01-23 16:59:58 -05003553/* Do the Hardware IO operations to send the txb */
3554static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
3555 struct ieee80211_txb *txb)
3556{
3557 int err = -ENODEV;
3558
Michael Buesch77db31e2006-02-12 16:47:44 +01003559 if (bcm43xx_using_pio(bcm))
3560 err = bcm43xx_pio_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003561 else
Michael Bueschea72ab22006-01-27 17:26:20 +01003562 err = bcm43xx_dma_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003563
3564 return err;
3565}
3566
3567static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
3568 u8 channel)
3569{
3570 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3571 unsigned long flags;
3572
3573 spin_lock_irqsave(&bcm->lock, flags);
3574 bcm43xx_mac_suspend(bcm);
3575 bcm43xx_radio_selectchannel(bcm, channel, 0);
3576 bcm43xx_mac_enable(bcm);
3577 spin_unlock_irqrestore(&bcm->lock, flags);
3578}
3579
3580/* set_security() callback in struct ieee80211_device */
3581static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
3582 struct ieee80211_security *sec)
3583{
3584 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3585 struct ieee80211_security *secinfo = &bcm->ieee->sec;
3586 unsigned long flags;
3587 int keyidx;
3588
3589 dprintk(KERN_INFO PFX "set security called\n");
3590
3591 spin_lock_irqsave(&bcm->lock, flags);
3592
3593 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
3594 if (sec->flags & (1<<keyidx)) {
3595 secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
3596 secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
3597 memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN);
3598 }
3599
3600 if (sec->flags & SEC_ACTIVE_KEY) {
3601 secinfo->active_key = sec->active_key;
3602 dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key);
3603 }
3604 if (sec->flags & SEC_UNICAST_GROUP) {
3605 secinfo->unicast_uses_group = sec->unicast_uses_group;
3606 dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group);
3607 }
3608 if (sec->flags & SEC_LEVEL) {
3609 secinfo->level = sec->level;
3610 dprintk(KERN_INFO PFX " .level = %d\n", sec->level);
3611 }
3612 if (sec->flags & SEC_ENABLED) {
3613 secinfo->enabled = sec->enabled;
3614 dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled);
3615 }
3616 if (sec->flags & SEC_ENCRYPT) {
3617 secinfo->encrypt = sec->encrypt;
3618 dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt);
3619 }
3620 if (bcm->initialized && !bcm->ieee->host_encrypt) {
3621 if (secinfo->enabled) {
3622 /* upload WEP keys to hardware */
3623 char null_address[6] = { 0 };
3624 u8 algorithm = 0;
3625 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
3626 if (!(sec->flags & (1<<keyidx)))
3627 continue;
3628 switch (sec->encode_alg[keyidx]) {
3629 case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
3630 case SEC_ALG_WEP:
3631 algorithm = BCM43xx_SEC_ALGO_WEP;
3632 if (secinfo->key_sizes[keyidx] == 13)
3633 algorithm = BCM43xx_SEC_ALGO_WEP104;
3634 break;
3635 case SEC_ALG_TKIP:
3636 FIXME();
3637 algorithm = BCM43xx_SEC_ALGO_TKIP;
3638 break;
3639 case SEC_ALG_CCMP:
3640 FIXME();
3641 algorithm = BCM43xx_SEC_ALGO_AES;
3642 break;
3643 default:
3644 assert(0);
3645 break;
3646 }
3647 bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
3648 bcm->key[keyidx].enabled = 1;
3649 bcm->key[keyidx].algorithm = algorithm;
3650 }
3651 } else
3652 bcm43xx_clear_keys(bcm);
3653 }
3654 spin_unlock_irqrestore(&bcm->lock, flags);
3655}
3656
3657/* hard_start_xmit() callback in struct ieee80211_device */
3658static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
3659 struct net_device *net_dev,
3660 int pri)
3661{
3662 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3663 int err = -ENODEV;
3664 unsigned long flags;
3665
3666 spin_lock_irqsave(&bcm->lock, flags);
3667 if (likely(bcm->initialized))
3668 err = bcm43xx_tx(bcm, txb);
3669 spin_unlock_irqrestore(&bcm->lock, flags);
3670
3671 return err;
3672}
3673
3674static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
3675{
3676 return &(bcm43xx_priv(net_dev)->ieee->stats);
3677}
3678
3679static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
3680{
3681 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3682
3683 bcm43xx_controller_restart(bcm, "TX timeout");
3684}
3685
3686#ifdef CONFIG_NET_POLL_CONTROLLER
3687static void bcm43xx_net_poll_controller(struct net_device *net_dev)
3688{
3689 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3690 unsigned long flags;
3691
3692 local_irq_save(flags);
3693 bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
3694 local_irq_restore(flags);
3695}
3696#endif /* CONFIG_NET_POLL_CONTROLLER */
3697
3698static int bcm43xx_net_open(struct net_device *net_dev)
3699{
3700 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3701
3702 return bcm43xx_init_board(bcm);
3703}
3704
3705static int bcm43xx_net_stop(struct net_device *net_dev)
3706{
3707 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3708
3709 ieee80211softmac_stop(net_dev);
3710 bcm43xx_disable_interrupts_sync(bcm, NULL);
3711 bcm43xx_free_board(bcm);
3712
3713 return 0;
3714}
3715
Michael Buesch77db31e2006-02-12 16:47:44 +01003716static int bcm43xx_init_private(struct bcm43xx_private *bcm,
3717 struct net_device *net_dev,
Michael Bueschab4977f2006-02-12 22:40:39 +01003718 struct pci_dev *pci_dev)
John W. Linvillef2223132006-01-23 16:59:58 -05003719{
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003720 int err;
3721
John W. Linvillef2223132006-01-23 16:59:58 -05003722 bcm->ieee = netdev_priv(net_dev);
3723 bcm->softmac = ieee80211_priv(net_dev);
3724 bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
John W. Linvillef2223132006-01-23 16:59:58 -05003725
3726#ifdef DEBUG_ENABLE_MMIO_PRINT
3727 bcm43xx_mmioprint_initial(bcm, 1);
3728#else
3729 bcm43xx_mmioprint_initial(bcm, 0);
3730#endif
3731#ifdef DEBUG_ENABLE_PCILOG
3732 bcm43xx_pciprint_initial(bcm, 1);
3733#else
3734 bcm43xx_pciprint_initial(bcm, 0);
3735#endif
3736
3737 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3738 bcm->pci_dev = pci_dev;
3739 bcm->net_dev = net_dev;
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003740 bcm->bad_frames_preempt = modparam_bad_frames_preempt;
John W. Linvillef2223132006-01-23 16:59:58 -05003741 spin_lock_init(&bcm->lock);
3742 tasklet_init(&bcm->isr_tasklet,
3743 (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
3744 (unsigned long)bcm);
3745 tasklet_disable_nosync(&bcm->isr_tasklet);
3746 if (modparam_pio) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003747 bcm->__using_pio = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05003748 } else {
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003749 err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
3750 err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
3751 if (err) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003752#ifdef CONFIG_BCM43XX_PIO
John W. Linvillef2223132006-01-23 16:59:58 -05003753 printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
Michael Buesch77db31e2006-02-12 16:47:44 +01003754 bcm->__using_pio = 1;
3755#else
3756 printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
3757 "Recompile the driver with PIO support, please.\n");
3758 return -ENODEV;
3759#endif /* CONFIG_BCM43XX_PIO */
John W. Linvillef2223132006-01-23 16:59:58 -05003760 }
3761 }
3762 bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
3763
3764 /* default to sw encryption for now */
3765 bcm->ieee->host_build_iv = 0;
3766 bcm->ieee->host_encrypt = 1;
3767 bcm->ieee->host_decrypt = 1;
3768
3769 bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
3770 bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
3771 bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
3772 bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
Michael Buesch77db31e2006-02-12 16:47:44 +01003773
3774 return 0;
John W. Linvillef2223132006-01-23 16:59:58 -05003775}
3776
3777static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
3778 const struct pci_device_id *ent)
3779{
3780 struct net_device *net_dev;
3781 struct bcm43xx_private *bcm;
John W. Linvillef2223132006-01-23 16:59:58 -05003782 int err;
3783
3784#ifdef CONFIG_BCM947XX
3785 if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
3786 return -ENODEV;
3787#endif
3788
3789#ifdef DEBUG_SINGLE_DEVICE_ONLY
3790 if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
3791 return -ENODEV;
3792#endif
3793
3794 net_dev = alloc_ieee80211softmac(sizeof(*bcm));
3795 if (!net_dev) {
3796 printk(KERN_ERR PFX
3797 "could not allocate ieee80211 device %s\n",
3798 pci_name(pdev));
3799 err = -ENOMEM;
3800 goto out;
3801 }
3802 /* initialize the net_device struct */
3803 SET_MODULE_OWNER(net_dev);
3804 SET_NETDEV_DEV(net_dev, &pdev->dev);
3805
3806 net_dev->open = bcm43xx_net_open;
3807 net_dev->stop = bcm43xx_net_stop;
3808 net_dev->get_stats = bcm43xx_net_get_stats;
3809 net_dev->tx_timeout = bcm43xx_net_tx_timeout;
3810#ifdef CONFIG_NET_POLL_CONTROLLER
3811 net_dev->poll_controller = bcm43xx_net_poll_controller;
3812#endif
3813 net_dev->wireless_handlers = &bcm43xx_wx_handlers_def;
3814 net_dev->irq = pdev->irq;
Michael Buesch6465ce12006-02-02 19:11:08 +01003815 SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops);
John W. Linvillef2223132006-01-23 16:59:58 -05003816
3817 /* initialize the bcm43xx_private struct */
3818 bcm = bcm43xx_priv(net_dev);
3819 memset(bcm, 0, sizeof(*bcm));
Michael Bueschab4977f2006-02-12 22:40:39 +01003820 err = bcm43xx_init_private(bcm, net_dev, pdev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003821 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003822 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003823
3824 pci_set_drvdata(pdev, net_dev);
3825
3826 err = bcm43xx_attach_board(bcm);
3827 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003828 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003829
3830 err = register_netdev(net_dev);
3831 if (err) {
3832 printk(KERN_ERR PFX "Cannot register net device, "
3833 "aborting.\n");
3834 err = -ENOMEM;
3835 goto err_detach_board;
3836 }
3837
3838 bcm43xx_debugfs_add_device(bcm);
3839
3840 assert(err == 0);
3841out:
3842 return err;
3843
3844err_detach_board:
3845 bcm43xx_detach_board(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003846err_free_netdev:
3847 free_ieee80211softmac(net_dev);
3848 goto out;
3849}
3850
3851static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
3852{
3853 struct net_device *net_dev = pci_get_drvdata(pdev);
3854 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3855
3856 bcm43xx_debugfs_remove_device(bcm);
3857 unregister_netdev(net_dev);
3858 bcm43xx_detach_board(bcm);
3859 assert(bcm->ucode == NULL);
John W. Linvillef2223132006-01-23 16:59:58 -05003860 free_ieee80211softmac(net_dev);
3861}
3862
3863/* Hard-reset the chip. Do not call this directly.
3864 * Use bcm43xx_controller_restart()
3865 */
3866static void bcm43xx_chip_reset(void *_bcm)
3867{
3868 struct bcm43xx_private *bcm = _bcm;
3869 struct net_device *net_dev = bcm->net_dev;
3870 struct pci_dev *pci_dev = bcm->pci_dev;
John W. Linvillef2223132006-01-23 16:59:58 -05003871 int err;
3872 int was_initialized = bcm->initialized;
3873
3874 netif_stop_queue(bcm->net_dev);
3875 tasklet_disable(&bcm->isr_tasklet);
3876
3877 bcm->firmware_norelease = 1;
3878 if (was_initialized)
3879 bcm43xx_free_board(bcm);
3880 bcm->firmware_norelease = 0;
3881 bcm43xx_detach_board(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003882 err = bcm43xx_init_private(bcm, net_dev, pci_dev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003883 if (err)
3884 goto failure;
John W. Linvillef2223132006-01-23 16:59:58 -05003885 err = bcm43xx_attach_board(bcm);
3886 if (err)
3887 goto failure;
3888 if (was_initialized) {
3889 err = bcm43xx_init_board(bcm);
3890 if (err)
3891 goto failure;
3892 }
3893 netif_wake_queue(bcm->net_dev);
3894 printk(KERN_INFO PFX "Controller restarted\n");
3895
3896 return;
3897failure:
3898 printk(KERN_ERR PFX "Controller restart failed\n");
3899}
3900
3901/* Hard-reset the chip.
3902 * This can be called from interrupt or process context.
3903 * Make sure to _not_ re-enable device interrupts after this has been called.
3904*/
3905void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
3906{
3907 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3908 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
3909 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003910 schedule_work(&bcm->restart_work);
John W. Linvillef2223132006-01-23 16:59:58 -05003911}
3912
3913#ifdef CONFIG_PM
3914
3915static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
3916{
3917 struct net_device *net_dev = pci_get_drvdata(pdev);
3918 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3919 unsigned long flags;
3920 int try_to_shutdown = 0, err;
3921
3922 dprintk(KERN_INFO PFX "Suspending...\n");
3923
3924 spin_lock_irqsave(&bcm->lock, flags);
3925 bcm->was_initialized = bcm->initialized;
3926 if (bcm->initialized)
3927 try_to_shutdown = 1;
3928 spin_unlock_irqrestore(&bcm->lock, flags);
3929
3930 netif_device_detach(net_dev);
3931 if (try_to_shutdown) {
3932 ieee80211softmac_stop(net_dev);
3933 err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
3934 if (unlikely(err)) {
3935 dprintk(KERN_ERR PFX "Suspend failed.\n");
3936 return -EAGAIN;
3937 }
3938 bcm->firmware_norelease = 1;
3939 bcm43xx_free_board(bcm);
3940 bcm->firmware_norelease = 0;
3941 }
3942 bcm43xx_chipset_detach(bcm);
3943
3944 pci_save_state(pdev);
3945 pci_disable_device(pdev);
3946 pci_set_power_state(pdev, pci_choose_state(pdev, state));
3947
3948 dprintk(KERN_INFO PFX "Device suspended.\n");
3949
3950 return 0;
3951}
3952
3953static int bcm43xx_resume(struct pci_dev *pdev)
3954{
3955 struct net_device *net_dev = pci_get_drvdata(pdev);
3956 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3957 int err = 0;
3958
3959 dprintk(KERN_INFO PFX "Resuming...\n");
3960
3961 pci_set_power_state(pdev, 0);
3962 pci_enable_device(pdev);
3963 pci_restore_state(pdev);
3964
3965 bcm43xx_chipset_attach(bcm);
3966 if (bcm->was_initialized) {
3967 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3968 err = bcm43xx_init_board(bcm);
3969 }
3970 if (err) {
3971 printk(KERN_ERR PFX "Resume failed!\n");
3972 return err;
3973 }
3974
3975 netif_device_attach(net_dev);
3976
3977 /*FIXME: This should be handled by softmac instead. */
3978 schedule_work(&bcm->softmac->associnfo.work);
3979
3980 dprintk(KERN_INFO PFX "Device resumed.\n");
3981
3982 return 0;
3983}
3984
3985#endif /* CONFIG_PM */
3986
3987static struct pci_driver bcm43xx_pci_driver = {
Michael Buesch65f3f192006-01-31 20:11:38 +01003988 .name = KBUILD_MODNAME,
John W. Linvillef2223132006-01-23 16:59:58 -05003989 .id_table = bcm43xx_pci_tbl,
3990 .probe = bcm43xx_init_one,
3991 .remove = __devexit_p(bcm43xx_remove_one),
3992#ifdef CONFIG_PM
3993 .suspend = bcm43xx_suspend,
3994 .resume = bcm43xx_resume,
3995#endif /* CONFIG_PM */
3996};
3997
3998static int __init bcm43xx_init(void)
3999{
Michael Buesch65f3f192006-01-31 20:11:38 +01004000 printk(KERN_INFO KBUILD_MODNAME " driver\n");
John W. Linvillef2223132006-01-23 16:59:58 -05004001 bcm43xx_debugfs_init();
4002 return pci_register_driver(&bcm43xx_pci_driver);
4003}
4004
4005static void __exit bcm43xx_exit(void)
4006{
4007 pci_unregister_driver(&bcm43xx_pci_driver);
4008 bcm43xx_debugfs_exit();
4009}
4010
4011module_init(bcm43xx_init)
4012module_exit(bcm43xx_exit)
4013
4014/* vim: set ts=8 sw=8 sts=8: */