blob: 899c06fe0bf54e22951f542fe15af948cbf21d69 [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"
John W. Linvillef2223132006-01-23 16:59:58 -050053
54
55MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
56MODULE_AUTHOR("Martin Langer");
57MODULE_AUTHOR("Stefano Brivio");
58MODULE_AUTHOR("Michael Buesch");
59MODULE_LICENSE("GPL");
60
61#ifdef CONFIG_BCM947XX
62extern char *nvram_get(char *name);
63#endif
64
Michael Buesch77db31e2006-02-12 16:47:44 +010065#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
John W. Linvillef2223132006-01-23 16:59:58 -050066static int modparam_pio;
67module_param_named(pio, modparam_pio, int, 0444);
68MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
Michael Buesch77db31e2006-02-12 16:47:44 +010069#elif defined(CONFIG_BCM43XX_DMA)
70# define modparam_pio 0
71#elif defined(CONFIG_BCM43XX_PIO)
72# define modparam_pio 1
73#endif
John W. Linvillef2223132006-01-23 16:59:58 -050074
75static int modparam_bad_frames_preempt;
76module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
77MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption");
78
79static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT;
80module_param_named(short_retry, modparam_short_retry, int, 0444);
81MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
82
83static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT;
84module_param_named(long_retry, modparam_long_retry, int, 0444);
85MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
86
87static int modparam_locale = -1;
88module_param_named(locale, modparam_locale, int, 0444);
89MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)");
90
John W. Linvillef2223132006-01-23 16:59:58 -050091static int modparam_noleds;
92module_param_named(noleds, modparam_noleds, int, 0444);
93MODULE_PARM_DESC(noleds, "Turn off all LED activity");
94
95#ifdef CONFIG_BCM43XX_DEBUG
96static char modparam_fwpostfix[64];
97module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
98MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
99#else
100# define modparam_fwpostfix ""
101#endif /* CONFIG_BCM43XX_DEBUG*/
102
103
104/* If you want to debug with just a single device, enable this,
105 * where the string is the pci device ID (as given by the kernel's
106 * pci_name function) of the device to be used.
107 */
108//#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0"
109
110/* If you want to enable printing of each MMIO access, enable this. */
111//#define DEBUG_ENABLE_MMIO_PRINT
112
113/* If you want to enable printing of MMIO access within
114 * ucode/pcm upload, initvals write, enable this.
115 */
116//#define DEBUG_ENABLE_UCODE_MMIO_PRINT
117
118/* If you want to enable printing of PCI Config Space access, enable this */
119//#define DEBUG_ENABLE_PCILOG
120
121
Michael Buesch489423c2006-02-13 00:11:07 +0100122/* Detailed list maintained at:
123 * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices
124 */
125 static struct pci_device_id bcm43xx_pci_tbl[] = {
126 /* Broadcom 4303 802.11b */
127 { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
128 /* Broadcom 4307 802.11b */
129 { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
130 /* Broadcom 4318 802.11b/g */
131 { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
132 /* Broadcom 4306 802.11b/g */
133 { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
134 /* Broadcom 4306 802.11a */
135// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
136 /* Broadcom 4309 802.11a/b/g */
137 { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
138 /* Broadcom 43XG 802.11b/g */
139 { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
John W. Linvillef2223132006-01-23 16:59:58 -0500140#ifdef CONFIG_BCM947XX
141 /* SB bus on BCM947xx */
142 { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
143#endif
Michael Buesch489423c2006-02-13 00:11:07 +0100144 { 0 },
John W. Linvillef2223132006-01-23 16:59:58 -0500145};
146MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
147
148static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val)
149{
150 u32 status;
151
152 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
153 if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP))
154 val = swab32(val);
155
156 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset);
157 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val);
158}
159
160static inline
161void bcm43xx_shm_control_word(struct bcm43xx_private *bcm,
162 u16 routing, u16 offset)
163{
164 u32 control;
165
166 /* "offset" is the WORD offset. */
167
168 control = routing;
169 control <<= 16;
170 control |= offset;
171 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control);
172}
173
174u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
175 u16 routing, u16 offset)
176{
177 u32 ret;
178
179 if (routing == BCM43xx_SHM_SHARED) {
180 if (offset & 0x0003) {
181 /* Unaligned access */
182 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
183 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
184 ret <<= 16;
185 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
186 ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
187
188 return ret;
189 }
190 offset >>= 2;
191 }
192 bcm43xx_shm_control_word(bcm, routing, offset);
193 ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA);
194
195 return ret;
196}
197
198u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
199 u16 routing, u16 offset)
200{
201 u16 ret;
202
203 if (routing == BCM43xx_SHM_SHARED) {
204 if (offset & 0x0003) {
205 /* Unaligned access */
206 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
207 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
208
209 return ret;
210 }
211 offset >>= 2;
212 }
213 bcm43xx_shm_control_word(bcm, routing, offset);
214 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
215
216 return ret;
217}
218
219void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
220 u16 routing, u16 offset,
221 u32 value)
222{
223 if (routing == BCM43xx_SHM_SHARED) {
224 if (offset & 0x0003) {
225 /* Unaligned access */
226 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
227 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
228 (value >> 16) & 0xffff);
229 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
230 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA,
231 value & 0xffff);
232 return;
233 }
234 offset >>= 2;
235 }
236 bcm43xx_shm_control_word(bcm, routing, offset);
237 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value);
238}
239
240void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
241 u16 routing, u16 offset,
242 u16 value)
243{
244 if (routing == BCM43xx_SHM_SHARED) {
245 if (offset & 0x0003) {
246 /* Unaligned access */
247 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
248 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
249 value);
250 return;
251 }
252 offset >>= 2;
253 }
254 bcm43xx_shm_control_word(bcm, routing, offset);
255 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value);
256}
257
258void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf)
259{
260 /* We need to be careful. As we read the TSF from multiple
261 * registers, we should take care of register overflows.
262 * In theory, the whole tsf read process should be atomic.
263 * We try to be atomic here, by restaring the read process,
264 * if any of the high registers changed (overflew).
265 */
266 if (bcm->current_core->rev >= 3) {
267 u32 low, high, high2;
268
269 do {
270 high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
271 low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW);
272 high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
273 } while (unlikely(high != high2));
274
275 *tsf = high;
276 *tsf <<= 32;
277 *tsf |= low;
278 } else {
279 u64 tmp;
280 u16 v0, v1, v2, v3;
281 u16 test1, test2, test3;
282
283 do {
284 v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
285 v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
286 v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
287 v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0);
288
289 test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
290 test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
291 test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
292 } while (v3 != test3 || v2 != test2 || v1 != test1);
293
294 *tsf = v3;
295 *tsf <<= 48;
296 tmp = v2;
297 tmp <<= 32;
298 *tsf |= tmp;
299 tmp = v1;
300 tmp <<= 16;
301 *tsf |= tmp;
302 *tsf |= v0;
303 }
304}
305
306void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf)
307{
308 u32 status;
309
310 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
311 status |= BCM43xx_SBF_TIME_UPDATE;
312 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
313
314 /* Be careful with the in-progress timer.
315 * First zero out the low register, so we have a full
316 * register-overflow duration to complete the operation.
317 */
318 if (bcm->current_core->rev >= 3) {
319 u32 lo = (tsf & 0x00000000FFFFFFFFULL);
320 u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
321
322 barrier();
323 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0);
324 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi);
325 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo);
326 } else {
327 u16 v0 = (tsf & 0x000000000000FFFFULL);
328 u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
329 u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
330 u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
331
332 barrier();
333 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0);
334 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3);
335 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2);
336 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1);
337 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0);
338 }
339
340 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
341 status &= ~BCM43xx_SBF_TIME_UPDATE;
342 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
343}
344
Michael Buesch489423c2006-02-13 00:11:07 +0100345static u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp,
346 const int ofdm_modulation)
John W. Linvillef2223132006-01-23 16:59:58 -0500347{
348 u8 rate;
349
350 if (ofdm_modulation) {
351 switch (plcp->raw[0] & 0xF) {
352 case 0xB:
353 rate = IEEE80211_OFDM_RATE_6MB;
354 break;
355 case 0xF:
356 rate = IEEE80211_OFDM_RATE_9MB;
357 break;
358 case 0xA:
359 rate = IEEE80211_OFDM_RATE_12MB;
360 break;
361 case 0xE:
362 rate = IEEE80211_OFDM_RATE_18MB;
363 break;
364 case 0x9:
365 rate = IEEE80211_OFDM_RATE_24MB;
366 break;
367 case 0xD:
368 rate = IEEE80211_OFDM_RATE_36MB;
369 break;
370 case 0x8:
371 rate = IEEE80211_OFDM_RATE_48MB;
372 break;
373 case 0xC:
374 rate = IEEE80211_OFDM_RATE_54MB;
375 break;
376 default:
377 rate = 0;
378 assert(0);
379 }
380 } else {
381 switch (plcp->raw[0]) {
382 case 0x0A:
383 rate = IEEE80211_CCK_RATE_1MB;
384 break;
385 case 0x14:
386 rate = IEEE80211_CCK_RATE_2MB;
387 break;
388 case 0x37:
389 rate = IEEE80211_CCK_RATE_5MB;
390 break;
391 case 0x6E:
392 rate = IEEE80211_CCK_RATE_11MB;
393 break;
394 default:
395 rate = 0;
396 assert(0);
397 }
398 }
399
400 return rate;
401}
402
Michael Buesch489423c2006-02-13 00:11:07 +0100403static u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
John W. Linvillef2223132006-01-23 16:59:58 -0500404{
405 switch (bitrate) {
406 case IEEE80211_CCK_RATE_1MB:
407 return 0x0A;
408 case IEEE80211_CCK_RATE_2MB:
409 return 0x14;
410 case IEEE80211_CCK_RATE_5MB:
411 return 0x37;
412 case IEEE80211_CCK_RATE_11MB:
413 return 0x6E;
414 }
415 assert(0);
416 return 0;
417}
418
Michael Buesch489423c2006-02-13 00:11:07 +0100419static u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
John W. Linvillef2223132006-01-23 16:59:58 -0500420{
421 switch (bitrate) {
422 case IEEE80211_OFDM_RATE_6MB:
423 return 0xB;
424 case IEEE80211_OFDM_RATE_9MB:
425 return 0xF;
426 case IEEE80211_OFDM_RATE_12MB:
427 return 0xA;
428 case IEEE80211_OFDM_RATE_18MB:
429 return 0xE;
430 case IEEE80211_OFDM_RATE_24MB:
431 return 0x9;
432 case IEEE80211_OFDM_RATE_36MB:
433 return 0xD;
434 case IEEE80211_OFDM_RATE_48MB:
435 return 0x8;
436 case IEEE80211_OFDM_RATE_54MB:
437 return 0xC;
438 }
439 assert(0);
440 return 0;
441}
442
443static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
444 u16 octets, const u8 bitrate,
445 const int ofdm_modulation)
446{
447 __le32 *data = &(plcp->data);
448 __u8 *raw = plcp->raw;
449
450 /* Account for hardware-appended FCS. */
451 octets += IEEE80211_FCS_LEN;
452
453 if (ofdm_modulation) {
454 *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
455 assert(!(octets & 0xF000));
456 *data |= (octets << 5);
457 *data = cpu_to_le32(*data);
458 } else {
459 u32 plen;
460
461 plen = octets * 16 / bitrate;
462 if ((octets * 16 % bitrate) > 0) {
463 plen++;
464 if ((bitrate == IEEE80211_CCK_RATE_11MB)
465 && ((octets * 8 % 11) < 4)) {
466 raw[1] = 0x84;
467 } else
468 raw[1] = 0x04;
469 } else
470 raw[1] = 0x04;
471 *data |= cpu_to_le32(plen << 16);
472 raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
473 }
474
475//bcm43xx_printk_bitdump(raw, 4, 0, "PLCP");
476}
477
Michael Buesch489423c2006-02-13 00:11:07 +0100478void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
479 struct bcm43xx_txhdr *txhdr,
480 const unsigned char *fragment_data,
481 unsigned int fragment_len,
482 const int is_first_fragment,
483 const u16 cookie)
John W. Linvillef2223132006-01-23 16:59:58 -0500484{
485 const struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
486 const struct ieee80211_hdr_1addr *wireless_header = (const struct ieee80211_hdr_1addr *)fragment_data;
487 const struct ieee80211_security *secinfo = &bcm->ieee->sec;
488 u8 bitrate;
489 int ofdm_modulation;
490 u8 fallback_bitrate;
491 int fallback_ofdm_modulation;
492 u16 tmp;
493 u16 encrypt_frame;
494
495 /* Now construct the TX header. */
496 memset(txhdr, 0, sizeof(*txhdr));
497
498 //TODO: Some RTS/CTS stuff has to be done.
499 //TODO: Encryption stuff.
500 //TODO: others?
501
502 bitrate = bcm->softmac->txrates.default_rate;
503 ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
504 fallback_bitrate = bcm->softmac->txrates.default_fallback;
505 fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
506
507 /* Set Frame Control from 80211 header. */
508 txhdr->frame_control = wireless_header->frame_ctl;
509 /* Copy address1 from 80211 header. */
510 memcpy(txhdr->mac1, wireless_header->addr1, 6);
511 /* Set the fallback duration ID. */
512 //FIXME: We use the original durid for now.
513 txhdr->fallback_dur_id = wireless_header->duration_id;
514
515 /* Set the cookie (used as driver internal ID for the frame) */
516 txhdr->cookie = cpu_to_le16(cookie);
517
518 encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED;
519 if (encrypt_frame && !bcm->ieee->host_encrypt) {
520 const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header;
521 if (fragment_len <= sizeof(struct ieee80211_hdr_3addr)+4) {
522 dprintkl(KERN_ERR PFX "invalid packet with PROTECTED"
523 "flag set discarded");
524 return;
525 }
526 memcpy(txhdr->wep_iv, hdr->payload, 4);
527 /* Hardware appends ICV. */
528 fragment_len += 4;
529 }
530
531 /* Generate the PLCP header and the fallback PLCP header. */
532 bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
533 fragment_len,
534 bitrate, ofdm_modulation);
535 bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, fragment_len,
536 fallback_bitrate, fallback_ofdm_modulation);
537
538 /* Set the CONTROL field */
539 tmp = 0;
540 if (ofdm_modulation)
541 tmp |= BCM43xx_TXHDRCTL_OFDM;
542 if (bcm->short_preamble) //FIXME: could be the other way around, please test
543 tmp |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE;
544 tmp |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT)
545 & BCM43xx_TXHDRCTL_ANTENNADIV_MASK;
546 txhdr->control = cpu_to_le16(tmp);
547
548 /* Set the FLAGS field */
549 tmp = 0;
550 if (!is_multicast_ether_addr(wireless_header->addr1) &&
551 !is_broadcast_ether_addr(wireless_header->addr1))
552 tmp |= BCM43xx_TXHDRFLAG_EXPECTACK;
553 if (1 /* FIXME: PS poll?? */)
554 tmp |= 0x10; // FIXME: unknown meaning.
555 if (fallback_ofdm_modulation)
556 tmp |= BCM43xx_TXHDRFLAG_FALLBACKOFDM;
557 if (is_first_fragment)
558 tmp |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT;
559 txhdr->flags = cpu_to_le16(tmp);
560
561 /* Set WSEC/RATE field */
562 if (encrypt_frame && !bcm->ieee->host_encrypt) {
563 tmp = (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT)
564 & BCM43xx_TXHDR_WSEC_ALGO_MASK;
565 tmp |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT)
566 & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK;
567 txhdr->wsec_rate = cpu_to_le16(tmp);
568 }
569
570//bcm43xx_printk_bitdump((const unsigned char *)txhdr, sizeof(*txhdr), 1, "TX header");
571}
572
573static
574void bcm43xx_macfilter_set(struct bcm43xx_private *bcm,
575 u16 offset,
576 const u8 *mac)
577{
578 u16 data;
579
580 offset |= 0x0020;
581 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset);
582
583 data = mac[0];
584 data |= mac[1] << 8;
585 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
586 data = mac[2];
587 data |= mac[3] << 8;
588 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
589 data = mac[4];
590 data |= mac[5] << 8;
591 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
592}
593
Michael Buesch489423c2006-02-13 00:11:07 +0100594static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm,
595 u16 offset)
John W. Linvillef2223132006-01-23 16:59:58 -0500596{
597 const u8 zero_addr[ETH_ALEN] = { 0 };
598
599 bcm43xx_macfilter_set(bcm, offset, zero_addr);
600}
601
602static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm)
603{
604 const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr);
605 const u8 *bssid = (const u8 *)(bcm->ieee->bssid);
606 u8 mac_bssid[ETH_ALEN * 2];
607 int i;
608
609 memcpy(mac_bssid, mac, ETH_ALEN);
610 memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
611
612 /* Write our MAC address and BSSID to template ram */
613 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
614 bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i)));
615 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
616 bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i)));
617 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
618 bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i)));
619}
620
Michael Buesch489423c2006-02-13 00:11:07 +0100621static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time)
John W. Linvillef2223132006-01-23 16:59:58 -0500622{
623 /* slot_time is in usec. */
624 if (bcm->current_core->phy->type != BCM43xx_PHYTYPE_G)
625 return;
626 bcm43xx_write16(bcm, 0x684, 510 + slot_time);
627 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time);
628}
629
Michael Buesch489423c2006-02-13 00:11:07 +0100630static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -0500631{
632 bcm43xx_set_slot_time(bcm, 9);
633}
634
Michael Buesch489423c2006-02-13 00:11:07 +0100635static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -0500636{
637 bcm43xx_set_slot_time(bcm, 20);
638}
639
640//FIXME: rename this func?
641static void bcm43xx_disassociate(struct bcm43xx_private *bcm)
642{
643 bcm43xx_mac_suspend(bcm);
644 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
645
646 bcm43xx_ram_write(bcm, 0x0026, 0x0000);
647 bcm43xx_ram_write(bcm, 0x0028, 0x0000);
648 bcm43xx_ram_write(bcm, 0x007E, 0x0000);
649 bcm43xx_ram_write(bcm, 0x0080, 0x0000);
650 bcm43xx_ram_write(bcm, 0x047E, 0x0000);
651 bcm43xx_ram_write(bcm, 0x0480, 0x0000);
652
653 if (bcm->current_core->rev < 3) {
654 bcm43xx_write16(bcm, 0x0610, 0x8000);
655 bcm43xx_write16(bcm, 0x060E, 0x0000);
656 } else
657 bcm43xx_write32(bcm, 0x0188, 0x80000000);
658
659 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
660
661 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G &&
662 ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate))
663 bcm43xx_short_slot_timing_enable(bcm);
664
665 bcm43xx_mac_enable(bcm);
666}
667
668//FIXME: rename this func?
669static void bcm43xx_associate(struct bcm43xx_private *bcm,
670 const u8 *mac)
671{
672 memcpy(bcm->ieee->bssid, mac, ETH_ALEN);
673
674 bcm43xx_mac_suspend(bcm);
675 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac);
676 bcm43xx_write_mac_bssid_templates(bcm);
677 bcm43xx_mac_enable(bcm);
678}
679
680/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
681 * Returns the _previously_ enabled IRQ mask.
682 */
683static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask)
684{
685 u32 old_mask;
686
687 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
688 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask);
689
690 return old_mask;
691}
692
693/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
694 * Returns the _previously_ enabled IRQ mask.
695 */
696static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask)
697{
698 u32 old_mask;
699
700 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
701 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
702
703 return old_mask;
704}
705
706/* Make sure we don't receive more data from the device. */
707static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
708{
709 u32 old;
710 unsigned long flags;
711
712 spin_lock_irqsave(&bcm->lock, flags);
713 if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
714 spin_unlock_irqrestore(&bcm->lock, flags);
715 return -EBUSY;
716 }
717 old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
718 tasklet_disable(&bcm->isr_tasklet);
719 spin_unlock_irqrestore(&bcm->lock, flags);
720 if (oldstate)
721 *oldstate = old;
722
723 return 0;
724}
725
726static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
727{
Michael Buesch489423c2006-02-13 00:11:07 +0100728 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
729 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -0500730 u32 radio_id;
731 u16 manufact;
732 u16 version;
733 u8 revision;
734 s8 i;
735
736 if (bcm->chip_id == 0x4317) {
737 if (bcm->chip_rev == 0x00)
738 radio_id = 0x3205017F;
739 else if (bcm->chip_rev == 0x01)
740 radio_id = 0x4205017F;
741 else
742 radio_id = 0x5205017F;
743 } else {
744 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
745 radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH);
746 radio_id <<= 16;
747 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
748 radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
749 }
750
751 manufact = (radio_id & 0x00000FFF);
752 version = (radio_id & 0x0FFFF000) >> 12;
753 revision = (radio_id & 0xF0000000) >> 28;
754
Michael Buesch489423c2006-02-13 00:11:07 +0100755 dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n",
John W. Linvillef2223132006-01-23 16:59:58 -0500756 radio_id, manufact, version, revision);
757
Michael Buesch489423c2006-02-13 00:11:07 +0100758 switch (phy->type) {
John W. Linvillef2223132006-01-23 16:59:58 -0500759 case BCM43xx_PHYTYPE_A:
760 if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f))
761 goto err_unsupported_radio;
762 break;
763 case BCM43xx_PHYTYPE_B:
764 if ((version & 0xFFF0) != 0x2050)
765 goto err_unsupported_radio;
766 break;
767 case BCM43xx_PHYTYPE_G:
768 if (version != 0x2050)
769 goto err_unsupported_radio;
770 break;
771 }
772
Michael Buesch489423c2006-02-13 00:11:07 +0100773 radio->manufact = manufact;
774 radio->version = version;
775 radio->revision = revision;
John W. Linvillef2223132006-01-23 16:59:58 -0500776
777 /* Set default attenuation values. */
Michael Buesch489423c2006-02-13 00:11:07 +0100778 radio->txpower[0] = 2;
779 radio->txpower[1] = 2;
John W. Linvillef2223132006-01-23 16:59:58 -0500780 if (revision == 1)
Michael Buesch489423c2006-02-13 00:11:07 +0100781 radio->txpower[2] = 3;
John W. Linvillef2223132006-01-23 16:59:58 -0500782 else
Michael Buesch489423c2006-02-13 00:11:07 +0100783 radio->txpower[2] = 0;
Michael Buesch393344f2006-02-05 15:28:20 +0100784 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
Michael Buesch489423c2006-02-13 00:11:07 +0100785 radio->txpower_desired = bcm->sprom.maxpower_aphy;
Michael Buesch393344f2006-02-05 15:28:20 +0100786 else
787 bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_bgphy;
John W. Linvillef2223132006-01-23 16:59:58 -0500788
789 /* Initialize the in-memory nrssi Lookup Table. */
790 for (i = 0; i < 64; i++)
Michael Buesch489423c2006-02-13 00:11:07 +0100791 radio->nrssi_lt[i] = i;
John W. Linvillef2223132006-01-23 16:59:58 -0500792
793 return 0;
794
795err_unsupported_radio:
796 printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n");
797 return -ENODEV;
798}
799
800static const char * bcm43xx_locale_iso(u8 locale)
801{
802 /* ISO 3166-1 country codes.
803 * Note that there aren't ISO 3166-1 codes for
804 * all or locales. (Not all locales are countries)
805 */
806 switch (locale) {
807 case BCM43xx_LOCALE_WORLD:
808 case BCM43xx_LOCALE_ALL:
809 return "XX";
810 case BCM43xx_LOCALE_THAILAND:
811 return "TH";
812 case BCM43xx_LOCALE_ISRAEL:
813 return "IL";
814 case BCM43xx_LOCALE_JORDAN:
815 return "JO";
816 case BCM43xx_LOCALE_CHINA:
817 return "CN";
818 case BCM43xx_LOCALE_JAPAN:
819 case BCM43xx_LOCALE_JAPAN_HIGH:
820 return "JP";
821 case BCM43xx_LOCALE_USA_CANADA_ANZ:
822 case BCM43xx_LOCALE_USA_LOW:
823 return "US";
824 case BCM43xx_LOCALE_EUROPE:
825 return "EU";
826 case BCM43xx_LOCALE_NONE:
827 return " ";
828 }
829 assert(0);
830 return " ";
831}
832
833static const char * bcm43xx_locale_string(u8 locale)
834{
835 switch (locale) {
836 case BCM43xx_LOCALE_WORLD:
837 return "World";
838 case BCM43xx_LOCALE_THAILAND:
839 return "Thailand";
840 case BCM43xx_LOCALE_ISRAEL:
841 return "Israel";
842 case BCM43xx_LOCALE_JORDAN:
843 return "Jordan";
844 case BCM43xx_LOCALE_CHINA:
845 return "China";
846 case BCM43xx_LOCALE_JAPAN:
847 return "Japan";
848 case BCM43xx_LOCALE_USA_CANADA_ANZ:
849 return "USA/Canada/ANZ";
850 case BCM43xx_LOCALE_EUROPE:
851 return "Europe";
852 case BCM43xx_LOCALE_USA_LOW:
853 return "USAlow";
854 case BCM43xx_LOCALE_JAPAN_HIGH:
855 return "JapanHigh";
856 case BCM43xx_LOCALE_ALL:
857 return "All";
858 case BCM43xx_LOCALE_NONE:
859 return "None";
860 }
861 assert(0);
862 return "";
863}
864
865static inline u8 bcm43xx_crc8(u8 crc, u8 data)
866{
867 static const u8 t[] = {
868 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
869 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
870 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
871 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
872 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
873 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
874 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
875 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
876 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
877 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
878 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
879 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
880 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
881 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
882 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
883 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
884 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
885 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
886 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
887 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
888 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
889 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
890 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
891 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
892 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
893 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
894 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
895 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
896 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
897 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
898 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
899 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
900 };
901 return t[crc ^ data];
902}
903
Michael Bueschad3f0862006-02-19 14:12:22 +0100904static u8 bcm43xx_sprom_crc(const u16 *sprom)
John W. Linvillef2223132006-01-23 16:59:58 -0500905{
906 int word;
907 u8 crc = 0xFF;
908
909 for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) {
910 crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF);
911 crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8);
912 }
913 crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF);
914 crc ^= 0xFF;
915
916 return crc;
917}
918
Michael Bueschea0922b2006-02-19 14:09:20 +0100919int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom)
John W. Linvillef2223132006-01-23 16:59:58 -0500920{
921 int i;
Michael Bueschea0922b2006-02-19 14:09:20 +0100922 u8 crc, expected_crc;
923
924 for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
925 sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
926 /* CRC-8 check. */
927 crc = bcm43xx_sprom_crc(sprom);
928 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
929 if (crc != expected_crc) {
930 printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum "
931 "(0x%02X, expected: 0x%02X)\n",
932 crc, expected_crc);
933 return -EINVAL;
934 }
935
936 return 0;
937}
938
939int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
940{
941 int i, err;
942 u8 crc, expected_crc;
943 u32 spromctl;
944
945 /* CRC-8 validation of the input data. */
946 crc = bcm43xx_sprom_crc(sprom);
947 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
948 if (crc != expected_crc) {
949 printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
950 return -EINVAL;
951 }
952
953 printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
954 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
955 if (err)
956 goto err_ctlreg;
957 spromctl |= 0x10; /* SPROM WRITE enable. */
958 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
959 if (err)
960 goto err_ctlreg;
961 /* We must burn lots of CPU cycles here, but that does not
962 * really matter as one does not write the SPROM every other minute...
963 */
964 printk(KERN_INFO PFX "[ 0%%");
965 mdelay(500);
966 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
967 if (i == 16)
968 printk("25%%");
969 else if (i == 32)
970 printk("50%%");
971 else if (i == 48)
972 printk("75%%");
973 else if (i % 2)
974 printk(".");
975 bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
976 mdelay(20);
977 }
978 spromctl &= ~0x10; /* SPROM WRITE enable. */
979 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
980 if (err)
981 goto err_ctlreg;
982 mdelay(500);
983 printk("100%% ]\n");
984 printk(KERN_INFO PFX "SPROM written.\n");
985 bcm43xx_controller_restart(bcm, "SPROM update");
986
987 return 0;
988err_ctlreg:
989 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
990 return -ENODEV;
991}
992
993static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
994{
John W. Linvillef2223132006-01-23 16:59:58 -0500995 u16 value;
996 u16 *sprom;
John W. Linvillef2223132006-01-23 16:59:58 -0500997#ifdef CONFIG_BCM947XX
998 char *c;
999#endif
1000
1001 sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
1002 GFP_KERNEL);
1003 if (!sprom) {
Michael Bueschea0922b2006-02-19 14:09:20 +01001004 printk(KERN_ERR PFX "sprom_extract OOM\n");
John W. Linvillef2223132006-01-23 16:59:58 -05001005 return -ENOMEM;
1006 }
1007#ifdef CONFIG_BCM947XX
1008 sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
1009 sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
1010
1011 if ((c = nvram_get("il0macaddr")) != NULL)
1012 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
1013
1014 if ((c = nvram_get("et1macaddr")) != NULL)
1015 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
1016
1017 sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
1018 sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
1019 sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
1020
1021 sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
1022 sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
1023 sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
1024
1025 sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
1026#else
Michael Bueschea0922b2006-02-19 14:09:20 +01001027 bcm43xx_sprom_read(bcm, sprom);
John W. Linvillef2223132006-01-23 16:59:58 -05001028#endif
1029
1030 /* boardflags2 */
1031 value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
1032 bcm->sprom.boardflags2 = value;
1033
1034 /* il0macaddr */
1035 value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
1036 *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
1037 value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
1038 *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
1039 value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
1040 *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
1041
1042 /* et0macaddr */
1043 value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
1044 *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
1045 value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
1046 *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
1047 value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
1048 *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
1049
1050 /* et1macaddr */
1051 value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
1052 *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
1053 value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
1054 *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
1055 value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
1056 *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
1057
1058 /* ethernet phy settings */
1059 value = sprom[BCM43xx_SPROM_ETHPHY];
1060 bcm->sprom.et0phyaddr = (value & 0x001F);
1061 bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;
1062 bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;
1063 bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;
1064
1065 /* boardrev, antennas, locale */
1066 value = sprom[BCM43xx_SPROM_BOARDREV];
1067 bcm->sprom.boardrev = (value & 0x00FF);
1068 bcm->sprom.locale = (value & 0x0F00) >> 8;
1069 bcm->sprom.antennas_aphy = (value & 0x3000) >> 12;
1070 bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14;
1071 if (modparam_locale != -1) {
1072 if (modparam_locale >= 0 && modparam_locale <= 11) {
1073 bcm->sprom.locale = modparam_locale;
1074 printk(KERN_WARNING PFX "Operating with modified "
1075 "LocaleCode %u (%s)\n",
1076 bcm->sprom.locale,
1077 bcm43xx_locale_string(bcm->sprom.locale));
1078 } else {
1079 printk(KERN_WARNING PFX "Module parameter \"locale\" "
1080 "invalid value. (0 - 11)\n");
1081 }
1082 }
1083
1084 /* pa0b* */
1085 value = sprom[BCM43xx_SPROM_PA0B0];
1086 bcm->sprom.pa0b0 = value;
1087 value = sprom[BCM43xx_SPROM_PA0B1];
1088 bcm->sprom.pa0b1 = value;
1089 value = sprom[BCM43xx_SPROM_PA0B2];
1090 bcm->sprom.pa0b2 = value;
1091
1092 /* wl0gpio* */
1093 value = sprom[BCM43xx_SPROM_WL0GPIO0];
1094 if (value == 0x0000)
1095 value = 0xFFFF;
1096 bcm->sprom.wl0gpio0 = value & 0x00FF;
1097 bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8;
1098 value = sprom[BCM43xx_SPROM_WL0GPIO2];
1099 if (value == 0x0000)
1100 value = 0xFFFF;
1101 bcm->sprom.wl0gpio2 = value & 0x00FF;
1102 bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8;
1103
1104 /* maxpower */
1105 value = sprom[BCM43xx_SPROM_MAXPWR];
1106 bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8;
1107 bcm->sprom.maxpower_bgphy = value & 0x00FF;
1108
1109 /* pa1b* */
1110 value = sprom[BCM43xx_SPROM_PA1B0];
1111 bcm->sprom.pa1b0 = value;
1112 value = sprom[BCM43xx_SPROM_PA1B1];
1113 bcm->sprom.pa1b1 = value;
1114 value = sprom[BCM43xx_SPROM_PA1B2];
1115 bcm->sprom.pa1b2 = value;
1116
1117 /* idle tssi target */
1118 value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT];
1119 bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF;
1120 bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8;
1121
1122 /* boardflags */
1123 value = sprom[BCM43xx_SPROM_BOARDFLAGS];
1124 if (value == 0xFFFF)
1125 value = 0x0000;
1126 bcm->sprom.boardflags = value;
1127
1128 /* antenna gain */
1129 value = sprom[BCM43xx_SPROM_ANTENNA_GAIN];
1130 if (value == 0x0000 || value == 0xFFFF)
1131 value = 0x0202;
1132 /* convert values to Q5.2 */
1133 bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4;
1134 bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4;
1135
1136 kfree(sprom);
1137
1138 return 0;
1139}
1140
John W. Linvillef2223132006-01-23 16:59:58 -05001141static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
1142{
1143 struct ieee80211_geo geo;
1144 struct ieee80211_channel *chan;
1145 int have_a = 0, have_bg = 0;
1146 int i, num80211;
Michael Buesch9e4a3752006-02-02 18:43:25 +01001147 u8 channel;
John W. Linvillef2223132006-01-23 16:59:58 -05001148 struct bcm43xx_phyinfo *phy;
1149 const char *iso_country;
1150
1151 memset(&geo, 0, sizeof(geo));
1152 num80211 = bcm43xx_num_80211_cores(bcm);
1153 for (i = 0; i < num80211; i++) {
1154 phy = bcm->phy + i;
1155 switch (phy->type) {
1156 case BCM43xx_PHYTYPE_B:
1157 case BCM43xx_PHYTYPE_G:
1158 have_bg = 1;
1159 break;
1160 case BCM43xx_PHYTYPE_A:
1161 have_a = 1;
1162 break;
1163 default:
1164 assert(0);
1165 }
1166 }
1167 iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
1168
1169 if (have_a) {
1170 for (i = 0, channel = 0; channel < 201; channel++) {
John W. Linvillef2223132006-01-23 16:59:58 -05001171 chan = &geo.a[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +01001172 chan->freq = bcm43xx_channel_to_freq_a(channel);
John W. Linvillef2223132006-01-23 16:59:58 -05001173 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -05001174 }
1175 geo.a_channels = i;
1176 }
1177 if (have_bg) {
1178 for (i = 0, channel = 1; channel < 15; channel++) {
John W. Linvillef2223132006-01-23 16:59:58 -05001179 chan = &geo.bg[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +01001180 chan->freq = bcm43xx_channel_to_freq_bg(channel);
John W. Linvillef2223132006-01-23 16:59:58 -05001181 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -05001182 }
1183 geo.bg_channels = i;
1184 }
1185 memcpy(geo.name, iso_country, 2);
1186 if (0 /*TODO: Outdoor use only */)
1187 geo.name[2] = 'O';
1188 else if (0 /*TODO: Indoor use only */)
1189 geo.name[2] = 'I';
1190 else
1191 geo.name[2] = ' ';
1192 geo.name[3] = '\0';
1193
1194 ieee80211_set_geo(bcm->ieee, &geo);
1195}
1196
1197/* DummyTransmission function, as documented on
1198 * http://bcm-specs.sipsolutions.net/DummyTransmission
1199 */
1200void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
1201{
Michael Buesch489423c2006-02-13 00:11:07 +01001202 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -05001203 unsigned int i, max_loop;
1204 u16 value = 0;
1205 u32 buffer[5] = {
1206 0x00000000,
1207 0x0000D400,
1208 0x00000000,
1209 0x00000001,
1210 0x00000000,
1211 };
1212
Michael Buesch489423c2006-02-13 00:11:07 +01001213 switch (phy->type) {
John W. Linvillef2223132006-01-23 16:59:58 -05001214 case BCM43xx_PHYTYPE_A:
1215 max_loop = 0x1E;
1216 buffer[0] = 0xCC010200;
1217 break;
1218 case BCM43xx_PHYTYPE_B:
1219 case BCM43xx_PHYTYPE_G:
1220 max_loop = 0xFA;
1221 buffer[0] = 0x6E840B00;
1222 break;
1223 default:
1224 assert(0);
1225 return;
1226 }
1227
1228 for (i = 0; i < 5; i++)
1229 bcm43xx_ram_write(bcm, i * 4, buffer[i]);
1230
1231 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
1232
1233 bcm43xx_write16(bcm, 0x0568, 0x0000);
1234 bcm43xx_write16(bcm, 0x07C0, 0x0000);
Michael Buesch489423c2006-02-13 00:11:07 +01001235 bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0));
John W. Linvillef2223132006-01-23 16:59:58 -05001236 bcm43xx_write16(bcm, 0x0508, 0x0000);
1237 bcm43xx_write16(bcm, 0x050A, 0x0000);
1238 bcm43xx_write16(bcm, 0x054C, 0x0000);
1239 bcm43xx_write16(bcm, 0x056A, 0x0014);
1240 bcm43xx_write16(bcm, 0x0568, 0x0826);
1241 bcm43xx_write16(bcm, 0x0500, 0x0000);
1242 bcm43xx_write16(bcm, 0x0502, 0x0030);
1243
1244 for (i = 0x00; i < max_loop; i++) {
1245 value = bcm43xx_read16(bcm, 0x050E);
1246 if ((value & 0x0080) != 0)
1247 break;
1248 udelay(10);
1249 }
1250 for (i = 0x00; i < 0x0A; i++) {
1251 value = bcm43xx_read16(bcm, 0x050E);
1252 if ((value & 0x0400) != 0)
1253 break;
1254 udelay(10);
1255 }
1256 for (i = 0x00; i < 0x0A; i++) {
1257 value = bcm43xx_read16(bcm, 0x0690);
1258 if ((value & 0x0100) == 0)
1259 break;
1260 udelay(10);
1261 }
1262}
1263
1264static void key_write(struct bcm43xx_private *bcm,
1265 u8 index, u8 algorithm, const u16 *key)
1266{
1267 unsigned int i, basic_wep = 0;
1268 u32 offset;
1269 u16 value;
1270
1271 /* Write associated key information */
1272 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2),
1273 ((index << 4) | (algorithm & 0x0F)));
1274
1275 /* The first 4 WEP keys need extra love */
1276 if (((algorithm == BCM43xx_SEC_ALGO_WEP) ||
1277 (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4))
1278 basic_wep = 1;
1279
1280 /* Write key payload, 8 little endian words */
1281 offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE);
1282 for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) {
1283 value = cpu_to_le16(key[i]);
1284 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1285 offset + (i * 2), value);
1286
1287 if (!basic_wep)
1288 continue;
1289
1290 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1291 offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE,
1292 value);
1293 }
1294}
1295
1296static void keymac_write(struct bcm43xx_private *bcm,
1297 u8 index, const u32 *addr)
1298{
1299 /* for keys 0-3 there is no associated mac address */
1300 if (index < 4)
1301 return;
1302
1303 index -= 4;
1304 if (bcm->current_core->rev >= 5) {
1305 bcm43xx_shm_write32(bcm,
1306 BCM43xx_SHM_HWMAC,
1307 index * 2,
1308 cpu_to_be32(*addr));
1309 bcm43xx_shm_write16(bcm,
1310 BCM43xx_SHM_HWMAC,
1311 (index * 2) + 1,
1312 cpu_to_be16(*((u16 *)(addr + 1))));
1313 } else {
1314 if (index < 8) {
1315 TODO(); /* Put them in the macaddress filter */
1316 } else {
1317 TODO();
1318 /* Put them BCM43xx_SHM_SHARED, stating index 0x0120.
1319 Keep in mind to update the count of keymacs in 0x003E as well! */
1320 }
1321 }
1322}
1323
1324static int bcm43xx_key_write(struct bcm43xx_private *bcm,
1325 u8 index, u8 algorithm,
1326 const u8 *_key, int key_len,
1327 const u8 *mac_addr)
1328{
1329 u8 key[BCM43xx_SEC_KEYSIZE] = { 0 };
1330
1331 if (index >= ARRAY_SIZE(bcm->key))
1332 return -EINVAL;
1333 if (key_len > ARRAY_SIZE(key))
1334 return -EINVAL;
1335 if (algorithm < 1 || algorithm > 5)
1336 return -EINVAL;
1337
1338 memcpy(key, _key, key_len);
1339 key_write(bcm, index, algorithm, (const u16 *)key);
1340 keymac_write(bcm, index, (const u32 *)mac_addr);
1341
1342 bcm->key[index].algorithm = algorithm;
1343
1344 return 0;
1345}
1346
1347static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
1348{
1349 static const u32 zero_mac[2] = { 0 };
1350 unsigned int i,j, nr_keys = 54;
1351 u16 offset;
1352
1353 if (bcm->current_core->rev < 5)
1354 nr_keys = 16;
1355 assert(nr_keys <= ARRAY_SIZE(bcm->key));
1356
1357 for (i = 0; i < nr_keys; i++) {
1358 bcm->key[i].enabled = 0;
1359 /* returns for i < 4 immediately */
1360 keymac_write(bcm, i, zero_mac);
1361 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1362 0x100 + (i * 2), 0x0000);
1363 for (j = 0; j < 8; j++) {
1364 offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE);
1365 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1366 offset, 0x0000);
1367 }
1368 }
1369 dprintk(KERN_INFO PFX "Keys cleared\n");
1370}
1371
John W. Linvillef2223132006-01-23 16:59:58 -05001372/* Lowlevel core-switch function. This is only to be used in
1373 * bcm43xx_switch_core() and bcm43xx_probe_cores()
1374 */
1375static int _switch_core(struct bcm43xx_private *bcm, int core)
1376{
1377 int err;
1378 int attempts = 0;
Michael Buesch489423c2006-02-13 00:11:07 +01001379 u32 current_core;
John W. Linvillef2223132006-01-23 16:59:58 -05001380
1381 assert(core >= 0);
Michael Buesch489423c2006-02-13 00:11:07 +01001382 while (1) {
1383 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
John W. Linvillef2223132006-01-23 16:59:58 -05001384 (core * 0x1000) + 0x18000000);
Michael Buesch489423c2006-02-13 00:11:07 +01001385 if (unlikely(err))
1386 goto error;
1387 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
1388 &current_core);
1389 if (unlikely(err))
1390 goto error;
1391 current_core = (current_core - 0x18000000) / 0x1000;
1392 if (current_core == core)
1393 break;
John W. Linvillef2223132006-01-23 16:59:58 -05001394
Michael Buesch489423c2006-02-13 00:11:07 +01001395 if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES))
1396 goto error;
1397 udelay(10);
1398 }
1399#ifdef CONFIG_BCM947XX
1400 if (bcm->pci_dev->bus->number == 0)
1401 bcm->current_core_offset = 0x1000 * core;
1402 else
1403 bcm->current_core_offset = 0;
1404#endif
1405
1406 return 0;
1407error:
1408 printk(KERN_ERR PFX "Failed to switch to core %d\n", core);
1409 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05001410}
1411
1412int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core)
1413{
1414 int err;
1415
Michael Buesch489423c2006-02-13 00:11:07 +01001416 if (unlikely(!new_core))
John W. Linvillef2223132006-01-23 16:59:58 -05001417 return 0;
John W. Linvillef2223132006-01-23 16:59:58 -05001418 if (!(new_core->flags & BCM43xx_COREFLAG_AVAILABLE))
1419 return -ENODEV;
1420 if (bcm->current_core == new_core)
1421 return 0;
1422 err = _switch_core(bcm, new_core->index);
Michael Buesch489423c2006-02-13 00:11:07 +01001423 if (likely(!err))
John W. Linvillef2223132006-01-23 16:59:58 -05001424 bcm->current_core = new_core;
1425
1426 return err;
1427}
1428
Michael Buesch489423c2006-02-13 00:11:07 +01001429static int bcm43xx_core_enabled(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001430{
1431 u32 value;
1432
1433 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1434 value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET
1435 | BCM43xx_SBTMSTATELOW_REJECT;
1436
1437 return (value == BCM43xx_SBTMSTATELOW_CLOCK);
1438}
1439
1440/* disable current core */
1441static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags)
1442{
1443 u32 sbtmstatelow;
1444 u32 sbtmstatehigh;
1445 int i;
1446
1447 /* fetch sbtmstatelow from core information registers */
1448 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1449
1450 /* core is already in reset */
1451 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET)
1452 goto out;
1453
1454 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) {
1455 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1456 BCM43xx_SBTMSTATELOW_REJECT;
1457 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1458
1459 for (i = 0; i < 1000; i++) {
1460 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1461 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) {
1462 i = -1;
1463 break;
1464 }
1465 udelay(10);
1466 }
1467 if (i != -1) {
1468 printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n");
1469 return -EBUSY;
1470 }
1471
1472 for (i = 0; i < 1000; i++) {
1473 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1474 if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) {
1475 i = -1;
1476 break;
1477 }
1478 udelay(10);
1479 }
1480 if (i != -1) {
1481 printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n");
1482 return -EBUSY;
1483 }
1484
1485 sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1486 BCM43xx_SBTMSTATELOW_REJECT |
1487 BCM43xx_SBTMSTATELOW_RESET |
1488 BCM43xx_SBTMSTATELOW_CLOCK |
1489 core_flags;
1490 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1491 udelay(10);
1492 }
1493
1494 sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET |
1495 BCM43xx_SBTMSTATELOW_REJECT |
1496 core_flags;
1497 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1498
1499out:
1500 bcm->current_core->flags &= ~ BCM43xx_COREFLAG_ENABLED;
1501 return 0;
1502}
1503
1504/* enable (reset) current core */
1505static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags)
1506{
1507 u32 sbtmstatelow;
1508 u32 sbtmstatehigh;
1509 u32 sbimstate;
1510 int err;
1511
1512 err = bcm43xx_core_disable(bcm, core_flags);
1513 if (err)
1514 goto out;
1515
1516 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1517 BCM43xx_SBTMSTATELOW_RESET |
1518 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1519 core_flags;
1520 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1521 udelay(1);
1522
1523 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1524 if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) {
1525 sbtmstatehigh = 0x00000000;
1526 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh);
1527 }
1528
1529 sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE);
1530 if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) {
1531 sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT);
1532 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate);
1533 }
1534
1535 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1536 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1537 core_flags;
1538 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1539 udelay(1);
1540
1541 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags;
1542 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1543 udelay(1);
1544
1545 bcm->current_core->flags |= BCM43xx_COREFLAG_ENABLED;
1546 assert(err == 0);
1547out:
1548 return err;
1549}
1550
1551/* http://bcm-specs.sipsolutions.net/80211CoreReset */
1552void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
1553{
1554 u32 flags = 0x00040000;
1555
Michael Buesch77db31e2006-02-12 16:47:44 +01001556 if ((bcm43xx_core_enabled(bcm)) &&
1557 !bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05001558//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
1559#ifndef CONFIG_BCM947XX
1560 /* reset all used DMA controllers. */
1561 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1562 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
1563 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
1564 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1565 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1566 if (bcm->current_core->rev < 5)
1567 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1568#endif
1569 }
1570 if (bcm->shutting_down) {
1571 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1572 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1573 & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
1574 } else {
1575 if (connect_phy)
1576 flags |= 0x20000000;
1577 bcm43xx_phy_connect(bcm, connect_phy);
1578 bcm43xx_core_enable(bcm, flags);
1579 bcm43xx_write16(bcm, 0x03E6, 0x0000);
1580 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1581 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1582 | BCM43xx_SBF_400);
1583 }
1584}
1585
1586static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
1587{
1588 bcm43xx_radio_turn_off(bcm);
1589 bcm43xx_write16(bcm, 0x03E6, 0x00F4);
1590 bcm43xx_core_disable(bcm, 0);
1591}
1592
1593/* Mark the current 80211 core inactive.
1594 * "active_80211_core" is the other 80211 core, which is used.
1595 */
1596static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
1597 struct bcm43xx_coreinfo *active_80211_core)
1598{
1599 u32 sbtmstatelow;
1600 struct bcm43xx_coreinfo *old_core;
1601 int err = 0;
1602
1603 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1604 bcm43xx_radio_turn_off(bcm);
1605 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1606 sbtmstatelow &= ~0x200a0000;
1607 sbtmstatelow |= 0xa0000;
1608 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1609 udelay(1);
1610 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1611 sbtmstatelow &= ~0xa0000;
1612 sbtmstatelow |= 0x80000;
1613 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1614 udelay(1);
1615
1616 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
1617 old_core = bcm->current_core;
1618 err = bcm43xx_switch_core(bcm, active_80211_core);
1619 if (err)
1620 goto out;
1621 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1622 sbtmstatelow &= ~0x20000000;
1623 sbtmstatelow |= 0x20000000;
1624 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1625 err = bcm43xx_switch_core(bcm, old_core);
1626 }
1627
1628out:
1629 return err;
1630}
1631
Michael Buesch489423c2006-02-13 00:11:07 +01001632static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001633{
1634 u32 v0, v1;
1635 u16 tmp;
1636 struct bcm43xx_xmitstatus stat;
1637
1638 assert(bcm->current_core->id == BCM43xx_COREID_80211);
1639 assert(bcm->current_core->rev >= 5);
1640
1641 while (1) {
1642 v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
1643 if (!v0)
1644 break;
1645 v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
1646
1647 stat.cookie = (v0 >> 16) & 0x0000FFFF;
1648 tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1));
1649 stat.flags = tmp & 0xFF;
1650 stat.cnt1 = (tmp & 0x0F00) >> 8;
1651 stat.cnt2 = (tmp & 0xF000) >> 12;
1652 stat.seq = (u16)(v1 & 0xFFFF);
1653 stat.unknown = (u16)((v1 >> 16) & 0xFF);
1654
1655 bcm43xx_debugfs_log_txstat(bcm, &stat);
1656
1657 if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE)
1658 continue;
1659 if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) {
1660 //TODO: packet was not acked (was lost)
1661 }
1662 //TODO: There are more (unknown) flags to test. see bcm43xx_main.h
1663
Michael Buesch77db31e2006-02-12 16:47:44 +01001664 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001665 bcm43xx_pio_handle_xmitstatus(bcm, &stat);
1666 else
1667 bcm43xx_dma_handle_xmitstatus(bcm, &stat);
1668 }
1669}
1670
Michael Buesch489423c2006-02-13 00:11:07 +01001671static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001672{
1673 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
1674 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F);
1675 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1676 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4));
1677 assert(bcm->noisecalc.core_at_start == bcm->current_core);
1678 assert(bcm->noisecalc.channel_at_start == bcm->current_core->radio->channel);
1679}
1680
1681static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm)
1682{
1683 /* Top half of Link Quality calculation. */
1684
1685 if (bcm->noisecalc.calculation_running)
1686 return;
1687 bcm->noisecalc.core_at_start = bcm->current_core;
1688 bcm->noisecalc.channel_at_start = bcm->current_core->radio->channel;
1689 bcm->noisecalc.calculation_running = 1;
1690 bcm->noisecalc.nr_samples = 0;
1691
1692 bcm43xx_generate_noise_sample(bcm);
1693}
1694
Michael Buesch489423c2006-02-13 00:11:07 +01001695static void handle_irq_noise(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001696{
1697 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1698 u16 tmp;
1699 u8 noise[4];
1700 u8 i, j;
1701 s32 average;
1702
1703 /* Bottom half of Link Quality calculation. */
1704
1705 assert(bcm->noisecalc.calculation_running);
1706 if (bcm->noisecalc.core_at_start != bcm->current_core ||
1707 bcm->noisecalc.channel_at_start != radio->channel)
1708 goto drop_calculation;
1709 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);
1710 noise[0] = (tmp & 0x00FF);
1711 noise[1] = (tmp & 0xFF00) >> 8;
1712 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A);
1713 noise[2] = (tmp & 0x00FF);
1714 noise[3] = (tmp & 0xFF00) >> 8;
1715 if (noise[0] == 0x7F || noise[1] == 0x7F ||
1716 noise[2] == 0x7F || noise[3] == 0x7F)
1717 goto generate_new;
1718
1719 /* Get the noise samples. */
1720 assert(bcm->noisecalc.nr_samples <= 8);
1721 i = bcm->noisecalc.nr_samples;
1722 noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1723 noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1724 noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1725 noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1726 bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]];
1727 bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]];
1728 bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]];
1729 bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]];
1730 bcm->noisecalc.nr_samples++;
1731 if (bcm->noisecalc.nr_samples == 8) {
1732 /* Calculate the Link Quality by the noise samples. */
1733 average = 0;
1734 for (i = 0; i < 8; i++) {
1735 for (j = 0; j < 4; j++)
1736 average += bcm->noisecalc.samples[i][j];
1737 }
1738 average /= (8 * 4);
1739 average *= 125;
1740 average += 64;
1741 average /= 128;
1742 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
1743 tmp = (tmp / 128) & 0x1F;
1744 if (tmp >= 8)
1745 average += 2;
1746 else
1747 average -= 25;
1748 if (tmp == 8)
1749 average -= 72;
1750 else
1751 average -= 48;
1752
1753 if (average > -65)
1754 bcm->stats.link_quality = 0;
1755 else if (average > -75)
1756 bcm->stats.link_quality = 1;
1757 else if (average > -85)
1758 bcm->stats.link_quality = 2;
1759 else
1760 bcm->stats.link_quality = 3;
1761// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
1762drop_calculation:
1763 bcm->noisecalc.calculation_running = 0;
1764 return;
1765 }
1766generate_new:
1767 bcm43xx_generate_noise_sample(bcm);
1768}
1769
Michael Buesch489423c2006-02-13 00:11:07 +01001770static void handle_irq_ps(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001771{
1772 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
1773 ///TODO: PS TBTT
1774 } else {
1775 if (1/*FIXME: the last PSpoll frame was sent successfully */)
1776 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
1777 }
1778 if (bcm->ieee->iw_mode == IW_MODE_ADHOC)
1779 bcm->reg124_set_0x4 = 1;
1780 //FIXME else set to false?
1781}
1782
Michael Buesch489423c2006-02-13 00:11:07 +01001783static void handle_irq_reg124(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001784{
1785 if (!bcm->reg124_set_0x4)
1786 return;
1787 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1788 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD)
1789 | 0x4);
1790 //FIXME: reset reg124_set_0x4 to false?
1791}
1792
Michael Buesch489423c2006-02-13 00:11:07 +01001793static void handle_irq_pmq(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001794{
1795 u32 tmp;
1796
1797 //TODO: AP mode.
1798
1799 while (1) {
1800 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS);
1801 if (!(tmp & 0x00000008))
1802 break;
1803 }
1804 /* 16bit write is odd, but correct. */
1805 bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);
1806}
1807
1808static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm,
1809 u16 ram_offset, u16 shm_size_offset)
1810{
1811 u32 value;
1812 u16 size = 0;
1813
1814 /* Timestamp. */
1815 //FIXME: assumption: The chip sets the timestamp
1816 value = 0;
1817 bcm43xx_ram_write(bcm, ram_offset++, value);
1818 bcm43xx_ram_write(bcm, ram_offset++, value);
1819 size += 8;
1820
1821 /* Beacon Interval / Capability Information */
1822 value = 0x0000;//FIXME: Which interval?
1823 value |= (1 << 0) << 16; /* ESS */
1824 value |= (1 << 2) << 16; /* CF Pollable */ //FIXME?
1825 value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME?
1826 if (!bcm->ieee->open_wep)
1827 value |= (1 << 4) << 16; /* Privacy */
1828 bcm43xx_ram_write(bcm, ram_offset++, value);
1829 size += 4;
1830
1831 /* SSID */
1832 //TODO
1833
1834 /* FH Parameter Set */
1835 //TODO
1836
1837 /* DS Parameter Set */
1838 //TODO
1839
1840 /* CF Parameter Set */
1841 //TODO
1842
1843 /* TIM */
1844 //TODO
1845
1846 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);
1847}
1848
Michael Buesch489423c2006-02-13 00:11:07 +01001849static void handle_irq_beacon(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001850{
1851 u32 status;
1852
1853 bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
1854 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
1855
1856 if ((status & 0x1) && (status & 0x2)) {
1857 /* ACK beacon IRQ. */
1858 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
1859 BCM43xx_IRQ_BEACON);
1860 bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;
1861 return;
1862 }
1863 if (!(status & 0x1)) {
1864 bcm43xx_generate_beacon_template(bcm, 0x68, 0x18);
1865 status |= 0x1;
1866 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1867 }
1868 if (!(status & 0x2)) {
1869 bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A);
1870 status |= 0x2;
1871 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1872 }
1873}
1874
1875/* Debug helper for irq bottom-half to print all reason registers. */
1876#define bcmirq_print_reasons(description) \
1877 do { \
1878 dprintkl(KERN_ERR PFX description "\n" \
1879 KERN_ERR PFX " Generic Reason: 0x%08x\n" \
1880 KERN_ERR PFX " DMA reasons: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n" \
1881 KERN_ERR PFX " DMA TX status: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", \
1882 reason, \
1883 dma_reason[0], dma_reason[1], \
1884 dma_reason[2], dma_reason[3], \
1885 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_BASE + BCM43xx_DMA_TX_STATUS), \
1886 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_BASE + BCM43xx_DMA_TX_STATUS), \
1887 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_BASE + BCM43xx_DMA_TX_STATUS), \
1888 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_BASE + BCM43xx_DMA_TX_STATUS)); \
1889 } while (0)
1890
1891/* Interrupt handler bottom-half */
1892static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
1893{
1894 u32 reason;
1895 u32 dma_reason[4];
1896 int activity = 0;
1897 unsigned long flags;
1898
1899#ifdef CONFIG_BCM43XX_DEBUG
1900 u32 _handled = 0x00000000;
1901# define bcmirq_handled(irq) do { _handled |= (irq); } while (0)
1902#else
1903# define bcmirq_handled(irq) do { /* nothing */ } while (0)
1904#endif /* CONFIG_BCM43XX_DEBUG*/
1905
1906 spin_lock_irqsave(&bcm->lock, flags);
1907 reason = bcm->irq_reason;
1908 dma_reason[0] = bcm->dma_reason[0];
1909 dma_reason[1] = bcm->dma_reason[1];
1910 dma_reason[2] = bcm->dma_reason[2];
1911 dma_reason[3] = bcm->dma_reason[3];
1912
1913 if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
1914 /* TX error. We get this when Template Ram is written in wrong endianess
1915 * in dummy_tx(). We also get this if something is wrong with the TX header
1916 * on DMA or PIO queues.
1917 * Maybe we get this in other error conditions, too.
1918 */
1919 bcmirq_print_reasons("XMIT ERROR");
1920 bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
1921 }
1922
1923 if (reason & BCM43xx_IRQ_PS) {
1924 handle_irq_ps(bcm);
1925 bcmirq_handled(BCM43xx_IRQ_PS);
1926 }
1927
1928 if (reason & BCM43xx_IRQ_REG124) {
1929 handle_irq_reg124(bcm);
1930 bcmirq_handled(BCM43xx_IRQ_REG124);
1931 }
1932
1933 if (reason & BCM43xx_IRQ_BEACON) {
1934 if (bcm->ieee->iw_mode == IW_MODE_MASTER)
1935 handle_irq_beacon(bcm);
1936 bcmirq_handled(BCM43xx_IRQ_BEACON);
1937 }
1938
1939 if (reason & BCM43xx_IRQ_PMQ) {
1940 handle_irq_pmq(bcm);
1941 bcmirq_handled(BCM43xx_IRQ_PMQ);
1942 }
1943
1944 if (reason & BCM43xx_IRQ_SCAN) {
1945 /*TODO*/
1946 //bcmirq_handled(BCM43xx_IRQ_SCAN);
1947 }
1948
1949 if (reason & BCM43xx_IRQ_NOISE) {
1950 handle_irq_noise(bcm);
1951 bcmirq_handled(BCM43xx_IRQ_NOISE);
1952 }
1953
1954 /* Check the DMA reason registers for received data. */
1955 assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
1956 assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
1957 if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
Michael Buesch77db31e2006-02-12 16:47:44 +01001958 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001959 bcm43xx_pio_rx(bcm->current_core->pio->queue0);
1960 else
1961 bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0);
Michael Bueschdcfd7202006-02-12 20:25:55 +01001962 /* We intentionally don't set "activity" to 1, here. */
John W. Linvillef2223132006-01-23 16:59:58 -05001963 }
1964 if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
1965 if (likely(bcm->current_core->rev < 5)) {
Michael Buesch77db31e2006-02-12 16:47:44 +01001966 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001967 bcm43xx_pio_rx(bcm->current_core->pio->queue3);
1968 else
1969 bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1);
1970 activity = 1;
1971 } else
1972 assert(0);
1973 }
1974 bcmirq_handled(BCM43xx_IRQ_RX);
1975
1976 if (reason & BCM43xx_IRQ_XMIT_STATUS) {
1977 if (bcm->current_core->rev >= 5) {
1978 handle_irq_transmit_status(bcm);
1979 activity = 1;
1980 }
1981 //TODO: In AP mode, this also causes sending of powersave responses.
1982 bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
1983 }
1984
1985 /* We get spurious IRQs, althought they are masked.
1986 * Assume they are void and ignore them.
1987 */
1988 bcmirq_handled(~(bcm->irq_savedstate));
1989 /* IRQ_PIO_WORKAROUND is handled in the top-half. */
1990 bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);
1991#ifdef CONFIG_BCM43XX_DEBUG
1992 if (unlikely(reason & ~_handled)) {
1993 printkl(KERN_WARNING PFX
1994 "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, "
1995 "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1996 reason, (reason & ~_handled),
1997 dma_reason[0], dma_reason[1],
1998 dma_reason[2], dma_reason[3]);
1999 }
2000#endif
2001#undef bcmirq_handled
2002
2003 if (!modparam_noleds)
2004 bcm43xx_leds_update(bcm, activity);
2005 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
2006 spin_unlock_irqrestore(&bcm->lock, flags);
2007}
2008
2009#undef bcmirq_print_reasons
2010
Michael Buesch489423c2006-02-13 00:11:07 +01002011static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm,
2012 u32 reason, u32 mask)
John W. Linvillef2223132006-01-23 16:59:58 -05002013{
2014 bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
2015 & 0x0001dc00;
2016 bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
2017 & 0x0000dc00;
2018 bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
2019 & 0x0000dc00;
2020 bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
2021 & 0x0001dc00;
2022
Michael Buesch77db31e2006-02-12 16:47:44 +01002023 if (bcm43xx_using_pio(bcm) &&
John W. Linvillef2223132006-01-23 16:59:58 -05002024 (bcm->current_core->rev < 3) &&
2025 (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
2026 /* Apply a PIO specific workaround to the dma_reasons */
2027
2028#define apply_pio_workaround(BASE, QNUM) \
2029 do { \
2030 if (bcm43xx_read16(bcm, BASE + BCM43xx_PIO_RXCTL) & BCM43xx_PIO_RXCTL_DATAAVAILABLE) \
2031 bcm->dma_reason[QNUM] |= 0x00010000; \
2032 else \
2033 bcm->dma_reason[QNUM] &= ~0x00010000; \
2034 } while (0)
2035
2036 apply_pio_workaround(BCM43xx_MMIO_PIO1_BASE, 0);
2037 apply_pio_workaround(BCM43xx_MMIO_PIO2_BASE, 1);
2038 apply_pio_workaround(BCM43xx_MMIO_PIO3_BASE, 2);
2039 apply_pio_workaround(BCM43xx_MMIO_PIO4_BASE, 3);
2040
2041#undef apply_pio_workaround
2042 }
2043
2044 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
2045 reason & mask);
2046
2047 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
2048 bcm->dma_reason[0]);
2049 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
2050 bcm->dma_reason[1]);
2051 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
2052 bcm->dma_reason[2]);
2053 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
2054 bcm->dma_reason[3]);
2055}
2056
2057/* Interrupt handler top-half */
2058static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
2059{
2060 struct bcm43xx_private *bcm = dev_id;
2061 u32 reason, mask;
2062
2063 if (!bcm)
2064 return IRQ_NONE;
2065
2066 spin_lock(&bcm->lock);
2067
2068 reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2069 if (reason == 0xffffffff) {
2070 /* irq not for us (shared irq) */
2071 spin_unlock(&bcm->lock);
2072 return IRQ_NONE;
2073 }
2074 mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
2075 if (!(reason & mask)) {
2076 spin_unlock(&bcm->lock);
2077 return IRQ_HANDLED;
2078 }
2079
2080 bcm43xx_interrupt_ack(bcm, reason, mask);
2081
Michael Bueschbf7b8762006-02-21 17:58:18 +01002082 /* Only accept IRQs, if we are initialized properly.
2083 * This avoids an RX race while initializing.
2084 * We should probably not enable IRQs before we are initialized
2085 * completely, but some careful work is needed to fix this. I think it
2086 * is best to stay with this cheap workaround for now... .
2087 */
2088 if (likely(bcm->initialized)) {
2089 /* disable all IRQs. They are enabled again in the bottom half. */
2090 bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
2091 /* save the reason code and call our bottom half. */
2092 bcm->irq_reason = reason;
2093 tasklet_schedule(&bcm->isr_tasklet);
2094 }
John W. Linvillef2223132006-01-23 16:59:58 -05002095
2096 spin_unlock(&bcm->lock);
2097
2098 return IRQ_HANDLED;
2099}
2100
Michael Buescha4a600d2006-02-01 22:09:52 +01002101static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
John W. Linvillef2223132006-01-23 16:59:58 -05002102{
Michael Buescha4a600d2006-02-01 22:09:52 +01002103 if (bcm->firmware_norelease && !force)
John W. Linvillef2223132006-01-23 16:59:58 -05002104 return; /* Suspending or controller reset. */
2105 release_firmware(bcm->ucode);
2106 bcm->ucode = NULL;
2107 release_firmware(bcm->pcm);
2108 bcm->pcm = NULL;
2109 release_firmware(bcm->initvals0);
2110 bcm->initvals0 = NULL;
2111 release_firmware(bcm->initvals1);
2112 bcm->initvals1 = NULL;
2113}
2114
2115static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
2116{
2117 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
2118 u8 rev = bcm->current_core->rev;
2119 int err = 0;
2120 int nr;
2121 char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
2122
2123 if (!bcm->ucode) {
2124 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
2125 (rev >= 5 ? 5 : rev),
2126 modparam_fwpostfix);
2127 err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
2128 if (err) {
2129 printk(KERN_ERR PFX
2130 "Error: Microcode \"%s\" not available or load failed.\n",
2131 buf);
2132 goto error;
2133 }
2134 }
2135
2136 if (!bcm->pcm) {
2137 snprintf(buf, ARRAY_SIZE(buf),
2138 "bcm43xx_pcm%d%s.fw",
2139 (rev < 5 ? 4 : 5),
2140 modparam_fwpostfix);
2141 err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
2142 if (err) {
2143 printk(KERN_ERR PFX
2144 "Error: PCM \"%s\" not available or load failed.\n",
2145 buf);
2146 goto error;
2147 }
2148 }
2149
2150 if (!bcm->initvals0) {
2151 if (rev == 2 || rev == 4) {
2152 switch (phy->type) {
2153 case BCM43xx_PHYTYPE_A:
2154 nr = 3;
2155 break;
2156 case BCM43xx_PHYTYPE_B:
2157 case BCM43xx_PHYTYPE_G:
2158 nr = 1;
2159 break;
2160 default:
2161 goto err_noinitval;
2162 }
2163
2164 } else if (rev >= 5) {
2165 switch (phy->type) {
2166 case BCM43xx_PHYTYPE_A:
2167 nr = 7;
2168 break;
2169 case BCM43xx_PHYTYPE_B:
2170 case BCM43xx_PHYTYPE_G:
2171 nr = 5;
2172 break;
2173 default:
2174 goto err_noinitval;
2175 }
2176 } else
2177 goto err_noinitval;
2178 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
2179 nr, modparam_fwpostfix);
2180
2181 err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
2182 if (err) {
2183 printk(KERN_ERR PFX
2184 "Error: InitVals \"%s\" not available or load failed.\n",
2185 buf);
2186 goto error;
2187 }
2188 if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
2189 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2190 goto error;
2191 }
2192 }
2193
2194 if (!bcm->initvals1) {
2195 if (rev >= 5) {
2196 u32 sbtmstatehigh;
2197
2198 switch (phy->type) {
2199 case BCM43xx_PHYTYPE_A:
2200 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
2201 if (sbtmstatehigh & 0x00010000)
2202 nr = 9;
2203 else
2204 nr = 10;
2205 break;
2206 case BCM43xx_PHYTYPE_B:
2207 case BCM43xx_PHYTYPE_G:
2208 nr = 6;
2209 break;
2210 default:
2211 goto err_noinitval;
2212 }
2213 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
2214 nr, modparam_fwpostfix);
2215
2216 err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
2217 if (err) {
2218 printk(KERN_ERR PFX
2219 "Error: InitVals \"%s\" not available or load failed.\n",
2220 buf);
2221 goto error;
2222 }
2223 if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
2224 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2225 goto error;
2226 }
2227 }
2228 }
2229
2230out:
2231 return err;
2232error:
Michael Buescha4a600d2006-02-01 22:09:52 +01002233 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002234 goto out;
2235err_noinitval:
2236 printk(KERN_ERR PFX "Error: No InitVals available!\n");
2237 err = -ENOENT;
2238 goto error;
2239}
2240
2241static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
2242{
2243 const u32 *data;
2244 unsigned int i, len;
2245
2246#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2247 bcm43xx_mmioprint_enable(bcm);
2248#else
2249 bcm43xx_mmioprint_disable(bcm);
2250#endif
2251
2252 /* Upload Microcode. */
2253 data = (u32 *)(bcm->ucode->data);
2254 len = bcm->ucode->size / sizeof(u32);
2255 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
2256 for (i = 0; i < len; i++) {
2257 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2258 be32_to_cpu(data[i]));
2259 udelay(10);
2260 }
2261
2262 /* Upload PCM data. */
2263 data = (u32 *)(bcm->pcm->data);
2264 len = bcm->pcm->size / sizeof(u32);
2265 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
2266 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
2267 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
2268 for (i = 0; i < len; i++) {
2269 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2270 be32_to_cpu(data[i]));
2271 udelay(10);
2272 }
2273
2274#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2275 bcm43xx_mmioprint_disable(bcm);
2276#else
2277 bcm43xx_mmioprint_enable(bcm);
2278#endif
2279}
2280
Michael Buescha4a600d2006-02-01 22:09:52 +01002281static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,
2282 const struct bcm43xx_initval *data,
2283 const unsigned int len)
John W. Linvillef2223132006-01-23 16:59:58 -05002284{
2285 u16 offset, size;
2286 u32 value;
2287 unsigned int i;
2288
2289 for (i = 0; i < len; i++) {
2290 offset = be16_to_cpu(data[i].offset);
2291 size = be16_to_cpu(data[i].size);
2292 value = be32_to_cpu(data[i].value);
2293
Michael Buescha4a600d2006-02-01 22:09:52 +01002294 if (unlikely(offset >= 0x1000))
2295 goto err_format;
2296 if (size == 2) {
2297 if (unlikely(value & 0xFFFF0000))
2298 goto err_format;
2299 bcm43xx_write16(bcm, offset, (u16)value);
2300 } else if (size == 4) {
John W. Linvillef2223132006-01-23 16:59:58 -05002301 bcm43xx_write32(bcm, offset, value);
Michael Buescha4a600d2006-02-01 22:09:52 +01002302 } else
2303 goto err_format;
John W. Linvillef2223132006-01-23 16:59:58 -05002304 }
Michael Buescha4a600d2006-02-01 22:09:52 +01002305
2306 return 0;
2307
2308err_format:
2309 printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. "
2310 "Please fix your bcm43xx firmware files.\n");
2311 return -EPROTO;
John W. Linvillef2223132006-01-23 16:59:58 -05002312}
2313
Michael Buescha4a600d2006-02-01 22:09:52 +01002314static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002315{
Michael Buescha4a600d2006-02-01 22:09:52 +01002316 int err;
2317
John W. Linvillef2223132006-01-23 16:59:58 -05002318#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2319 bcm43xx_mmioprint_enable(bcm);
2320#else
2321 bcm43xx_mmioprint_disable(bcm);
2322#endif
2323
Michael Buescha4a600d2006-02-01 22:09:52 +01002324 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
2325 bcm->initvals0->size / sizeof(struct bcm43xx_initval));
2326 if (err)
2327 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002328 if (bcm->initvals1) {
Michael Buescha4a600d2006-02-01 22:09:52 +01002329 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
2330 bcm->initvals1->size / sizeof(struct bcm43xx_initval));
2331 if (err)
2332 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002333 }
2334
Michael Buescha4a600d2006-02-01 22:09:52 +01002335out:
John W. Linvillef2223132006-01-23 16:59:58 -05002336#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2337 bcm43xx_mmioprint_disable(bcm);
2338#else
2339 bcm43xx_mmioprint_enable(bcm);
2340#endif
Michael Buescha4a600d2006-02-01 22:09:52 +01002341 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002342}
2343
2344static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
2345{
2346 int res;
2347 unsigned int i;
2348 u32 data;
2349
2350 bcm->irq = bcm->pci_dev->irq;
2351#ifdef CONFIG_BCM947XX
2352 if (bcm->pci_dev->bus->number == 0) {
2353 struct pci_dev *d = NULL;
2354 /* FIXME: we will probably need more device IDs here... */
2355 d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
2356 if (d != NULL) {
2357 bcm->irq = d->irq;
2358 }
2359 }
2360#endif
2361 res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
Michael Buesch65f3f192006-01-31 20:11:38 +01002362 SA_SHIRQ, KBUILD_MODNAME, bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002363 if (res) {
2364 printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
Michael Buesch489423c2006-02-13 00:11:07 +01002365 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002366 }
2367 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
2368 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
2369 i = 0;
2370 while (1) {
2371 data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2372 if (data == BCM43xx_IRQ_READY)
2373 break;
2374 i++;
2375 if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
2376 printk(KERN_ERR PFX "Card IRQ register not responding. "
2377 "Giving up.\n");
2378 free_irq(bcm->irq, bcm);
2379 return -ENODEV;
2380 }
2381 udelay(10);
2382 }
2383 // dummy read
2384 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2385
2386 return 0;
2387}
2388
2389/* Switch to the core used to write the GPIO register.
2390 * This is either the ChipCommon, or the PCI core.
2391 */
Michael Buesch489423c2006-02-13 00:11:07 +01002392static int switch_to_gpio_core(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002393{
2394 int err;
2395
2396 /* Where to find the GPIO register depends on the chipset.
2397 * If it has a ChipCommon, its register at offset 0x6c is the GPIO
2398 * control register. Otherwise the register at offset 0x6c in the
2399 * PCI core is the GPIO control register.
2400 */
2401 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
2402 if (err == -ENODEV) {
2403 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
Michael Buesch489423c2006-02-13 00:11:07 +01002404 if (unlikely(err == -ENODEV)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002405 printk(KERN_ERR PFX "gpio error: "
2406 "Neither ChipCommon nor PCI core available!\n");
2407 return -ENODEV;
Michael Buesch489423c2006-02-13 00:11:07 +01002408 } else if (unlikely(err != 0))
John W. Linvillef2223132006-01-23 16:59:58 -05002409 return -ENODEV;
Michael Buesch489423c2006-02-13 00:11:07 +01002410 } else if (unlikely(err != 0))
John W. Linvillef2223132006-01-23 16:59:58 -05002411 return -ENODEV;
2412
2413 return 0;
2414}
2415
2416/* Initialize the GPIOs
2417 * http://bcm-specs.sipsolutions.net/GPIO
2418 */
2419static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
2420{
2421 struct bcm43xx_coreinfo *old_core;
2422 int err;
2423 u32 mask, value;
2424
2425 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2426 value &= ~0xc000;
2427 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
2428
2429 mask = 0x0000001F;
2430 value = 0x0000000F;
2431 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL,
2432 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0);
2433 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2434 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
2435
2436 old_core = bcm->current_core;
2437
2438 err = switch_to_gpio_core(bcm);
2439 if (err)
2440 return err;
2441
2442 if (bcm->current_core->rev >= 2){
2443 mask |= 0x10;
2444 value |= 0x10;
2445 }
2446 if (bcm->chip_id == 0x4301) {
2447 mask |= 0x60;
2448 value |= 0x60;
2449 }
2450 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
2451 mask |= 0x200;
2452 value |= 0x200;
2453 }
2454
2455 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
2456 (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value);
2457
2458 err = bcm43xx_switch_core(bcm, old_core);
2459 assert(err == 0);
2460
2461 return 0;
2462}
2463
2464/* Turn off all GPIO stuff. Call this on module unload, for example. */
2465static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
2466{
2467 struct bcm43xx_coreinfo *old_core;
2468 int err;
2469
2470 old_core = bcm->current_core;
2471 err = switch_to_gpio_core(bcm);
2472 if (err)
2473 return err;
2474 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);
2475 err = bcm43xx_switch_core(bcm, old_core);
2476 assert(err == 0);
2477
2478 return 0;
2479}
2480
2481/* http://bcm-specs.sipsolutions.net/EnableMac */
2482void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
2483{
2484 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2485 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2486 | BCM43xx_SBF_MAC_ENABLED);
2487 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
2488 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
2489 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2490 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
2491}
2492
2493/* http://bcm-specs.sipsolutions.net/SuspendMAC */
2494void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
2495{
2496 int i;
2497 u32 tmp;
2498
2499 bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
2500 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2501 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2502 & ~BCM43xx_SBF_MAC_ENABLED);
2503 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
Michael Buesch921e4852006-02-08 17:55:55 +01002504 for (i = 100000; i; i--) {
John W. Linvillef2223132006-01-23 16:59:58 -05002505 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch921e4852006-02-08 17:55:55 +01002506 if (tmp & BCM43xx_IRQ_READY)
2507 return;
John W. Linvillef2223132006-01-23 16:59:58 -05002508 udelay(10);
2509 }
Michael Buesch921e4852006-02-08 17:55:55 +01002510 printkl(KERN_ERR PFX "MAC suspend failed\n");
John W. Linvillef2223132006-01-23 16:59:58 -05002511}
2512
2513void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
2514 int iw_mode)
2515{
2516 unsigned long flags;
2517 u32 status;
2518
2519 spin_lock_irqsave(&bcm->ieee->lock, flags);
2520 bcm->ieee->iw_mode = iw_mode;
2521 spin_unlock_irqrestore(&bcm->ieee->lock, flags);
2522 if (iw_mode == IW_MODE_MONITOR)
2523 bcm->net_dev->type = ARPHRD_IEEE80211;
2524 else
2525 bcm->net_dev->type = ARPHRD_ETHER;
2526
2527 if (!bcm->initialized)
2528 return;
2529
2530 bcm43xx_mac_suspend(bcm);
2531 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2532 /* Reset status to infrastructured mode */
2533 status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
2534 /*FIXME: We actually set promiscuous mode as well, until we don't
2535 * get the HW mac filter working */
2536 status |= BCM43xx_SBF_MODE_NOTADHOC | BCM43xx_SBF_MODE_PROMISC;
2537
2538 switch (iw_mode) {
2539 case IW_MODE_MONITOR:
2540 status |= (BCM43xx_SBF_MODE_PROMISC |
2541 BCM43xx_SBF_MODE_MONITOR);
2542 break;
2543 case IW_MODE_ADHOC:
2544 status &= ~BCM43xx_SBF_MODE_NOTADHOC;
2545 break;
2546 case IW_MODE_MASTER:
2547 case IW_MODE_SECOND:
2548 case IW_MODE_REPEAT:
2549 /* TODO: No AP/Repeater mode for now :-/ */
2550 TODO();
2551 break;
2552 case IW_MODE_INFRA:
2553 /* nothing to be done here... */
2554 break;
2555 default:
2556 printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode);
2557 }
2558
2559 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
2560 bcm43xx_mac_enable(bcm);
2561}
2562
2563/* This is the opposite of bcm43xx_chip_init() */
2564static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
2565{
2566 bcm43xx_radio_turn_off(bcm);
2567 if (!modparam_noleds)
2568 bcm43xx_leds_exit(bcm);
2569 bcm43xx_gpio_cleanup(bcm);
2570 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002571 bcm43xx_release_firmware(bcm, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05002572}
2573
2574/* Initialize the chip
2575 * http://bcm-specs.sipsolutions.net/ChipInit
2576 */
2577static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
2578{
2579 int err;
2580 int iw_mode = bcm->ieee->iw_mode;
2581 int tmp;
2582 u32 value32;
2583 u16 value16;
2584
2585 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2586 BCM43xx_SBF_CORE_READY
2587 | BCM43xx_SBF_400);
2588
2589 err = bcm43xx_request_firmware(bcm);
2590 if (err)
2591 goto out;
2592 bcm43xx_upload_microcode(bcm);
2593
2594 err = bcm43xx_initialize_irq(bcm);
2595 if (err)
Michael Buescha4a600d2006-02-01 22:09:52 +01002596 goto err_release_fw;
John W. Linvillef2223132006-01-23 16:59:58 -05002597
2598 err = bcm43xx_gpio_init(bcm);
2599 if (err)
2600 goto err_free_irq;
2601
Michael Buescha4a600d2006-02-01 22:09:52 +01002602 err = bcm43xx_upload_initvals(bcm);
2603 if (err)
2604 goto err_gpio_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002605 bcm43xx_radio_turn_on(bcm);
2606
2607 if (modparam_noleds)
2608 bcm43xx_leds_turn_off(bcm);
2609 else
2610 bcm43xx_leds_update(bcm, 0);
2611
2612 bcm43xx_write16(bcm, 0x03E6, 0x0000);
2613 err = bcm43xx_phy_init(bcm);
2614 if (err)
2615 goto err_radio_off;
2616
2617 /* Select initial Interference Mitigation. */
2618 tmp = bcm->current_core->radio->interfmode;
2619 bcm->current_core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
2620 bcm43xx_radio_set_interference_mitigation(bcm, tmp);
2621
2622 bcm43xx_phy_set_antenna_diversity(bcm);
2623 bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT);
2624 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) {
2625 value16 = bcm43xx_read16(bcm, 0x005E);
2626 value16 |= 0x0004;
2627 bcm43xx_write16(bcm, 0x005E, value16);
2628 }
2629 bcm43xx_write32(bcm, 0x0100, 0x01000000);
2630 if (bcm->current_core->rev < 5)
2631 bcm43xx_write32(bcm, 0x010C, 0x01000000);
2632
2633 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2634 value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC;
2635 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2636 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2637 value32 |= BCM43xx_SBF_MODE_NOTADHOC;
2638 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2639 /*FIXME: For now, use promiscuous mode at all times; otherwise we don't
2640 get broadcast or multicast packets */
2641 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2642 value32 |= BCM43xx_SBF_MODE_PROMISC;
2643 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2644
2645 if (iw_mode == IW_MODE_MONITOR) {
2646 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2647 value32 |= BCM43xx_SBF_MODE_PROMISC;
2648 value32 |= BCM43xx_SBF_MODE_MONITOR;
2649 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2650 }
2651 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2652 value32 |= 0x100000; //FIXME: What's this? Is this correct?
2653 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2654
Michael Buesch77db31e2006-02-12 16:47:44 +01002655 if (bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002656 bcm43xx_write32(bcm, 0x0210, 0x00000100);
2657 bcm43xx_write32(bcm, 0x0230, 0x00000100);
2658 bcm43xx_write32(bcm, 0x0250, 0x00000100);
2659 bcm43xx_write32(bcm, 0x0270, 0x00000100);
2660 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000);
2661 }
2662
2663 /* Probe Response Timeout value */
2664 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2665 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
2666
2667 if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
2668 if ((bcm->chip_id == 0x4306) && (bcm->chip_rev == 3))
2669 bcm43xx_write16(bcm, 0x0612, 0x0064);
2670 else
2671 bcm43xx_write16(bcm, 0x0612, 0x0032);
2672 } else
2673 bcm43xx_write16(bcm, 0x0612, 0x0002);
2674
2675 if (bcm->current_core->rev < 3) {
2676 bcm43xx_write16(bcm, 0x060E, 0x0000);
2677 bcm43xx_write16(bcm, 0x0610, 0x8000);
2678 bcm43xx_write16(bcm, 0x0604, 0x0000);
2679 bcm43xx_write16(bcm, 0x0606, 0x0200);
2680 } else {
2681 bcm43xx_write32(bcm, 0x0188, 0x80000000);
2682 bcm43xx_write32(bcm, 0x018C, 0x02000000);
2683 }
2684 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
2685 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
2686 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2687 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
2688 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
2689
2690 value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
2691 value32 |= 0x00100000;
2692 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
2693
2694 bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
2695
2696 assert(err == 0);
2697 dprintk(KERN_INFO PFX "Chip initialized\n");
2698out:
2699 return err;
2700
2701err_radio_off:
2702 bcm43xx_radio_turn_off(bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002703err_gpio_cleanup:
John W. Linvillef2223132006-01-23 16:59:58 -05002704 bcm43xx_gpio_cleanup(bcm);
2705err_free_irq:
2706 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002707err_release_fw:
2708 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002709 goto out;
2710}
2711
2712/* Validate chip access
2713 * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
2714static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
2715{
John W. Linvillef2223132006-01-23 16:59:58 -05002716 u32 value;
2717 u32 shm_backup;
2718
2719 shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000);
2720 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA);
Michael Buesch489423c2006-02-13 00:11:07 +01002721 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA)
2722 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002723 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
Michael Buesch489423c2006-02-13 00:11:07 +01002724 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55)
2725 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002726 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup);
2727
2728 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
Michael Buesch489423c2006-02-13 00:11:07 +01002729 if ((value | 0x80000000) != 0x80000400)
2730 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002731
2732 value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch489423c2006-02-13 00:11:07 +01002733 if (value != 0x00000000)
2734 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002735
Michael Buesch489423c2006-02-13 00:11:07 +01002736 return 0;
2737error:
2738 printk(KERN_ERR PFX "Failed to validate the chipaccess\n");
2739 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002740}
2741
2742static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
2743{
2744 int err, i;
2745 int current_core;
2746 u32 core_vendor, core_id, core_rev;
2747 u32 sb_id_hi, chip_id_32 = 0;
2748 u16 pci_device, chip_id_16;
2749 u8 core_count;
2750
2751 memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo));
2752 memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo));
2753 memset(&bcm->core_v90, 0, sizeof(struct bcm43xx_coreinfo));
2754 memset(&bcm->core_pcmcia, 0, sizeof(struct bcm43xx_coreinfo));
2755 memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo)
2756 * BCM43xx_MAX_80211_CORES);
2757
2758 memset(&bcm->phy, 0, sizeof(struct bcm43xx_phyinfo)
2759 * BCM43xx_MAX_80211_CORES);
2760 memset(&bcm->radio, 0, sizeof(struct bcm43xx_radioinfo)
2761 * BCM43xx_MAX_80211_CORES);
2762
2763 /* map core 0 */
2764 err = _switch_core(bcm, 0);
2765 if (err)
2766 goto out;
2767
2768 /* fetch sb_id_hi from core information registers */
2769 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2770
2771 core_id = (sb_id_hi & 0xFFF0) >> 4;
2772 core_rev = (sb_id_hi & 0xF);
2773 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2774
2775 /* if present, chipcommon is always core 0; read the chipid from it */
2776 if (core_id == BCM43xx_COREID_CHIPCOMMON) {
2777 chip_id_32 = bcm43xx_read32(bcm, 0);
2778 chip_id_16 = chip_id_32 & 0xFFFF;
2779 bcm->core_chipcommon.flags |= BCM43xx_COREFLAG_AVAILABLE;
2780 bcm->core_chipcommon.id = core_id;
2781 bcm->core_chipcommon.rev = core_rev;
2782 bcm->core_chipcommon.index = 0;
2783 /* While we are at it, also read the capabilities. */
2784 bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES);
2785 } else {
2786 /* without a chipCommon, use a hard coded table. */
2787 pci_device = bcm->pci_dev->device;
2788 if (pci_device == 0x4301)
2789 chip_id_16 = 0x4301;
2790 else if ((pci_device >= 0x4305) && (pci_device <= 0x4307))
2791 chip_id_16 = 0x4307;
2792 else if ((pci_device >= 0x4402) && (pci_device <= 0x4403))
2793 chip_id_16 = 0x4402;
2794 else if ((pci_device >= 0x4610) && (pci_device <= 0x4615))
2795 chip_id_16 = 0x4610;
2796 else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
2797 chip_id_16 = 0x4710;
2798#ifdef CONFIG_BCM947XX
2799 else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
2800 chip_id_16 = 0x4309;
2801#endif
2802 else {
2803 printk(KERN_ERR PFX "Could not determine Chip ID\n");
2804 return -ENODEV;
2805 }
2806 }
2807
2808 /* ChipCommon with Core Rev >=4 encodes number of cores,
2809 * otherwise consult hardcoded table */
2810 if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) {
2811 core_count = (chip_id_32 & 0x0F000000) >> 24;
2812 } else {
2813 switch (chip_id_16) {
2814 case 0x4610:
2815 case 0x4704:
2816 case 0x4710:
2817 core_count = 9;
2818 break;
2819 case 0x4310:
2820 core_count = 8;
2821 break;
2822 case 0x5365:
2823 core_count = 7;
2824 break;
2825 case 0x4306:
2826 core_count = 6;
2827 break;
2828 case 0x4301:
2829 case 0x4307:
2830 core_count = 5;
2831 break;
2832 case 0x4402:
2833 core_count = 3;
2834 break;
2835 default:
2836 /* SOL if we get here */
2837 assert(0);
2838 core_count = 1;
2839 }
2840 }
2841
2842 bcm->chip_id = chip_id_16;
2843 bcm->chip_rev = (chip_id_32 & 0x000f0000) >> 16;
2844
2845 dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
2846 bcm->chip_id, bcm->chip_rev);
2847 dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
2848 if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) {
2849 dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2850 core_id, core_rev, core_vendor,
2851 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
2852 }
2853
2854 if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE)
2855 current_core = 1;
2856 else
2857 current_core = 0;
2858 for ( ; current_core < core_count; current_core++) {
2859 struct bcm43xx_coreinfo *core;
2860
2861 err = _switch_core(bcm, current_core);
2862 if (err)
2863 goto out;
2864 /* Gather information */
2865 /* fetch sb_id_hi from core information registers */
2866 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2867
2868 /* extract core_id, core_rev, core_vendor */
2869 core_id = (sb_id_hi & 0xFFF0) >> 4;
2870 core_rev = (sb_id_hi & 0xF);
2871 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2872
2873 dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2874 current_core, core_id, core_rev, core_vendor,
2875 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
2876
2877 core = NULL;
2878 switch (core_id) {
2879 case BCM43xx_COREID_PCI:
2880 core = &bcm->core_pci;
2881 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2882 printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
2883 continue;
2884 }
2885 break;
2886 case BCM43xx_COREID_V90:
2887 core = &bcm->core_v90;
2888 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2889 printk(KERN_WARNING PFX "Multiple V90 cores found.\n");
2890 continue;
2891 }
2892 break;
2893 case BCM43xx_COREID_PCMCIA:
2894 core = &bcm->core_pcmcia;
2895 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2896 printk(KERN_WARNING PFX "Multiple PCMCIA cores found.\n");
2897 continue;
2898 }
2899 break;
2900 case BCM43xx_COREID_ETHERNET:
2901 core = &bcm->core_ethernet;
2902 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
2903 printk(KERN_WARNING PFX "Multiple Ethernet cores found.\n");
2904 continue;
2905 }
2906 break;
2907 case BCM43xx_COREID_80211:
2908 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
2909 core = &(bcm->core_80211[i]);
2910 if (!(core->flags & BCM43xx_COREFLAG_AVAILABLE))
2911 break;
2912 core = NULL;
2913 }
2914 if (!core) {
2915 printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n",
2916 BCM43xx_MAX_80211_CORES);
2917 continue;
2918 }
2919 if (i != 0) {
2920 /* More than one 80211 core is only supported
2921 * by special chips.
2922 * There are chips with two 80211 cores, but with
2923 * dangling pins on the second core. Be careful
2924 * and ignore these cores here.
2925 */
2926 if (bcm->pci_dev->device != 0x4324) {
2927 dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
2928 continue;
2929 }
2930 }
2931 switch (core_rev) {
2932 case 2:
2933 case 4:
2934 case 5:
2935 case 6:
2936 case 7:
2937 case 9:
2938 break;
2939 default:
2940 printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
2941 core_rev);
2942 err = -ENODEV;
2943 goto out;
2944 }
2945 core->phy = &bcm->phy[i];
2946 core->phy->antenna_diversity = 0xffff;
2947 core->phy->savedpctlreg = 0xFFFF;
2948 core->phy->minlowsig[0] = 0xFFFF;
2949 core->phy->minlowsig[1] = 0xFFFF;
2950 core->phy->minlowsigpos[0] = 0;
2951 core->phy->minlowsigpos[1] = 0;
2952 spin_lock_init(&core->phy->lock);
2953 core->radio = &bcm->radio[i];
Michael Bueschab4977f2006-02-12 22:40:39 +01002954 core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
John W. Linvillef2223132006-01-23 16:59:58 -05002955 core->radio->channel = 0xFF;
2956 core->radio->initial_channel = 0xFF;
2957 core->radio->lofcal = 0xFFFF;
2958 core->radio->initval = 0xFFFF;
2959 core->radio->nrssi[0] = -1000;
2960 core->radio->nrssi[1] = -1000;
2961 core->dma = &bcm->dma[i];
2962 core->pio = &bcm->pio[i];
2963 break;
2964 case BCM43xx_COREID_CHIPCOMMON:
2965 printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
2966 break;
2967 default:
2968 printk(KERN_WARNING PFX "Unknown core found (ID 0x%x)\n", core_id);
2969 }
2970 if (core) {
2971 core->flags |= BCM43xx_COREFLAG_AVAILABLE;
2972 core->id = core_id;
2973 core->rev = core_rev;
2974 core->index = current_core;
2975 }
2976 }
2977
2978 if (!(bcm->core_80211[0].flags & BCM43xx_COREFLAG_AVAILABLE)) {
2979 printk(KERN_ERR PFX "Error: No 80211 core found!\n");
2980 err = -ENODEV;
2981 goto out;
2982 }
2983
2984 err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
2985
2986 assert(err == 0);
2987out:
2988 return err;
2989}
2990
2991static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm)
2992{
2993 const u8 *mac = (const u8*)(bcm->net_dev->dev_addr);
2994 u8 *bssid = bcm->ieee->bssid;
2995
2996 switch (bcm->ieee->iw_mode) {
2997 case IW_MODE_ADHOC:
2998 random_ether_addr(bssid);
2999 break;
3000 case IW_MODE_MASTER:
3001 case IW_MODE_INFRA:
3002 case IW_MODE_REPEAT:
3003 case IW_MODE_SECOND:
3004 case IW_MODE_MONITOR:
3005 memcpy(bssid, mac, ETH_ALEN);
3006 break;
3007 default:
3008 assert(0);
3009 }
3010}
3011
3012static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm,
3013 u16 rate,
3014 int is_ofdm)
3015{
3016 u16 offset;
3017
3018 if (is_ofdm) {
3019 offset = 0x480;
3020 offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
3021 }
3022 else {
3023 offset = 0x4C0;
3024 offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
3025 }
3026 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20,
3027 bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset));
3028}
3029
3030static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm)
3031{
3032 switch (bcm->current_core->phy->type) {
3033 case BCM43xx_PHYTYPE_A:
3034 case BCM43xx_PHYTYPE_G:
3035 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1);
3036 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1);
3037 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1);
3038 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1);
3039 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1);
3040 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1);
3041 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1);
3042 case BCM43xx_PHYTYPE_B:
3043 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0);
3044 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0);
3045 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0);
3046 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0);
3047 break;
3048 default:
3049 assert(0);
3050 }
3051}
3052
3053static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
3054{
3055 bcm43xx_chip_cleanup(bcm);
3056 bcm43xx_pio_free(bcm);
3057 bcm43xx_dma_free(bcm);
3058
3059 bcm->current_core->flags &= ~ BCM43xx_COREFLAG_INITIALIZED;
3060}
3061
3062/* http://bcm-specs.sipsolutions.net/80211Init */
3063static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
3064{
3065 u32 ucodeflags;
3066 int err;
3067 u32 sbimconfiglow;
3068 u8 limit;
3069
3070 if (bcm->chip_rev < 5) {
3071 sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
3072 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
3073 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
3074 if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
3075 sbimconfiglow |= 0x32;
3076 else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
3077 sbimconfiglow |= 0x53;
3078 else
3079 assert(0);
3080 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
3081 }
3082
3083 bcm43xx_phy_calibrate(bcm);
3084 err = bcm43xx_chip_init(bcm);
3085 if (err)
3086 goto out;
3087
3088 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
3089 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
3090
3091 if (0 /*FIXME: which condition has to be used here? */)
3092 ucodeflags |= 0x00000010;
3093
3094 /* HW decryption needs to be set now */
3095 ucodeflags |= 0x40000000;
3096
3097 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
3098 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
3099 if (bcm->current_core->phy->rev == 1)
3100 ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
3101 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
3102 ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
3103 } else if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) {
3104 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
3105 if ((bcm->current_core->phy->rev >= 2) &&
3106 (bcm->current_core->radio->version == 0x2050))
3107 ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY;
3108 }
3109
3110 if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
3111 BCM43xx_UCODEFLAGS_OFFSET)) {
3112 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
3113 BCM43xx_UCODEFLAGS_OFFSET, ucodeflags);
3114 }
3115
3116 /* Short/Long Retry Limit.
3117 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
3118 * the chip-internal counter.
3119 */
3120 limit = limit_value(modparam_short_retry, 0, 0xF);
3121 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit);
3122 limit = limit_value(modparam_long_retry, 0, 0xF);
3123 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit);
3124
3125 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3);
3126 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2);
3127
3128 bcm43xx_rate_memory_init(bcm);
3129
3130 /* Minimum Contention Window */
3131 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B)
3132 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f);
3133 else
3134 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f);
3135 /* Maximum Contention Window */
3136 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
3137
3138 bcm43xx_gen_bssid(bcm);
3139 bcm43xx_write_mac_bssid_templates(bcm);
3140
3141 if (bcm->current_core->rev >= 5)
3142 bcm43xx_write16(bcm, 0x043C, 0x000C);
3143
Michael Buesch77db31e2006-02-12 16:47:44 +01003144 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05003145 err = bcm43xx_pio_init(bcm);
Michael Buesch77db31e2006-02-12 16:47:44 +01003146 else
3147 err = bcm43xx_dma_init(bcm);
3148 if (err)
3149 goto err_chip_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05003150 bcm43xx_write16(bcm, 0x0612, 0x0050);
3151 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
3152 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
3153
3154 bcm43xx_mac_enable(bcm);
3155 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
3156
3157 bcm->current_core->flags |= BCM43xx_COREFLAG_INITIALIZED;
3158out:
3159 return err;
3160
3161err_chip_cleanup:
3162 bcm43xx_chip_cleanup(bcm);
3163 goto out;
3164}
3165
3166static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
3167{
3168 int err;
3169 u16 pci_status;
3170
3171 err = bcm43xx_pctl_set_crystal(bcm, 1);
3172 if (err)
3173 goto out;
3174 bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
3175 bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
3176
3177out:
3178 return err;
3179}
3180
3181static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm)
3182{
3183 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
3184 bcm43xx_pctl_set_crystal(bcm, 0);
3185}
3186
Michael Buesch489423c2006-02-13 00:11:07 +01003187static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
3188 u32 address,
3189 u32 data)
John W. Linvillef2223132006-01-23 16:59:58 -05003190{
3191 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address);
3192 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data);
3193}
3194
3195static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
3196{
3197 int err;
3198 struct bcm43xx_coreinfo *old_core;
3199
3200 old_core = bcm->current_core;
3201 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
3202 if (err)
3203 goto out;
3204
3205 bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
3206
3207 bcm43xx_switch_core(bcm, old_core);
3208 assert(err == 0);
3209out:
3210 return err;
3211}
3212
3213/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
3214 * To enable core 0, pass a core_mask of 1<<0
3215 */
3216static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
3217 u32 core_mask)
3218{
3219 u32 backplane_flag_nr;
3220 u32 value;
3221 struct bcm43xx_coreinfo *old_core;
3222 int err = 0;
3223
3224 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG);
3225 backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK;
3226
3227 old_core = bcm->current_core;
3228 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
3229 if (err)
3230 goto out;
3231
3232 if (bcm->core_pci.rev < 6) {
3233 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
3234 value |= (1 << backplane_flag_nr);
3235 bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
3236 } else {
3237 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value);
3238 if (err) {
3239 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3240 goto out_switch_back;
3241 }
3242 value |= core_mask << 8;
3243 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value);
3244 if (err) {
3245 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3246 goto out_switch_back;
3247 }
3248 }
3249
3250 value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
3251 value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
3252 bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
3253
3254 if (bcm->core_pci.rev < 5) {
3255 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
3256 value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
3257 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
3258 value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
3259 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
3260 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
3261 err = bcm43xx_pcicore_commit_settings(bcm);
3262 assert(err == 0);
3263 }
3264
3265out_switch_back:
3266 err = bcm43xx_switch_core(bcm, old_core);
3267out:
3268 return err;
3269}
3270
3271static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
3272{
3273 ieee80211softmac_start(bcm->net_dev);
3274}
3275
Michael Bueschab4977f2006-02-12 22:40:39 +01003276static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003277{
Michael Bueschab4977f2006-02-12 22:40:39 +01003278 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -05003279
Michael Bueschab4977f2006-02-12 22:40:39 +01003280 if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2)
3281 return;
John W. Linvillef2223132006-01-23 16:59:58 -05003282
Michael Bueschab4977f2006-02-12 22:40:39 +01003283 bcm43xx_mac_suspend(bcm);
3284 bcm43xx_phy_lo_g_measure(bcm);
3285 bcm43xx_mac_enable(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003286}
3287
Michael Bueschab4977f2006-02-12 22:40:39 +01003288static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003289{
John W. Linvillef2223132006-01-23 16:59:58 -05003290 bcm43xx_phy_lo_mark_all_unused(bcm);
3291 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3292 bcm43xx_mac_suspend(bcm);
3293 bcm43xx_calc_nrssi_slope(bcm);
3294 bcm43xx_mac_enable(bcm);
3295 }
John W. Linvillef2223132006-01-23 16:59:58 -05003296}
3297
Michael Bueschab4977f2006-02-12 22:40:39 +01003298static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003299{
John W. Linvillef2223132006-01-23 16:59:58 -05003300 /* Update device statistics. */
3301 bcm43xx_calculate_link_quality(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003302}
John W. Linvillef2223132006-01-23 16:59:58 -05003303
Michael Bueschab4977f2006-02-12 22:40:39 +01003304static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
3305{
3306 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
3307 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
3308
3309 if (phy->type == BCM43xx_PHYTYPE_G) {
3310 //TODO: update_aci_moving_average
3311 if (radio->aci_enable && radio->aci_wlan_automatic) {
3312 bcm43xx_mac_suspend(bcm);
3313 if (!radio->aci_enable && 1 /*TODO: not scanning? */) {
3314 if (0 /*TODO: bunch of conditions*/) {
3315 bcm43xx_radio_set_interference_mitigation(bcm,
3316 BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
3317 }
3318 } else if (1/*TODO*/) {
3319 /*
3320 if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) {
3321 bcm43xx_radio_set_interference_mitigation(bcm,
3322 BCM43xx_RADIO_INTERFMODE_NONE);
3323 }
3324 */
3325 }
3326 bcm43xx_mac_enable(bcm);
3327 } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN &&
3328 phy->rev == 1) {
3329 //TODO: implement rev1 workaround
3330 }
John W. Linvillef2223132006-01-23 16:59:58 -05003331 }
Michael Bueschab4977f2006-02-12 22:40:39 +01003332 bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
3333 //TODO for APHY (temperature?)
3334}
3335
3336static void bcm43xx_periodic_task_handler(unsigned long d)
3337{
3338 struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
3339 unsigned long flags;
3340 unsigned int state;
3341
3342 spin_lock_irqsave(&bcm->lock, flags);
3343
3344 assert(bcm->initialized);
3345 state = bcm->periodic_state;
3346 if (state % 8 == 0)
3347 bcm43xx_periodic_every120sec(bcm);
3348 if (state % 4 == 0)
3349 bcm43xx_periodic_every60sec(bcm);
3350 if (state % 2 == 0)
3351 bcm43xx_periodic_every30sec(bcm);
3352 bcm43xx_periodic_every15sec(bcm);
3353 bcm->periodic_state = state + 1;
3354
3355 mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
3356
John W. Linvillef2223132006-01-23 16:59:58 -05003357 spin_unlock_irqrestore(&bcm->lock, flags);
3358}
3359
John W. Linvillef2223132006-01-23 16:59:58 -05003360static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
3361{
Michael Bueschab4977f2006-02-12 22:40:39 +01003362 del_timer_sync(&bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003363}
3364
John W. Linvillef2223132006-01-23 16:59:58 -05003365static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
3366{
Michael Bueschab4977f2006-02-12 22:40:39 +01003367 struct timer_list *timer = &(bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003368
Michael Buesch1d1a73c2006-02-21 18:19:59 +01003369 assert(bcm->initialized);
Michael Bueschab4977f2006-02-12 22:40:39 +01003370 setup_timer(timer,
3371 bcm43xx_periodic_task_handler,
3372 (unsigned long)bcm);
3373 timer->expires = jiffies;
3374 add_timer(timer);
John W. Linvillef2223132006-01-23 16:59:58 -05003375}
3376
3377static void bcm43xx_security_init(struct bcm43xx_private *bcm)
3378{
3379 bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
3380 0x0056) * 2;
3381 bcm43xx_clear_keys(bcm);
3382}
3383
3384/* This is the opposite of bcm43xx_init_board() */
3385static void bcm43xx_free_board(struct bcm43xx_private *bcm)
3386{
3387 int i, err;
3388 unsigned long flags;
3389
Michael Bueschab4977f2006-02-12 22:40:39 +01003390 bcm43xx_periodic_tasks_delete(bcm);
3391
John W. Linvillef2223132006-01-23 16:59:58 -05003392 spin_lock_irqsave(&bcm->lock, flags);
3393 bcm->initialized = 0;
3394 bcm->shutting_down = 1;
3395 spin_unlock_irqrestore(&bcm->lock, flags);
3396
John W. Linvillef2223132006-01-23 16:59:58 -05003397 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3398 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE))
3399 continue;
3400 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED))
3401 continue;
3402
3403 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3404 assert(err == 0);
3405 bcm43xx_wireless_core_cleanup(bcm);
3406 }
3407
3408 bcm43xx_pctl_set_crystal(bcm, 0);
3409
3410 spin_lock_irqsave(&bcm->lock, flags);
3411 bcm->shutting_down = 0;
3412 spin_unlock_irqrestore(&bcm->lock, flags);
3413}
3414
3415static int bcm43xx_init_board(struct bcm43xx_private *bcm)
3416{
3417 int i, err;
3418 int num_80211_cores;
3419 int connect_phy;
3420 unsigned long flags;
3421
3422 might_sleep();
3423
3424 spin_lock_irqsave(&bcm->lock, flags);
3425 bcm->initialized = 0;
3426 bcm->shutting_down = 0;
3427 spin_unlock_irqrestore(&bcm->lock, flags);
3428
3429 err = bcm43xx_pctl_set_crystal(bcm, 1);
3430 if (err)
3431 goto out;
3432 err = bcm43xx_pctl_init(bcm);
3433 if (err)
3434 goto err_crystal_off;
3435 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
3436 if (err)
3437 goto err_crystal_off;
3438
3439 tasklet_enable(&bcm->isr_tasklet);
3440 num_80211_cores = bcm43xx_num_80211_cores(bcm);
3441 for (i = 0; i < num_80211_cores; i++) {
3442 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3443 assert(err != -ENODEV);
3444 if (err)
3445 goto err_80211_unwind;
3446
3447 /* Enable the selected wireless core.
3448 * Connect PHY only on the first core.
3449 */
3450 if (!bcm43xx_core_enabled(bcm)) {
3451 if (num_80211_cores == 1) {
3452 connect_phy = bcm->current_core->phy->connected;
3453 } else {
3454 if (i == 0)
3455 connect_phy = 1;
3456 else
3457 connect_phy = 0;
3458 }
3459 bcm43xx_wireless_core_reset(bcm, connect_phy);
3460 }
3461
3462 if (i != 0)
3463 bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
3464
3465 err = bcm43xx_wireless_core_init(bcm);
3466 if (err)
3467 goto err_80211_unwind;
3468
3469 if (i != 0) {
3470 bcm43xx_mac_suspend(bcm);
3471 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3472 bcm43xx_radio_turn_off(bcm);
3473 }
3474 }
3475 bcm->active_80211_core = &bcm->core_80211[0];
3476 if (num_80211_cores >= 2) {
3477 bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
3478 bcm43xx_mac_enable(bcm);
3479 }
3480 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
3481 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
3482 dprintk(KERN_INFO PFX "80211 cores initialized\n");
3483 bcm43xx_security_init(bcm);
3484 bcm43xx_softmac_init(bcm);
3485
3486 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
3487
John W. Linvillef2223132006-01-23 16:59:58 -05003488 if (bcm->current_core->radio->initial_channel != 0xFF) {
3489 bcm43xx_mac_suspend(bcm);
3490 bcm43xx_radio_selectchannel(bcm, bcm->current_core->radio->initial_channel, 0);
3491 bcm43xx_mac_enable(bcm);
3492 }
Michael Bueschcad2b312006-02-21 18:08:55 +01003493
3494 /* Initialization of the board is done. Flag it as such. */
3495 spin_lock_irqsave(&bcm->lock, flags);
3496 bcm->initialized = 1;
3497 spin_unlock_irqrestore(&bcm->lock, flags);
3498
John W. Linvillef2223132006-01-23 16:59:58 -05003499 bcm43xx_periodic_tasks_setup(bcm);
3500
3501 assert(err == 0);
3502out:
3503 return err;
3504
3505err_80211_unwind:
3506 tasklet_disable(&bcm->isr_tasklet);
3507 /* unwind all 80211 initialization */
3508 for (i = 0; i < num_80211_cores; i++) {
3509 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED))
3510 continue;
3511 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3512 bcm43xx_wireless_core_cleanup(bcm);
3513 }
3514err_crystal_off:
3515 bcm43xx_pctl_set_crystal(bcm, 0);
3516 goto out;
3517}
3518
3519static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
3520{
3521 struct pci_dev *pci_dev = bcm->pci_dev;
3522 int i;
3523
3524 bcm43xx_chipset_detach(bcm);
3525 /* Do _not_ access the chip, after it is detached. */
3526 iounmap(bcm->mmio_addr);
3527
3528 pci_release_regions(pci_dev);
3529 pci_disable_device(pci_dev);
3530
3531 /* Free allocated structures/fields */
3532 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3533 kfree(bcm->phy[i]._lo_pairs);
3534 if (bcm->phy[i].dyn_tssi_tbl)
3535 kfree(bcm->phy[i].tssi2dbm);
3536 }
3537}
3538
3539static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
3540{
Michael Buesch489423c2006-02-13 00:11:07 +01003541 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
John W. Linvillef2223132006-01-23 16:59:58 -05003542 u16 value;
3543 u8 phy_version;
3544 u8 phy_type;
3545 u8 phy_rev;
3546 int phy_rev_ok = 1;
3547 void *p;
3548
3549 value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
3550
3551 phy_version = (value & 0xF000) >> 12;
3552 phy_type = (value & 0x0F00) >> 8;
3553 phy_rev = (value & 0x000F);
3554
3555 dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
3556 phy_version, phy_type, phy_rev);
3557
3558 switch (phy_type) {
3559 case BCM43xx_PHYTYPE_A:
3560 if (phy_rev >= 4)
3561 phy_rev_ok = 0;
3562 /*FIXME: We need to switch the ieee->modulation, etc.. flags,
3563 * if we switch 80211 cores after init is done.
3564 * As we do not implement on the fly switching between
3565 * wireless cores, I will leave this as a future task.
3566 */
3567 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION;
3568 bcm->ieee->mode = IEEE_A;
3569 bcm->ieee->freq_band = IEEE80211_52GHZ_BAND |
3570 IEEE80211_24GHZ_BAND;
3571 break;
3572 case BCM43xx_PHYTYPE_B:
3573 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7)
3574 phy_rev_ok = 0;
3575 bcm->ieee->modulation = IEEE80211_CCK_MODULATION;
3576 bcm->ieee->mode = IEEE_B;
3577 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3578 break;
3579 case BCM43xx_PHYTYPE_G:
3580 if (phy_rev > 7)
3581 phy_rev_ok = 0;
3582 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
3583 IEEE80211_CCK_MODULATION;
3584 bcm->ieee->mode = IEEE_G;
3585 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3586 break;
3587 default:
3588 printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n",
3589 phy_type);
3590 return -ENODEV;
3591 };
3592 if (!phy_rev_ok) {
3593 printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
3594 phy_rev);
3595 }
3596
Michael Buesch489423c2006-02-13 00:11:07 +01003597 phy->version = phy_version;
3598 phy->type = phy_type;
3599 phy->rev = phy_rev;
John W. Linvillef2223132006-01-23 16:59:58 -05003600 if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
3601 p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT,
3602 GFP_KERNEL);
3603 if (!p)
3604 return -ENOMEM;
Michael Buesch489423c2006-02-13 00:11:07 +01003605 phy->_lo_pairs = p;
John W. Linvillef2223132006-01-23 16:59:58 -05003606 }
3607
3608 return 0;
3609}
3610
3611static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
3612{
3613 struct pci_dev *pci_dev = bcm->pci_dev;
3614 struct net_device *net_dev = bcm->net_dev;
3615 int err;
3616 int i;
3617 void __iomem *ioaddr;
3618 unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
3619 int num_80211_cores;
3620 u32 coremask;
3621
3622 err = pci_enable_device(pci_dev);
3623 if (err) {
3624 printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
3625 err = -ENODEV;
3626 goto out;
3627 }
3628
3629 mmio_start = pci_resource_start(pci_dev, 0);
3630 mmio_end = pci_resource_end(pci_dev, 0);
3631 mmio_flags = pci_resource_flags(pci_dev, 0);
3632 mmio_len = pci_resource_len(pci_dev, 0);
3633
3634 /* make sure PCI base addr is MMIO */
3635 if (!(mmio_flags & IORESOURCE_MEM)) {
3636 printk(KERN_ERR PFX
3637 "%s, region #0 not an MMIO resource, aborting\n",
3638 pci_name(pci_dev));
3639 err = -ENODEV;
3640 goto err_pci_disable;
3641 }
3642//FIXME: Why is this check disabled for BCM947XX? What is the IO_SIZE there?
3643#ifndef CONFIG_BCM947XX
3644 if (mmio_len != BCM43xx_IO_SIZE) {
3645 printk(KERN_ERR PFX
3646 "%s: invalid PCI mem region size(s), aborting\n",
3647 pci_name(pci_dev));
3648 err = -ENODEV;
3649 goto err_pci_disable;
3650 }
3651#endif
3652
Michael Buesch65f3f192006-01-31 20:11:38 +01003653 err = pci_request_regions(pci_dev, KBUILD_MODNAME);
John W. Linvillef2223132006-01-23 16:59:58 -05003654 if (err) {
3655 printk(KERN_ERR PFX
3656 "could not access PCI resources (%i)\n", err);
3657 goto err_pci_disable;
3658 }
3659
3660 /* enable PCI bus-mastering */
3661 pci_set_master(pci_dev);
3662
3663 /* ioremap MMIO region */
3664 ioaddr = ioremap(mmio_start, mmio_len);
3665 if (!ioaddr) {
3666 printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
3667 pci_name(pci_dev));
3668 err = -EIO;
3669 goto err_pci_release;
3670 }
3671
3672 net_dev->base_addr = (unsigned long)ioaddr;
3673 bcm->mmio_addr = ioaddr;
3674 bcm->mmio_len = mmio_len;
3675
3676 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
3677 &bcm->board_vendor);
3678 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
3679 &bcm->board_type);
3680 bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
3681 &bcm->board_revision);
3682
3683 err = bcm43xx_chipset_attach(bcm);
3684 if (err)
3685 goto err_iounmap;
3686 err = bcm43xx_pctl_init(bcm);
3687 if (err)
3688 goto err_chipset_detach;
3689 err = bcm43xx_probe_cores(bcm);
3690 if (err)
3691 goto err_chipset_detach;
3692
3693 num_80211_cores = bcm43xx_num_80211_cores(bcm);
3694
3695 /* Attach all IO cores to the backplane. */
3696 coremask = 0;
3697 for (i = 0; i < num_80211_cores; i++)
3698 coremask |= (1 << bcm->core_80211[i].index);
3699 //FIXME: Also attach some non80211 cores?
3700 err = bcm43xx_setup_backplane_pci_connection(bcm, coremask);
3701 if (err) {
3702 printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
3703 goto err_chipset_detach;
3704 }
3705
Michael Bueschea0922b2006-02-19 14:09:20 +01003706 err = bcm43xx_sprom_extract(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003707 if (err)
3708 goto err_chipset_detach;
3709 err = bcm43xx_leds_init(bcm);
3710 if (err)
3711 goto err_chipset_detach;
3712
3713 for (i = 0; i < num_80211_cores; i++) {
3714 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3715 assert(err != -ENODEV);
3716 if (err)
3717 goto err_80211_unwind;
3718
3719 /* Enable the selected wireless core.
3720 * Connect PHY only on the first core.
3721 */
3722 bcm43xx_wireless_core_reset(bcm, (i == 0));
3723
3724 err = bcm43xx_read_phyinfo(bcm);
3725 if (err && (i == 0))
3726 goto err_80211_unwind;
3727
3728 err = bcm43xx_read_radioinfo(bcm);
3729 if (err && (i == 0))
3730 goto err_80211_unwind;
3731
3732 err = bcm43xx_validate_chip(bcm);
3733 if (err && (i == 0))
3734 goto err_80211_unwind;
3735
3736 bcm43xx_radio_turn_off(bcm);
3737 err = bcm43xx_phy_init_tssi2dbm_table(bcm);
3738 if (err)
3739 goto err_80211_unwind;
3740 bcm43xx_wireless_core_disable(bcm);
3741 }
3742 bcm43xx_pctl_set_crystal(bcm, 0);
3743
3744 /* Set the MAC address in the networking subsystem */
3745 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
3746 memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
3747 else
3748 memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
3749
3750 bcm43xx_geo_init(bcm);
3751
3752 snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
3753 "Broadcom %04X", bcm->chip_id);
3754
3755 assert(err == 0);
3756out:
3757 return err;
3758
3759err_80211_unwind:
3760 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3761 kfree(bcm->phy[i]._lo_pairs);
3762 if (bcm->phy[i].dyn_tssi_tbl)
3763 kfree(bcm->phy[i].tssi2dbm);
3764 }
3765err_chipset_detach:
3766 bcm43xx_chipset_detach(bcm);
3767err_iounmap:
3768 iounmap(bcm->mmio_addr);
3769err_pci_release:
3770 pci_release_regions(pci_dev);
3771err_pci_disable:
3772 pci_disable_device(pci_dev);
3773 goto out;
3774}
3775
Michael Buesch489423c2006-02-13 00:11:07 +01003776static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm,
3777 u8 in_rssi, int ofdm,
3778 int adjust_2053, int adjust_2050)
John W. Linvillef2223132006-01-23 16:59:58 -05003779{
3780 s32 tmp;
3781
3782 switch (bcm->current_core->radio->version) {
3783 case 0x2050:
3784 if (ofdm) {
3785 tmp = in_rssi;
3786 if (tmp > 127)
3787 tmp -= 256;
3788 tmp *= 73;
3789 tmp /= 64;
3790 if (adjust_2050)
3791 tmp += 25;
3792 else
3793 tmp -= 3;
3794 } else {
3795 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3796 if (in_rssi > 63)
3797 in_rssi = 63;
3798 tmp = bcm->current_core->radio->nrssi_lt[in_rssi];
3799 tmp = 31 - tmp;
3800 tmp *= -131;
3801 tmp /= 128;
3802 tmp -= 57;
3803 } else {
3804 tmp = in_rssi;
3805 tmp = 31 - tmp;
3806 tmp *= -149;
3807 tmp /= 128;
3808 tmp -= 68;
3809 }
3810 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G &&
3811 adjust_2050)
3812 tmp += 25;
3813 }
3814 break;
3815 case 0x2060:
3816 if (in_rssi > 127)
3817 tmp = in_rssi - 256;
3818 else
3819 tmp = in_rssi;
3820 break;
3821 default:
3822 tmp = in_rssi;
3823 tmp -= 11;
3824 tmp *= 103;
3825 tmp /= 64;
3826 if (adjust_2053)
3827 tmp -= 109;
3828 else
3829 tmp -= 83;
3830 }
3831
3832 return (s8)tmp;
3833}
3834
Michael Buesch489423c2006-02-13 00:11:07 +01003835static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm,
3836 u8 in_rssi)
John W. Linvillef2223132006-01-23 16:59:58 -05003837{
3838 s8 ret;
3839
3840 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) {
3841 //TODO: Incomplete specs.
3842 ret = 0;
3843 } else
3844 ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1);
3845
3846 return ret;
3847}
3848
3849static inline
3850int bcm43xx_rx_packet(struct bcm43xx_private *bcm,
3851 struct sk_buff *skb,
3852 struct ieee80211_rx_stats *stats)
3853{
3854 int err;
3855
3856 err = ieee80211_rx(bcm->ieee, skb, stats);
3857 if (unlikely(err == 0))
3858 return -EINVAL;
3859 return 0;
3860}
3861
Michael Buesch489423c2006-02-13 00:11:07 +01003862int bcm43xx_rx(struct bcm43xx_private *bcm,
3863 struct sk_buff *skb,
3864 struct bcm43xx_rxhdr *rxhdr)
John W. Linvillef2223132006-01-23 16:59:58 -05003865{
3866 struct bcm43xx_plcp_hdr4 *plcp;
3867 struct ieee80211_rx_stats stats;
3868 struct ieee80211_hdr_4addr *wlhdr;
3869 u16 frame_ctl;
3870 int is_packet_for_us = 0;
3871 int err = -EINVAL;
3872 const u16 rxflags1 = le16_to_cpu(rxhdr->flags1);
3873 const u16 rxflags2 = le16_to_cpu(rxhdr->flags2);
3874 const u16 rxflags3 = le16_to_cpu(rxhdr->flags3);
3875 const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM);
3876
3877 if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) {
3878 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2);
3879 /* Skip two unknown bytes and the PLCP header. */
3880 skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6));
3881 } else {
3882 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data);
3883 /* Skip the PLCP header. */
3884 skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6));
3885 }
3886 /* The SKB contains the PAYLOAD (wireless header + data)
3887 * at this point. The FCS at the end is stripped.
3888 */
3889
3890 memset(&stats, 0, sizeof(stats));
3891 stats.mac_time = le16_to_cpu(rxhdr->mactime);
3892 stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
3893 !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
3894 !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
3895 stats.signal = rxhdr->signal_quality; //FIXME
3896//TODO stats.noise =
3897 stats.rate = bcm43xx_plcp_get_bitrate(plcp, is_ofdm);
3898//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
3899 stats.received_channel = bcm->current_core->radio->channel;
3900//TODO stats.control =
3901 stats.mask = IEEE80211_STATMASK_SIGNAL |
3902//TODO IEEE80211_STATMASK_NOISE |
3903 IEEE80211_STATMASK_RATE |
3904 IEEE80211_STATMASK_RSSI;
3905 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
3906 stats.freq = IEEE80211_52GHZ_BAND;
3907 else
3908 stats.freq = IEEE80211_24GHZ_BAND;
3909 stats.len = skb->len;
3910
3911 bcm->stats.last_rx = jiffies;
3912 if (bcm->ieee->iw_mode == IW_MODE_MONITOR)
3913 return bcm43xx_rx_packet(bcm, skb, &stats);
3914
3915 wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
3916
3917 switch (bcm->ieee->iw_mode) {
3918 case IW_MODE_ADHOC:
3919 if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
3920 memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
3921 is_broadcast_ether_addr(wlhdr->addr1) ||
3922 is_multicast_ether_addr(wlhdr->addr1) ||
3923 bcm->net_dev->flags & IFF_PROMISC)
3924 is_packet_for_us = 1;
3925 break;
3926 case IW_MODE_INFRA:
3927 default:
3928 /* When receiving multicast or broadcast packets, filter out
3929 the packets we send ourself; we shouldn't see those */
3930 if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
3931 memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
3932 (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) &&
3933 (is_broadcast_ether_addr(wlhdr->addr1) ||
3934 is_multicast_ether_addr(wlhdr->addr1) ||
3935 bcm->net_dev->flags & IFF_PROMISC)))
3936 is_packet_for_us = 1;
3937 break;
3938 }
3939
3940 frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
John W. Linvillef2223132006-01-23 16:59:58 -05003941 if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) {
3942 frame_ctl &= ~IEEE80211_FCTL_PROTECTED;
3943 wlhdr->frame_ctl = cpu_to_le16(frame_ctl);
3944 /* trim IV and ICV */
3945 /* FIXME: this must be done only for WEP encrypted packets */
3946 if (skb->len < 32) {
3947 dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag "
3948 "set and length < 32)\n");
3949 return -EINVAL;
3950 } else {
3951 memmove(skb->data + 4, skb->data, 24);
3952 skb_pull(skb, 4);
3953 skb_trim(skb, skb->len - 4);
3954 stats.len -= 8;
3955 }
Michael Bueschea72ab22006-01-27 17:26:20 +01003956 wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
John W. Linvillef2223132006-01-23 16:59:58 -05003957 }
3958
3959 switch (WLAN_FC_GET_TYPE(frame_ctl)) {
3960 case IEEE80211_FTYPE_MGMT:
Michael Bueschea72ab22006-01-27 17:26:20 +01003961 ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
John W. Linvillef2223132006-01-23 16:59:58 -05003962 break;
3963 case IEEE80211_FTYPE_DATA:
3964 if (is_packet_for_us)
3965 err = bcm43xx_rx_packet(bcm, skb, &stats);
3966 break;
3967 case IEEE80211_FTYPE_CTL:
3968 break;
3969 default:
3970 assert(0);
3971 return -EINVAL;
3972 }
3973
3974 return err;
3975}
3976
3977/* Do the Hardware IO operations to send the txb */
3978static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
3979 struct ieee80211_txb *txb)
3980{
3981 int err = -ENODEV;
3982
Michael Buesch77db31e2006-02-12 16:47:44 +01003983 if (bcm43xx_using_pio(bcm))
3984 err = bcm43xx_pio_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003985 else
Michael Bueschea72ab22006-01-27 17:26:20 +01003986 err = bcm43xx_dma_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003987
3988 return err;
3989}
3990
3991static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
3992 u8 channel)
3993{
3994 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3995 unsigned long flags;
3996
3997 spin_lock_irqsave(&bcm->lock, flags);
3998 bcm43xx_mac_suspend(bcm);
3999 bcm43xx_radio_selectchannel(bcm, channel, 0);
4000 bcm43xx_mac_enable(bcm);
4001 spin_unlock_irqrestore(&bcm->lock, flags);
4002}
4003
4004/* set_security() callback in struct ieee80211_device */
4005static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
4006 struct ieee80211_security *sec)
4007{
4008 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4009 struct ieee80211_security *secinfo = &bcm->ieee->sec;
4010 unsigned long flags;
4011 int keyidx;
4012
4013 dprintk(KERN_INFO PFX "set security called\n");
4014
4015 spin_lock_irqsave(&bcm->lock, flags);
4016
4017 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
4018 if (sec->flags & (1<<keyidx)) {
4019 secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
4020 secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
4021 memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN);
4022 }
4023
4024 if (sec->flags & SEC_ACTIVE_KEY) {
4025 secinfo->active_key = sec->active_key;
4026 dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key);
4027 }
4028 if (sec->flags & SEC_UNICAST_GROUP) {
4029 secinfo->unicast_uses_group = sec->unicast_uses_group;
4030 dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group);
4031 }
4032 if (sec->flags & SEC_LEVEL) {
4033 secinfo->level = sec->level;
4034 dprintk(KERN_INFO PFX " .level = %d\n", sec->level);
4035 }
4036 if (sec->flags & SEC_ENABLED) {
4037 secinfo->enabled = sec->enabled;
4038 dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled);
4039 }
4040 if (sec->flags & SEC_ENCRYPT) {
4041 secinfo->encrypt = sec->encrypt;
4042 dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt);
4043 }
4044 if (bcm->initialized && !bcm->ieee->host_encrypt) {
4045 if (secinfo->enabled) {
4046 /* upload WEP keys to hardware */
4047 char null_address[6] = { 0 };
4048 u8 algorithm = 0;
4049 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
4050 if (!(sec->flags & (1<<keyidx)))
4051 continue;
4052 switch (sec->encode_alg[keyidx]) {
4053 case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
4054 case SEC_ALG_WEP:
4055 algorithm = BCM43xx_SEC_ALGO_WEP;
4056 if (secinfo->key_sizes[keyidx] == 13)
4057 algorithm = BCM43xx_SEC_ALGO_WEP104;
4058 break;
4059 case SEC_ALG_TKIP:
4060 FIXME();
4061 algorithm = BCM43xx_SEC_ALGO_TKIP;
4062 break;
4063 case SEC_ALG_CCMP:
4064 FIXME();
4065 algorithm = BCM43xx_SEC_ALGO_AES;
4066 break;
4067 default:
4068 assert(0);
4069 break;
4070 }
4071 bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
4072 bcm->key[keyidx].enabled = 1;
4073 bcm->key[keyidx].algorithm = algorithm;
4074 }
4075 } else
4076 bcm43xx_clear_keys(bcm);
4077 }
4078 spin_unlock_irqrestore(&bcm->lock, flags);
4079}
4080
4081/* hard_start_xmit() callback in struct ieee80211_device */
4082static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
4083 struct net_device *net_dev,
4084 int pri)
4085{
4086 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4087 int err = -ENODEV;
4088 unsigned long flags;
4089
4090 spin_lock_irqsave(&bcm->lock, flags);
4091 if (likely(bcm->initialized))
4092 err = bcm43xx_tx(bcm, txb);
4093 spin_unlock_irqrestore(&bcm->lock, flags);
4094
4095 return err;
4096}
4097
4098static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
4099{
4100 return &(bcm43xx_priv(net_dev)->ieee->stats);
4101}
4102
4103static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
4104{
4105 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4106
4107 bcm43xx_controller_restart(bcm, "TX timeout");
4108}
4109
4110#ifdef CONFIG_NET_POLL_CONTROLLER
4111static void bcm43xx_net_poll_controller(struct net_device *net_dev)
4112{
4113 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4114 unsigned long flags;
4115
4116 local_irq_save(flags);
4117 bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
4118 local_irq_restore(flags);
4119}
4120#endif /* CONFIG_NET_POLL_CONTROLLER */
4121
4122static int bcm43xx_net_open(struct net_device *net_dev)
4123{
4124 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4125
4126 return bcm43xx_init_board(bcm);
4127}
4128
4129static int bcm43xx_net_stop(struct net_device *net_dev)
4130{
4131 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4132
4133 ieee80211softmac_stop(net_dev);
4134 bcm43xx_disable_interrupts_sync(bcm, NULL);
4135 bcm43xx_free_board(bcm);
4136
4137 return 0;
4138}
4139
Michael Buesch77db31e2006-02-12 16:47:44 +01004140static int bcm43xx_init_private(struct bcm43xx_private *bcm,
4141 struct net_device *net_dev,
Michael Bueschab4977f2006-02-12 22:40:39 +01004142 struct pci_dev *pci_dev)
John W. Linvillef2223132006-01-23 16:59:58 -05004143{
4144 bcm->ieee = netdev_priv(net_dev);
4145 bcm->softmac = ieee80211_priv(net_dev);
4146 bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
John W. Linvillef2223132006-01-23 16:59:58 -05004147
4148#ifdef DEBUG_ENABLE_MMIO_PRINT
4149 bcm43xx_mmioprint_initial(bcm, 1);
4150#else
4151 bcm43xx_mmioprint_initial(bcm, 0);
4152#endif
4153#ifdef DEBUG_ENABLE_PCILOG
4154 bcm43xx_pciprint_initial(bcm, 1);
4155#else
4156 bcm43xx_pciprint_initial(bcm, 0);
4157#endif
4158
4159 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
4160 bcm->pci_dev = pci_dev;
4161 bcm->net_dev = net_dev;
4162 if (modparam_bad_frames_preempt)
4163 bcm->bad_frames_preempt = 1;
4164 spin_lock_init(&bcm->lock);
4165 tasklet_init(&bcm->isr_tasklet,
4166 (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
4167 (unsigned long)bcm);
4168 tasklet_disable_nosync(&bcm->isr_tasklet);
4169 if (modparam_pio) {
Michael Buesch77db31e2006-02-12 16:47:44 +01004170 bcm->__using_pio = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05004171 } else {
Michael Buesch77db31e2006-02-12 16:47:44 +01004172 if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK)) {
4173#ifdef CONFIG_BCM43XX_PIO
John W. Linvillef2223132006-01-23 16:59:58 -05004174 printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
Michael Buesch77db31e2006-02-12 16:47:44 +01004175 bcm->__using_pio = 1;
4176#else
4177 printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
4178 "Recompile the driver with PIO support, please.\n");
4179 return -ENODEV;
4180#endif /* CONFIG_BCM43XX_PIO */
John W. Linvillef2223132006-01-23 16:59:58 -05004181 }
4182 }
4183 bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
4184
4185 /* default to sw encryption for now */
4186 bcm->ieee->host_build_iv = 0;
4187 bcm->ieee->host_encrypt = 1;
4188 bcm->ieee->host_decrypt = 1;
4189
4190 bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
4191 bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
4192 bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
4193 bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
Michael Buesch77db31e2006-02-12 16:47:44 +01004194
4195 return 0;
John W. Linvillef2223132006-01-23 16:59:58 -05004196}
4197
4198static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
4199 const struct pci_device_id *ent)
4200{
4201 struct net_device *net_dev;
4202 struct bcm43xx_private *bcm;
John W. Linvillef2223132006-01-23 16:59:58 -05004203 int err;
4204
4205#ifdef CONFIG_BCM947XX
4206 if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
4207 return -ENODEV;
4208#endif
4209
4210#ifdef DEBUG_SINGLE_DEVICE_ONLY
4211 if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
4212 return -ENODEV;
4213#endif
4214
4215 net_dev = alloc_ieee80211softmac(sizeof(*bcm));
4216 if (!net_dev) {
4217 printk(KERN_ERR PFX
4218 "could not allocate ieee80211 device %s\n",
4219 pci_name(pdev));
4220 err = -ENOMEM;
4221 goto out;
4222 }
4223 /* initialize the net_device struct */
4224 SET_MODULE_OWNER(net_dev);
4225 SET_NETDEV_DEV(net_dev, &pdev->dev);
4226
4227 net_dev->open = bcm43xx_net_open;
4228 net_dev->stop = bcm43xx_net_stop;
4229 net_dev->get_stats = bcm43xx_net_get_stats;
4230 net_dev->tx_timeout = bcm43xx_net_tx_timeout;
4231#ifdef CONFIG_NET_POLL_CONTROLLER
4232 net_dev->poll_controller = bcm43xx_net_poll_controller;
4233#endif
4234 net_dev->wireless_handlers = &bcm43xx_wx_handlers_def;
4235 net_dev->irq = pdev->irq;
Michael Buesch6465ce12006-02-02 19:11:08 +01004236 SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops);
John W. Linvillef2223132006-01-23 16:59:58 -05004237
4238 /* initialize the bcm43xx_private struct */
4239 bcm = bcm43xx_priv(net_dev);
4240 memset(bcm, 0, sizeof(*bcm));
Michael Bueschab4977f2006-02-12 22:40:39 +01004241 err = bcm43xx_init_private(bcm, net_dev, pdev);
Michael Buesch77db31e2006-02-12 16:47:44 +01004242 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01004243 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05004244
4245 pci_set_drvdata(pdev, net_dev);
4246
4247 err = bcm43xx_attach_board(bcm);
4248 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01004249 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05004250
4251 err = register_netdev(net_dev);
4252 if (err) {
4253 printk(KERN_ERR PFX "Cannot register net device, "
4254 "aborting.\n");
4255 err = -ENOMEM;
4256 goto err_detach_board;
4257 }
4258
4259 bcm43xx_debugfs_add_device(bcm);
4260
4261 assert(err == 0);
4262out:
4263 return err;
4264
4265err_detach_board:
4266 bcm43xx_detach_board(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05004267err_free_netdev:
4268 free_ieee80211softmac(net_dev);
4269 goto out;
4270}
4271
4272static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
4273{
4274 struct net_device *net_dev = pci_get_drvdata(pdev);
4275 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4276
4277 bcm43xx_debugfs_remove_device(bcm);
4278 unregister_netdev(net_dev);
4279 bcm43xx_detach_board(bcm);
4280 assert(bcm->ucode == NULL);
John W. Linvillef2223132006-01-23 16:59:58 -05004281 free_ieee80211softmac(net_dev);
4282}
4283
4284/* Hard-reset the chip. Do not call this directly.
4285 * Use bcm43xx_controller_restart()
4286 */
4287static void bcm43xx_chip_reset(void *_bcm)
4288{
4289 struct bcm43xx_private *bcm = _bcm;
4290 struct net_device *net_dev = bcm->net_dev;
4291 struct pci_dev *pci_dev = bcm->pci_dev;
John W. Linvillef2223132006-01-23 16:59:58 -05004292 int err;
4293 int was_initialized = bcm->initialized;
4294
4295 netif_stop_queue(bcm->net_dev);
4296 tasklet_disable(&bcm->isr_tasklet);
4297
4298 bcm->firmware_norelease = 1;
4299 if (was_initialized)
4300 bcm43xx_free_board(bcm);
4301 bcm->firmware_norelease = 0;
4302 bcm43xx_detach_board(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01004303 err = bcm43xx_init_private(bcm, net_dev, pci_dev);
Michael Buesch77db31e2006-02-12 16:47:44 +01004304 if (err)
4305 goto failure;
John W. Linvillef2223132006-01-23 16:59:58 -05004306 err = bcm43xx_attach_board(bcm);
4307 if (err)
4308 goto failure;
4309 if (was_initialized) {
4310 err = bcm43xx_init_board(bcm);
4311 if (err)
4312 goto failure;
4313 }
4314 netif_wake_queue(bcm->net_dev);
4315 printk(KERN_INFO PFX "Controller restarted\n");
4316
4317 return;
4318failure:
4319 printk(KERN_ERR PFX "Controller restart failed\n");
4320}
4321
4322/* Hard-reset the chip.
4323 * This can be called from interrupt or process context.
4324 * Make sure to _not_ re-enable device interrupts after this has been called.
4325*/
4326void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
4327{
4328 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
4329 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
4330 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01004331 schedule_work(&bcm->restart_work);
John W. Linvillef2223132006-01-23 16:59:58 -05004332}
4333
4334#ifdef CONFIG_PM
4335
4336static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
4337{
4338 struct net_device *net_dev = pci_get_drvdata(pdev);
4339 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4340 unsigned long flags;
4341 int try_to_shutdown = 0, err;
4342
4343 dprintk(KERN_INFO PFX "Suspending...\n");
4344
4345 spin_lock_irqsave(&bcm->lock, flags);
4346 bcm->was_initialized = bcm->initialized;
4347 if (bcm->initialized)
4348 try_to_shutdown = 1;
4349 spin_unlock_irqrestore(&bcm->lock, flags);
4350
4351 netif_device_detach(net_dev);
4352 if (try_to_shutdown) {
4353 ieee80211softmac_stop(net_dev);
4354 err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
4355 if (unlikely(err)) {
4356 dprintk(KERN_ERR PFX "Suspend failed.\n");
4357 return -EAGAIN;
4358 }
4359 bcm->firmware_norelease = 1;
4360 bcm43xx_free_board(bcm);
4361 bcm->firmware_norelease = 0;
4362 }
4363 bcm43xx_chipset_detach(bcm);
4364
4365 pci_save_state(pdev);
4366 pci_disable_device(pdev);
4367 pci_set_power_state(pdev, pci_choose_state(pdev, state));
4368
4369 dprintk(KERN_INFO PFX "Device suspended.\n");
4370
4371 return 0;
4372}
4373
4374static int bcm43xx_resume(struct pci_dev *pdev)
4375{
4376 struct net_device *net_dev = pci_get_drvdata(pdev);
4377 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4378 int err = 0;
4379
4380 dprintk(KERN_INFO PFX "Resuming...\n");
4381
4382 pci_set_power_state(pdev, 0);
4383 pci_enable_device(pdev);
4384 pci_restore_state(pdev);
4385
4386 bcm43xx_chipset_attach(bcm);
4387 if (bcm->was_initialized) {
4388 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
4389 err = bcm43xx_init_board(bcm);
4390 }
4391 if (err) {
4392 printk(KERN_ERR PFX "Resume failed!\n");
4393 return err;
4394 }
4395
4396 netif_device_attach(net_dev);
4397
4398 /*FIXME: This should be handled by softmac instead. */
4399 schedule_work(&bcm->softmac->associnfo.work);
4400
4401 dprintk(KERN_INFO PFX "Device resumed.\n");
4402
4403 return 0;
4404}
4405
4406#endif /* CONFIG_PM */
4407
4408static struct pci_driver bcm43xx_pci_driver = {
Michael Buesch65f3f192006-01-31 20:11:38 +01004409 .name = KBUILD_MODNAME,
John W. Linvillef2223132006-01-23 16:59:58 -05004410 .id_table = bcm43xx_pci_tbl,
4411 .probe = bcm43xx_init_one,
4412 .remove = __devexit_p(bcm43xx_remove_one),
4413#ifdef CONFIG_PM
4414 .suspend = bcm43xx_suspend,
4415 .resume = bcm43xx_resume,
4416#endif /* CONFIG_PM */
4417};
4418
4419static int __init bcm43xx_init(void)
4420{
Michael Buesch65f3f192006-01-31 20:11:38 +01004421 printk(KERN_INFO KBUILD_MODNAME " driver\n");
John W. Linvillef2223132006-01-23 16:59:58 -05004422 bcm43xx_debugfs_init();
4423 return pci_register_driver(&bcm43xx_pci_driver);
4424}
4425
4426static void __exit bcm43xx_exit(void)
4427{
4428 pci_unregister_driver(&bcm43xx_pci_driver);
4429 bcm43xx_debugfs_exit();
4430}
4431
4432module_init(bcm43xx_init)
4433module_exit(bcm43xx_exit)
4434
4435/* vim: set ts=8 sw=8 sts=8: */